GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_report_utils.cc Lines: 150 177 84.7 %
Date: 2022-05-12 11:26:12 Branches: 62 92 67.4 %

Line Branch Exec Source
1
#include "json_utils.h"
2
#include "node_internals.h"
3
#include "node_report.h"
4
#include "util-inl.h"
5
6
namespace report {
7
8
using node::JSONWriter;
9
using node::MallocedBuffer;
10
11
static constexpr auto null = JSONWriter::Null{};
12
13
// Utility function to format socket information.
14
10
static void ReportEndpoint(uv_handle_t* h,
15
                           struct sockaddr* addr,
16
                           const char* name,
17
                           JSONWriter* writer) {
18
10
  if (addr == nullptr) {
19
2
    writer->json_keyvalue(name, null);
20
2
    return;
21
  }
22
23
  uv_getnameinfo_t endpoint;
24
8
  char* host = nullptr;
25
  char hostbuf[INET6_ADDRSTRLEN];
26
8
  const int family = addr->sa_family;
27
8
  const int port = ntohs(family == AF_INET ?
28
3
                         reinterpret_cast<sockaddr_in*>(addr)->sin_port :
29
5
                         reinterpret_cast<sockaddr_in6*>(addr)->sin6_port);
30
31
8
  if (uv_getnameinfo(h->loop, &endpoint, nullptr, addr, NI_NUMERICSERV) == 0) {
32
8
    host = endpoint.host;
33
    DCHECK_EQ(port, std::stoi(endpoint.service));
34
  } else {
35
    const void* src = family == AF_INET ?
36
                      static_cast<void*>(
37
                        &(reinterpret_cast<sockaddr_in*>(addr)->sin_addr)) :
38
                      static_cast<void*>(
39
                        &(reinterpret_cast<sockaddr_in6*>(addr)->sin6_addr));
40
    if (uv_inet_ntop(family, src, hostbuf, sizeof(hostbuf)) == 0) {
41
      host = hostbuf;
42
    }
43
  }
44
8
  writer->json_objectstart(name);
45
8
  if (host != nullptr) {
46
8
    writer->json_keyvalue("host", host);
47
  }
48
8
  writer->json_keyvalue("port", port);
49
8
  writer->json_objectend();
50
}
51
52
// Utility function to format libuv socket information.
53
5
static void ReportEndpoints(uv_handle_t* h, JSONWriter* writer) {
54
  struct sockaddr_storage addr_storage;
55
5
  struct sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage);
56
5
  uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
57
5
  int addr_size = sizeof(addr_storage);
58
5
  int rc = -1;
59
60
5
  switch (h->type) {
61
2
    case UV_UDP:
62
2
      rc = uv_udp_getsockname(&handle->udp, addr, &addr_size);
63
2
      break;
64
3
    case UV_TCP:
65
3
      rc = uv_tcp_getsockname(&handle->tcp, addr, &addr_size);
66
3
      break;
67
    default:
68
      break;
69
  }
70
5
  ReportEndpoint(h, rc == 0 ? addr : nullptr,  "localEndpoint", writer);
71
72
5
  switch (h->type) {
73
2
    case UV_UDP:
74
2
      rc = uv_udp_getpeername(&handle->udp, addr, &addr_size);
75
2
      break;
76
3
    case UV_TCP:
77
3
      rc = uv_tcp_getpeername(&handle->tcp, addr, &addr_size);
78
3
      break;
79
    default:
80
      break;
81
  }
82
5
  ReportEndpoint(h, rc == 0 ? addr : nullptr, "remoteEndpoint", writer);
83
5
}
84
85
// Utility function to format libuv pipe information.
86
7
static void ReportPipeEndpoints(uv_handle_t* h, JSONWriter* writer) {
87
7
  uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
88
14
  MallocedBuffer<char> buffer(0);
89
7
  size_t buffer_size = 0;
90
7
  int rc = -1;
91
92
  // First call to get required buffer size.
93
7
  rc = uv_pipe_getsockname(&handle->pipe, buffer.data, &buffer_size);
94
7
  if (rc == UV_ENOBUFS) {
95
7
    buffer = MallocedBuffer<char>(buffer_size);
96
7
    if (buffer.data != nullptr) {
97
7
      rc = uv_pipe_getsockname(&handle->pipe, buffer.data, &buffer_size);
98
    } else {
99
      buffer_size = 0;
100
    }
101
  }
102

7
  if (rc == 0 && buffer_size != 0 && buffer.data != nullptr) {
103
2
    writer->json_keyvalue("localEndpoint", buffer.data);
104
  } else {
105
5
    writer->json_keyvalue("localEndpoint", null);
106
  }
107
108
  // First call to get required buffer size.
109
7
  rc = uv_pipe_getpeername(&handle->pipe, buffer.data, &buffer_size);
110
7
  if (rc == UV_ENOBUFS) {
111
5
    buffer = MallocedBuffer<char>(buffer_size);
112
5
    if (buffer.data != nullptr) {
113
5
      rc = uv_pipe_getpeername(&handle->pipe, buffer.data, &buffer_size);
114
    }
115
  }
116

7
  if (rc == 0 && buffer_size != 0 && buffer.data != nullptr) {
117
1
    writer->json_keyvalue("remoteEndpoint", buffer.data);
118
  } else {
119
6
    writer->json_keyvalue("remoteEndpoint", null);
120
  }
121
7
}
122
123
// Utility function to format libuv path information.
124
2
static void ReportPath(uv_handle_t* h, JSONWriter* writer) {
125
4
  MallocedBuffer<char> buffer(0);
126
2
  int rc = -1;
127
2
  size_t size = 0;
128
2
  uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
129
2
  bool wrote_filename = false;
130
  // First call to get required buffer size.
131
2
  switch (h->type) {
132
1
    case UV_FS_EVENT:
133
1
      rc = uv_fs_event_getpath(&(handle->fs_event), buffer.data, &size);
134
1
      break;
135
1
    case UV_FS_POLL:
136
1
      rc = uv_fs_poll_getpath(&(handle->fs_poll), buffer.data, &size);
137
1
      break;
138
    default:
139
      break;
140
  }
141
2
  if (rc == UV_ENOBUFS) {
142
2
    buffer = MallocedBuffer<char>(size + 1);
143
2
    switch (h->type) {
144
1
      case UV_FS_EVENT:
145
1
        rc = uv_fs_event_getpath(&(handle->fs_event), buffer.data, &size);
146
1
        break;
147
1
      case UV_FS_POLL:
148
1
        rc = uv_fs_poll_getpath(&(handle->fs_poll), buffer.data, &size);
149
1
        break;
150
      default:
151
        break;
152
    }
153
2
    if (rc == 0) {
154
      // buffer is not null terminated.
155
2
      buffer.data[size] = '\0';
156
2
      writer->json_keyvalue("filename", buffer.data);
157
2
      wrote_filename = true;
158
    }
159
  }
160
2
  if (!wrote_filename) writer->json_keyvalue("filename", null);
161
2
}
162
163
// Utility function to walk libuv handles.
164
220
void WalkHandle(uv_handle_t* h, void* arg) {
165
220
  const char* type = uv_handle_type_name(h->type);
166
220
  JSONWriter* writer = static_cast<JSONWriter*>(arg);
167
220
  uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
168
169
220
  writer->json_start();
170
220
  writer->json_keyvalue("type", type);
171
220
  writer->json_keyvalue("is_active", static_cast<bool>(uv_is_active(h)));
172
220
  writer->json_keyvalue("is_referenced", static_cast<bool>(uv_has_ref(h)));
173
220
  writer->json_keyvalue("address",
174
440
                        ValueToHexString(reinterpret_cast<uint64_t>(h)));
175
176


220
  switch (h->type) {
177
2
    case UV_FS_EVENT:
178
    case UV_FS_POLL:
179
2
      ReportPath(h, writer);
180
2
      break;
181
1
    case UV_PROCESS:
182
1
      writer->json_keyvalue("pid", handle->process.pid);
183
1
      break;
184
5
    case UV_TCP:
185
    case UV_UDP:
186
5
      ReportEndpoints(h, writer);
187
5
      break;
188
7
    case UV_NAMED_PIPE:
189
7
      ReportPipeEndpoints(h, writer);
190
7
      break;
191
30
    case UV_TIMER: {
192
30
      uint64_t due = handle->timer.timeout;
193
30
      uint64_t now = uv_now(handle->timer.loop);
194
30
      writer->json_keyvalue("repeat", uv_timer_get_repeat(&handle->timer));
195
30
      writer->json_keyvalue("firesInMsFromNow",
196
30
                            static_cast<int64_t>(due - now));
197
30
      writer->json_keyvalue("expired", now >= due);
198
30
      break;
199
    }
200
    case UV_TTY: {
201
      int height, width, rc;
202
      rc = uv_tty_get_winsize(&(handle->tty), &width, &height);
203
      if (rc == 0) {
204
        writer->json_keyvalue("width", width);
205
        writer->json_keyvalue("height", height);
206
      }
207
      break;
208
    }
209
1
    case UV_SIGNAL:
210
      // SIGWINCH is used by libuv so always appears.
211
      // See http://docs.libuv.org/en/v1.x/signal.html
212
1
      writer->json_keyvalue("signum", handle->signal.signum);
213
1
      writer->json_keyvalue("signal",
214
1
                            node::signo_string(handle->signal.signum));
215
1
      break;
216
174
    default:
217
174
      break;
218
  }
219
220

220
  if (h->type == UV_TCP || h->type == UV_UDP
221
#ifndef _WIN32
222
215
      || h->type == UV_NAMED_PIPE
223
#endif
224
  ) {
225
    // These *must* be 0 or libuv will set the buffer sizes to the non-zero
226
    // values they contain.
227
12
    int send_size = 0;
228
12
    int recv_size = 0;
229
12
    uv_send_buffer_size(h, &send_size);
230
12
    uv_recv_buffer_size(h, &recv_size);
231
12
    writer->json_keyvalue("sendBufferSize", send_size);
232
12
    writer->json_keyvalue("recvBufferSize", recv_size);
233
  }
234
235
#ifndef _WIN32
236

220
  if (h->type == UV_TCP || h->type == UV_NAMED_PIPE || h->type == UV_TTY ||
237

210
      h->type == UV_UDP || h->type == UV_POLL) {
238
    uv_os_fd_t fd_v;
239
12
    int rc = uv_fileno(h, &fd_v);
240
241
12
    if (rc == 0) {
242
12
      writer->json_keyvalue("fd", static_cast<int>(fd_v));
243

12
      switch (fd_v) {
244
        case STDIN_FILENO:
245
          writer->json_keyvalue("stdio", "stdin");
246
          break;
247
        case STDOUT_FILENO:
248
          writer->json_keyvalue("stdio", "stdout");
249
          break;
250
        case STDERR_FILENO:
251
          writer->json_keyvalue("stdio", "stderr");
252
          break;
253
12
        default:
254
12
          break;
255
      }
256
    }
257
  }
258
#endif
259
260

220
  if (h->type == UV_TCP || h->type == UV_NAMED_PIPE || h->type == UV_TTY) {
261
10
    writer->json_keyvalue("writeQueueSize", handle->stream.write_queue_size);
262
10
    writer->json_keyvalue("readable",
263
10
                          static_cast<bool>(uv_is_readable(&handle->stream)));
264
10
    writer->json_keyvalue("writable",
265
10
                          static_cast<bool>(uv_is_writable(&handle->stream)));
266
  }
267
268
220
  writer->json_end();
269
220
}
270
271
}  // namespace report