• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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