• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  // Copyright (c) 2012 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  // This file provides infrastructure for dispatching messasges from host
6  // resource, inlcuding reply messages or unsolicited replies. Normal IPC Reply
7  // handlers can't take extra parameters. We want to take a
8  // ResourceMessageReplyParams as a parameter.
9  
10  #ifndef PPAPI_PROXY_DISPATCH_REPLY_MESSAGE_H_
11  #define PPAPI_PROXY_DISPATCH_REPLY_MESSAGE_H_
12  
13  #include "base/callback.h"
14  #include "base/profiler/scoped_profile.h"  // For TRACK_RUN_IN_IPC_HANDLER.
15  #include "ipc/ipc_message_macros.h"
16  #include "ppapi/c/pp_errors.h"
17  
18  namespace ppapi {
19  namespace proxy {
20  
21  class ResourceMessageReplyParams;
22  
23  template <class ObjT, class Method>
DispatchResourceReply(ObjT * obj,Method method,const ResourceMessageReplyParams & params,const Tuple0 & arg)24  inline void DispatchResourceReply(ObjT* obj, Method method,
25                                    const ResourceMessageReplyParams& params,
26                                    const Tuple0& arg) {
27    (obj->*method)(params);
28  }
29  
30  template <class ObjT, class Method, class A>
DispatchResourceReply(ObjT * obj,Method method,const ResourceMessageReplyParams & params,const Tuple1<A> & arg)31  inline void DispatchResourceReply(ObjT* obj, Method method,
32                                    const ResourceMessageReplyParams& params,
33                                    const Tuple1<A>& arg) {
34    (obj->*method)(params, arg.a);
35  }
36  
37  template<class ObjT, class Method, class A, class B>
DispatchResourceReply(ObjT * obj,Method method,const ResourceMessageReplyParams & params,const Tuple2<A,B> & arg)38  inline void DispatchResourceReply(ObjT* obj, Method method,
39                                    const ResourceMessageReplyParams& params,
40                                    const Tuple2<A, B>& arg) {
41    (obj->*method)(params, arg.a, arg.b);
42  }
43  
44  template<class ObjT, class Method, class A, class B, class C>
DispatchResourceReply(ObjT * obj,Method method,const ResourceMessageReplyParams & params,const Tuple3<A,B,C> & arg)45  inline void DispatchResourceReply(ObjT* obj, Method method,
46                                    const ResourceMessageReplyParams& params,
47                                    const Tuple3<A, B, C>& arg) {
48    (obj->*method)(params, arg.a, arg.b, arg.c);
49  }
50  
51  template<class ObjT, class Method, class A, class B, class C, class D>
DispatchResourceReply(ObjT * obj,Method method,const ResourceMessageReplyParams & params,const Tuple4<A,B,C,D> & arg)52  inline void DispatchResourceReply(ObjT* obj, Method method,
53                                    const ResourceMessageReplyParams& params,
54                                    const Tuple4<A, B, C, D>& arg) {
55    (obj->*method)(params, arg.a, arg.b, arg.c, arg.d);
56  }
57  
58  template<class ObjT, class Method, class A, class B, class C, class D, class E>
DispatchResourceReply(ObjT * obj,Method method,const ResourceMessageReplyParams & params,const Tuple5<A,B,C,D,E> & arg)59  inline void DispatchResourceReply(ObjT* obj, Method method,
60                                    const ResourceMessageReplyParams& params,
61                                    const Tuple5<A, B, C, D, E>& arg) {
62    (obj->*method)(params, arg.a, arg.b, arg.c, arg.d, arg.e);
63  }
64  
65  // Used to dispatch resource replies. In most cases, you should not call this
66  // function to dispatch a resource reply manually, but instead use
67  // |PluginResource::CallBrowser|/|PluginResource::CallRenderer| with a
68  // |base::Callback| which will be called when a reply message is received
69  // (see plugin_resource.h).
70  //
71  // This function will call your callback with the nested reply message's
72  // parameters on success. On failure, your callback will be called with each
73  // parameter having its default constructed value.
74  //
75  // Resource replies are a bit weird in that the host will automatically
76  // generate a reply in error cases (when the call handler returns error rather
77  // than returning "completion pending"). This makes it more convenient to write
78  // the call message handlers. But this also means that the reply handler has to
79  // handle both the success case (when all of the reply message paramaters are
80  // specified) and the error case (when the nested reply message is empty).
81  // In both cases the resource will want to issue completion callbacks to the
82  // plugin.
83  //
84  // This function handles the error case by calling your reply handler with the
85  // default value for each paramater in the error case. In most situations this
86  // will be the right thing. You should always dispatch completion callbacks
87  // using the result code present in the ResourceMessageReplyParams.
88  template<class MsgClass, class ObjT, class Method>
DispatchResourceReplyOrDefaultParams(ObjT * obj,Method method,const ResourceMessageReplyParams & reply_params,const IPC::Message & msg)89  void DispatchResourceReplyOrDefaultParams(
90      ObjT* obj,
91      Method method,
92      const ResourceMessageReplyParams& reply_params,
93      const IPC::Message& msg) {
94    typename MsgClass::Schema::Param msg_params;
95    // We either expect the nested message type to match, or that there is no
96    // nested message. No nested message indicates a default reply sent from
97    // the host: when the resource message handler returns an error, a reply
98    // is implicitly sent with no nested message.
99    DCHECK(msg.type() == MsgClass::ID || msg.type() == 0)
100        << "Resource reply message of unexpected type.";
101    if (msg.type() == MsgClass::ID && MsgClass::Read(&msg, &msg_params)) {
102      // Message type matches and the parameters were successfully read.
103      DispatchResourceReply(obj, method, reply_params, msg_params);
104    } else {
105      // The nested message is empty because the host handler didn't explicitly
106      // send a reply (likely), or you screwed up and didn't use the correct
107      // message type when calling this function (you should have hit the
108      // assertion above, Einstein).
109      //
110      // Dispatch the reply function with the default parameters. We explicitly
111      // use a new Params() structure since if the Read failed due to an invalid
112      // message, the params could have been partially filled in.
113      DispatchResourceReply(obj, method, reply_params,
114          typename MsgClass::Schema::Param());
115    }
116  }
117  
118  // Template specialization for |Callback|s that only accept a
119  // |ResourceMessageReplyParams|. In this case |msg| shouldn't contain any
120  // arguments, so just call the |method| with the |reply_params|.
121  template<class MsgClass, class Method>
DispatchResourceReplyOrDefaultParams(base::Callback<void (const ResourceMessageReplyParams &)> * obj,Method method,const ResourceMessageReplyParams & reply_params,const IPC::Message & msg)122  void DispatchResourceReplyOrDefaultParams(
123      base::Callback<void(const ResourceMessageReplyParams&)>* obj,
124      Method method,
125      const ResourceMessageReplyParams& reply_params,
126      const IPC::Message& msg) {
127    DCHECK(msg.type() == MsgClass::ID || msg.type() == 0)
128        << "Resource reply message of unexpected type.";
129    (obj->*method)(reply_params);
130  }
131  
132  // Note that this only works for message with 1 or more parameters. For
133  // 0-parameter messages you need to use the _0 version below (since there are
134  // no params in the message).
135  #define PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(msg_class, member_func) \
136      case msg_class::ID: { \
137        msg_class::Schema::Param p; \
138        if (msg_class::Read(&ipc_message__, &p)) { \
139          ppapi::proxy::DispatchResourceReply( \
140              this, \
141              &_IpcMessageHandlerClass::member_func, \
142              params, p); \
143        } else { \
144          NOTREACHED(); \
145        } \
146        break; \
147      }
148  
149  #define PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_0(msg_class, member_func) \
150    case msg_class::ID: { \
151      member_func(params); \
152      break; \
153    }
154  
155  #define PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(code) \
156      default: { \
157          code; \
158      } \
159      break;
160  
161  }  // namespace proxy
162  }  // namespace ppapi
163  
164  #endif  // PPAPI_PROXY_DISPATCH_REPLY_MESSAGE_H_
165