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