1/* 2 * Copyright (C) 2010 Apple 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 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "Connection.h" 28 29#include "DataReference.h" 30#include <wtf/Functional.h> 31#include <wtf/RandomNumber.h> 32#include <wtf/text/WTFString.h> 33#include <wtf/threads/BinarySemaphore.h> 34 35using namespace std; 36 37namespace CoreIPC { 38 39// FIXME: Rename this or use a different constant on windows. 40static const size_t inlineMessageMaxSize = 4096; 41 42bool Connection::createServerAndClientIdentifiers(HANDLE& serverIdentifier, HANDLE& clientIdentifier) 43{ 44 String pipeName; 45 46 while (true) { 47 unsigned uniqueID = randomNumber() * std::numeric_limits<unsigned>::max(); 48 pipeName = String::format("\\\\.\\pipe\\com.apple.WebKit.%x", uniqueID); 49 50 serverIdentifier = ::CreateNamedPipe(pipeName.charactersWithNullTermination(), 51 PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, 52 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, inlineMessageMaxSize, inlineMessageMaxSize, 53 0, 0); 54 if (!serverIdentifier && ::GetLastError() == ERROR_PIPE_BUSY) { 55 // There was already a pipe with this name, try again. 56 continue; 57 } 58 59 break; 60 } 61 62 if (!serverIdentifier) 63 return false; 64 65 clientIdentifier = ::CreateFileW(pipeName.charactersWithNullTermination(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); 66 if (!clientIdentifier) { 67 ::CloseHandle(serverIdentifier); 68 return false; 69 } 70 71 DWORD mode = PIPE_READMODE_MESSAGE; 72 if (!::SetNamedPipeHandleState(clientIdentifier, &mode, 0, 0)) { 73 ::CloseHandle(serverIdentifier); 74 ::CloseHandle(clientIdentifier); 75 return false; 76 } 77 78 return true; 79} 80 81void Connection::platformInitialize(Identifier identifier) 82{ 83 memset(&m_readState, 0, sizeof(m_readState)); 84 m_readState.hEvent = ::CreateEventW(0, FALSE, FALSE, 0); 85 86 memset(&m_writeState, 0, sizeof(m_writeState)); 87 m_writeState.hEvent = ::CreateEventW(0, FALSE, FALSE, 0); 88 89 m_connectionPipe = identifier; 90} 91 92void Connection::platformInvalidate() 93{ 94 if (m_connectionPipe == INVALID_HANDLE_VALUE) 95 return; 96 97 m_isConnected = false; 98 99 m_connectionQueue->unregisterAndCloseHandle(m_readState.hEvent); 100 m_readState.hEvent = 0; 101 102 m_connectionQueue->unregisterAndCloseHandle(m_writeState.hEvent); 103 m_writeState.hEvent = 0; 104 105 ::CloseHandle(m_connectionPipe); 106 m_connectionPipe = INVALID_HANDLE_VALUE; 107} 108 109void Connection::readEventHandler() 110{ 111 if (m_connectionPipe == INVALID_HANDLE_VALUE) 112 return; 113 114 while (true) { 115 // Check if we got some data. 116 DWORD numberOfBytesRead = 0; 117 if (!::GetOverlappedResult(m_connectionPipe, &m_readState, &numberOfBytesRead, FALSE)) { 118 DWORD error = ::GetLastError(); 119 120 switch (error) { 121 case ERROR_BROKEN_PIPE: 122 connectionDidClose(); 123 return; 124 case ERROR_MORE_DATA: { 125 // Read the rest of the message out of the pipe. 126 127 DWORD bytesToRead = 0; 128 if (!::PeekNamedPipe(m_connectionPipe, 0, 0, 0, 0, &bytesToRead)) { 129 DWORD error = ::GetLastError(); 130 if (error == ERROR_BROKEN_PIPE) { 131 connectionDidClose(); 132 return; 133 } 134 ASSERT_NOT_REACHED(); 135 return; 136 } 137 138 // ::GetOverlappedResult told us there's more data. ::PeekNamedPipe shouldn't 139 // contradict it! 140 ASSERT(bytesToRead); 141 if (!bytesToRead) 142 break; 143 144 m_readBuffer.grow(m_readBuffer.size() + bytesToRead); 145 if (!::ReadFile(m_connectionPipe, m_readBuffer.data() + numberOfBytesRead, bytesToRead, 0, &m_readState)) { 146 DWORD error = ::GetLastError(); 147 ASSERT_NOT_REACHED(); 148 return; 149 } 150 continue; 151 } 152 153 // FIXME: We should figure out why we're getting this error. 154 case ERROR_IO_INCOMPLETE: 155 return; 156 default: 157 ASSERT_NOT_REACHED(); 158 } 159 } 160 161 if (!m_readBuffer.isEmpty()) { 162 // We have a message, let's dispatch it. 163 164 OwnPtr<MessageDecoder> decoder = MessageDecoder::create(DataReference(m_readBuffer.data(), m_readBuffer.size())); 165 processIncomingMessage(decoder.release()); 166 } 167 168 // Find out the size of the next message in the pipe (if there is one) so that we can read 169 // it all in one operation. (This is just an optimization to avoid an extra pass through the 170 // loop (if we chose a buffer size that was too small) or allocating extra memory (if we 171 // chose a buffer size that was too large).) 172 DWORD bytesToRead = 0; 173 if (!::PeekNamedPipe(m_connectionPipe, 0, 0, 0, 0, &bytesToRead)) { 174 DWORD error = ::GetLastError(); 175 if (error == ERROR_BROKEN_PIPE) { 176 connectionDidClose(); 177 return; 178 } 179 ASSERT_NOT_REACHED(); 180 } 181 if (!bytesToRead) { 182 // There's no message waiting in the pipe. Schedule a read of the first byte of the 183 // next message. We'll find out the message's actual size when it arrives. (If we 184 // change this to read more than a single byte for performance reasons, we'll have to 185 // deal with m_readBuffer potentially being larger than the message we read after 186 // calling ::GetOverlappedResult above.) 187 bytesToRead = 1; 188 } 189 190 m_readBuffer.resize(bytesToRead); 191 192 // Either read the next available message (which should occur synchronously), or start an 193 // asynchronous read of the next message that becomes available. 194 BOOL result = ::ReadFile(m_connectionPipe, m_readBuffer.data(), m_readBuffer.size(), 0, &m_readState); 195 if (result) { 196 // There was already a message waiting in the pipe, and we read it synchronously. 197 // Process it. 198 continue; 199 } 200 201 DWORD error = ::GetLastError(); 202 203 if (error == ERROR_IO_PENDING) { 204 // There are no messages in the pipe currently. readEventHandler will be called again once there is a message. 205 return; 206 } 207 208 if (error == ERROR_MORE_DATA) { 209 // Either a message is available when we didn't think one was, or the message is larger 210 // than ::PeekNamedPipe told us. The former seems far more likely. Probably the message 211 // became available between our calls to ::PeekNamedPipe and ::ReadFile above. Go back 212 // to the top of the loop to use ::GetOverlappedResult to retrieve the available data. 213 continue; 214 } 215 216 // FIXME: We need to handle other errors here. 217 ASSERT_NOT_REACHED(); 218 } 219} 220 221void Connection::writeEventHandler() 222{ 223 if (m_connectionPipe == INVALID_HANDLE_VALUE) 224 return; 225 226 DWORD numberOfBytesWritten = 0; 227 if (!::GetOverlappedResult(m_connectionPipe, &m_writeState, &numberOfBytesWritten, FALSE)) { 228 DWORD error = ::GetLastError(); 229 if (error == ERROR_IO_INCOMPLETE) { 230 // FIXME: We should figure out why we're getting this error. 231 return; 232 } 233 if (error == ERROR_BROKEN_PIPE) { 234 connectionDidClose(); 235 return; 236 } 237 ASSERT_NOT_REACHED(); 238 } 239 240 // The pending write has finished, so we are now done with its encoder. Clearing this member 241 // will allow us to send messages again. 242 m_pendingWriteEncoder = nullptr; 243 244 // Now that the pending write has finished, we can try to send a new message. 245 sendOutgoingMessages(); 246} 247 248bool Connection::open() 249{ 250 // We connected the two ends of the pipe in createServerAndClientIdentifiers. 251 m_isConnected = true; 252 253 // Start listening for read and write state events. 254 m_connectionQueue->registerHandle(m_readState.hEvent, bind(&Connection::readEventHandler, this)); 255 m_connectionQueue->registerHandle(m_writeState.hEvent, bind(&Connection::writeEventHandler, this)); 256 257 // Schedule a read. 258 m_connectionQueue->dispatch(bind(&Connection::readEventHandler, this)); 259 260 return true; 261} 262 263bool Connection::platformCanSendOutgoingMessages() const 264{ 265 // We only allow sending one asynchronous message at a time. If we wanted to send more than one 266 // at once, we'd have to use multiple OVERLAPPED structures and hold onto multiple pending 267 // MessageEncoders (one of each for each simultaneous asynchronous message). 268 return !m_pendingWriteEncoder; 269} 270 271bool Connection::sendOutgoingMessage(PassOwnPtr<MessageEncoder> encoder) 272{ 273 ASSERT(!m_pendingWriteEncoder); 274 275 // Just bail if the handle has been closed. 276 if (m_connectionPipe == INVALID_HANDLE_VALUE) 277 return false; 278 279 // We put the message ID last. 280 *encoder << 0; 281 282 // Write the outgoing message. 283 284 if (::WriteFile(m_connectionPipe, encoder->buffer(), encoder->bufferSize(), 0, &m_writeState)) { 285 // We successfully sent this message. 286 return true; 287 } 288 289 DWORD error = ::GetLastError(); 290 291 if (error == ERROR_NO_DATA) { 292 // The pipe is being closed. 293 connectionDidClose(); 294 return false; 295 } 296 297 if (error != ERROR_IO_PENDING) { 298 ASSERT_NOT_REACHED(); 299 return false; 300 } 301 302 // The message will be sent soon. Hold onto the encoder so that it won't be destroyed 303 // before the write completes. 304 m_pendingWriteEncoder = encoder; 305 306 // We can only send one asynchronous message at a time (see comment in platformCanSendOutgoingMessages). 307 return false; 308} 309 310bool Connection::dispatchSentMessagesUntil(const Vector<HWND>& windows, WTF::BinarySemaphore& semaphore, double absoluteTime) 311{ 312 if (windows.isEmpty()) 313 return semaphore.wait(absoluteTime); 314 315 HANDLE handle = semaphore.event(); 316 DWORD handleCount = 1; 317 318 while (true) { 319 DWORD interval = absoluteTimeToWaitTimeoutInterval(absoluteTime); 320 if (!interval) { 321 // Consider the wait to have timed out, even if the semaphore is currently signaled. 322 // This matches the WTF::ThreadCondition implementation of BinarySemaphore::wait. 323 return false; 324 } 325 326 DWORD result = ::MsgWaitForMultipleObjectsEx(handleCount, &handle, interval, QS_SENDMESSAGE, 0); 327 if (result == WAIT_OBJECT_0) { 328 // The semaphore was signaled. 329 return true; 330 } 331 if (result == WAIT_TIMEOUT) { 332 // absoluteTime was reached. 333 return false; 334 } 335 if (result == WAIT_OBJECT_0 + handleCount) { 336 // One or more sent messages are available. Process sent messages for all the windows 337 // we were given, since we don't have a way of knowing which window has available sent 338 // messages. 339 for (size_t i = 0; i < windows.size(); ++i) { 340 MSG message; 341 ::PeekMessageW(&message, windows[i], 0, 0, PM_NOREMOVE | PM_QS_SENDMESSAGE); 342 } 343 continue; 344 } 345 ASSERT_WITH_MESSAGE(result != WAIT_FAILED, "::MsgWaitForMultipleObjectsEx failed with error %lu", ::GetLastError()); 346 ASSERT_WITH_MESSAGE(false, "::MsgWaitForMultipleObjectsEx returned unexpected result %lu", result); 347 return false; 348 } 349} 350 351} // namespace CoreIPC 352