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