blob: f5c28cca4a68978b3b5794d12a9d5e7108726eee [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>
12
13#include "base/logging.h"
ssid49c48222016-03-29 04:56:49 +090014#include "base/trace_event/trace_event.h"
mdempskyfba51c12016-02-09 14:41:47 +090015#include "base/tuple.h"
16#include "build/build_config.h"
17#include "ipc/ipc_message.h"
18#include "ipc/ipc_message_utils.h"
19
20namespace IPC {
21
22// This function is for all the async IPCs that don't pass an extra parameter
23// using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
24template <typename ObjT, typename Method, typename P, typename Tuple>
25void DispatchToMethod(ObjT* obj, Method method, P*, const Tuple& tuple) {
26 base::DispatchToMethod(obj, method, tuple);
27}
28
29template <typename ObjT,
30 typename Method,
31 typename P,
32 typename Tuple,
33 size_t... Ns>
34void DispatchToMethodImpl(ObjT* obj,
35 Method method,
36 P* parameter,
37 const Tuple& tuple,
38 base::IndexSequence<Ns...>) {
39 // TODO(mdempsky): Apply UnwrapTraits like base::DispatchToMethod?
tzika088e352016-03-08 14:47:44 +090040 (obj->*method)(parameter, std::get<Ns>(tuple)...);
mdempskyfba51c12016-02-09 14:41:47 +090041}
42
43// The following function is for async IPCs which have a dispatcher with an
44// extra parameter specified using IPC_BEGIN_MESSAGE_MAP_WITH_PARAM.
45template <typename ObjT, typename P, typename... Args, typename... Ts>
46typename std::enable_if<sizeof...(Args) == sizeof...(Ts)>::type
47DispatchToMethod(ObjT* obj,
48 void (ObjT::*method)(P*, Args...),
49 P* parameter,
tzika088e352016-03-08 14:47:44 +090050 const std::tuple<Ts...>& tuple) {
mdempskyfba51c12016-02-09 14:41:47 +090051 DispatchToMethodImpl(obj, method, parameter, tuple,
52 base::MakeIndexSequence<sizeof...(Ts)>());
53}
54
55enum class MessageKind {
56 CONTROL,
57 ROUTED,
58};
59
60// Routing is a helper struct so MessageT's private common constructor has a
61// different type signature than the public "int32_t routing_id" one.
62struct Routing {
63 explicit Routing(int32_t id) : id(id) {}
64 int32_t id;
65};
66
67// We want to restrict MessageT's constructors so that a routing_id is always
68// provided for ROUTED messages and never provided for CONTROL messages, so
69// use the SFINAE technique from N4387's "Implementation Hint" section.
70#if defined(COMPILER_MSVC)
71// MSVC 2013 doesn't support default arguments for template member functions
72// of templated classes, so there we have to rely on the DCHECKs instead.
73// TODO(mdempsky): Reevaluate once MSVC 2015.
74#define IPC_MESSAGET_SFINAE(x)
75#else
76#define IPC_MESSAGET_SFINAE(x) \
77 template <bool X = (x), typename std::enable_if<X, bool>::type = false>
78#endif
79
80// MessageT is the common template used for all user-defined message types.
81// It's intended to be used via the macros defined in ipc_message_macros.h.
82template <typename Meta,
83 typename InTuple = typename Meta::InTuple,
84 typename OutTuple = typename Meta::OutTuple>
85class MessageT;
86
87// Asynchronous message partial specialization.
88template <typename Meta, typename... Ins>
tzika088e352016-03-08 14:47:44 +090089class MessageT<Meta, std::tuple<Ins...>, void> : public Message {
mdempskyfba51c12016-02-09 14:41:47 +090090 public:
tzika088e352016-03-08 14:47:44 +090091 using Param = std::tuple<Ins...>;
mdempskyfba51c12016-02-09 14:41:47 +090092 enum { ID = Meta::ID };
93
94 // TODO(mdempsky): Remove. Uses of MyMessage::Schema::Param can be replaced
95 // with just MyMessage::Param.
96 using Schema = MessageT;
97
98 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
99 MessageT(const Ins&... ins) : MessageT(Routing(MSG_ROUTING_CONTROL), ins...) {
100 DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
101 }
102
103 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
104 MessageT(int32_t routing_id, const Ins&... ins)
105 : MessageT(Routing(routing_id), ins...) {
106 DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
107 }
108
109 static bool Read(const Message* msg, Param* p);
110 static void Log(std::string* name, const Message* msg, std::string* l);
111
112 template <class T, class S, class P, class Method>
113 static bool Dispatch(const Message* msg,
114 T* obj,
115 S* sender,
116 P* parameter,
117 Method func) {
ssid49c48222016-03-29 04:56:49 +0900118 TRACE_EVENT0("ipc", Meta::kName);
mdempskyfba51c12016-02-09 14:41:47 +0900119 Param p;
120 if (Read(msg, &p)) {
121 DispatchToMethod(obj, func, parameter, p);
122 return true;
123 }
124 return false;
125 }
126
127 private:
128 MessageT(Routing routing, const Ins&... ins);
129};
130
131// Synchronous message partial specialization.
132template <typename Meta, typename... Ins, typename... Outs>
tzika088e352016-03-08 14:47:44 +0900133class MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>
mdempskyfba51c12016-02-09 14:41:47 +0900134 : public SyncMessage {
135 public:
tzika088e352016-03-08 14:47:44 +0900136 using SendParam = std::tuple<Ins...>;
137 using ReplyParam = std::tuple<Outs...>;
mdempskyfba51c12016-02-09 14:41:47 +0900138 enum { ID = Meta::ID };
139
140 // TODO(mdempsky): Remove. Uses of MyMessage::Schema::{Send,Reply}Param can
141 // be replaced with just MyMessage::{Send,Reply}Param.
142 using Schema = MessageT;
143
144 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::CONTROL)
145 MessageT(const Ins&... ins, Outs*... outs)
146 : MessageT(Routing(MSG_ROUTING_CONTROL), ins..., outs...) {
147 DCHECK(Meta::kKind == MessageKind::CONTROL) << Meta::kName;
148 }
149
150 IPC_MESSAGET_SFINAE(Meta::kKind == MessageKind::ROUTED)
151 MessageT(int32_t routing_id, const Ins&... ins, Outs*... outs)
152 : MessageT(Routing(routing_id), ins..., outs...) {
153 DCHECK(Meta::kKind == MessageKind::ROUTED) << Meta::kName;
154 }
155
156 static bool ReadSendParam(const Message* msg, SendParam* p);
157 static bool ReadReplyParam(const Message* msg, ReplyParam* p);
158 static void WriteReplyParams(Message* reply, const Outs&... outs);
159 static void Log(std::string* name, const Message* msg, std::string* l);
160
161 template <class T, class S, class P, class Method>
162 static bool Dispatch(const Message* msg,
163 T* obj,
164 S* sender,
165 P* parameter,
166 Method func) {
ssid49c48222016-03-29 04:56:49 +0900167 TRACE_EVENT0("ipc", Meta::kName);
mdempskyfba51c12016-02-09 14:41:47 +0900168 SendParam send_params;
169 bool ok = ReadSendParam(msg, &send_params);
170 Message* reply = SyncMessage::GenerateReply(msg);
171 if (ok) {
172 ReplyParam reply_params;
173 base::DispatchToMethod(obj, func, send_params, &reply_params);
174 WriteParam(reply, reply_params);
175 LogReplyParamsToMessage(reply_params, msg);
176 } else {
177 NOTREACHED() << "Error deserializing message " << msg->type();
178 reply->set_reply_error();
179 }
180 sender->Send(reply);
181 return ok;
182 }
183
184 template <class T, class P, class Method>
185 static bool DispatchDelayReply(const Message* msg,
186 T* obj,
187 P* parameter,
188 Method func) {
ssid49c48222016-03-29 04:56:49 +0900189 TRACE_EVENT0("ipc", Meta::kName);
mdempskyfba51c12016-02-09 14:41:47 +0900190 SendParam send_params;
191 bool ok = ReadSendParam(msg, &send_params);
192 Message* reply = SyncMessage::GenerateReply(msg);
193 if (ok) {
tzika088e352016-03-08 14:47:44 +0900194 std::tuple<Message&> t = std::tie(*reply);
mdempskyfba51c12016-02-09 14:41:47 +0900195 ConnectMessageAndReply(msg, reply);
196 base::DispatchToMethod(obj, func, send_params, &t);
197 } else {
198 NOTREACHED() << "Error deserializing message " << msg->type();
199 reply->set_reply_error();
200 obj->Send(reply);
201 }
202 return ok;
203 }
204
205 private:
206 MessageT(Routing routing, const Ins&... ins, Outs*... outs);
207};
208
209} // namespace IPC
210
211#if defined(IPC_MESSAGE_IMPL)
212#include "ipc/ipc_message_templates_impl.h"
213#endif
214
215#endif // IPC_IPC_MESSAGE_TEMPLATES_H_