Coverage Report

Created: 2025-12-10 07:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/node/src/node_report_utils.cc
Line
Count
Source
1
#include "json_utils.h"
2
#include "node_internals.h"
3
#include "node_report.h"
4
#include "util-inl.h"
5
6
namespace node {
7
namespace report {
8
9
static constexpr auto null = JSONWriter::Null{};
10
11
// Utility function to format socket information.
12
static void ReportEndpoint(uv_handle_t* h,
13
                           struct sockaddr* addr,
14
                           const char* name,
15
                           JSONWriter* writer,
16
0
                           bool exclude_network) {
17
0
  if (addr == nullptr) {
18
0
    writer->json_keyvalue(name, null);
19
0
    return;
20
0
  }
21
22
0
  uv_getnameinfo_t endpoint;
23
0
  char* host = nullptr;
24
0
  const int family = addr->sa_family;
25
0
  const int port = ntohs(family == AF_INET ?
26
0
                         reinterpret_cast<sockaddr_in*>(addr)->sin_port :
27
0
                         reinterpret_cast<sockaddr_in6*>(addr)->sin6_port);
28
29
0
  writer->json_objectstart(name);
30
0
  if (!exclude_network &&
31
0
      uv_getnameinfo(h->loop, &endpoint, nullptr, addr, NI_NUMERICSERV) == 0) {
32
0
    host = endpoint.host;
33
0
    DCHECK_EQ(port, std::stoi(endpoint.service));
34
0
    writer->json_keyvalue("host", host);
35
0
  }
36
37
0
  if (family == AF_INET) {
38
0
    char ipbuf[INET_ADDRSTRLEN];
39
0
    if (uv_ip4_name(
40
0
            reinterpret_cast<sockaddr_in*>(addr), ipbuf, sizeof(ipbuf)) == 0) {
41
0
      writer->json_keyvalue("ip4", ipbuf);
42
0
      if (host == nullptr) writer->json_keyvalue("host", ipbuf);
43
0
    }
44
0
  } else {
45
0
    char ipbuf[INET6_ADDRSTRLEN];
46
0
    if (uv_ip6_name(
47
0
            reinterpret_cast<sockaddr_in6*>(addr), ipbuf, sizeof(ipbuf)) == 0) {
48
0
      writer->json_keyvalue("ip6", ipbuf);
49
0
      if (host == nullptr) writer->json_keyvalue("host", ipbuf);
50
0
    }
51
0
  }
52
0
  writer->json_keyvalue("port", port);
53
0
  writer->json_objectend();
54
0
}
55
56
// Utility function to format libuv socket information.
57
static void ReportEndpoints(uv_handle_t* h,
58
                            JSONWriter* writer,
59
0
                            bool exclude_network) {
60
0
  struct sockaddr_storage addr_storage;
61
0
  struct sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage);
62
0
  uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
63
0
  int addr_size = sizeof(addr_storage);
64
0
  int rc = -1;
65
66
0
  switch (h->type) {
67
0
    case UV_UDP:
68
0
      rc = uv_udp_getsockname(&handle->udp, addr, &addr_size);
69
0
      break;
70
0
    case UV_TCP:
71
0
      rc = uv_tcp_getsockname(&handle->tcp, addr, &addr_size);
72
0
      break;
73
0
    default:
74
0
      break;
75
0
  }
76
0
  ReportEndpoint(
77
0
      h, rc == 0 ? addr : nullptr, "localEndpoint", writer, exclude_network);
78
79
0
  switch (h->type) {
80
0
    case UV_UDP:
81
0
      rc = uv_udp_getpeername(&handle->udp, addr, &addr_size);
82
0
      break;
83
0
    case UV_TCP:
84
0
      rc = uv_tcp_getpeername(&handle->tcp, addr, &addr_size);
85
0
      break;
86
0
    default:
87
0
      break;
88
0
  }
89
0
  ReportEndpoint(
90
0
      h, rc == 0 ? addr : nullptr, "remoteEndpoint", writer, exclude_network);
91
0
}
92
93
// Utility function to format libuv pipe information.
94
0
static void ReportPipeEndpoints(uv_handle_t* h, JSONWriter* writer) {
95
0
  uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
96
0
  MaybeStackBuffer<char> buffer;
97
0
  size_t buffer_size = buffer.capacity();
98
0
  int rc = -1;
99
100
  // First call to get required buffer size.
101
0
  rc = uv_pipe_getsockname(&handle->pipe, buffer.out(), &buffer_size);
102
0
  if (rc == UV_ENOBUFS) {
103
0
    buffer.AllocateSufficientStorage(buffer_size);
104
0
    rc = uv_pipe_getsockname(&handle->pipe, buffer.out(), &buffer_size);
105
0
  }
106
0
  if (rc == 0 && buffer_size != 0) {
107
0
    buffer.SetLength(buffer_size);
108
0
    writer->json_keyvalue("localEndpoint", buffer.ToStringView());
109
0
  } else {
110
0
    writer->json_keyvalue("localEndpoint", null);
111
0
  }
112
113
  // First call to get required buffer size.
114
0
  buffer_size = buffer.capacity();
115
0
  rc = uv_pipe_getpeername(&handle->pipe, buffer.out(), &buffer_size);
116
0
  if (rc == UV_ENOBUFS) {
117
0
    buffer.AllocateSufficientStorage(buffer_size);
118
0
    rc = uv_pipe_getpeername(&handle->pipe, buffer.out(), &buffer_size);
119
0
  }
120
0
  if (rc == 0 && buffer_size != 0) {
121
0
    buffer.SetLength(buffer_size);
122
0
    writer->json_keyvalue("remoteEndpoint", buffer.ToStringView());
123
0
  } else {
124
0
    writer->json_keyvalue("remoteEndpoint", null);
125
0
  }
126
0
}
127
128
// Utility function to format libuv path information.
129
0
static void ReportPath(uv_handle_t* h, JSONWriter* writer) {
130
0
  MaybeStackBuffer<char> buffer;
131
0
  int rc = -1;
132
0
  size_t size = buffer.capacity();
133
0
  uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
134
  // First call to get required buffer size.
135
0
  switch (h->type) {
136
0
    case UV_FS_EVENT:
137
0
      rc = uv_fs_event_getpath(&(handle->fs_event), buffer.out(), &size);
138
0
      break;
139
0
    case UV_FS_POLL:
140
0
      rc = uv_fs_poll_getpath(&(handle->fs_poll), buffer.out(), &size);
141
0
      break;
142
0
    default:
143
0
      break;
144
0
  }
145
0
  if (rc == UV_ENOBUFS) {
146
0
    buffer.AllocateSufficientStorage(size);
147
0
    switch (h->type) {
148
0
      case UV_FS_EVENT:
149
0
        rc = uv_fs_event_getpath(&(handle->fs_event), buffer.out(), &size);
150
0
        break;
151
0
      case UV_FS_POLL:
152
0
        rc = uv_fs_poll_getpath(&(handle->fs_poll), buffer.out(), &size);
153
0
        break;
154
0
      default:
155
0
        break;
156
0
    }
157
0
  }
158
159
0
  if (rc == 0 && size > 0) {
160
0
    buffer.SetLength(size);
161
0
    writer->json_keyvalue("filename", buffer.ToStringView());
162
0
  } else {
163
0
    writer->json_keyvalue("filename", null);
164
0
  }
165
0
}
166
167
// Utility function to walk libuv handles.
168
0
void WalkHandle(uv_handle_t* h, void* arg, bool exclude_network = false) {
169
0
  const char* type = uv_handle_type_name(h->type);
170
0
  JSONWriter* writer = static_cast<JSONWriter*>(arg);
171
0
  uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
172
173
0
  writer->json_start();
174
0
  writer->json_keyvalue("type", type);
175
0
  writer->json_keyvalue("is_active", static_cast<bool>(uv_is_active(h)));
176
0
  writer->json_keyvalue("is_referenced", static_cast<bool>(uv_has_ref(h)));
177
0
  writer->json_keyvalue("address",
178
0
                        ValueToHexString(reinterpret_cast<uint64_t>(h)));
179
180
0
  switch (h->type) {
181
0
    case UV_FS_EVENT:
182
0
    case UV_FS_POLL:
183
0
      ReportPath(h, writer);
184
0
      break;
185
0
    case UV_PROCESS:
186
0
      writer->json_keyvalue("pid", handle->process.pid);
187
0
      break;
188
0
    case UV_TCP:
189
0
    case UV_UDP:
190
0
      ReportEndpoints(h, writer, exclude_network);
191
0
      break;
192
0
    case UV_NAMED_PIPE:
193
0
      ReportPipeEndpoints(h, writer);
194
0
      break;
195
0
    case UV_TIMER: {
196
0
      uint64_t due = handle->timer.timeout;
197
0
      uint64_t now = uv_now(handle->timer.loop);
198
0
      writer->json_keyvalue("repeat", uv_timer_get_repeat(&handle->timer));
199
0
      writer->json_keyvalue("firesInMsFromNow",
200
0
                            static_cast<int64_t>(due - now));
201
0
      writer->json_keyvalue("expired", now >= due);
202
0
      break;
203
0
    }
204
0
    case UV_TTY: {
205
0
      int height, width, rc;
206
0
      rc = uv_tty_get_winsize(&(handle->tty), &width, &height);
207
0
      if (rc == 0) {
208
0
        writer->json_keyvalue("width", width);
209
0
        writer->json_keyvalue("height", height);
210
0
      }
211
0
      break;
212
0
    }
213
0
    case UV_SIGNAL:
214
      // SIGWINCH is used by libuv so always appears.
215
      // See http://docs.libuv.org/en/v1.x/signal.html
216
0
      writer->json_keyvalue("signum", handle->signal.signum);
217
0
      writer->json_keyvalue("signal", signo_string(handle->signal.signum));
218
0
      break;
219
0
    default:
220
0
      break;
221
0
  }
222
223
0
  if (h->type == UV_TCP || h->type == UV_UDP
224
0
#ifndef _WIN32
225
0
      || h->type == UV_NAMED_PIPE
226
0
#endif
227
0
  ) {
228
    // These *must* be 0 or libuv will set the buffer sizes to the non-zero
229
    // values they contain.
230
0
    int send_size = 0;
231
0
    int recv_size = 0;
232
0
    uv_send_buffer_size(h, &send_size);
233
0
    uv_recv_buffer_size(h, &recv_size);
234
0
    writer->json_keyvalue("sendBufferSize", send_size);
235
0
    writer->json_keyvalue("recvBufferSize", recv_size);
236
0
  }
237
238
0
#ifndef _WIN32
239
0
  if (h->type == UV_TCP || h->type == UV_NAMED_PIPE || h->type == UV_TTY ||
240
0
      h->type == UV_UDP || h->type == UV_POLL) {
241
0
    uv_os_fd_t fd_v;
242
0
    int rc = uv_fileno(h, &fd_v);
243
244
0
    if (rc == 0) {
245
0
      writer->json_keyvalue("fd", static_cast<int>(fd_v));
246
0
      switch (fd_v) {
247
0
        case STDIN_FILENO:
248
0
          writer->json_keyvalue("stdio", "stdin");
249
0
          break;
250
0
        case STDOUT_FILENO:
251
0
          writer->json_keyvalue("stdio", "stdout");
252
0
          break;
253
0
        case STDERR_FILENO:
254
0
          writer->json_keyvalue("stdio", "stderr");
255
0
          break;
256
0
        default:
257
0
          break;
258
0
      }
259
0
    }
260
0
  }
261
0
#endif
262
263
0
  if (h->type == UV_TCP || h->type == UV_NAMED_PIPE || h->type == UV_TTY) {
264
0
    writer->json_keyvalue("writeQueueSize", handle->stream.write_queue_size);
265
0
    writer->json_keyvalue("readable",
266
0
                          static_cast<bool>(uv_is_readable(&handle->stream)));
267
0
    writer->json_keyvalue("writable",
268
0
                          static_cast<bool>(uv_is_writable(&handle->stream)));
269
0
  }
270
0
  if (h->type == UV_UDP) {
271
0
    writer->json_keyvalue(
272
0
        "writeQueueSize",
273
0
        uv_udp_get_send_queue_size(reinterpret_cast<uv_udp_t*>(h)));
274
0
    writer->json_keyvalue(
275
0
        "writeQueueCount",
276
0
        uv_udp_get_send_queue_count(reinterpret_cast<uv_udp_t*>(h)));
277
0
  }
278
0
  writer->json_end();
279
0
}
280
0
void WalkHandleNetwork(uv_handle_t* h, void* arg) {
281
0
  WalkHandle(h, arg, false);
282
0
}
283
0
void WalkHandleNoNetwork(uv_handle_t* h, void* arg) {
284
0
  WalkHandle(h, arg, true);
285
0
}
286
}  // namespace report
287
}  // namespace node