1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file provides infrastructure for dispatching messasges from host
// resource, inlcuding reply messages or unsolicited replies. Normal IPC Reply
// handlers can't take extra parameters. We want to take a
// ResourceMessageReplyParams as a parameter.
#ifndef PPAPI_PROXY_DISPATCH_REPLY_MESSAGE_H_
#define PPAPI_PROXY_DISPATCH_REPLY_MESSAGE_H_
#include <tuple>
#include <utility>
#include "base/functional/callback.h"
#include "base/notreached.h"
#include "base/tuple.h"
#include "ipc/ipc_message_macros.h"
#include "ppapi/c/pp_errors.h"
namespace ppapi {
namespace proxy {
class ResourceMessageReplyParams;
template <typename ObjT, typename Method, typename TupleType, size_t... indices>
inline void DispatchResourceReplyImpl(ObjT* obj,
Method method,
const ResourceMessageReplyParams& params,
TupleType&& args_tuple,
std::index_sequence<indices...>) {
(obj->*method)(params,
std::get<indices>(std::forward<TupleType>(args_tuple))...);
}
// Runs |method| on |obj| with |params| and expanded |args_tuple|.
// I.e. Followings are equivalent.
// DispatchResourceReply(obj, &Obj::Method, params, std::tie(a, b, c));
// obj->Method(params, a, b, c);
template <typename ObjT, typename Method, typename TupleType>
inline void DispatchResourceReply(ObjT* obj,
Method method,
const ResourceMessageReplyParams& params,
TupleType&& args_tuple) {
constexpr size_t size = std::tuple_size<std::decay_t<TupleType>>::value;
DispatchResourceReplyImpl(obj, method, params,
std::forward<TupleType>(args_tuple),
std::make_index_sequence<size>());
}
template <typename CallbackType, typename TupleType, size_t... indices>
inline void DispatchResourceReplyImpl(CallbackType&& callback,
const ResourceMessageReplyParams& params,
TupleType&& args_tuple,
std::index_sequence<indices...>) {
std::forward<CallbackType>(callback).Run(
params, std::get<indices>(std::forward<TupleType>(args_tuple))...);
}
// Runs |callback| with |params| and expanded |args_tuple|.
// I.e. Followings are equivalent.
// DispatchResourceReply(callback, params, std::tie(a, b, c));
// callback.Run(params, a, b, c);
template <typename CallbackType, typename TupleType>
inline void DispatchResourceReply(CallbackType&& callback,
const ResourceMessageReplyParams& params,
TupleType&& args_tuple) {
constexpr size_t size = std::tuple_size<std::decay_t<TupleType>>::value;
DispatchResourceReplyImpl(std::forward<CallbackType>(callback), params,
std::forward<TupleType>(args_tuple),
std::make_index_sequence<size>());
}
// Used to dispatch resource replies. In most cases, you should not call this
// function to dispatch a resource reply manually, but instead use
// |PluginResource::CallBrowser|/|PluginResource::CallRenderer| with a
// |base::OnceCallback| which will be called when a reply message is received
// (see plugin_resource.h).
//
// This function will call your callback with the nested reply message's
// parameters on success. On failure, your callback will be called with each
// parameter having its default constructed value.
//
// Resource replies are a bit weird in that the host will automatically
// generate a reply in error cases (when the call handler returns error rather
// than returning "completion pending"). This makes it more convenient to write
// the call message handlers. But this also means that the reply handler has to
// handle both the success case (when all of the reply message paramaters are
// specified) and the error case (when the nested reply message is empty).
// In both cases the resource will want to issue completion callbacks to the
// plugin.
//
// This function handles the error case by calling your reply handler with the
// default value for each paramater in the error case. In most situations this
// will be the right thing. You should always dispatch completion callbacks
// using the result code present in the ResourceMessageReplyParams.
template<class MsgClass, class ObjT, class Method>
void DispatchResourceReplyOrDefaultParams(
ObjT* obj,
Method method,
const ResourceMessageReplyParams& reply_params,
const IPC::Message& msg) {
typename MsgClass::Schema::Param msg_params;
// We either expect the nested message type to match, or that there is no
// nested message. No nested message indicates a default reply sent from
// the host: when the resource message handler returns an error, a reply
// is implicitly sent with no nested message.
DCHECK(msg.type() == MsgClass::ID || msg.type() == 0)
<< "Resource reply message of unexpected type.";
if (msg.type() == MsgClass::ID && MsgClass::Read(&msg, &msg_params)) {
// Message type matches and the parameters were successfully read.
DispatchResourceReply(obj, method, reply_params, msg_params);
} else {
// The nested message is empty because the host handler didn't explicitly
// send a reply (likely), or you screwed up and didn't use the correct
// message type when calling this function (you should have hit the
// assertion above, Einstein).
//
// Dispatch the reply function with the default parameters. We explicitly
// use a new Params() structure since if the Read failed due to an invalid
// message, the params could have been partially filled in.
DispatchResourceReply(obj, method, reply_params,
typename MsgClass::Schema::Param());
}
}
template <typename MsgClass, typename CallbackType>
void DispatchResourceReplyOrDefaultParams(
CallbackType&& callback,
const ResourceMessageReplyParams& reply_params,
const IPC::Message& msg) {
typename MsgClass::Schema::Param msg_params;
// We either expect the nested message type to match, or that there is no
// nested message. No nested message indicates a default reply sent from
// the host: when the resource message handler returns an error, a reply
// is implicitly sent with no nested message.
DCHECK(msg.type() == MsgClass::ID || msg.type() == 0)
<< "Resource reply message of unexpected type.";
if (msg.type() == MsgClass::ID && MsgClass::Read(&msg, &msg_params)) {
// Message type matches and the parameters were successfully read.
DispatchResourceReply(std::forward<CallbackType>(callback), reply_params,
msg_params);
} else {
// The nested message is empty because the host handler didn't explicitly
// send a reply (likely), or you screwed up and didn't use the correct
// message type when calling this function (you should have hit the
// assertion above, Einstein).
//
// Dispatch the reply function with the default parameters. We explicitly
// use a new Params() structure since if the Read failed due to an invalid
// message, the params could have been partially filled in.
DispatchResourceReply(std::forward<CallbackType>(callback), reply_params,
typename MsgClass::Schema::Param());
}
}
// When using PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL* below, use this macro to
// begin the map instead of IPC_BEGIN_MESSAGE_MAP. The reason is that the macros
// in src/ipc are all closely tied together, and there might be errors for
// unused variables or other errors if they're used with these macros.
#define PPAPI_BEGIN_MESSAGE_MAP(class_name, msg) \
{ \
using _IpcMessageHandlerClass [[maybe_unused]] = class_name; \
const IPC::Message& ipc_message__ = msg; \
switch (ipc_message__.type()) {
// Note that this only works for message with 1 or more parameters. For
// 0-parameter messages you need to use the _0 version below (since there are
// no params in the message).
#define PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL(msg_class, member_func) \
case msg_class::ID: { \
msg_class::Schema::Param p; \
if (msg_class::Read(&ipc_message__, &p)) { \
ppapi::proxy::DispatchResourceReply( \
this, &_IpcMessageHandlerClass::member_func, params, p); \
} else { \
NOTREACHED(); \
} \
break; \
}
#define PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_0(msg_class, member_func) \
case msg_class::ID: { \
member_func(params); \
break; \
}
#define PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL_UNHANDLED(code) \
default: { \
code; \
} \
break;
#define PPAPI_END_MESSAGE_MAP() \
} \
}
} // namespace proxy
} // namespace ppapi
#endif // PPAPI_PROXY_DISPATCH_REPLY_MESSAGE_H_
|