Home | History | Annotate | Download | only in win
      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