1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef IPC_IPC_MESSAGE_TEMPLATES_H_
6 #define IPC_IPC_MESSAGE_TEMPLATES_H_
7
8 #include <stdint.h>
9
10 #include <tuple>
11 #include <type_traits>
12 #include <utility>
13
14 #include "base/logging.h"
15 #include "base/trace_event/trace_event.h"
16 #include "base/tuple.h"
17 #include "build/build_config.h"
18 #include "ipc/ipc_message.h"
19 #include "ipc/ipc_message_utils.h"
20
21 namespace IPC {
22
23 template <typename Tuple, size_t... Ns>
24 auto TupleForwardImpl(Tuple&& tuple, std::index_sequence<Ns...>) -> decltype(
25 std::forward_as_tuple(std::get<Ns>(std::forward<Tuple>(tuple))...)) {
26 return std::forward_as_tuple(std::get<Ns>(std::forward<Tuple>(tuple))...);
27 }
28
29 // Transforms std::tuple contents to the forwarding form.
30 // Example:
31 // std::tuple<int, int&, const int&, int&&>&&
32 // -> std::tuple<int&&, int&, const int&, int&&>.
33 // const std::tuple<int, const int&, int&&>&
34 // -> std::tuple<const int&, int&, const int&, int&>.
35 //
36 // TupleForward(std::make_tuple(a, b, c)) is equivalent to
37 // std::forward_as_tuple(a, b, c).
38 template <typename Tuple>
39 auto TupleForward(Tuple&& tuple) -> decltype(TupleForwardImpl(
40 std::forward<Tuple>(tuple),
41 std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>())) {
42 return TupleForwardImpl(
43 std::forward<Tuple>(tuple),
44 std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>());
45 }
46
47 // This function is for all the async IPCs that don't pass an extra parameter
48 // using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
49 template <typename ObjT, typename Method, typename P, typename Tuple>
DispatchToMethod(ObjT * obj,Method method,P *,Tuple && tuple)50 void DispatchToMethod(ObjT* obj, Method method, P*, Tuple&& tuple) {
51 base::DispatchToMethod(obj, method, std::forward<Tuple>(tuple));
52 }
53
54 template <typename ObjT,
55 typename Method,
56 typename P,
57 typename Tuple,
58 size_t... Ns>
DispatchToMethodImpl(ObjT * obj,Method method,P * parameter,Tuple && tuple,std::index_sequence<Ns...>)59 void DispatchToMethodImpl(ObjT* obj,
60 Method method,
61 P* parameter,
62 Tuple&& tuple,
63 std::index_sequence<Ns...>) {
64 (obj->*method)(parameter, std::get<Ns>(std::forward<Tuple>(tuple))...);
65 }
66
67 // The following function is for async IPCs which have a dispatcher with an
68 // extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
69 template <typename ObjT, typename P, typename... Args, typename Tuple>
70 std::enable_if_t<sizeof...(Args) == std::tuple_size<std::decay_t<Tuple>>::value>
DispatchToMethod(ObjT * obj,void (ObjT::* method)(P *,Args...),P * parameter,Tuple && tuple)71 DispatchToMethod(ObjT* obj,
72 void (ObjT::*method)(P*, Args...),
73 P* parameter,
74 Tuple&& tuple) {
75 constexpr size_t size = std::tuple_size<std::decay_t<Tuple>>::value;
76 DispatchToMethodImpl(obj, method, parameter, std::forward<Tuple>(tuple),
77 std::make_index_sequence<size>());
78 }
79
80 enum class MessageKind {
81 CONTROL,
82 ROUTED,
83 };
84
85 // Routing is a helper struct so MessageT's private common constructor has a
86 // different type signature than the public "int32_t routing_id" one.
87 struct Routing {
RoutingRouting88 explicit Routing(int32_t id) : id(id) {}
89 int32_t id;
90 };
91
92 // We want to restrict MessageT's constructors so that a routing_id is always
93 // provided for ROUTED messages and never provided for CONTROL messages, so
94 // use the SFINAE technique from N4387's "Implementation Hint" section.
95 #if defined(COMPILER_MSVC)
96 // MSVC 2013 doesn't support default arguments for template member functions
97 // of templated classes, so there we have to rely on the DCHECKs instead.
98 // TODO(mdempsky): Reevaluate once MSVC 2015.
99 #define IPC_MESSAGET_SFINAE(x)
100 #else
101 #define IPC_MESSAGET_SFINAE(x) \
102 template <bool X = (x), typename std::enable_if<X, bool>::type = false>
103 #endif
104
105 // MessageT is the common template used for all user-defined message types.
106 // It's intended to be used via the macros defined in ipc_message_macros.h.
107 template <typename Meta,
108 typename InTuple = typename Meta::InTuple,
109 typename OutTuple = typename Meta::OutTuple>
110 class MessageT;
111
112 // Asynchronous message partial specialization.
113 template <typename Meta, typename... Ins>
114 class MessageT<Meta, std::tuple<Ins...>, void> : public Message {
115 public:
116 using Param = std::tuple<Ins...>;
117 enum { ID = Meta::ID };
118
119 // TODO(mdempsky): Remove. Uses of MyMessage::Schema::Param can be replaced
120 // with just MyMessage::Param.
121 using Schema = MessageT;
122
123 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
MessageT(const Ins &...ins)124 MessageT(const Ins&... ins) : MessageT(Routing(MSG_ROUTING_CONTROL), ins...) {
125 DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
126 }
127
128 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
MessageT(int32_t routing_id,const Ins &...ins)129 MessageT(int32_t routing_id, const Ins&... ins)
130 : MessageT(Routing(routing_id), ins...) {
131 DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
132 }
133
134 static bool Read(const Message* msg, Param* p);
135 static void Log(std::string* name, const Message* msg, std::string* l);
136
137 template <class T, class S, class P, class Method>
Dispatch(const Message * msg,T * obj,S * sender,P * parameter,Method func)138 static bool Dispatch(const Message* msg,
139 T* obj,
140 S* sender,
141 P* parameter,
142 Method func) {
143 TRACE_EVENT0("ipc", Meta::kName);
144 Param p;
145 if (Read(msg, &p)) {
146 DispatchToMethod(obj, func, parameter, std::move(p));
147 return true;
148 }
149 return false;
150 }
151
152 private:
153 MessageT(Routing routing, const Ins&... ins);
154 };
155
156 // Synchronous message partial specialization.
157 template <typename Meta, typename... Ins, typename... Outs>
158 class MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>
159 : public SyncMessage {
160 public:
161 using SendParam = std::tuple<Ins...>;
162 using ReplyParam = std::tuple<Outs...>;
163 enum { ID = Meta::ID };
164
165 // TODO(mdempsky): Remove. Uses of MyMessage::Schema::{Send,Reply}Param can
166 // be replaced with just MyMessage::{Send,Reply}Param.
167 using Schema = MessageT;
168
169 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
MessageT(const Ins &...ins,Outs * ...outs)170 MessageT(const Ins&... ins, Outs*... outs)
171 : MessageT(Routing(MSG_ROUTING_CONTROL), ins..., outs...) {
172 DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
173 }
174
175 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
MessageT(int32_t routing_id,const Ins &...ins,Outs * ...outs)176 MessageT(int32_t routing_id, const Ins&... ins, Outs*... outs)
177 : MessageT(Routing(routing_id), ins..., outs...) {
178 DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
179 }
180
181 static bool ReadSendParam(const Message* msg, SendParam* p);
182 static bool ReadReplyParam(const Message* msg, ReplyParam* p);
183 static void WriteReplyParams(Message* reply, const Outs&... outs);
184 static void Log(std::string* name, const Message* msg, std::string* l);
185
186 template <class T, class S, class P, class Method>
Dispatch(const Message * msg,T * obj,S * sender,P *,Method func)187 static bool Dispatch(const Message* msg,
188 T* obj,
189 S* sender,
190 P* /* parameter */,
191 Method func) {
192 TRACE_EVENT0("ipc", Meta::kName);
193 SendParam send_params;
194 bool ok = ReadSendParam(msg, &send_params);
195 Message* reply = SyncMessage::GenerateReply(msg);
196 if (!ok) {
197 NOTREACHED() << "Error deserializing message " << msg->type();
198 reply->set_reply_error();
199 sender->Send(reply);
200 return false;
201 }
202
203 ReplyParam reply_params;
204 base::DispatchToMethod(obj, func, std::move(send_params), &reply_params);
205 WriteParam(reply, reply_params);
206 LogReplyParamsToMessage(reply_params, msg);
207 sender->Send(reply);
208 return true;
209 }
210
211 template <class T, class P, class Method>
DispatchDelayReply(const Message * msg,T * obj,P *,Method func)212 static bool DispatchDelayReply(const Message* msg,
213 T* obj,
214 P* /* parameter */,
215 Method func) {
216 TRACE_EVENT0("ipc", Meta::kName);
217 SendParam send_params;
218 bool ok = ReadSendParam(msg, &send_params);
219 Message* reply = SyncMessage::GenerateReply(msg);
220 if (!ok) {
221 NOTREACHED() << "Error deserializing message " << msg->type();
222 reply->set_reply_error();
223 obj->Send(reply);
224 return false;
225 }
226
227 std::tuple<Message&> t = std::tie(*reply);
228 ConnectMessageAndReply(msg, reply);
229 base::DispatchToMethod(obj, func, std::move(send_params), &t);
230 return true;
231 }
232
233 template <class T, class P, class Method>
DispatchWithParamDelayReply(const Message * msg,T * obj,P * parameter,Method func)234 static bool DispatchWithParamDelayReply(const Message* msg,
235 T* obj,
236 P* parameter,
237 Method func) {
238 TRACE_EVENT0("ipc", Meta::kName);
239 SendParam send_params;
240 bool ok = ReadSendParam(msg, &send_params);
241 Message* reply = SyncMessage::GenerateReply(msg);
242 if (!ok) {
243 NOTREACHED() << "Error deserializing message " << msg->type();
244 reply->set_reply_error();
245 obj->Send(reply);
246 return false;
247 }
248
249 std::tuple<Message&> t = std::tie(*reply);
250 ConnectMessageAndReply(msg, reply);
251 std::tuple<P*> parameter_tuple(parameter);
252 base::DispatchToMethod(
253 obj, func,
254 std::tuple_cat(std::move(parameter_tuple), TupleForward(send_params)),
255 &t);
256 return true;
257 }
258
259 private:
260 MessageT(Routing routing, const Ins&... ins, Outs*... outs);
261 };
262
263 } // namespace IPC
264
265 #if defined(IPC_MESSAGE_IMPL)
266 #include "ipc/ipc_message_templates_impl.h"
267 #endif
268
269 #endif // IPC_IPC_MESSAGE_TEMPLATES_H_
270