798d3b306d6428c76492215ae07b34682629e87b
[WebKit.git] / Source / JavaScriptCore / inspector / remote / socket / RemoteInspectorSocketEndpoint.cpp
1 /*
2  * Copyright (C) 2019 Sony Interactive Entertainment Inc.
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 "RemoteInspectorSocketEndpoint.h"
28
29 #if ENABLE(REMOTE_INSPECTOR)
30
31 #include <wtf/CryptographicallyRandomNumber.h>
32 #include <wtf/MainThread.h>
33 #include <wtf/text/WTFString.h>
34
35 namespace Inspector {
36
37 RemoteInspectorSocketEndpoint& RemoteInspectorSocketEndpoint::singleton()
38 {
39     static NeverDestroyed<RemoteInspectorSocketEndpoint> shared;
40     return shared;
41 }
42
43 RemoteInspectorSocketEndpoint::RemoteInspectorSocketEndpoint()
44 {
45     if (auto sockets = Socket::createPair()) {
46         m_wakeupSendSocket = sockets->at(0);
47         m_wakeupReceiveSocket = sockets->at(1);
48     }
49
50     m_workerThread = Thread::create("SocketEndpoint", [this] {
51         workerThread();
52     });
53 }
54
55 RemoteInspectorSocketEndpoint::~RemoteInspectorSocketEndpoint()
56 {
57     ASSERT(m_workerThread.get() != &Thread::current());
58
59     m_shouldAbortWorkerThread = true;
60     wakeupWorkerThread();
61     m_workerThread->waitForCompletion();
62
63     Socket::close(m_wakeupSendSocket);
64     Socket::close(m_wakeupReceiveSocket);
65     for (const auto& connection : m_connections.values())
66         Socket::close(connection->socket);
67 }
68
69 void RemoteInspectorSocketEndpoint::wakeupWorkerThread()
70 {
71     if (Socket::isValid(m_wakeupSendSocket))
72         Socket::write(m_wakeupSendSocket, "1", 1);
73 }
74
75 Optional<ConnectionID> RemoteInspectorSocketEndpoint::connectInet(const char* serverAddress, uint16_t serverPort, Client& client)
76 {
77     if (auto socket = Socket::connect(serverAddress, serverPort))
78         return createClient(*socket, client);
79     return WTF::nullopt;
80 }
81
82 Optional<ConnectionID> RemoteInspectorSocketEndpoint::listenInet(const char* address, uint16_t port, Client& client)
83 {
84     if (auto socket = Socket::listen(address, port))
85         return createClient(*socket, client);
86
87     return WTF::nullopt;
88 }
89
90 bool RemoteInspectorSocketEndpoint::isListening(ConnectionID id)
91 {
92     LockHolder lock(m_connectionsLock);
93     if (const auto& connection = m_connections.get(id))
94         return Socket::isListening(connection->socket);
95     return false;
96 }
97
98 void RemoteInspectorSocketEndpoint::workerThread()
99 {
100     PollingDescriptor wakeup = Socket::preparePolling(m_wakeupReceiveSocket);
101
102     while (!m_shouldAbortWorkerThread) {
103         Vector<PollingDescriptor> pollfds;
104         Vector<ConnectionID> ids;
105         {
106             LockHolder lock(m_connectionsLock);
107             for (const auto& connection : m_connections) {
108                 pollfds.append(connection.value->poll);
109                 ids.append(connection.key);
110             }
111         }
112         pollfds.append(wakeup);
113
114         if (!Socket::poll(pollfds, -1))
115             continue;
116
117         if (Socket::isReadable(pollfds.last())) {
118             char wakeMessage;
119             Socket::read(m_wakeupReceiveSocket, &wakeMessage, sizeof(wakeMessage));
120             continue;
121         }
122
123         for (size_t i = 0; i < ids.size(); i++) {
124             auto id = ids[i];
125
126             if (Socket::isReadable(pollfds[i]) && isListening(id))
127                 acceptInetSocketIfEnabled(id);
128             else if (Socket::isReadable(pollfds[i]))
129                 recvIfEnabled(id);
130             else if (Socket::isWritable(pollfds[i]))
131                 sendIfEnabled(id);
132         }
133     }
134 }
135
136 Optional<ConnectionID> RemoteInspectorSocketEndpoint::createClient(PlatformSocketType socket, Client& client)
137 {
138     if (!Socket::isValid(socket))
139         return WTF::nullopt;
140
141     LockHolder lock(m_connectionsLock);
142
143     ConnectionID id;
144     do {
145         id = cryptographicallyRandomNumber();
146     } while (!id || m_connections.contains(id));
147
148     Socket::setup(socket);
149
150     auto connection = makeUnique<Connection>(client);
151
152     connection->id = id;
153     connection->poll = Socket::preparePolling(socket);
154     connection->socket = socket;
155     m_connections.add(id, WTFMove(connection));
156     wakeupWorkerThread();
157
158     return id;
159 }
160
161 void RemoteInspectorSocketEndpoint::invalidateClient(Client& client)
162 {
163     LockHolder lock(m_connectionsLock);
164     m_connections.removeIf([&client](auto& keyValue) {
165         const auto& connection = keyValue.value;
166
167         if (&connection->client != &client)
168             return false;
169
170         Socket::close(connection->socket);
171         // do not call client.didClose because client is already invalidating phase.
172         return true;
173     });
174 }
175
176 Optional<uint16_t> RemoteInspectorSocketEndpoint::getPort(ConnectionID id) const
177 {
178     LockHolder lock(m_connectionsLock);
179     if (const auto& connection = m_connections.get(id))
180         return Socket::getPort(connection->socket);
181
182     return WTF::nullopt;
183 }
184
185 void RemoteInspectorSocketEndpoint::recvIfEnabled(ConnectionID id)
186 {
187     LockHolder lock(m_connectionsLock);
188     if (const auto& connection = m_connections.get(id)) {
189         Vector<uint8_t> recvBuffer(Socket::BufferSize);
190         if (auto readSize = Socket::read(connection->socket, recvBuffer.data(), recvBuffer.size())) {
191             if (*readSize > 0) {
192                 recvBuffer.shrink(*readSize);
193                 connection->client.didReceive(id, WTFMove(recvBuffer));
194                 return;
195             }
196         }
197
198         Socket::close(connection->socket);
199         m_connections.remove(id);
200
201         lock.unlockEarly();
202         connection->client.didClose(id);
203     }
204 }
205
206 void RemoteInspectorSocketEndpoint::sendIfEnabled(ConnectionID id)
207 {
208     LockHolder lock(m_connectionsLock);
209     if (const auto& connection = m_connections.get(id)) {
210         Socket::clearWaitingWritable(connection->poll);
211
212         auto& buffer = connection->sendBuffer;
213         if (buffer.isEmpty())
214             return;
215
216         if (auto writeSize = Socket::write(connection->socket, buffer.data(), std::min(buffer.size(), Socket::BufferSize))) {
217             auto size = *writeSize;
218             if (size == buffer.size()) {
219                 buffer.clear();
220                 return;
221             }
222
223             if (size > 0)
224                 buffer.remove(0, size);
225         }
226
227         Socket::markWaitingWritable(connection->poll);
228     }
229 }
230
231 void RemoteInspectorSocketEndpoint::send(ConnectionID id, const uint8_t* data, size_t size)
232 {
233     LockHolder lock(m_connectionsLock);
234     if (const auto& connection = m_connections.get(id)) {
235         size_t offset = 0;
236         if (connection->sendBuffer.isEmpty()) {
237             // Try to call send() directly if buffer is empty.
238             if (auto writeSize = Socket::write(connection->socket, data, std::min(size, Socket::BufferSize)))
239                 offset = *writeSize;
240             // @TODO need to handle closed socket case?
241         }
242
243         // Check all data is sent.
244         if (offset == size)
245             return;
246
247         // Copy remaining data to send later.
248         connection->sendBuffer.appendRange(data + offset, data + size);
249         Socket::markWaitingWritable(connection->poll);
250
251         wakeupWorkerThread();
252     }
253 }
254
255 void RemoteInspectorSocketEndpoint::acceptInetSocketIfEnabled(ConnectionID id)
256 {
257     if (!isListening(id))
258         return;
259
260     LockHolder lock(m_connectionsLock);
261     if (const auto& connection = m_connections.get(id)) {
262         if (auto socket = Socket::accept(connection->socket)) {
263             // Need to unlock before calling createClient as it also attempts to lock.
264             lock.unlockEarly();
265             if (auto newID = createClient(*socket, connection->client)) {
266                 connection->client.didAccept(newID.value(), id, Socket::Domain::Network);
267                 return;
268             }
269
270             Socket::close(*socket);
271         }
272     }
273 }
274
275 } // namespace Inspector
276
277 #endif // ENABLE(REMOTE_INSPECTOR)