blob: 21eaac60b72a0c44324601e1ad1da13dcb9b14c5 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// 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/callback.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::Callback| 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) \
{ \
typedef class_name _IpcMessageHandlerClass ALLOW_UNUSED_TYPE; \
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_