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
43using namespace WebKit;
44
45namespace WebCore {
46
47PassOwnPtr<MessagePortChannel> MessagePortChannel::create(PassRefPtr<PlatformMessagePortChannel> channel)
48{
49    return new MessagePortChannel(channel);
50}
51
52void MessagePortChannel::createChannel(PassRefPtr<MessagePort> port1, PassRefPtr<MessagePort> port2)
53{
54    PlatformMessagePortChannel::createChannel(port1, port2);
55}
56
57MessagePortChannel::MessagePortChannel(PassRefPtr<PlatformMessagePortChannel> channel)
58    : m_channel(channel)
59{
60}
61
62MessagePortChannel::~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
68bool MessagePortChannel::entangleIfOpen(MessagePort* port)
69{
70    return m_channel->entangleIfOpen(port);
71}
72
73void MessagePortChannel::disentangle()
74{
75    m_channel->disentangle();
76}
77
78void MessagePortChannel::postMessageToRemote(PassOwnPtr<MessagePortChannel::EventData> message)
79{
80    m_channel->postMessageToRemote(message);
81}
82
83bool MessagePortChannel::tryGetMessageFromRemote(OwnPtr<MessagePortChannel::EventData>& result)
84{
85    return m_channel->tryGetMessageFromRemote(result);
86}
87
88void MessagePortChannel::close()
89{
90    m_channel->close();
91}
92
93bool MessagePortChannel::isConnectedTo(MessagePort* port)
94{
95    return m_channel->isConnectedTo(port);
96}
97
98bool MessagePortChannel::hasPendingActivity()
99{
100    return m_channel->hasPendingActivity();
101}
102
103MessagePort* MessagePortChannel::locallyEntangledPort(const ScriptExecutionContext* context)
104{
105    // This is just an optimization, so return 0 always.
106    return 0;
107}
108
109
110PassRefPtr<PlatformMessagePortChannel> PlatformMessagePortChannel::create()
111{
112    return adoptRef(new PlatformMessagePortChannel());
113}
114
115PassRefPtr<PlatformMessagePortChannel> PlatformMessagePortChannel::create(
116    WebMessagePortChannel* channel)
117{
118    return adoptRef(new PlatformMessagePortChannel(channel));
119}
120
121
122PlatformMessagePortChannel::PlatformMessagePortChannel()
123    : m_localPort(0)
124{
125    m_webChannel = webKitClient()->createMessagePortChannel();
126    if (m_webChannel)
127        m_webChannel->setClient(this);
128}
129
130PlatformMessagePortChannel::PlatformMessagePortChannel(WebMessagePortChannel* channel)
131    : m_localPort(0)
132    , m_webChannel(channel)
133{
134}
135
136PlatformMessagePortChannel::~PlatformMessagePortChannel()
137{
138    if (m_webChannel)
139        m_webChannel->destroy();
140}
141
142void 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
157void PlatformMessagePortChannel::messageAvailable()
158{
159    MutexLocker lock(m_mutex);
160    if (m_localPort)
161        m_localPort->messageAvailable();
162}
163
164bool PlatformMessagePortChannel::entangleIfOpen(MessagePort* port)
165{
166    MutexLocker lock(m_mutex);
167    m_localPort = port;
168    return true;
169}
170
171void PlatformMessagePortChannel::disentangle()
172{
173    MutexLocker lock(m_mutex);
174    m_localPort = 0;
175}
176
177void 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
196bool 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
221void 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
230bool PlatformMessagePortChannel::isConnectedTo(MessagePort* port)
231{
232    MutexLocker lock(m_mutex);
233    return m_entangledChannel && m_entangledChannel->m_localPort == port;
234}
235
236bool PlatformMessagePortChannel::hasPendingActivity()
237{
238    MutexLocker lock(m_mutex);
239    return m_localPort;
240}
241
242void 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
251WebMessagePortChannel* PlatformMessagePortChannel::webChannelRelease()
252{
253    WebMessagePortChannel* rv = m_webChannel;
254    m_webChannel = 0;
255    return rv;
256}
257
258} // namespace WebCore
259