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> 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> 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> 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 { 88 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) 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) 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> 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) 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) 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> 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> 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> 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