1 /*
2 * Copyright (C) 2009 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "PlatformMessagePortChannel.h"
33
34 #include "MessagePort.h"
35 #include "ScriptExecutionContext.h"
36 #include "SerializedScriptValue.h"
37
38 #include "WebKit.h"
39 #include "WebKitClient.h"
40 #include "WebMessagePortChannel.h"
41 #include "WebString.h"
42
43 using namespace WebKit;
44
45 namespace WebCore {
46
create(PassRefPtr<PlatformMessagePortChannel> channel)47 PassOwnPtr<MessagePortChannel> MessagePortChannel::create(PassRefPtr<PlatformMessagePortChannel> channel)
48 {
49 return new MessagePortChannel(channel);
50 }
51
createChannel(PassRefPtr<MessagePort> port1,PassRefPtr<MessagePort> port2)52 void MessagePortChannel::createChannel(PassRefPtr<MessagePort> port1, PassRefPtr<MessagePort> port2)
53 {
54 PlatformMessagePortChannel::createChannel(port1, port2);
55 }
56
MessagePortChannel(PassRefPtr<PlatformMessagePortChannel> channel)57 MessagePortChannel::MessagePortChannel(PassRefPtr<PlatformMessagePortChannel> channel)
58 : m_channel(channel)
59 {
60 }
61
~MessagePortChannel()62 MessagePortChannel::~MessagePortChannel()
63 {
64 // Make sure we close our platform channel when the base is freed, to keep the channel objects from leaking.
65 m_channel->close();
66 }
67
entangleIfOpen(MessagePort * port)68 bool MessagePortChannel::entangleIfOpen(MessagePort* port)
69 {
70 return m_channel->entangleIfOpen(port);
71 }
72
disentangle()73 void MessagePortChannel::disentangle()
74 {
75 m_channel->disentangle();
76 }
77
postMessageToRemote(PassOwnPtr<MessagePortChannel::EventData> message)78 void MessagePortChannel::postMessageToRemote(PassOwnPtr<MessagePortChannel::EventData> message)
79 {
80 m_channel->postMessageToRemote(message);
81 }
82
tryGetMessageFromRemote(OwnPtr<MessagePortChannel::EventData> & result)83 bool MessagePortChannel::tryGetMessageFromRemote(OwnPtr<MessagePortChannel::EventData>& result)
84 {
85 return m_channel->tryGetMessageFromRemote(result);
86 }
87
close()88 void MessagePortChannel::close()
89 {
90 m_channel->close();
91 }
92
isConnectedTo(MessagePort * port)93 bool MessagePortChannel::isConnectedTo(MessagePort* port)
94 {
95 return m_channel->isConnectedTo(port);
96 }
97
hasPendingActivity()98 bool MessagePortChannel::hasPendingActivity()
99 {
100 return m_channel->hasPendingActivity();
101 }
102
locallyEntangledPort(const ScriptExecutionContext * context)103 MessagePort* MessagePortChannel::locallyEntangledPort(const ScriptExecutionContext* context)
104 {
105 // This is just an optimization, so return 0 always.
106 return 0;
107 }
108
109
create()110 PassRefPtr<PlatformMessagePortChannel> PlatformMessagePortChannel::create()
111 {
112 return adoptRef(new PlatformMessagePortChannel());
113 }
114
create(WebMessagePortChannel * channel)115 PassRefPtr<PlatformMessagePortChannel> PlatformMessagePortChannel::create(
116 WebMessagePortChannel* channel)
117 {
118 return adoptRef(new PlatformMessagePortChannel(channel));
119 }
120
121
PlatformMessagePortChannel()122 PlatformMessagePortChannel::PlatformMessagePortChannel()
123 : m_localPort(0)
124 {
125 m_webChannel = webKitClient()->createMessagePortChannel();
126 if (m_webChannel)
127 m_webChannel->setClient(this);
128 }
129
PlatformMessagePortChannel(WebMessagePortChannel * channel)130 PlatformMessagePortChannel::PlatformMessagePortChannel(WebMessagePortChannel* channel)
131 : m_localPort(0)
132 , m_webChannel(channel)
133 {
134 }
135
~PlatformMessagePortChannel()136 PlatformMessagePortChannel::~PlatformMessagePortChannel()
137 {
138 if (m_webChannel)
139 m_webChannel->destroy();
140 }
141
createChannel(PassRefPtr<MessagePort> port1,PassRefPtr<MessagePort> port2)142 void PlatformMessagePortChannel::createChannel(PassRefPtr<MessagePort> port1, PassRefPtr<MessagePort> port2)
143 {
144 // Create proxies for each endpoint.
145 RefPtr<PlatformMessagePortChannel> channel1 = PlatformMessagePortChannel::create();
146 RefPtr<PlatformMessagePortChannel> channel2 = PlatformMessagePortChannel::create();
147
148 // Entangle the two endpoints.
149 channel1->setEntangledChannel(channel2);
150 channel2->setEntangledChannel(channel1);
151
152 // Now entangle the proxies with the appropriate local ports.
153 port1->entangle(MessagePortChannel::create(channel2));
154 port2->entangle(MessagePortChannel::create(channel1));
155 }
156
messageAvailable()157 void PlatformMessagePortChannel::messageAvailable()
158 {
159 MutexLocker lock(m_mutex);
160 if (m_localPort)
161 m_localPort->messageAvailable();
162 }
163
entangleIfOpen(MessagePort * port)164 bool PlatformMessagePortChannel::entangleIfOpen(MessagePort* port)
165 {
166 MutexLocker lock(m_mutex);
167 m_localPort = port;
168 return true;
169 }
170
disentangle()171 void PlatformMessagePortChannel::disentangle()
172 {
173 MutexLocker lock(m_mutex);
174 m_localPort = 0;
175 }
176
postMessageToRemote(PassOwnPtr<MessagePortChannel::EventData> message)177 void PlatformMessagePortChannel::postMessageToRemote(PassOwnPtr<MessagePortChannel::EventData> message)
178 {
179 if (!m_localPort || !m_webChannel)
180 return;
181
182 WebString messageString = message->message()->toWireString();
183 OwnPtr<WebCore::MessagePortChannelArray> channels = message->channels();
184 WebMessagePortChannelArray* webChannels = 0;
185 if (channels.get() && channels->size()) {
186 webChannels = new WebMessagePortChannelArray(channels->size());
187 for (size_t i = 0; i < channels->size(); ++i) {
188 WebCore::PlatformMessagePortChannel* platformChannel = (*channels)[i]->channel();
189 (*webChannels)[i] = platformChannel->webChannelRelease();
190 (*webChannels)[i]->setClient(0);
191 }
192 }
193 m_webChannel->postMessage(messageString, webChannels);
194 }
195
tryGetMessageFromRemote(OwnPtr<MessagePortChannel::EventData> & result)196 bool PlatformMessagePortChannel::tryGetMessageFromRemote(OwnPtr<MessagePortChannel::EventData>& result)
197 {
198 if (!m_webChannel)
199 return false;
200
201 WebString message;
202 WebMessagePortChannelArray webChannels;
203 bool rv = m_webChannel->tryGetMessage(&message, webChannels);
204 if (rv) {
205 OwnPtr<MessagePortChannelArray> channels;
206 if (webChannels.size()) {
207 channels = new MessagePortChannelArray(webChannels.size());
208 for (size_t i = 0; i < webChannels.size(); ++i) {
209 RefPtr<PlatformMessagePortChannel> platformChannel = create(webChannels[i]);
210 webChannels[i]->setClient(platformChannel.get());
211 (*channels)[i] = MessagePortChannel::create(platformChannel);
212 }
213 }
214 RefPtr<SerializedScriptValue> serializedMessage = SerializedScriptValue::createFromWire(message);
215 result = MessagePortChannel::EventData::create(serializedMessage.release(), channels.release());
216 }
217
218 return rv;
219 }
220
close()221 void PlatformMessagePortChannel::close()
222 {
223 MutexLocker lock(m_mutex);
224 // Disentangle ourselves from the other end. We still maintain a reference to m_webChannel,
225 // since previously-existing messages should still be delivered.
226 m_localPort = 0;
227 m_entangledChannel = 0;
228 }
229
isConnectedTo(MessagePort * port)230 bool PlatformMessagePortChannel::isConnectedTo(MessagePort* port)
231 {
232 MutexLocker lock(m_mutex);
233 return m_entangledChannel && m_entangledChannel->m_localPort == port;
234 }
235
hasPendingActivity()236 bool PlatformMessagePortChannel::hasPendingActivity()
237 {
238 MutexLocker lock(m_mutex);
239 return m_localPort;
240 }
241
setEntangledChannel(PassRefPtr<PlatformMessagePortChannel> remote)242 void PlatformMessagePortChannel::setEntangledChannel(PassRefPtr<PlatformMessagePortChannel> remote)
243 {
244 if (m_webChannel)
245 m_webChannel->entangle(remote->m_webChannel);
246
247 MutexLocker lock(m_mutex);
248 m_entangledChannel = remote;
249 }
250
webChannelRelease()251 WebMessagePortChannel* PlatformMessagePortChannel::webChannelRelease()
252 {
253 WebMessagePortChannel* rv = m_webChannel;
254 m_webChannel = 0;
255 return rv;
256 }
257
258 } // namespace WebCore
259