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 |
✓✓ |
16 |
const int port = ntohs(family == AF_INET ? |
28 |
|
5 |
reinterpret_cast<sockaddr_in*>(addr)->sin_port : |
29 |
|
11 |
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 |
|
|
case UV_UDP: |
62 |
|
2 |
rc = uv_udp_getsockname(&handle->udp, addr, &addr_size); |
63 |
|
2 |
break; |
64 |
|
|
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 |
|
|
case UV_UDP: |
74 |
|
2 |
rc = uv_udp_getpeername(&handle->udp, addr, &addr_size); |
75 |
|
2 |
break; |
76 |
|
|
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 path information. |
86 |
|
2 |
static void ReportPath(uv_handle_t* h, JSONWriter* writer) { |
87 |
|
4 |
MallocedBuffer<char> buffer(0); |
88 |
|
2 |
int rc = -1; |
89 |
|
2 |
size_t size = 0; |
90 |
|
2 |
uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h); |
91 |
|
2 |
bool wrote_filename = false; |
92 |
|
|
// First call to get required buffer size. |
93 |
✓✓✗ |
2 |
switch (h->type) { |
94 |
|
|
case UV_FS_EVENT: |
95 |
|
1 |
rc = uv_fs_event_getpath(&(handle->fs_event), buffer.data, &size); |
96 |
|
1 |
break; |
97 |
|
|
case UV_FS_POLL: |
98 |
|
1 |
rc = uv_fs_poll_getpath(&(handle->fs_poll), buffer.data, &size); |
99 |
|
1 |
break; |
100 |
|
|
default: |
101 |
|
|
break; |
102 |
|
|
} |
103 |
✓✗ |
2 |
if (rc == UV_ENOBUFS) { |
104 |
|
2 |
buffer = MallocedBuffer<char>(size + 1); |
105 |
✓✓✗ |
2 |
switch (h->type) { |
106 |
|
|
case UV_FS_EVENT: |
107 |
|
1 |
rc = uv_fs_event_getpath(&(handle->fs_event), buffer.data, &size); |
108 |
|
1 |
break; |
109 |
|
|
case UV_FS_POLL: |
110 |
|
1 |
rc = uv_fs_poll_getpath(&(handle->fs_poll), buffer.data, &size); |
111 |
|
1 |
break; |
112 |
|
|
default: |
113 |
|
|
break; |
114 |
|
|
} |
115 |
✓✗ |
2 |
if (rc == 0) { |
116 |
|
|
// buffer is not null terminated. |
117 |
|
2 |
buffer.data[size] = '\0'; |
118 |
|
2 |
writer->json_keyvalue("filename", buffer.data); |
119 |
|
2 |
wrote_filename = true; |
120 |
|
|
} |
121 |
|
|
} |
122 |
✗✓ |
2 |
if (!wrote_filename) writer->json_keyvalue("filename", null); |
123 |
|
2 |
} |
124 |
|
|
|
125 |
|
|
// Utility function to walk libuv handles. |
126 |
|
155 |
void WalkHandle(uv_handle_t* h, void* arg) { |
127 |
|
155 |
const char* type = uv_handle_type_name(h->type); |
128 |
|
155 |
JSONWriter* writer = static_cast<JSONWriter*>(arg); |
129 |
|
155 |
uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h); |
130 |
|
|
|
131 |
|
155 |
writer->json_start(); |
132 |
|
155 |
writer->json_keyvalue("type", type); |
133 |
|
155 |
writer->json_keyvalue("is_active", static_cast<bool>(uv_is_active(h))); |
134 |
|
155 |
writer->json_keyvalue("is_referenced", static_cast<bool>(uv_has_ref(h))); |
135 |
|
|
writer->json_keyvalue("address", |
136 |
|
155 |
ValueToHexString(reinterpret_cast<uint64_t>(h))); |
137 |
|
|
|
138 |
✓✓✓✓ ✗✓✓ |
155 |
switch (h->type) { |
139 |
|
|
case UV_FS_EVENT: |
140 |
|
|
case UV_FS_POLL: |
141 |
|
2 |
ReportPath(h, writer); |
142 |
|
2 |
break; |
143 |
|
|
case UV_PROCESS: |
144 |
|
1 |
writer->json_keyvalue("pid", handle->process.pid); |
145 |
|
1 |
break; |
146 |
|
|
case UV_TCP: |
147 |
|
|
case UV_UDP: |
148 |
|
5 |
ReportEndpoints(h, writer); |
149 |
|
5 |
break; |
150 |
|
|
case UV_TIMER: { |
151 |
|
26 |
uint64_t due = handle->timer.timeout; |
152 |
|
26 |
uint64_t now = uv_now(handle->timer.loop); |
153 |
|
26 |
writer->json_keyvalue("repeat", uv_timer_get_repeat(&handle->timer)); |
154 |
|
|
writer->json_keyvalue("firesInMsFromNow", |
155 |
|
26 |
static_cast<int64_t>(due - now)); |
156 |
|
26 |
writer->json_keyvalue("expired", now >= due); |
157 |
|
26 |
break; |
158 |
|
|
} |
159 |
|
|
case UV_TTY: { |
160 |
|
|
int height, width, rc; |
161 |
|
|
rc = uv_tty_get_winsize(&(handle->tty), &width, &height); |
162 |
|
|
if (rc == 0) { |
163 |
|
|
writer->json_keyvalue("width", width); |
164 |
|
|
writer->json_keyvalue("height", height); |
165 |
|
|
} |
166 |
|
|
break; |
167 |
|
|
} |
168 |
|
|
case UV_SIGNAL: |
169 |
|
|
// SIGWINCH is used by libuv so always appears. |
170 |
|
|
// See http://docs.libuv.org/en/v1.x/signal.html |
171 |
|
1 |
writer->json_keyvalue("signum", handle->signal.signum); |
172 |
|
|
writer->json_keyvalue("signal", |
173 |
|
1 |
node::signo_string(handle->signal.signum)); |
174 |
|
1 |
break; |
175 |
|
|
default: |
176 |
|
120 |
break; |
177 |
|
|
} |
178 |
|
|
|
179 |
✓✓✓✓
|
155 |
if (h->type == UV_TCP || h->type == UV_UDP |
180 |
|
|
#ifndef _WIN32 |
181 |
✓✓ |
150 |
|| h->type == UV_NAMED_PIPE |
182 |
|
|
#endif |
183 |
|
|
) { |
184 |
|
|
// These *must* be 0 or libuv will set the buffer sizes to the non-zero |
185 |
|
|
// values they contain. |
186 |
|
9 |
int send_size = 0; |
187 |
|
9 |
int recv_size = 0; |
188 |
|
9 |
uv_send_buffer_size(h, &send_size); |
189 |
|
9 |
uv_recv_buffer_size(h, &recv_size); |
190 |
|
9 |
writer->json_keyvalue("sendBufferSize", send_size); |
191 |
|
9 |
writer->json_keyvalue("recvBufferSize", recv_size); |
192 |
|
|
} |
193 |
|
|
|
194 |
|
|
#ifndef _WIN32 |
195 |
✓✓✓✓ ✓✗✓✓
|
303 |
if (h->type == UV_TCP || h->type == UV_NAMED_PIPE || h->type == UV_TTY || |
196 |
✗✓ |
294 |
h->type == UV_UDP || h->type == UV_POLL) { |
197 |
|
|
uv_os_fd_t fd_v; |
198 |
|
9 |
int rc = uv_fileno(h, &fd_v); |
199 |
|
|
|
200 |
✓✗ |
9 |
if (rc == 0) { |
201 |
|
9 |
writer->json_keyvalue("fd", static_cast<int>(fd_v)); |
202 |
✗✗✗✓
|
9 |
switch (fd_v) { |
203 |
|
|
case STDIN_FILENO: |
204 |
|
|
writer->json_keyvalue("stdio", "stdin"); |
205 |
|
|
break; |
206 |
|
|
case STDOUT_FILENO: |
207 |
|
|
writer->json_keyvalue("stdio", "stdout"); |
208 |
|
|
break; |
209 |
|
|
case STDERR_FILENO: |
210 |
|
|
writer->json_keyvalue("stdio", "stderr"); |
211 |
|
|
break; |
212 |
|
|
default: |
213 |
|
9 |
break; |
214 |
|
|
} |
215 |
|
|
} |
216 |
|
|
} |
217 |
|
|
#endif |
218 |
|
|
|
219 |
✓✓✓✓ ✗✓ |
155 |
if (h->type == UV_TCP || h->type == UV_NAMED_PIPE || h->type == UV_TTY) { |
220 |
|
7 |
writer->json_keyvalue("writeQueueSize", handle->stream.write_queue_size); |
221 |
|
|
writer->json_keyvalue("readable", |
222 |
|
7 |
static_cast<bool>(uv_is_readable(&handle->stream))); |
223 |
|
|
writer->json_keyvalue("writable", |
224 |
|
7 |
static_cast<bool>(uv_is_writable(&handle->stream))); |
225 |
|
|
} |
226 |
|
|
|
227 |
|
155 |
writer->json_end(); |
228 |
|
155 |
} |
229 |
|
|
|
230 |
✓✗✓✗
|
14073 |
} // namespace report |