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 #include "ppapi/proxy/ppp_messaging_proxy.h"
6
7 #include <algorithm>
8
9 #include "ppapi/c/ppp_messaging.h"
10 #include "ppapi/proxy/host_dispatcher.h"
11 #include "ppapi/proxy/message_handler.h"
12 #include "ppapi/proxy/plugin_dispatcher.h"
13 #include "ppapi/proxy/plugin_resource_tracker.h"
14 #include "ppapi/proxy/plugin_var_tracker.h"
15 #include "ppapi/proxy/ppapi_messages.h"
16 #include "ppapi/proxy/serialized_var.h"
17 #include "ppapi/shared_impl/ppapi_globals.h"
18 #include "ppapi/shared_impl/proxy_lock.h"
19 #include "ppapi/shared_impl/scoped_pp_var.h"
20 #include "ppapi/shared_impl/var_tracker.h"
21
22 namespace ppapi {
23 namespace proxy {
24
25 namespace {
26
GetMessageHandler(Dispatcher * dispatcher,PP_Instance instance)27 MessageHandler* GetMessageHandler(Dispatcher* dispatcher,
28 PP_Instance instance) {
29 if (!dispatcher || !dispatcher->IsPlugin()) {
30 NOTREACHED();
31 return NULL;
32 }
33 PluginDispatcher* plugin_dispatcher =
34 static_cast<PluginDispatcher*>(dispatcher);
35 InstanceData* instance_data = plugin_dispatcher->GetInstanceData(instance);
36 if (!instance_data)
37 return NULL;
38
39 return instance_data->message_handler.get();
40 }
41
ResetMessageHandler(Dispatcher * dispatcher,PP_Instance instance)42 void ResetMessageHandler(Dispatcher* dispatcher, PP_Instance instance) {
43 if (!dispatcher || !dispatcher->IsPlugin()) {
44 NOTREACHED();
45 return;
46 }
47 PluginDispatcher* plugin_dispatcher =
48 static_cast<PluginDispatcher*>(dispatcher);
49 InstanceData* instance_data = plugin_dispatcher->GetInstanceData(instance);
50 if (!instance_data)
51 return;
52
53 instance_data->message_handler.reset();
54 }
55
56 } // namespace
57
PPP_Messaging_Proxy(Dispatcher * dispatcher)58 PPP_Messaging_Proxy::PPP_Messaging_Proxy(Dispatcher* dispatcher)
59 : InterfaceProxy(dispatcher),
60 ppp_messaging_impl_(NULL) {
61 if (dispatcher->IsPlugin()) {
62 ppp_messaging_impl_ = static_cast<const PPP_Messaging*>(
63 dispatcher->local_get_interface()(PPP_MESSAGING_INTERFACE));
64 }
65 }
66
~PPP_Messaging_Proxy()67 PPP_Messaging_Proxy::~PPP_Messaging_Proxy() {
68 }
69
OnMessageReceived(const IPC::Message & msg)70 bool PPP_Messaging_Proxy::OnMessageReceived(const IPC::Message& msg) {
71 if (!dispatcher()->IsPlugin())
72 return false;
73
74 bool handled = true;
75 IPC_BEGIN_MESSAGE_MAP(PPP_Messaging_Proxy, msg)
76 IPC_MESSAGE_HANDLER(PpapiMsg_PPPMessaging_HandleMessage,
77 OnMsgHandleMessage)
78 IPC_MESSAGE_HANDLER_DELAY_REPLY(
79 PpapiMsg_PPPMessageHandler_HandleBlockingMessage,
80 OnMsgHandleBlockingMessage)
81 IPC_MESSAGE_UNHANDLED(handled = false)
82 IPC_END_MESSAGE_MAP()
83 return handled;
84 }
85
OnMsgHandleMessage(PP_Instance instance,SerializedVarReceiveInput message_data)86 void PPP_Messaging_Proxy::OnMsgHandleMessage(
87 PP_Instance instance, SerializedVarReceiveInput message_data) {
88 PP_Var received_var(message_data.GetForInstance(dispatcher(), instance));
89 MessageHandler* message_handler = GetMessageHandler(dispatcher(), instance);
90 if (message_handler) {
91 if (message_handler->LoopIsValid()) {
92 message_handler->HandleMessage(ScopedPPVar(received_var));
93 return;
94 } else {
95 // If the MessageHandler's loop has been quit, then we should treat it as
96 // though it has been unregistered and start sending messages to the
97 // default handler. This might mean the plugin has lost messages, but
98 // there's not really anything sane we can do about it. They should have
99 // used UnregisterMessageHandler.
100 ResetMessageHandler(dispatcher(), instance);
101 }
102 }
103 // If we reach this point, then there's no message handler registered, so
104 // we send to the default PPP_Messaging one for the instance.
105
106 // SerializedVarReceiveInput will decrement the reference count, but we want
107 // to give the recipient a reference in the legacy API.
108 PpapiGlobals::Get()->GetVarTracker()->AddRefVar(received_var);
109 CallWhileUnlocked(ppp_messaging_impl_->HandleMessage,
110 instance,
111 received_var);
112 }
113
OnMsgHandleBlockingMessage(PP_Instance instance,SerializedVarReceiveInput message_data,IPC::Message * reply_msg)114 void PPP_Messaging_Proxy::OnMsgHandleBlockingMessage(
115 PP_Instance instance,
116 SerializedVarReceiveInput message_data,
117 IPC::Message* reply_msg) {
118 ScopedPPVar received_var(message_data.GetForInstance(dispatcher(), instance));
119 MessageHandler* message_handler = GetMessageHandler(dispatcher(), instance);
120 if (message_handler) {
121 if (message_handler->LoopIsValid()) {
122 message_handler->HandleBlockingMessage(
123 received_var, scoped_ptr<IPC::Message>(reply_msg));
124 return;
125 } else {
126 // If the MessageHandler's loop has been quit, then we should treat it as
127 // though it has been unregistered. Also see the note for PostMessage.
128 ResetMessageHandler(dispatcher(), instance);
129 }
130 }
131 // We have no handler, but we still need to respond to unblock the renderer
132 // and inform the JavaScript caller.
133 PpapiMsg_PPPMessageHandler_HandleBlockingMessage::WriteReplyParams(
134 reply_msg,
135 SerializedVarReturnValue::Convert(dispatcher(), PP_MakeUndefined()),
136 false /* was_handled */);
137 dispatcher()->Send(reply_msg);
138 }
139
140
141 } // namespace proxy
142 } // namespace ppapi
143