Home | History | Annotate | Download | only in ipc
      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