1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "inspector_socket_server.h"
16
17 #include <algorithm>
18 #include <cstdio>
19 #include <iostream>
20 #include <map>
21 #include <securec.h>
22 #include <set>
23 #include <sstream>
24 #include <string>
25 #include <unistd.h>
26
27 #include "jsvm_dfx.h"
28 #include "jsvm_version.h"
29 #include "uv.h"
30 #include "v8_inspector_protocol_json.h"
31 #include "zlib.h"
32
33 namespace jsvm {
34 namespace inspector {
35
36 // Function is declared in inspector_io.h so the rest of the node does not
37 // depend on inspector_socket_server.h
38 std::string FormatWsAddress(const std::string& host, int port, const std::string& targetId, bool includeProtocol);
39 namespace {
FormatHostPort(const std::string & host,int port)40 std::string FormatHostPort(const std::string& host, int port)
41 {
42 // Host is valid (socket was bound) so colon means it's a v6 IP address
43 bool isIPV6 = (host.find(':') != std::string::npos);
44 std::ostringstream url;
45 if (isIPV6) {
46 url << '[' << host << ']';
47 } else {
48 url << host;
49 }
50 url << ':' << port;
51 return url.str();
52 }
53
Escape(std::string * string)54 void Escape(std::string* string)
55 {
56 for (char& c : *string) {
57 c = (c == '\"' || c == '\\') ? '_' : c;
58 }
59 }
60
FormatAddress(const std::string & host,const std::string & targetId,bool includeProtocol)61 std::string FormatAddress(const std::string& host, const std::string& targetId, bool includeProtocol)
62 {
63 std::ostringstream url;
64 if (includeProtocol) {
65 url << "ws://";
66 }
67 url << host << '/' << targetId;
68 return url.str();
69 }
70
MapToString(const std::map<std::string,std::string> & object)71 std::string MapToString(const std::map<std::string, std::string>& object)
72 {
73 bool first = true;
74 std::ostringstream json;
75 json << "{\n";
76 for (const auto& nameValue : object) {
77 if (!first) {
78 json << ",\n";
79 }
80 first = false;
81 json << " \"" << nameValue.first << "\": \"";
82 json << nameValue.second << "\"";
83 }
84 json << "\n} ";
85 return json.str();
86 }
87
MapsToString(const std::vector<std::map<std::string,std::string>> & array)88 std::string MapsToString(const std::vector<std::map<std::string, std::string>>& array)
89 {
90 bool isFirst = true;
91 std::ostringstream json;
92 json << "[ ";
93 for (const auto& object : array) {
94 if (!isFirst) {
95 json << ", ";
96 }
97 isFirst = false;
98 json << MapToString(object);
99 }
100 json << "]\n\n";
101 return json.str();
102 }
103
SendHttpResponse(InspectorSocket * socket,const std::string & response,int code)104 void SendHttpResponse(InspectorSocket* socket, const std::string& response, int code)
105 {
106 const char headers[] = "HTTP/1.0 %d OK\r\n"
107 "Content-Type: application/json; charset=UTF-8\r\n"
108 "Cache-Control: no-cache\r\n"
109 "Content-Length: %zu\r\n"
110 "\r\n";
111 char header[sizeof(headers) + 20];
112 int headerLen = snprintf_s(header, sizeof(header), sizeof(header) - 1, headers, code, response.size());
113 CHECK(headerLen >= 0);
114 socket->Write(header, headerLen);
115 socket->Write(response.data(), response.size());
116 }
117
MatchPathSegment(const char * path,const char * expected)118 const char* MatchPathSegment(const char* path, const char* expected)
119 {
120 size_t len = strlen(expected);
121 if (StringEqualNoCaseN(path, expected, len)) {
122 if (path[len] == '/') {
123 return path + len + 1;
124 }
125 if (path[len] == '\0') {
126 return path + len;
127 }
128 }
129 return nullptr;
130 }
131
132 enum HttpStatusCode : int {
133 HTTP_OK = 200,
134 HTTP_NOT_FOUND = 404,
135 };
136
SendHttpNotFound(InspectorSocket * socket)137 void SendHttpNotFound(InspectorSocket* socket)
138 {
139 SendHttpResponse(socket, "", HttpStatusCode::HTTP_NOT_FOUND);
140 }
141
SendVersionResponse(InspectorSocket * socket)142 void SendVersionResponse(InspectorSocket* socket)
143 {
144 std::map<std::string, std::string> response;
145 response["Protocol-Version"] = "1.1";
146 response["Browser"] = "jsvm/" JSVM_VERSION_STRING;
147 SendHttpResponse(socket, MapToString(response), HttpStatusCode::HTTP_OK);
148 }
149
SendProtocolJson(InspectorSocket * socket)150 void SendProtocolJson(InspectorSocket* socket)
151 {
152 z_stream strm;
153 strm.zalloc = Z_NULL;
154 strm.zfree = Z_NULL;
155 strm.opaque = Z_NULL;
156 CHECK_EQ(inflateInit(&strm), Z_OK);
157 static const size_t decompressedSize = PROTOCOL_JSON[0] * 0x10000u + PROTOCOL_JSON[1] * 0x100u + PROTOCOL_JSON[2];
158 strm.next_in = const_cast<uint8_t*>(PROTOCOL_JSON + ByteOffset::BYTE_3);
159 strm.avail_in = sizeof(PROTOCOL_JSON) - ByteOffset::BYTE_3;
160 std::string data(decompressedSize, '\0');
161 strm.next_out = reinterpret_cast<Byte*>(data.data());
162 strm.avail_out = data.size();
163 CHECK_EQ(inflate(&strm, Z_FINISH), Z_STREAM_END);
164 CHECK_EQ(strm.avail_out, 0);
165 CHECK_EQ(inflateEnd(&strm), Z_OK);
166 SendHttpResponse(socket, data, HttpStatusCode::HTTP_OK);
167 }
168 } // namespace
169
FormatWsAddress(const std::string & host,int port,const std::string & targetId,bool includeProtocol)170 std::string FormatWsAddress(const std::string& host, int port, const std::string& targetId, bool includeProtocol)
171 {
172 return FormatAddress(FormatHostPort(host, port), targetId, includeProtocol);
173 }
174
175 class SocketSession {
176 public:
177 SocketSession(InspectorSocketServer* server, int id, int serverPort);
Close()178 void Close()
179 {
180 wsSocket.reset();
181 }
182 void Send(const std::string& message);
Own(InspectorSocket::Pointer wsSocketParam)183 void Own(InspectorSocket::Pointer wsSocketParam)
184 {
185 wsSocket = std::move(wsSocketParam);
186 }
GetId() const187 int GetId() const
188 {
189 return id;
190 }
ServerPort()191 int ServerPort()
192 {
193 return serverPort;
194 }
GetWsSocket()195 InspectorSocket* GetWsSocket()
196 {
197 return wsSocket.get();
198 }
Accept(const std::string & wsKey)199 void Accept(const std::string& wsKey)
200 {
201 wsSocket->AcceptUpgrade(wsKey);
202 }
Decline()203 void Decline()
204 {
205 wsSocket->CancelHandshake();
206 }
207
208 class Delegate : public InspectorSocket::Delegate {
209 public:
Delegate(InspectorSocketServer * server,int sessionId)210 Delegate(InspectorSocketServer* server, int sessionId) : server(server), usessionId(sessionId) {}
~Delegate()211 ~Delegate() override
212 {
213 server->SessionTerminated(usessionId);
214 }
215 void OnHttpGet(const std::string& host, const std::string& path) override;
216 void OnSocketUpgrade(const std::string& host, const std::string& path, const std::string& wsKey) override;
217 void OnWsFrame(const std::vector<char>& data) override;
218
219 private:
Session()220 SocketSession* Session()
221 {
222 return server->Session(usessionId);
223 }
224
225 InspectorSocketServer* server;
226 int usessionId;
227 };
228
229 private:
230 const int id;
231 InspectorSocket::Pointer wsSocket;
232 const int serverPort;
233 };
234
235 class ServerSocket {
236 public:
ServerSocket(InspectorSocketServer * server)237 explicit ServerSocket(InspectorSocketServer* server)
238 : tcpSocket(uv_tcp_t()), server(server), unixSocket(uv_pipe_t())
239 {}
240 int Listen(sockaddr* addr, uv_loop_t* loop, int pid = -1);
Close()241 void Close()
242 {
243 uv_close(reinterpret_cast<uv_handle_t*>(&tcpSocket), FreeOnCloseCallback);
244 }
CloseUnix()245 void CloseUnix()
246 {
247 if (unixSocketOn) {
248 uv_close(reinterpret_cast<uv_handle_t*>(&unixSocket), nullptr);
249 unixSocketOn = false;
250 }
251 }
GetPort() const252 int GetPort() const
253 {
254 return port;
255 }
256
257 private:
258 template<typename UvHandle>
FromTcpSocket(UvHandle * socket)259 static ServerSocket* FromTcpSocket(UvHandle* socket)
260 {
261 return jsvm::inspector::ContainerOf(&ServerSocket::tcpSocket, reinterpret_cast<uv_tcp_t*>(socket));
262 }
263 static void SocketConnectedCallback(uv_stream_t* tcpSocket, int status);
264 static void UnixSocketConnectedCallback(uv_stream_t* unixSocket, int status);
FreeOnCloseCallback(uv_handle_t * tcpSocket)265 static void FreeOnCloseCallback(uv_handle_t* tcpSocket)
266 {
267 delete FromTcpSocket(tcpSocket);
268 }
269 int DetectPort(uv_loop_t* loop, int pid);
270 ~ServerSocket() = default;
271
272 uv_tcp_t tcpSocket;
273 InspectorSocketServer* server;
274 uv_pipe_t unixSocket;
275 int port = -1;
276 bool unixSocketOn = false;
277 };
278
PrintDebuggerReadyMessage(const std::string & host,const std::vector<InspectorSocketServer::ServerSocketPtr> & serverSockets,const std::vector<std::string> & ids,const char * verb,bool publishUidStderr,FILE * out)279 void PrintDebuggerReadyMessage(const std::string& host,
280 const std::vector<InspectorSocketServer::ServerSocketPtr>& serverSockets,
281 const std::vector<std::string>& ids,
282 const char* verb,
283 bool publishUidStderr,
284 FILE* out)
285 {
286 if (!publishUidStderr || out == nullptr) {
287 return;
288 }
289 for (const auto& serverSocket : serverSockets) {
290 for (const std::string& id : ids) {
291 if (fprintf(out, "Debugger %s on %s\n", verb,
292 FormatWsAddress(host, serverSocket->GetPort(), id, true).c_str()) < 0) {
293 return;
294 }
295 }
296 }
297 if (fprintf(out, "For help, see: %s\n", "https://nodejs.org/en/docs/inspector") < 0) {
298 return;
299 }
300 if (fflush(out) != 0) {
301 return;
302 }
303 }
304
InspectorSocketServer(std::unique_ptr<SocketServerDelegate> delegateParam,uv_loop_t * loop,const std::string & host,int port,const InspectPublishUid & inspectPublishUid,FILE * out,int pid)305 InspectorSocketServer::InspectorSocketServer(std::unique_ptr<SocketServerDelegate> delegateParam,
306 uv_loop_t* loop,
307 const std::string& host,
308 int port,
309 const InspectPublishUid& inspectPublishUid,
310 FILE* out,
311 int pid)
312 : loop(loop), delegate(std::move(delegateParam)), host(host), port(port), inspectPublishUid(inspectPublishUid),
313 nextSessionId(0), out(out), pid(pid)
314 {
315 delegate->AssignServer(this);
316 state = ServerState::NEW;
317 }
318
319 InspectorSocketServer::~InspectorSocketServer() = default;
320
Session(int sessionId)321 SocketSession* InspectorSocketServer::Session(int sessionId)
322 {
323 auto it = connectedSessions.find(sessionId);
324 return it == connectedSessions.end() ? nullptr : it->second.second.get();
325 }
326
SessionStarted(int sessionId,const std::string & targetId,const std::string & wsKey)327 void InspectorSocketServer::SessionStarted(int sessionId, const std::string& targetId, const std::string& wsKey)
328 {
329 SocketSession* session = Session(sessionId);
330 DCHECK(session != nullptr);
331 if (!TargetExists(targetId)) {
332 session->Decline();
333 return;
334 }
335 connectedSessions[sessionId].first = targetId;
336 session->Accept(wsKey);
337 delegate->StartSession(sessionId, targetId);
338 }
339
SessionTerminated(int sessionId)340 void InspectorSocketServer::SessionTerminated(int sessionId)
341 {
342 if (Session(sessionId) == nullptr) {
343 return;
344 }
345 bool wasAttached = connectedSessions[sessionId].first != "";
346 if (wasAttached) {
347 delegate->EndSession(sessionId);
348 }
349 connectedSessions.erase(sessionId);
350 if (connectedSessions.empty()) {
351 if (wasAttached && state == ServerState::RUNNING && !serverSockets.empty()) {
352 PrintDebuggerReadyMessage(host, serverSockets, delegate->GetTargetIds(), "ending",
353 inspectPublishUid.console, out);
354 }
355 if (state == ServerState::STOPPED) {
356 delegate.reset();
357 }
358 }
359 }
360
HandleGetRequest(int sessionId,const std::string & hostName,const std::string & path)361 bool InspectorSocketServer::HandleGetRequest(int sessionId, const std::string& hostName, const std::string& path)
362 {
363 SocketSession* session = Session(sessionId);
364 DCHECK(session != nullptr);
365 InspectorSocket* socket = session->GetWsSocket();
366 if (!inspectPublishUid.http) {
367 SendHttpNotFound(socket);
368 return true;
369 }
370 const char* command = MatchPathSegment(path.c_str(), "/json");
371 if (!command) {
372 return false;
373 }
374
375 bool hasHandled = false;
376 if (MatchPathSegment(command, "list") || command[0] == '\0') {
377 SendListResponse(socket, hostName, session);
378 hasHandled = true;
379 } else if (MatchPathSegment(command, "protocol")) {
380 SendProtocolJson(socket);
381 hasHandled = true;
382 } else if (MatchPathSegment(command, "version")) {
383 SendVersionResponse(socket);
384 hasHandled = true;
385 }
386 return hasHandled;
387 }
388
SendListResponse(InspectorSocket * socket,const std::string & hostName,SocketSession * session)389 void InspectorSocketServer::SendListResponse(InspectorSocket* socket,
390 const std::string& hostName,
391 SocketSession* session)
392 {
393 std::vector<std::map<std::string, std::string>> response;
394 for (const std::string& id : delegate->GetTargetIds()) {
395 response.push_back(std::map<std::string, std::string>());
396 std::map<std::string, std::string>& targetMap = response.back();
397 targetMap["description"] = "jsvm instance";
398 targetMap["id"] = id;
399 targetMap["title"] = delegate->GetTargetTitle(id);
400 Escape(&targetMap["title"]);
401 targetMap["type"] = "node";
402 // This attribute value is a "best effort" URL that is passed as a JSON
403 // string. It is not guaranteed to resolve to a valid resource.
404 targetMap["url"] = delegate->GetTargetUrl(id);
405 Escape(&targetMap["url"]);
406
407 std::string detectedHost = hostName;
408 if (detectedHost.empty()) {
409 detectedHost = FormatHostPort(socket->GetHost(), session->ServerPort());
410 }
411 std::string formattedAddress = FormatAddress(detectedHost, id, false);
412 targetMap["devtoolsFrontendUrl"] = GetFrontendURL(false, formattedAddress);
413 // The compat URL is for Chrome browsers older than 66.0.3345.0
414 targetMap["devtoolsFrontendUrlCompat"] = GetFrontendURL(true, formattedAddress);
415 targetMap["webSocketDebuggerUrl"] = FormatAddress(detectedHost, id, true);
416 }
417 SendHttpResponse(socket, MapsToString(response), HttpStatusCode::HTTP_OK);
418 }
419
GetFrontendURL(bool isCompat,const std::string & formattedAddress)420 std::string InspectorSocketServer::GetFrontendURL(bool isCompat, const std::string& formattedAddress)
421 {
422 std::ostringstream frontendUrl;
423 frontendUrl << "devtools://devtools/bundled/";
424 frontendUrl << (isCompat ? "inspector" : "js_app");
425 frontendUrl << ".html?v8only=true&ws=";
426 frontendUrl << formattedAddress;
427 return frontendUrl.str();
428 }
429
Start()430 bool InspectorSocketServer::Start()
431 {
432 CHECK_NOT_NULL(delegate);
433 CHECK_EQ(state, ServerState::NEW);
434 std::unique_ptr<SocketServerDelegate> delegateHolder;
435 // We will return it if startup is successful
436 delegate.swap(delegateHolder);
437 struct addrinfo hints;
438 memset_s(&hints, sizeof(hints), 0, sizeof(hints));
439 hints.ai_flags = AI_NUMERICSERV;
440 hints.ai_socktype = SOCK_STREAM;
441 uv_getaddrinfo_t req;
442 const std::string portString = std::to_string(port);
443 int err = uv_getaddrinfo(loop, &req, nullptr, host.c_str(), portString.c_str(), &hints);
444 if (err < 0) {
445 if (out != nullptr) {
446 if (fprintf(out, "Unable to resolve \"%s\": %s\n", host.c_str(), uv_strerror(err)) < 0) {
447 return false;
448 }
449 }
450 return false;
451 }
452 for (addrinfo* address = req.addrinfo; address != nullptr; address = address->ai_next) {
453 auto serverSocket = ServerSocketPtr(new ServerSocket(this));
454 err = serverSocket->Listen(address->ai_addr, loop, pid);
455 if (err == 0) {
456 serverSockets.push_back(std::move(serverSocket));
457 }
458 }
459 uv_freeaddrinfo(req.addrinfo);
460
461 // We only show error if we failed to start server on all addresses. We only
462 // show one error, for the last address.
463 if (serverSockets.empty()) {
464 if (out != nullptr) {
465 if (fprintf(out, "Starting inspector on %s:%d failed: %s\n", host.c_str(), port, uv_strerror(err)) < 0) {
466 return false;
467 }
468 if (fflush(out) != 0) {
469 return false;
470 }
471 }
472 return false;
473 }
474 delegate.swap(delegateHolder);
475 state = ServerState::RUNNING;
476 PrintDebuggerReadyMessage(host, serverSockets, delegate->GetTargetIds(), "listening", inspectPublishUid.console,
477 out);
478 return true;
479 }
480
Stop()481 void InspectorSocketServer::Stop()
482 {
483 if (state == ServerState::STOPPED) {
484 return;
485 }
486 CHECK_EQ(state, ServerState::RUNNING);
487 state = ServerState::STOPPED;
488 serverSockets.clear();
489 if (Done()) {
490 delegate.reset();
491 }
492 }
493
TerminateConnections()494 void InspectorSocketServer::TerminateConnections()
495 {
496 for (const auto& keyValue : connectedSessions) {
497 keyValue.second.second->Close();
498 }
499 }
500
TargetExists(const std::string & id)501 bool InspectorSocketServer::TargetExists(const std::string& id)
502 {
503 const std::vector<std::string>& targetIds = delegate->GetTargetIds();
504 const auto& found = std::find(targetIds.begin(), targetIds.end(), id);
505 return found != targetIds.end();
506 }
507
GetPort() const508 int InspectorSocketServer::GetPort() const
509 {
510 if (!serverSockets.empty()) {
511 return serverSockets[0]->GetPort();
512 }
513 return port;
514 }
515
Accept(int serverPort,uv_stream_t * serverSocket)516 void InspectorSocketServer::Accept(int serverPort, uv_stream_t* serverSocket)
517 {
518 std::unique_ptr<SocketSession> session = std::make_unique<SocketSession>(this, nextSessionId++, serverPort);
519
520 InspectorSocket::DelegatePointer delegatePointer =
521 InspectorSocket::DelegatePointer(new SocketSession::Delegate(this, session->GetId()));
522
523 InspectorSocket::Pointer inspector = InspectorSocket::Accept(serverSocket, std::move(delegatePointer));
524 if (inspector) {
525 session->Own(std::move(inspector));
526 connectedSessions[session->GetId()].second = std::move(session);
527 }
528 }
529
Send(int sessionId,const std::string & message)530 void InspectorSocketServer::Send(int sessionId, const std::string& message)
531 {
532 SocketSession* session = Session(sessionId);
533 if (session != nullptr) {
534 session->Send(message);
535 }
536 }
537
CloseServerSocket(ServerSocket * server)538 void InspectorSocketServer::CloseServerSocket(ServerSocket* server)
539 {
540 server->Close();
541 server->CloseUnix();
542 }
543
544 // InspectorSession tracking
SocketSession(InspectorSocketServer * server,int id,int serverPort)545 SocketSession::SocketSession(InspectorSocketServer* server, int id, int serverPort) : id(id), serverPort(serverPort) {}
546
Send(const std::string & message)547 void SocketSession::Send(const std::string& message)
548 {
549 wsSocket->Write(message.data(), message.length());
550 }
551
OnHttpGet(const std::string & host,const std::string & path)552 void SocketSession::Delegate::OnHttpGet(const std::string& host, const std::string& path)
553 {
554 if (!server->HandleGetRequest(usessionId, host, path)) {
555 SocketSession* session = Session();
556 DCHECK(session != nullptr);
557 session->GetWsSocket()->CancelHandshake();
558 }
559 }
560
OnSocketUpgrade(const std::string & host,const std::string & path,const std::string & wsKey)561 void SocketSession::Delegate::OnSocketUpgrade(const std::string& host,
562 const std::string& path,
563 const std::string& wsKey)
564 {
565 std::string id = path.empty() ? path : path.substr(1);
566 server->SessionStarted(usessionId, id, wsKey);
567 }
568
OnWsFrame(const std::vector<char> & data)569 void SocketSession::Delegate::OnWsFrame(const std::vector<char>& data)
570 {
571 server->MessageReceived(usessionId, std::string(data.data(), data.size()));
572 }
573
574 // ServerSocket implementation
DetectPort(uv_loop_t * loop,int pid)575 int ServerSocket::DetectPort(uv_loop_t* loop, int pid)
576 {
577 sockaddr_storage addr;
578 int len = sizeof(addr);
579 int err = uv_tcp_getsockname(&tcpSocket, reinterpret_cast<struct sockaddr*>(&addr), &len);
580 if (err != 0) {
581 return err;
582 }
583 int portNum;
584 if (addr.ss_family == AF_INET6) {
585 portNum = reinterpret_cast<const sockaddr_in6*>(&addr)->sin6_port;
586 } else {
587 portNum = reinterpret_cast<const sockaddr_in*>(&addr)->sin_port;
588 }
589 port = ntohs(portNum);
590 if (!unixSocketOn && pid != -1) {
591 auto unixDomainSocketPath = "jsvm_devtools_remote_" + std::to_string(port) + "_" + std::to_string(pid);
592 auto* abstract = new char[unixDomainSocketPath.length() + 2];
593 abstract[0] = '\0';
594 int ret = strcpy_s(abstract + 1, unixDomainSocketPath.length() + 2, unixDomainSocketPath.c_str());
595 CHECK(ret == 0);
596 auto status = uv_pipe_init(loop, &unixSocket, 0);
597 if (status == 0) {
598 status = uv_pipe_bind2(&unixSocket, abstract, unixDomainSocketPath.length() + 1, 0);
599 }
600 if (status == 0) {
601 constexpr int unixBacklog = 128;
602 status = uv_listen(reinterpret_cast<uv_stream_t*>(&unixSocket), unixBacklog,
603 ServerSocket::UnixSocketConnectedCallback);
604 }
605 unixSocketOn = status == 0;
606 delete[] abstract;
607 }
608 return err;
609 }
610
Listen(sockaddr * addr,uv_loop_t * loop,int pid)611 int ServerSocket::Listen(sockaddr* addr, uv_loop_t* loop, int pid)
612 {
613 uv_tcp_t* server = &tcpSocket;
614 CHECK_EQ(0, uv_tcp_init(loop, server));
615 int err = uv_tcp_bind(server, addr, 0);
616 if (err == 0) {
617 // 511 is the value used by a 'net' module by default
618 err = uv_listen(reinterpret_cast<uv_stream_t*>(server), 511, ServerSocket::SocketConnectedCallback);
619 }
620 if (err == 0) {
621 err = DetectPort(loop, pid);
622 }
623 return err;
624 }
625
626 // static
SocketConnectedCallback(uv_stream_t * tcpSocket,int status)627 void ServerSocket::SocketConnectedCallback(uv_stream_t* tcpSocket, int status)
628 {
629 if (status == 0) {
630 ServerSocket* serverSocket = ServerSocket::FromTcpSocket(tcpSocket);
631 // Memory is freed when the socket closes.
632 serverSocket->server->Accept(serverSocket->port, tcpSocket);
633 }
634 }
635
UnixSocketConnectedCallback(uv_stream_t * unixSocket,int status)636 void ServerSocket::UnixSocketConnectedCallback(uv_stream_t* unixSocket, int status)
637 {
638 if (status == 0) {
639 (void)unixSocket;
640 }
641 }
642 } // namespace inspector
643 } // namespace jsvm
644