• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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