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 "ArgumentEncoder.h" 30 #include "WorkItem.h" 31 #include <wtf/RandomNumber.h> 32 #include <wtf/text/WTFString.h> 33 34 using namespace std; 35 // We explicitly don't use the WebCore namespace here because CoreIPC should only use WTF types and 36 // WTF::String is really in WTF. 37 using WTF::String; 38 39 namespace CoreIPC { 40 41 // FIXME: Rename this or use a different constant on windows. 42 static const size_t inlineMessageMaxSize = 4096; 43 44 bool Connection::createServerAndClientIdentifiers(HANDLE& serverIdentifier, HANDLE& clientIdentifier) 45 { 46 String pipeName; 47 48 while (true) { 49 unsigned uniqueID = randomNumber() * std::numeric_limits<unsigned>::max(); 50 pipeName = String::format("\\\\.\\pipe\\com.apple.WebKit.%x", uniqueID); 51 52 serverIdentifier = ::CreateNamedPipe(pipeName.charactersWithNullTermination(), 53 PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, 54 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, inlineMessageMaxSize, inlineMessageMaxSize, 55 0, 0); 56 if (!serverIdentifier && ::GetLastError() == ERROR_PIPE_BUSY) { 57 // There was already a pipe with this name, try again. 58 continue; 59 } 60 61 break; 62 } 63 64 if (!serverIdentifier) 65 return false; 66 67 clientIdentifier = ::CreateFileW(pipeName.charactersWithNullTermination(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); 68 if (!clientIdentifier) { 69 ::CloseHandle(serverIdentifier); 70 return false; 71 } 72 73 DWORD mode = PIPE_READMODE_MESSAGE; 74 if (!::SetNamedPipeHandleState(clientIdentifier, &mode, 0, 0)) { 75 ::CloseHandle(serverIdentifier); 76 ::CloseHandle(clientIdentifier); 77 return false; 78 } 79 80 return true; 81 } 82 83 void Connection::platformInitialize(Identifier identifier) 84 { 85 memset(&m_readState, 0, sizeof(m_readState)); 86 m_readState.hEvent = ::CreateEventW(0, FALSE, FALSE, 0); 87 88 memset(&m_writeState, 0, sizeof(m_writeState)); 89 m_writeState.hEvent = ::CreateEventW(0, FALSE, FALSE, 0); 90 91 m_connectionPipe = identifier; 92 } 93 94 void Connection::platformInvalidate() 95 { 96 if (m_connectionPipe == INVALID_HANDLE_VALUE) 97 return; 98 99 m_isConnected = false; 100 101 m_connectionQueue.unregisterAndCloseHandle(m_readState.hEvent); 102 m_readState.hEvent = 0; 103 104 m_connectionQueue.unregisterAndCloseHandle(m_writeState.hEvent); 105 m_writeState.hEvent = 0; 106 107 ::CloseHandle(m_connectionPipe); 108 m_connectionPipe = INVALID_HANDLE_VALUE; 109 } 110 111 void Connection::readEventHandler() 112 { 113 if (m_connectionPipe == INVALID_HANDLE_VALUE) 114 return; 115 116 while (true) { 117 // Check if we got some data. 118 DWORD numberOfBytesRead = 0; 119 if (!::GetOverlappedResult(m_connectionPipe, &m_readState, &numberOfBytesRead, FALSE)) { 120 DWORD error = ::GetLastError(); 121 122 switch (error) { 123 case ERROR_BROKEN_PIPE: 124 connectionDidClose(); 125 return; 126 case ERROR_MORE_DATA: { 127 // Read the rest of the message out of the pipe. 128 129 DWORD bytesToRead = 0; 130 if (!::PeekNamedPipe(m_connectionPipe, 0, 0, 0, 0, &bytesToRead)) { 131 DWORD error = ::GetLastError(); 132 if (error == ERROR_BROKEN_PIPE) { 133 connectionDidClose(); 134 return; 135 } 136 ASSERT_NOT_REACHED(); 137 return; 138 } 139 140 // ::GetOverlappedResult told us there's more data. ::PeekNamedPipe shouldn't 141 // contradict it! 142 ASSERT(bytesToRead); 143 if (!bytesToRead) 144 break; 145 146 m_readBuffer.grow(m_readBuffer.size() + bytesToRead); 147 if (!::ReadFile(m_connectionPipe, m_readBuffer.data() + numberOfBytesRead, bytesToRead, 0, &m_readState)) { 148 DWORD error = ::GetLastError(); 149 ASSERT_NOT_REACHED(); 150 return; 151 } 152 continue; 153 } 154 155 // FIXME: We should figure out why we're getting this error. 156 case ERROR_IO_INCOMPLETE: 157 return; 158 default: 159 ASSERT_NOT_REACHED(); 160 } 161 } 162 163 if (!m_readBuffer.isEmpty()) { 164 // We have a message, let's dispatch it. 165 166 // The messageID is encoded at the end of the buffer. 167 // Note that we assume here that the message is the same size as m_readBuffer. We can 168 // assume this because we always size m_readBuffer to exactly match the size of the message, 169 // either when receiving ERROR_MORE_DATA from ::GetOverlappedResult above or when 170 // ::PeekNamedPipe tells us the size below. We never set m_readBuffer to a size larger 171 // than the message. 172 ASSERT(m_readBuffer.size() >= sizeof(MessageID)); 173 size_t realBufferSize = m_readBuffer.size() - sizeof(MessageID); 174 175 unsigned messageID = *reinterpret_cast<unsigned*>(m_readBuffer.data() + realBufferSize); 176 177 processIncomingMessage(MessageID::fromInt(messageID), adoptPtr(new ArgumentDecoder(m_readBuffer.data(), realBufferSize))); 178 } 179 180 // Find out the size of the next message in the pipe (if there is one) so that we can read 181 // it all in one operation. (This is just an optimization to avoid an extra pass through the 182 // loop (if we chose a buffer size that was too small) or allocating extra memory (if we 183 // chose a buffer size that was too large).) 184 DWORD bytesToRead = 0; 185 if (!::PeekNamedPipe(m_connectionPipe, 0, 0, 0, 0, &bytesToRead)) { 186 DWORD error = ::GetLastError(); 187 if (error == ERROR_BROKEN_PIPE) { 188 connectionDidClose(); 189 return; 190 } 191 ASSERT_NOT_REACHED(); 192 } 193 if (!bytesToRead) { 194 // There's no message waiting in the pipe. Schedule a read of the first byte of the 195 // next message. We'll find out the message's actual size when it arrives. (If we 196 // change this to read more than a single byte for performance reasons, we'll have to 197 // deal with m_readBuffer potentially being larger than the message we read after 198 // calling ::GetOverlappedResult above.) 199 bytesToRead = 1; 200 } 201 202 m_readBuffer.resize(bytesToRead); 203 204 // Either read the next available message (which should occur synchronously), or start an 205 // asynchronous read of the next message that becomes available. 206 BOOL result = ::ReadFile(m_connectionPipe, m_readBuffer.data(), m_readBuffer.size(), 0, &m_readState); 207 if (result) { 208 // There was already a message waiting in the pipe, and we read it synchronously. 209 // Process it. 210 continue; 211 } 212 213 DWORD error = ::GetLastError(); 214 215 if (error == ERROR_IO_PENDING) { 216 // There are no messages in the pipe currently. readEventHandler will be called again once there is a message. 217 return; 218 } 219 220 if (error == ERROR_MORE_DATA) { 221 // Either a message is available when we didn't think one was, or the message is larger 222 // than ::PeekNamedPipe told us. The former seems far more likely. Probably the message 223 // became available between our calls to ::PeekNamedPipe and ::ReadFile above. Go back 224 // to the top of the loop to use ::GetOverlappedResult to retrieve the available data. 225 continue; 226 } 227 228 // FIXME: We need to handle other errors here. 229 ASSERT_NOT_REACHED(); 230 } 231 } 232 233 void Connection::writeEventHandler() 234 { 235 if (m_connectionPipe == INVALID_HANDLE_VALUE) 236 return; 237 238 DWORD numberOfBytesWritten = 0; 239 if (!::GetOverlappedResult(m_connectionPipe, &m_writeState, &numberOfBytesWritten, FALSE)) { 240 DWORD error = ::GetLastError(); 241 if (error == ERROR_IO_INCOMPLETE) { 242 // FIXME: We should figure out why we're getting this error. 243 return; 244 } 245 if (error == ERROR_BROKEN_PIPE) { 246 connectionDidClose(); 247 return; 248 } 249 ASSERT_NOT_REACHED(); 250 } 251 252 // The pending write has finished, so we are now done with its arguments. Clearing this member 253 // will allow us to send messages again. 254 m_pendingWriteArguments = 0; 255 256 // Now that the pending write has finished, we can try to send a new message. 257 sendOutgoingMessages(); 258 } 259 260 bool Connection::open() 261 { 262 // We connected the two ends of the pipe in createServerAndClientIdentifiers. 263 m_isConnected = true; 264 265 // Start listening for read and write state events. 266 m_connectionQueue.registerHandle(m_readState.hEvent, WorkItem::create(this, &Connection::readEventHandler)); 267 m_connectionQueue.registerHandle(m_writeState.hEvent, WorkItem::create(this, &Connection::writeEventHandler)); 268 269 // Schedule a read. 270 m_connectionQueue.scheduleWork(WorkItem::create(this, &Connection::readEventHandler)); 271 272 return true; 273 } 274 275 bool Connection::platformCanSendOutgoingMessages() const 276 { 277 // We only allow sending one asynchronous message at a time. If we wanted to send more than one 278 // at once, we'd have to use multiple OVERLAPPED structures and hold onto multiple pending 279 // ArgumentEncoders (one of each for each simultaneous asynchronous message). 280 return !m_pendingWriteArguments; 281 } 282 283 bool Connection::sendOutgoingMessage(MessageID messageID, PassOwnPtr<ArgumentEncoder> arguments) 284 { 285 ASSERT(!m_pendingWriteArguments); 286 287 // Just bail if the handle has been closed. 288 if (m_connectionPipe == INVALID_HANDLE_VALUE) 289 return false; 290 291 // We put the message ID last. 292 arguments->encodeUInt32(messageID.toInt()); 293 294 // Write the outgoing message. 295 296 if (::WriteFile(m_connectionPipe, arguments->buffer(), arguments->bufferSize(), 0, &m_writeState)) { 297 // We successfully sent this message. 298 return true; 299 } 300 301 DWORD error = ::GetLastError(); 302 303 if (error == ERROR_NO_DATA) { 304 // The pipe is being closed. 305 connectionDidClose(); 306 return false; 307 } 308 309 if (error != ERROR_IO_PENDING) { 310 ASSERT_NOT_REACHED(); 311 return false; 312 } 313 314 // The message will be sent soon. Hold onto the arguments so that they won't be destroyed 315 // before the write completes. 316 m_pendingWriteArguments = arguments; 317 318 // We can only send one asynchronous message at a time (see comment in platformCanSendOutgoingMessages). 319 return false; 320 } 321 322 } // namespace CoreIPC 323