GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/inspector_socket_server.cc Lines: 326 369 88.3 %
Date: 2017-10-21 Branches: 112 177 63.3 %

Line Branch Exec Source
1
#include "inspector_socket_server.h"
2
3
#include "node.h"
4
#include "uv.h"
5
#include "zlib.h"
6
7
#include <algorithm>
8
#include <map>
9
#include <set>
10
#include <sstream>
11
12
namespace node {
13
namespace inspector {
14
15
// Function is declared in inspector_io.h so the rest of the node does not
16
// depend on inspector_socket_server.h
17
93
std::string FormatWsAddress(const std::string& host, int port,
18
                            const std::string& target_id,
19
                            bool include_protocol) {
20
  // Host is valid (socket was bound) so colon means it's a v6 IP address
21
93
  bool v6 = host.find(':') != std::string::npos;
22
93
  std::ostringstream url;
23
93
  if (include_protocol)
24
81
    url << "ws://";
25
93
  if (v6) {
26
4
    url << '[';
27
  }
28
93
  url << host;
29
93
  if (v6) {
30
4
    url << ']';
31
  }
32
93
  url << ':' << port << '/' << target_id;
33
93
  return url.str();
34
}
35
36
37
namespace {
38
39
static const uint8_t PROTOCOL_JSON[] = {
40
  #include "v8_inspector_protocol_json.h"  // NOLINT(build/include_order)
41
};
42
43
26
void Escape(std::string* string) {
44
2065
  for (char& c : *string) {
45

2039
    c = (c == '\"' || c == '\\') ? '_' : c;
46
  }
47
26
}
48
49
14
std::string MapToString(const std::map<std::string, std::string>& object) {
50
14
  bool first = true;
51
14
  std::ostringstream json;
52
14
  json << "{\n";
53
118
  for (const auto& name_value : object) {
54
104
    if (!first)
55
90
      json << ",\n";
56
104
    first = false;
57
104
    json << "  \"" << name_value.first << "\": \"";
58
104
    json << name_value.second << "\"";
59
  }
60
14
  json << "\n} ";
61
14
  return json.str();
62
}
63
64
13
std::string MapsToString(
65
    const std::vector<std::map<std::string, std::string>>& array) {
66
13
  bool first = true;
67
13
  std::ostringstream json;
68
13
  json << "[ ";
69
26
  for (const auto& object : array) {
70
13
    if (!first)
71
      json << ", ";
72
13
    first = false;
73
13
    json << MapToString(object);
74
  }
75
13
  json << "]\n\n";
76
13
  return json.str();
77
}
78
79
45
const char* MatchPathSegment(const char* path, const char* expected) {
80
45
  size_t len = strlen(expected);
81
45
  if (StringEqualNoCaseN(path, expected, len)) {
82
32
    if (path[len] == '/') return path + len + 1;
83
15
    if (path[len] == '\0') return path + len;
84
  }
85
13
  return nullptr;
86
}
87
88
87
void OnBufferAlloc(uv_handle_t* handle, size_t len, uv_buf_t* buf) {
89
87
  buf->base = new char[len];
90
87
  buf->len = len;
91
87
}
92
93
66
void PrintDebuggerReadyMessage(const std::string& host,
94
                               int port,
95
                               const std::vector<std::string>& ids,
96
                               FILE* out) {
97
66
  if (out == NULL) {
98
66
    return;
99
  }
100
132
  for (const std::string& id : ids) {
101
    fprintf(out, "Debugger listening on %s\n",
102
66
            FormatWsAddress(host, port, id, true).c_str());
103
  }
104
  fprintf(out, "For help see %s\n",
105
66
          "https://nodejs.org/en/docs/inspector");
106
66
  fflush(out);
107
}
108
109
14
void SendHttpResponse(InspectorSocket* socket, const std::string& response) {
110
  const char HEADERS[] = "HTTP/1.0 200 OK\r\n"
111
                         "Content-Type: application/json; charset=UTF-8\r\n"
112
                         "Cache-Control: no-cache\r\n"
113
                         "Content-Length: %zu\r\n"
114
14
                         "\r\n";
115
  char header[sizeof(HEADERS) + 20];
116
14
  int header_len = snprintf(header, sizeof(header), HEADERS, response.size());
117
14
  inspector_write(socket, header, header_len);
118
14
  inspector_write(socket, response.data(), response.size());
119
14
}
120
121
1
void SendVersionResponse(InspectorSocket* socket) {
122
1
  std::map<std::string, std::string> response;
123
1
  response["Browser"] = "node.js/" NODE_VERSION;
124
1
  response["Protocol-Version"] = "1.1";
125
1
  SendHttpResponse(socket, MapToString(response));
126
1
}
127
128
void SendProtocolJson(InspectorSocket* socket) {
129
  z_stream strm;
130
  strm.zalloc = Z_NULL;
131
  strm.zfree = Z_NULL;
132
  strm.opaque = Z_NULL;
133
  CHECK_EQ(Z_OK, inflateInit(&strm));
134
  static const size_t kDecompressedSize =
135
      PROTOCOL_JSON[0] * 0x10000u +
136
      PROTOCOL_JSON[1] * 0x100u +
137
      PROTOCOL_JSON[2];
138
  strm.next_in = const_cast<uint8_t*>(PROTOCOL_JSON + 3);
139
  strm.avail_in = sizeof(PROTOCOL_JSON) - 3;
140
  std::string data(kDecompressedSize, '\0');
141
  strm.next_out = reinterpret_cast<Byte*>(&data[0]);
142
  strm.avail_out = data.size();
143
  CHECK_EQ(Z_STREAM_END, inflate(&strm, Z_FINISH));
144
  CHECK_EQ(0, strm.avail_out);
145
  CHECK_EQ(Z_OK, inflateEnd(&strm));
146
  SendHttpResponse(socket, data);
147
}
148
149
12
int GetSocketHost(uv_tcp_t* socket, std::string* out_host) {
150
  char ip[INET6_ADDRSTRLEN];
151
  sockaddr_storage addr;
152
12
  int len = sizeof(addr);
153
  int err = uv_tcp_getsockname(socket,
154
                               reinterpret_cast<struct sockaddr*>(&addr),
155
12
                               &len);
156
12
  if (err != 0)
157
    return err;
158
12
  if (addr.ss_family == AF_INET6) {
159
    const sockaddr_in6* v6 = reinterpret_cast<const sockaddr_in6*>(&addr);
160
    err = uv_ip6_name(v6, ip, sizeof(ip));
161
  } else {
162
12
    const sockaddr_in* v4 = reinterpret_cast<const sockaddr_in*>(&addr);
163
12
    err = uv_ip4_name(v4, ip, sizeof(ip));
164
  }
165
12
  if (err != 0)
166
    return err;
167
12
  *out_host = ip;
168
12
  return err;
169
}
170
}  // namespace
171
172
173
14
class Closer {
174
 public:
175
14
  explicit Closer(InspectorSocketServer* server) : server_(server),
176
14
                                                   close_count_(0) { }
177
178
14
  void AddCallback(InspectorSocketServer::ServerCallback callback) {
179
14
    if (callback == nullptr)
180
28
      return;
181
    callbacks_.insert(callback);
182
  }
183
184
14
  void DecreaseExpectedCount() {
185
14
    --close_count_;
186
14
    NotifyIfDone();
187
14
  }
188
189
14
  void IncreaseExpectedCount() {
190
14
    ++close_count_;
191
14
  }
192
193
28
  void NotifyIfDone() {
194
28
    if (close_count_ == 0) {
195
14
      for (auto callback : callbacks_) {
196
        callback(server_);
197
      }
198
14
      InspectorSocketServer* server = server_;
199
14
      delete server->closer_;
200
14
      server->closer_ = nullptr;
201
    }
202
28
  }
203
204
 private:
205
  InspectorSocketServer* server_;
206
  std::set<InspectorSocketServer::ServerCallback> callbacks_;
207
  int close_count_;
208
};
209
210
30
class SocketSession {
211
 public:
212
  static int Accept(InspectorSocketServer* server, int server_port,
213
                    uv_stream_t* server_socket);
214
  void Send(const std::string& message);
215
  void Close();
216
217
50
  int id() const { return id_; }
218
1
  bool IsForTarget(const std::string& target_id) const {
219
1
    return target_id_ == target_id;
220
  }
221
12
  static int ServerPortForClient(InspectorSocket* client) {
222
12
    return From(client)->server_port_;
223
  }
224
225
 private:
226
  SocketSession(InspectorSocketServer* server, int server_port);
227
175
  static SocketSession* From(InspectorSocket* socket) {
228
175
    return node::ContainerOf(&SocketSession::socket_, socket);
229
  }
230
231
  enum class State { kHttp, kWebSocket, kClosing, kEOF, kDeclined };
232
  static bool HandshakeCallback(InspectorSocket* socket,
233
                                enum inspector_handshake_event state,
234
                                const std::string& path);
235
  static void ReadCallback(uv_stream_t* stream, ssize_t read,
236
                           const uv_buf_t* buf);
237
  static void CloseCallback(InspectorSocket* socket, int code);
238
239
  void FrontendConnected();
240
  void SetDeclined() { state_ = State::kDeclined; }
241
10
  void SetTargetId(const std::string& target_id) {
242
10
    CHECK(target_id_.empty());
243
10
    target_id_ = target_id;
244
10
  }
245
246
  const int id_;
247
  InspectorSocket socket_;
248
  InspectorSocketServer* server_;
249
  std::string target_id_;
250
  State state_;
251
  const int server_port_;
252
};
253
254
class ServerSocket {
255
 public:
256
  static int Listen(InspectorSocketServer* inspector_server,
257
                    sockaddr* addr, uv_loop_t* loop);
258
14
  void Close() {
259
    uv_close(reinterpret_cast<uv_handle_t*>(&tcp_socket_),
260
14
             SocketClosedCallback);
261
14
  }
262
132
  int port() const { return port_; }
263
264
 private:
265
69
  explicit ServerSocket(InspectorSocketServer* server)
266
69
      : tcp_socket_(uv_tcp_t()), server_(server), port_(-1) {}
267
  template<typename UvHandle>
268
46
  static ServerSocket* FromTcpSocket(UvHandle* socket) {
269
    return node::ContainerOf(&ServerSocket::tcp_socket_,
270
46
                             reinterpret_cast<uv_tcp_t*>(socket));
271
  }
272
273
  static void SocketConnectedCallback(uv_stream_t* tcp_socket, int status);
274
  static void SocketClosedCallback(uv_handle_t* tcp_socket);
275
2
  static void FreeOnCloseCallback(uv_handle_t* tcp_socket_) {
276
2
    delete FromTcpSocket(tcp_socket_);
277
2
  }
278
  int DetectPort();
279
280
  uv_tcp_t tcp_socket_;
281
  InspectorSocketServer* server_;
282
  int port_;
283
};
284
285
68
InspectorSocketServer::InspectorSocketServer(SocketServerDelegate* delegate,
286
                                             uv_loop_t* loop,
287
                                             const std::string& host,
288
                                             int port,
289
                                             FILE* out) : loop_(loop),
290
                                                          delegate_(delegate),
291
                                                          host_(host),
292
                                                          port_(port),
293
                                                          closer_(nullptr),
294
                                                          next_session_id_(0),
295
68
                                                          out_(out) {
296
68
  state_ = ServerState::kNew;
297
68
}
298
299
10
bool InspectorSocketServer::SessionStarted(SocketSession* session,
300
                                           const std::string& id) {
301

10
  if (TargetExists(id) && delegate_->StartSession(session->id(), id)) {
302
10
    connected_sessions_[session->id()] = session;
303
10
    return true;
304
  } else {
305
    return false;
306
  }
307
}
308
309
30
void InspectorSocketServer::SessionTerminated(SocketSession* session) {
310
30
  int id = session->id();
311
30
  if (connected_sessions_.erase(id) != 0) {
312
10
    delegate_->EndSession(id);
313
10
    if (connected_sessions_.empty()) {
314

10
      if (state_ == ServerState::kRunning && !server_sockets_.empty()) {
315
        PrintDebuggerReadyMessage(host_, server_sockets_[0]->port(),
316
                                  delegate_->GetTargetIds(), out_);
317
      }
318
10
      if (state_ == ServerState::kStopped) {
319
10
        delegate_->ServerDone();
320
      }
321
    }
322
  }
323
30
  delete session;
324
30
}
325
326
17
bool InspectorSocketServer::HandleGetRequest(InspectorSocket* socket,
327
                                             const std::string& path) {
328
17
  const char* command = MatchPathSegment(path.c_str(), "/json");
329
17
  if (command == nullptr)
330
    return false;
331
332

17
  if (MatchPathSegment(command, "list") || command[0] == '\0') {
333
13
    SendListResponse(socket);
334
13
    return true;
335
4
  } else if (MatchPathSegment(command, "protocol")) {
336
    SendProtocolJson(socket);
337
    return true;
338
4
  } else if (MatchPathSegment(command, "version")) {
339
1
    SendVersionResponse(socket);
340
1
    return true;
341
3
  } else if (const char* target_id = MatchPathSegment(command, "activate")) {
342
2
    if (TargetExists(target_id)) {
343
      SendHttpResponse(socket, "Target activated");
344
      return true;
345
    }
346
2
    return false;
347
  }
348
1
  return false;
349
}
350
351
13
void InspectorSocketServer::SendListResponse(InspectorSocket* socket) {
352
13
  std::vector<std::map<std::string, std::string>> response;
353
26
  for (const std::string& id : delegate_->GetTargetIds()) {
354
13
    response.push_back(std::map<std::string, std::string>());
355
13
    std::map<std::string, std::string>& target_map = response.back();
356
13
    target_map["description"] = "node.js instance";
357
13
    target_map["faviconUrl"] = "https://nodejs.org/static/favicon.ico";
358
13
    target_map["id"] = id;
359
13
    target_map["title"] = delegate_->GetTargetTitle(id);
360
13
    Escape(&target_map["title"]);
361
13
    target_map["type"] = "node";
362
    // This attribute value is a "best effort" URL that is passed as a JSON
363
    // string. It is not guaranteed to resolve to a valid resource.
364
13
    target_map["url"] = delegate_->GetTargetUrl(id);
365
13
    Escape(&target_map["url"]);
366
367
13
    bool connected = false;
368
13
    for (const auto& session : connected_sessions_) {
369
1
      if (session.second->IsForTarget(id)) {
370
1
        connected = true;
371
1
        break;
372
      }
373
    }
374
13
    if (!connected) {
375
12
      std::string host;
376
12
      int port = SocketSession::ServerPortForClient(socket);
377
12
      GetSocketHost(&socket->tcp, &host);
378
24
      std::ostringstream frontend_url;
379
12
      frontend_url << "chrome-devtools://devtools/bundled";
380
12
      frontend_url << "/inspector.html?experiments=true&v8only=true&ws=";
381
12
      frontend_url << FormatWsAddress(host, port, id, false);
382
12
      target_map["devtoolsFrontendUrl"] += frontend_url.str();
383
24
      target_map["webSocketDebuggerUrl"] =
384
24
          FormatWsAddress(host, port, id, true);
385
    }
386
13
  }
387
13
  SendHttpResponse(socket, MapsToString(response));
388
13
}
389
390
68
bool InspectorSocketServer::Start() {
391
68
  CHECK_EQ(state_, ServerState::kNew);
392
  struct addrinfo hints;
393
68
  memset(&hints, 0, sizeof(hints));
394
68
  hints.ai_flags = AI_NUMERICSERV;
395
68
  hints.ai_socktype = SOCK_STREAM;
396
  uv_getaddrinfo_t req;
397
68
  const std::string port_string = std::to_string(port_);
398
  int err = uv_getaddrinfo(loop_, &req, nullptr, host_.c_str(),
399
68
                           port_string.c_str(), &hints);
400
68
  if (err < 0) {
401
    if (out_ != NULL) {
402
      fprintf(out_, "Unable to resolve \"%s\": %s\n", host_.c_str(),
403
              uv_strerror(err));
404
    }
405
    return false;
406
  }
407
137
  for (addrinfo* address = req.addrinfo; address != nullptr;
408
       address = address->ai_next) {
409
69
    err = ServerSocket::Listen(this, address->ai_addr, loop_);
410
  }
411
68
  uv_freeaddrinfo(req.addrinfo);
412
413
68
  if (!connected_sessions_.empty()) {
414
    return true;
415
  }
416
  // We only show error if we failed to start server on all addresses. We only
417
  // show one error, for the last address.
418
68
  if (server_sockets_.empty()) {
419
2
    if (out_ != NULL) {
420
      fprintf(out_, "Starting inspector on %s:%d failed: %s\n",
421
2
              host_.c_str(), port_, uv_strerror(err));
422
2
      fflush(out_);
423
    }
424
2
    return false;
425
  }
426
66
  state_ = ServerState::kRunning;
427
  // getaddrinfo sorts the addresses, so the first port is most relevant.
428
66
  PrintDebuggerReadyMessage(host_, server_sockets_[0]->port(),
429
132
                            delegate_->GetTargetIds(), out_);
430
66
  return true;
431
}
432
433
14
void InspectorSocketServer::Stop(ServerCallback cb) {
434
14
  CHECK_EQ(state_, ServerState::kRunning);
435
14
  if (closer_ == nullptr) {
436
14
    closer_ = new Closer(this);
437
  }
438
14
  closer_->AddCallback(cb);
439
14
  closer_->IncreaseExpectedCount();
440
14
  state_ = ServerState::kStopping;
441
28
  for (ServerSocket* server_socket : server_sockets_)
442
14
    server_socket->Close();
443
14
  closer_->NotifyIfDone();
444
14
}
445
446
5
void InspectorSocketServer::TerminateConnections() {
447
6
  for (const auto& session : connected_sessions_) {
448
1
    session.second->Close();
449
  }
450
5
}
451
452
12
bool InspectorSocketServer::TargetExists(const std::string& id) {
453
12
  const std::vector<std::string>& target_ids = delegate_->GetTargetIds();
454
12
  const auto& found = std::find(target_ids.begin(), target_ids.end(), id);
455
12
  return found != target_ids.end();
456
}
457
458
1012
void InspectorSocketServer::Send(int session_id, const std::string& message) {
459
1012
  auto session_iterator = connected_sessions_.find(session_id);
460
1012
  if (session_iterator != connected_sessions_.end()) {
461
1012
    session_iterator->second->Send(message);
462
  }
463
1012
}
464
465
67
void InspectorSocketServer::ServerSocketListening(ServerSocket* server_socket) {
466
67
  server_sockets_.push_back(server_socket);
467
67
}
468
469
14
void InspectorSocketServer::ServerSocketClosed(ServerSocket* server_socket) {
470
14
  CHECK_EQ(state_, ServerState::kStopping);
471
472
  server_sockets_.erase(std::remove(server_sockets_.begin(),
473
                                    server_sockets_.end(), server_socket),
474
14
                        server_sockets_.end());
475
14
  if (!server_sockets_.empty())
476
14
    return;
477
478
14
  if (closer_ != nullptr) {
479
14
    closer_->DecreaseExpectedCount();
480
  }
481
14
  if (connected_sessions_.empty()) {
482
4
    delegate_->ServerDone();
483
  }
484
14
  state_ = ServerState::kStopped;
485
}
486
487
66
int InspectorSocketServer::Port() const {
488
66
  if (!server_sockets_.empty()) {
489
66
    return server_sockets_[0]->port();
490
  }
491
  return port_;
492
}
493
494
// InspectorSession tracking
495
30
SocketSession::SocketSession(InspectorSocketServer* server, int server_port)
496
30
                             : id_(server->GenerateSessionId()),
497
                               server_(server),
498
                               state_(State::kHttp),
499
30
                               server_port_(server_port) { }
500
501
10
void SocketSession::Close() {
502
10
  CHECK_NE(state_, State::kClosing);
503
10
  state_ = State::kClosing;
504
10
  inspector_close(&socket_, CloseCallback);
505
10
}
506
507
// static
508
30
int SocketSession::Accept(InspectorSocketServer* server, int server_port,
509
                          uv_stream_t* server_socket) {
510
  // Memory is freed when the socket closes.
511
30
  SocketSession* session = new SocketSession(server, server_port);
512
  int err = inspector_accept(server_socket, &session->socket_,
513
30
                             HandshakeCallback);
514
30
  if (err != 0) {
515
    delete session;
516
  }
517
30
  return err;
518
}
519
520
// static
521
57
bool SocketSession::HandshakeCallback(InspectorSocket* socket,
522
                                      inspector_handshake_event event,
523
                                      const std::string& path) {
524
57
  SocketSession* session = SocketSession::From(socket);
525
57
  InspectorSocketServer* server = session->server_;
526
57
  const std::string& id = path.empty() ? path : path.substr(1);
527

57
  switch (event) {
528
  case kInspectorHandshakeHttpGet:
529
17
    return server->HandleGetRequest(socket, path);
530
  case kInspectorHandshakeUpgrading:
531
10
    if (server->SessionStarted(session, id)) {
532
10
      session->SetTargetId(id);
533
10
      return true;
534
    } else {
535
      session->SetDeclined();
536
      return false;
537
    }
538
  case kInspectorHandshakeUpgraded:
539
10
    session->FrontendConnected();
540
10
    return true;
541
  case kInspectorHandshakeFailed:
542
20
    server->SessionTerminated(session);
543
20
    return false;
544
  default:
545
    UNREACHABLE();
546
    return false;
547
57
  }
548
}
549
550
// static
551
10
void SocketSession::CloseCallback(InspectorSocket* socket, int code) {
552
10
  SocketSession* session = SocketSession::From(socket);
553
10
  CHECK_EQ(State::kClosing, session->state_);
554
10
  session->server_->SessionTerminated(session);
555
10
}
556
557
10
void SocketSession::FrontendConnected() {
558
10
  CHECK_EQ(State::kHttp, state_);
559
10
  state_ = State::kWebSocket;
560
10
  inspector_read_start(&socket_, OnBufferAlloc, ReadCallback);
561
10
}
562
563
// static
564
96
void SocketSession::ReadCallback(uv_stream_t* stream, ssize_t read,
565
                                 const uv_buf_t* buf) {
566
96
  InspectorSocket* socket = inspector_from_stream(stream);
567
96
  SocketSession* session = SocketSession::From(socket);
568
96
  if (read > 0) {
569
    session->server_->MessageReceived(session->id_,
570
87
                                      std::string(buf->base, read));
571
  } else {
572
9
    session->Close();
573
  }
574

96
  if (buf != nullptr && buf->base != nullptr)
575
87
    delete[] buf->base;
576
96
}
577
578
1012
void SocketSession::Send(const std::string& message) {
579
1012
  inspector_write(&socket_, message.data(), message.length());
580
1012
}
581
582
// ServerSocket implementation
583
67
int ServerSocket::DetectPort() {
584
  sockaddr_storage addr;
585
67
  int len = sizeof(addr);
586
  int err = uv_tcp_getsockname(&tcp_socket_,
587
67
                               reinterpret_cast<struct sockaddr*>(&addr), &len);
588
67
  if (err != 0)
589
    return err;
590
  int port;
591
67
  if (addr.ss_family == AF_INET6)
592
5
    port = reinterpret_cast<const sockaddr_in6*>(&addr)->sin6_port;
593
  else
594
62
    port = reinterpret_cast<const sockaddr_in*>(&addr)->sin_port;
595
67
  port_ = ntohs(port);
596
67
  return err;
597
}
598
599
// static
600
69
int ServerSocket::Listen(InspectorSocketServer* inspector_server,
601
                         sockaddr* addr, uv_loop_t* loop) {
602
69
  ServerSocket* server_socket = new ServerSocket(inspector_server);
603
69
  uv_tcp_t* server = &server_socket->tcp_socket_;
604
69
  CHECK_EQ(0, uv_tcp_init(loop, server));
605
69
  int err = uv_tcp_bind(server, addr, 0);
606
69
  if (err == 0) {
607
    err = uv_listen(reinterpret_cast<uv_stream_t*>(server), 1,
608
69
                    ServerSocket::SocketConnectedCallback);
609
  }
610
69
  if (err == 0) {
611
67
    err = server_socket->DetectPort();
612
  }
613
69
  if (err == 0) {
614
67
    inspector_server->ServerSocketListening(server_socket);
615
  } else {
616
2
    uv_close(reinterpret_cast<uv_handle_t*>(server), FreeOnCloseCallback);
617
  }
618
69
  return err;
619
}
620
621
// static
622
30
void ServerSocket::SocketConnectedCallback(uv_stream_t* tcp_socket,
623
                                           int status) {
624
30
  if (status == 0) {
625
30
    ServerSocket* server_socket = ServerSocket::FromTcpSocket(tcp_socket);
626
    // Memory is freed when the socket closes.
627
    SocketSession::Accept(server_socket->server_, server_socket->port_,
628
30
                          tcp_socket);
629
  }
630
30
}
631
632
// static
633
14
void ServerSocket::SocketClosedCallback(uv_handle_t* tcp_socket) {
634
14
  ServerSocket* server_socket = ServerSocket::FromTcpSocket(tcp_socket);
635
14
  server_socket->server_->ServerSocketClosed(server_socket);
636
14
  delete server_socket;
637
14
}
638
639
}  // namespace inspector
640
}  // namespace node