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> 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> 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> 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> 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> 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> 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> 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> 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