1/*
2 * Copyright (C) 2012 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 "ChildProcessProxy.h"
28
29#include <wtf/RunLoop.h>
30
31namespace WebKit {
32
33ChildProcessProxy::ChildProcessProxy()
34{
35}
36
37ChildProcessProxy::~ChildProcessProxy()
38{
39    if (m_connection)
40        m_connection->invalidate();
41
42    if (m_processLauncher) {
43        m_processLauncher->invalidate();
44        m_processLauncher = 0;
45    }
46}
47
48ChildProcessProxy* ChildProcessProxy::fromConnection(IPC::Connection* connection)
49{
50    ASSERT(connection);
51
52    ChildProcessProxy* childProcessProxy = static_cast<ChildProcessProxy*>(connection->client());
53    ASSERT(childProcessProxy->connection() == connection);
54
55    return childProcessProxy;
56}
57
58void ChildProcessProxy::connect()
59{
60    ASSERT(!m_processLauncher);
61    ProcessLauncher::LaunchOptions launchOptions;
62    getLaunchOptions(launchOptions);
63    m_processLauncher = ProcessLauncher::create(this, launchOptions);
64}
65
66void ChildProcessProxy::terminate()
67{
68#if PLATFORM(COCOA)
69    if (m_connection && m_connection->kill())
70        return;
71#endif
72
73    // FIXME: We should really merge process launching into IPC connection creation and get rid of the process launcher.
74    if (m_processLauncher)
75        m_processLauncher->terminateProcess();
76}
77
78ChildProcessProxy::State ChildProcessProxy::state() const
79{
80    if (m_processLauncher && m_processLauncher->isLaunching())
81        return ChildProcessProxy::State::Launching;
82
83    if (!m_connection)
84        return ChildProcessProxy::State::Terminated;
85
86    return ChildProcessProxy::State::Running;
87}
88
89bool ChildProcessProxy::sendMessage(std::unique_ptr<IPC::MessageEncoder> encoder, unsigned messageSendFlags)
90{
91    switch (state()) {
92    case State::Launching:
93        // If we're waiting for the child process to launch, we need to stash away the messages so we can send them once we have a connection.
94        m_pendingMessages.append(std::make_pair(WTF::move(encoder), messageSendFlags));
95        return true;
96
97    case State::Running:
98        return connection()->sendMessage(WTF::move(encoder), messageSendFlags);
99
100    case State::Terminated:
101        return false;
102    }
103
104    return false;
105}
106
107void ChildProcessProxy::addMessageReceiver(IPC::StringReference messageReceiverName, IPC::MessageReceiver& messageReceiver)
108{
109    m_messageReceiverMap.addMessageReceiver(messageReceiverName, messageReceiver);
110}
111
112void ChildProcessProxy::addMessageReceiver(IPC::StringReference messageReceiverName, uint64_t destinationID, IPC::MessageReceiver& messageReceiver)
113{
114    m_messageReceiverMap.addMessageReceiver(messageReceiverName, destinationID, messageReceiver);
115}
116
117void ChildProcessProxy::removeMessageReceiver(IPC::StringReference messageReceiverName, uint64_t destinationID)
118{
119    m_messageReceiverMap.removeMessageReceiver(messageReceiverName, destinationID);
120}
121
122bool ChildProcessProxy::dispatchMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder)
123{
124    return m_messageReceiverMap.dispatchMessage(connection, decoder);
125}
126
127bool ChildProcessProxy::dispatchSyncMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& replyEncoder)
128{
129    return m_messageReceiverMap.dispatchSyncMessage(connection, decoder, replyEncoder);
130}
131
132void ChildProcessProxy::didFinishLaunching(ProcessLauncher*, IPC::Connection::Identifier connectionIdentifier)
133{
134    ASSERT(!m_connection);
135
136    m_connection = IPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main());
137#if PLATFORM(MAC)
138    m_connection->setShouldCloseConnectionOnMachExceptions();
139#endif
140
141    connectionWillOpen(m_connection.get());
142    m_connection->open();
143
144    for (size_t i = 0; i < m_pendingMessages.size(); ++i) {
145        std::unique_ptr<IPC::MessageEncoder> message = WTF::move(m_pendingMessages[i].first);
146        unsigned messageSendFlags = m_pendingMessages[i].second;
147        m_connection->sendMessage(WTF::move(message), messageSendFlags);
148    }
149
150    m_pendingMessages.clear();
151}
152
153void ChildProcessProxy::abortProcessLaunchIfNeeded()
154{
155    if (state() != State::Launching)
156        return;
157
158    m_processLauncher->invalidate();
159    m_processLauncher = nullptr;
160}
161
162void ChildProcessProxy::clearConnection()
163{
164    if (!m_connection)
165        return;
166
167    connectionWillClose(m_connection.get());
168
169    m_connection->invalidate();
170    m_connection = nullptr;
171}
172
173void ChildProcessProxy::connectionWillOpen(IPC::Connection*)
174{
175}
176
177void ChildProcessProxy::connectionWillClose(IPC::Connection*)
178{
179}
180
181} // namespace WebKit
182