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 "core/dom/default/PlatformMessagePortChannel.h" 34 35 #include "core/dom/MessagePort.h" 36 #include "core/dom/ScriptExecutionContext.h" 37 38 namespace WebCore { 39 40 PassOwnPtr<PlatformMessagePortChannel::EventData> PlatformMessagePortChannel::EventData::create(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels) 41 { 42 return adoptPtr(new EventData(message, channels)); 43 } 44 45 PlatformMessagePortChannel::EventData::EventData(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels) 46 : m_message(message) 47 , m_channels(channels) 48 { 49 } 50 51 void MessagePortChannel::createChannel(PassRefPtr<MessagePort> port1, PassRefPtr<MessagePort> port2) 52 { 53 RefPtr<PlatformMessagePortChannel::MessagePortQueue> queue1 = PlatformMessagePortChannel::MessagePortQueue::create(); 54 RefPtr<PlatformMessagePortChannel::MessagePortQueue> queue2 = PlatformMessagePortChannel::MessagePortQueue::create(); 55 56 OwnPtr<MessagePortChannel> channel1 = adoptPtr(new MessagePortChannel(PlatformMessagePortChannel::create(queue1, queue2))); 57 OwnPtr<MessagePortChannel> channel2 = adoptPtr(new MessagePortChannel(PlatformMessagePortChannel::create(queue2, queue1))); 58 59 channel1->m_channel->m_entangledChannel = channel2->m_channel; 60 channel2->m_channel->m_entangledChannel = channel1->m_channel; 61 62 port1->entangle(channel2.release()); 63 port2->entangle(channel1.release()); 64 } 65 66 MessagePortChannel::MessagePortChannel(PassRefPtr<PlatformMessagePortChannel> channel) 67 : m_channel(channel) 68 { 69 } 70 71 MessagePortChannel::~MessagePortChannel() 72 { 73 close(); 74 } 75 76 bool MessagePortChannel::entangleIfOpen(MessagePort* port) 77 { 78 // We can't call member functions on our remote pair while holding our mutex or we'll deadlock, 79 // but we need to guard against the remote port getting closed/freed, so create a standalone reference. 80 RefPtr<PlatformMessagePortChannel> remote = m_channel->entangledChannel(); 81 if (!remote) 82 return false; 83 remote->setRemotePort(port); 84 return true; 85 } 86 87 void MessagePortChannel::disentangle() 88 { 89 RefPtr<PlatformMessagePortChannel> remote = m_channel->entangledChannel(); 90 if (remote) 91 remote->setRemotePort(0); 92 } 93 94 void MessagePortChannel::postMessageToRemote(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels) 95 { 96 MutexLocker lock(m_channel->m_mutex); 97 if (!m_channel->m_outgoingQueue) 98 return; 99 bool wasEmpty = m_channel->m_outgoingQueue->appendAndCheckEmpty(PlatformMessagePortChannel::EventData::create(message, channels)); 100 if (wasEmpty && m_channel->m_remotePort) 101 m_channel->m_remotePort->messageAvailable(); 102 } 103 104 bool MessagePortChannel::tryGetMessageFromRemote(RefPtr<SerializedScriptValue>& message, OwnPtr<MessagePortChannelArray>& channels) 105 { 106 MutexLocker lock(m_channel->m_mutex); 107 OwnPtr<PlatformMessagePortChannel::EventData> result = m_channel->m_incomingQueue->tryGetMessage(); 108 if (!result) 109 return false; 110 111 message = result->message(); 112 channels = result->channels(); 113 114 return true; 115 } 116 117 void MessagePortChannel::close() 118 { 119 RefPtr<PlatformMessagePortChannel> remote = m_channel->entangledChannel(); 120 if (!remote) 121 return; 122 m_channel->closeInternal(); 123 remote->closeInternal(); 124 } 125 126 bool MessagePortChannel::isConnectedTo(MessagePort* port) 127 { 128 // FIXME: What guarantees that the result remains the same after we release the lock? 129 MutexLocker lock(m_channel->m_mutex); 130 return m_channel->m_remotePort == port; 131 } 132 133 bool MessagePortChannel::hasPendingActivity() 134 { 135 // FIXME: What guarantees that the result remains the same after we release the lock? 136 MutexLocker lock(m_channel->m_mutex); 137 return !m_channel->m_incomingQueue->isEmpty(); 138 } 139 140 MessagePort* MessagePortChannel::locallyEntangledPort(const ScriptExecutionContext* context) 141 { 142 MutexLocker lock(m_channel->m_mutex); 143 // See if both contexts are run by the same thread (are the same context, or are both documents). 144 if (m_channel->m_remotePort) { 145 // The remote port's ScriptExecutionContext is guaranteed not to change here - MessagePort::contextDestroyed() 146 // will close the port before the context goes away, and close() will block because we are holding the mutex. 147 ScriptExecutionContext* remoteContext = m_channel->m_remotePort->scriptExecutionContext(); 148 if (remoteContext == context || (remoteContext && remoteContext->isDocument() && context->isDocument())) 149 return m_channel->m_remotePort; 150 } 151 return 0; 152 } 153 154 PassRefPtr<PlatformMessagePortChannel> PlatformMessagePortChannel::create(PassRefPtr<MessagePortQueue> incoming, PassRefPtr<MessagePortQueue> outgoing) 155 { 156 return adoptRef(new PlatformMessagePortChannel(incoming, outgoing)); 157 } 158 159 PlatformMessagePortChannel::PlatformMessagePortChannel(PassRefPtr<MessagePortQueue> incoming, PassRefPtr<MessagePortQueue> outgoing) 160 : m_incomingQueue(incoming) 161 , m_outgoingQueue(outgoing) 162 , m_remotePort(0) 163 { 164 } 165 166 PlatformMessagePortChannel::~PlatformMessagePortChannel() 167 { 168 } 169 170 void PlatformMessagePortChannel::setRemotePort(MessagePort* port) 171 { 172 MutexLocker lock(m_mutex); 173 // Should never set port if it is already set. 174 ASSERT(!port || !m_remotePort); 175 m_remotePort = port; 176 } 177 178 PassRefPtr<PlatformMessagePortChannel> PlatformMessagePortChannel::entangledChannel() 179 { 180 // FIXME: What guarantees that the result remains the same after we release the lock? 181 // This lock only guarantees that the returned pointer will not be pointing to released memory, 182 // but not that it will still be pointing to this object's entangled port channel. 183 MutexLocker lock(m_mutex); 184 return m_entangledChannel; 185 } 186 187 void PlatformMessagePortChannel::closeInternal() 188 { 189 MutexLocker lock(m_mutex); 190 // Disentangle ourselves from the other end. We still maintain a reference to our incoming queue, since previously-existing messages should still be delivered. 191 m_remotePort = 0; 192 m_entangledChannel = 0; 193 m_outgoingQueue = 0; 194 } 195 196 } // namespace WebCore 197