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
34using 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.
37using WTF::String;
38
39namespace CoreIPC {
40
41// FIXME: Rename this or use a different constant on windows.
42static const size_t inlineMessageMaxSize = 4096;
43
44bool 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
83void 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
94void 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
111void 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
233void 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
260bool 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
275bool 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
283bool 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