blob: c856ed98108e7f8028da8d110db3119761d29dcc [file] [log] [blame]
mdempskyfba51c12016-02-09 14:41:47 +09001// 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
tzika088e352016-03-08 14:47:44 +090010#include <tuple>
mdempskyfba51c12016-02-09 14:41:47 +090011#include <type_traits>
Jeremy Roman773e7f22017-08-17 00:55:20 +090012#include <utility>
mdempskyfba51c12016-02-09 14:41:47 +090013
14#include "base/logging.h"
ssid49c48222016-03-29 04:56:49 +090015#include "base/trace_event/trace_event.h"
mdempskyfba51c12016-02-09 14:41:47 +090016#include "base/tuple.h"
17#include "build/build_config.h"
18#include "ipc/ipc_message.h"
19#include "ipc/ipc_message_utils.h"
20
21namespace IPC {
22
tzikc8447f52017-08-31 20:49:59 +090023template <typename Tuple, size_t... Ns>
24auto 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).
38template <typename Tuple>
39auto 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
mdempskyfba51c12016-02-09 14:41:47 +090047// This function is for all the async IPCs that don't pass an extra parameter
48// using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
49template <typename ObjT, typename Method, typename P, typename Tuple>
tzikd1402912017-08-30 22:39:03 +090050void DispatchToMethod(ObjT* obj, Method method, P*, Tuple&& tuple) {
51 base::DispatchToMethod(obj, method, std::forward<Tuple>(tuple));
mdempskyfba51c12016-02-09 14:41:47 +090052}
53
54template <typename ObjT,
55 typename Method,
56 typename P,
57 typename Tuple,
58 size_t... Ns>
59void DispatchToMethodImpl(ObjT* obj,
60 Method method,
61 P* parameter,
tzikd1402912017-08-30 22:39:03 +090062 Tuple&& tuple,
Jeremy Roman773e7f22017-08-17 00:55:20 +090063 std::index_sequence<Ns...>) {
tzikd1402912017-08-30 22:39:03 +090064 (obj->*method)(parameter, std::get<Ns>(std::forward<Tuple>(tuple))...);
mdempskyfba51c12016-02-09 14:41:47 +090065}
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.
tzikd1402912017-08-30 22:39:03 +090069template <typename ObjT, typename P, typename... Args, typename Tuple>
70std::enable_if_t<sizeof...(Args) == std::tuple_size<std::decay_t<Tuple>>::value>
mdempskyfba51c12016-02-09 14:41:47 +090071DispatchToMethod(ObjT* obj,
72 void (ObjT::*method)(P*, Args...),
73 P* parameter,
tzikd1402912017-08-30 22:39:03 +090074 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>());
mdempskyfba51c12016-02-09 14:41:47 +090078}
79
80enum 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.
87struct 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.
107template <typename Meta,
108 typename InTuple = typename Meta::InTuple,
109 typename OutTuple = typename Meta::OutTuple>
110class MessageT;
111
112// Asynchronous message partial specialization.
113template <typename Meta, typename... Ins>
tzika088e352016-03-08 14:47:44 +0900114class MessageT<Meta, std::tuple<Ins...>, void> : public Message {
mdempskyfba51c12016-02-09 14:41:47 +0900115 public:
tzika088e352016-03-08 14:47:44 +0900116 using Param = std::tuple<Ins...>;
mdempskyfba51c12016-02-09 14:41:47 +0900117 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) {
ssid49c48222016-03-29 04:56:49 +0900143 TRACE_EVENT0("ipc", Meta::kName);
mdempskyfba51c12016-02-09 14:41:47 +0900144 Param p;
145 if (Read(msg, &p)) {
tzikd1402912017-08-30 22:39:03 +0900146 DispatchToMethod(obj, func, parameter, std::move(p));
mdempskyfba51c12016-02-09 14:41:47 +0900147 return true;
148 }
149 return false;
150 }
151
152 private:
153 MessageT(Routing routing, const Ins&... ins);
154};
155
156// Synchronous message partial specialization.
157template <typename Meta, typename... Ins, typename... Outs>
tzika088e352016-03-08 14:47:44 +0900158class MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>
mdempskyfba51c12016-02-09 14:41:47 +0900159 : public SyncMessage {
160 public:
tzika088e352016-03-08 14:47:44 +0900161 using SendParam = std::tuple<Ins...>;
162 using ReplyParam = std::tuple<Outs...>;
mdempskyfba51c12016-02-09 14:41:47 +0900163 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,
thestig286ee102016-11-17 14:56:32 +0900190 P* /* parameter */,
mdempskyfba51c12016-02-09 14:41:47 +0900191 Method func) {
ssid49c48222016-03-29 04:56:49 +0900192 TRACE_EVENT0("ipc", Meta::kName);
mdempskyfba51c12016-02-09 14:41:47 +0900193 SendParam send_params;
194 bool ok = ReadSendParam(msg, &send_params);
195 Message* reply = SyncMessage::GenerateReply(msg);
tzikc8447f52017-08-31 20:49:59 +0900196 if (!ok) {
mdempskyfba51c12016-02-09 14:41:47 +0900197 NOTREACHED() << "Error deserializing message " << msg->type();
198 reply->set_reply_error();
tzikc8447f52017-08-31 20:49:59 +0900199 sender->Send(reply);
200 return false;
mdempskyfba51c12016-02-09 14:41:47 +0900201 }
tzikc8447f52017-08-31 20:49:59 +0900202
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);
mdempskyfba51c12016-02-09 14:41:47 +0900207 sender->Send(reply);
tzikc8447f52017-08-31 20:49:59 +0900208 return true;
mdempskyfba51c12016-02-09 14:41:47 +0900209 }
210
211 template <class T, class P, class Method>
212 static bool DispatchDelayReply(const Message* msg,
213 T* obj,
thestig286ee102016-11-17 14:56:32 +0900214 P* /* parameter */,
mdempskyfba51c12016-02-09 14:41:47 +0900215 Method func) {
ssid49c48222016-03-29 04:56:49 +0900216 TRACE_EVENT0("ipc", Meta::kName);
mdempskyfba51c12016-02-09 14:41:47 +0900217 SendParam send_params;
218 bool ok = ReadSendParam(msg, &send_params);
219 Message* reply = SyncMessage::GenerateReply(msg);
tzikc8447f52017-08-31 20:49:59 +0900220 if (!ok) {
mdempskyfba51c12016-02-09 14:41:47 +0900221 NOTREACHED() << "Error deserializing message " << msg->type();
222 reply->set_reply_error();
223 obj->Send(reply);
tzikc8447f52017-08-31 20:49:59 +0900224 return false;
mdempskyfba51c12016-02-09 14:41:47 +0900225 }
tzikc8447f52017-08-31 20:49:59 +0900226
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;
mdempskyfba51c12016-02-09 14:41:47 +0900231 }
232
thestig286ee102016-11-17 14:56:32 +0900233 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);
tzikc8447f52017-08-31 20:49:59 +0900242 if (!ok) {
thestig286ee102016-11-17 14:56:32 +0900243 NOTREACHED() << "Error deserializing message " << msg->type();
244 reply->set_reply_error();
245 obj->Send(reply);
tzikc8447f52017-08-31 20:49:59 +0900246 return false;
thestig286ee102016-11-17 14:56:32 +0900247 }
tzikc8447f52017-08-31 20:49:59 +0900248
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;
thestig286ee102016-11-17 14:56:32 +0900257 }
258
mdempskyfba51c12016-02-09 14:41:47 +0900259 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_