1/* 2 * Copyright (C) 2009 Google Inc. All rights reserved. 3 * Copyright (C) 2013 Apple Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include "config.h" 33#include "PlatformMessagePortChannel.h" 34 35#include "MessagePort.h" 36#include "ScriptExecutionContext.h" 37 38namespace WebCore { 39 40PlatformMessagePortChannel::EventData::EventData(PassRefPtr<SerializedScriptValue> message, std::unique_ptr<MessagePortChannelArray> channels) 41 : m_message(message) 42 , m_channels(WTF::move(channels)) 43{ 44} 45 46void MessagePortChannel::createChannel(PassRefPtr<MessagePort> port1, PassRefPtr<MessagePort> port2) 47{ 48 RefPtr<PlatformMessagePortChannel::MessagePortQueue> queue1 = PlatformMessagePortChannel::MessagePortQueue::create(); 49 RefPtr<PlatformMessagePortChannel::MessagePortQueue> queue2 = PlatformMessagePortChannel::MessagePortQueue::create(); 50 51 auto channel1 = std::make_unique<MessagePortChannel>(PlatformMessagePortChannel::create(queue1, queue2)); 52 auto channel2 = std::make_unique<MessagePortChannel>(PlatformMessagePortChannel::create(queue2, queue1)); 53 54 channel1->m_channel->m_entangledChannel = channel2->m_channel; 55 channel2->m_channel->m_entangledChannel = channel1->m_channel; 56 57 port1->entangle(WTF::move(channel2)); 58 port2->entangle(WTF::move(channel1)); 59} 60 61MessagePortChannel::MessagePortChannel(PassRefPtr<PlatformMessagePortChannel> channel) 62 : m_channel(channel) 63{ 64} 65 66MessagePortChannel::~MessagePortChannel() 67{ 68 close(); 69} 70 71bool MessagePortChannel::entangleIfOpen(MessagePort* port) 72{ 73 // We can't call member functions on our remote pair while holding our mutex or we'll deadlock, 74 // but we need to guard against the remote port getting closed/freed, so create a standalone reference. 75 RefPtr<PlatformMessagePortChannel> remote = m_channel->entangledChannel(); 76 if (!remote) 77 return false; 78 remote->setRemotePort(port); 79 return true; 80} 81 82void MessagePortChannel::disentangle() 83{ 84 RefPtr<PlatformMessagePortChannel> remote = m_channel->entangledChannel(); 85 if (remote) 86 remote->setRemotePort(0); 87} 88 89void MessagePortChannel::postMessageToRemote(PassRefPtr<SerializedScriptValue> message, std::unique_ptr<MessagePortChannelArray> channels) 90{ 91 MutexLocker lock(m_channel->m_mutex); 92 if (!m_channel->m_outgoingQueue) 93 return; 94 bool wasEmpty = m_channel->m_outgoingQueue->appendAndCheckEmpty(std::make_unique<PlatformMessagePortChannel::EventData>(message, WTF::move(channels))); 95 if (wasEmpty && m_channel->m_remotePort) 96 m_channel->m_remotePort->messageAvailable(); 97} 98 99bool MessagePortChannel::tryGetMessageFromRemote(RefPtr<SerializedScriptValue>& message, std::unique_ptr<MessagePortChannelArray>& channels) 100{ 101 MutexLocker lock(m_channel->m_mutex); 102 auto result = m_channel->m_incomingQueue->tryGetMessage(); 103 if (!result) 104 return false; 105 106 message = result->message(); 107 channels = result->channels(); 108 109 return true; 110} 111 112void MessagePortChannel::close() 113{ 114 RefPtr<PlatformMessagePortChannel> remote = m_channel->entangledChannel(); 115 if (!remote) 116 return; 117 m_channel->closeInternal(); 118 remote->closeInternal(); 119} 120 121bool MessagePortChannel::isConnectedTo(MessagePort* port) 122{ 123 // FIXME: What guarantees that the result remains the same after we release the lock? 124 MutexLocker lock(m_channel->m_mutex); 125 return m_channel->m_remotePort == port; 126} 127 128bool MessagePortChannel::hasPendingActivity() 129{ 130 // FIXME: What guarantees that the result remains the same after we release the lock? 131 MutexLocker lock(m_channel->m_mutex); 132 return !m_channel->m_incomingQueue->isEmpty(); 133} 134 135MessagePort* MessagePortChannel::locallyEntangledPort(const ScriptExecutionContext* context) 136{ 137 MutexLocker lock(m_channel->m_mutex); 138 // See if both contexts are run by the same thread (are the same context, or are both documents). 139 if (m_channel->m_remotePort) { 140 // The remote port's ScriptExecutionContext is guaranteed not to change here - MessagePort::contextDestroyed() 141 // will close the port before the context goes away, and close() will block because we are holding the mutex. 142 ScriptExecutionContext* remoteContext = m_channel->m_remotePort->scriptExecutionContext(); 143 if (remoteContext == context || (remoteContext && remoteContext->isDocument() && context->isDocument())) 144 return m_channel->m_remotePort; 145 } 146 return 0; 147} 148 149PassRefPtr<PlatformMessagePortChannel> PlatformMessagePortChannel::create(PassRefPtr<MessagePortQueue> incoming, PassRefPtr<MessagePortQueue> outgoing) 150{ 151 return adoptRef(new PlatformMessagePortChannel(incoming, outgoing)); 152} 153 154PlatformMessagePortChannel::PlatformMessagePortChannel(PassRefPtr<MessagePortQueue> incoming, PassRefPtr<MessagePortQueue> outgoing) 155 : m_incomingQueue(incoming) 156 , m_outgoingQueue(outgoing) 157 , m_remotePort(0) 158{ 159} 160 161PlatformMessagePortChannel::~PlatformMessagePortChannel() 162{ 163} 164 165void PlatformMessagePortChannel::setRemotePort(MessagePort* port) 166{ 167 MutexLocker lock(m_mutex); 168 // Should never set port if it is already set. 169 ASSERT(!port || !m_remotePort); 170 m_remotePort = port; 171} 172 173PassRefPtr<PlatformMessagePortChannel> PlatformMessagePortChannel::entangledChannel() 174{ 175 // FIXME: What guarantees that the result remains the same after we release the lock? 176 // This lock only guarantees that the returned pointer will not be pointing to released memory, 177 // but not that it will still be pointing to this object's entangled port channel. 178 MutexLocker lock(m_mutex); 179 return m_entangledChannel; 180} 181 182void PlatformMessagePortChannel::closeInternal() 183{ 184 MutexLocker lock(m_mutex); 185 // Disentangle ourselves from the other end. We still maintain a reference to our incoming queue, since previously-existing messages should still be delivered. 186 m_remotePort = 0; 187 m_entangledChannel = 0; 188 m_outgoingQueue = 0; 189} 190 191} // namespace WebCore 192