1 |
|
|
#include "node_internals.h" |
2 |
|
|
#include "node_report.h" |
3 |
|
|
#include "util-inl.h" |
4 |
|
|
|
5 |
|
|
namespace report { |
6 |
|
|
|
7 |
|
|
using node::MallocedBuffer; |
8 |
|
|
|
9 |
|
|
static constexpr auto null = JSONWriter::Null{}; |
10 |
|
|
|
11 |
|
|
// Utility function to format socket information. |
12 |
|
10 |
static void ReportEndpoint(uv_handle_t* h, |
13 |
|
|
struct sockaddr* addr, |
14 |
|
|
const char* name, |
15 |
|
|
JSONWriter* writer) { |
16 |
✓✓ |
10 |
if (addr == nullptr) { |
17 |
|
2 |
writer->json_keyvalue(name, null); |
18 |
|
12 |
return; |
19 |
|
|
} |
20 |
|
|
|
21 |
|
|
uv_getnameinfo_t endpoint; |
22 |
|
8 |
char* host = nullptr; |
23 |
|
|
char hostbuf[INET6_ADDRSTRLEN]; |
24 |
|
8 |
const int family = addr->sa_family; |
25 |
|
|
const int port = ntohs(family == AF_INET ? |
26 |
|
|
reinterpret_cast<sockaddr_in*>(addr)->sin_port : |
27 |
✓✓ |
8 |
reinterpret_cast<sockaddr_in6*>(addr)->sin6_port); |
28 |
|
|
|
29 |
✓✗ |
8 |
if (uv_getnameinfo(h->loop, &endpoint, nullptr, addr, NI_NUMERICSERV) == 0) { |
30 |
|
8 |
host = endpoint.host; |
31 |
|
|
DCHECK_EQ(port, std::stoi(endpoint.service)); |
32 |
|
|
} else { |
33 |
|
|
const void* src = family == AF_INET ? |
34 |
|
|
static_cast<void*>( |
35 |
|
|
&(reinterpret_cast<sockaddr_in*>(addr)->sin_addr)) : |
36 |
|
|
static_cast<void*>( |
37 |
|
|
&(reinterpret_cast<sockaddr_in6*>(addr)->sin6_addr)); |
38 |
|
|
if (uv_inet_ntop(family, src, hostbuf, sizeof(hostbuf)) == 0) { |
39 |
|
|
host = hostbuf; |
40 |
|
|
} |
41 |
|
|
} |
42 |
|
8 |
writer->json_objectstart(name); |
43 |
✓✗ |
8 |
if (host != nullptr) { |
44 |
|
8 |
writer->json_keyvalue("host", host); |
45 |
|
|
} |
46 |
|
8 |
writer->json_keyvalue("port", port); |
47 |
|
8 |
writer->json_objectend(); |
48 |
|
|
} |
49 |
|
|
|
50 |
|
|
// Utility function to format libuv socket information. |
51 |
|
5 |
static void ReportEndpoints(uv_handle_t* h, JSONWriter* writer) { |
52 |
|
|
struct sockaddr_storage addr_storage; |
53 |
|
5 |
struct sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); |
54 |
|
5 |
uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h); |
55 |
|
5 |
int addr_size = sizeof(addr_storage); |
56 |
|
5 |
int rc = -1; |
57 |
|
|
|
58 |
✓✓✗ |
5 |
switch (h->type) { |
59 |
|
|
case UV_UDP: |
60 |
|
2 |
rc = uv_udp_getsockname(&handle->udp, addr, &addr_size); |
61 |
|
2 |
break; |
62 |
|
|
case UV_TCP: |
63 |
|
3 |
rc = uv_tcp_getsockname(&handle->tcp, addr, &addr_size); |
64 |
|
3 |
break; |
65 |
|
|
default: |
66 |
|
|
break; |
67 |
|
|
} |
68 |
✓✗ |
5 |
ReportEndpoint(h, rc == 0 ? addr : nullptr, "localEndpoint", writer); |
69 |
|
|
|
70 |
✓✓✗ |
5 |
switch (h->type) { |
71 |
|
|
case UV_UDP: |
72 |
|
2 |
rc = uv_udp_getpeername(&handle->udp, addr, &addr_size); |
73 |
|
2 |
break; |
74 |
|
|
case UV_TCP: |
75 |
|
3 |
rc = uv_tcp_getpeername(&handle->tcp, addr, &addr_size); |
76 |
|
3 |
break; |
77 |
|
|
default: |
78 |
|
|
break; |
79 |
|
|
} |
80 |
✓✓ |
5 |
ReportEndpoint(h, rc == 0 ? addr : nullptr, "remoteEndpoint", writer); |
81 |
|
5 |
} |
82 |
|
|
|
83 |
|
|
// Utility function to format libuv path information. |
84 |
|
2 |
static void ReportPath(uv_handle_t* h, JSONWriter* writer) { |
85 |
|
2 |
MallocedBuffer<char> buffer(0); |
86 |
|
2 |
int rc = -1; |
87 |
|
2 |
size_t size = 0; |
88 |
|
2 |
uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h); |
89 |
|
2 |
bool wrote_filename = false; |
90 |
|
|
// First call to get required buffer size. |
91 |
✓✓✗ |
2 |
switch (h->type) { |
92 |
|
|
case UV_FS_EVENT: |
93 |
|
1 |
rc = uv_fs_event_getpath(&(handle->fs_event), buffer.data, &size); |
94 |
|
1 |
break; |
95 |
|
|
case UV_FS_POLL: |
96 |
|
1 |
rc = uv_fs_poll_getpath(&(handle->fs_poll), buffer.data, &size); |
97 |
|
1 |
break; |
98 |
|
|
default: |
99 |
|
|
break; |
100 |
|
|
} |
101 |
✓✗ |
2 |
if (rc == UV_ENOBUFS) { |
102 |
|
2 |
buffer = MallocedBuffer<char>(size + 1); |
103 |
✓✓✗ |
2 |
switch (h->type) { |
104 |
|
|
case UV_FS_EVENT: |
105 |
|
1 |
rc = uv_fs_event_getpath(&(handle->fs_event), buffer.data, &size); |
106 |
|
1 |
break; |
107 |
|
|
case UV_FS_POLL: |
108 |
|
1 |
rc = uv_fs_poll_getpath(&(handle->fs_poll), buffer.data, &size); |
109 |
|
1 |
break; |
110 |
|
|
default: |
111 |
|
|
break; |
112 |
|
|
} |
113 |
✓✗ |
2 |
if (rc == 0) { |
114 |
|
|
// buffer is not null terminated. |
115 |
|
2 |
buffer.data[size] = '\0'; |
116 |
|
2 |
writer->json_keyvalue("filename", buffer.data); |
117 |
|
2 |
wrote_filename = true; |
118 |
|
|
} |
119 |
|
|
} |
120 |
✗✓ |
2 |
if (!wrote_filename) writer->json_keyvalue("filename", null); |
121 |
|
2 |
} |
122 |
|
|
|
123 |
|
|
// Utility function to walk libuv handles. |
124 |
|
135 |
void WalkHandle(uv_handle_t* h, void* arg) { |
125 |
|
135 |
const char* type = uv_handle_type_name(h->type); |
126 |
|
135 |
JSONWriter* writer = static_cast<JSONWriter*>(arg); |
127 |
|
135 |
uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h); |
128 |
|
|
|
129 |
|
135 |
writer->json_start(); |
130 |
|
135 |
writer->json_keyvalue("type", type); |
131 |
|
135 |
writer->json_keyvalue("is_active", static_cast<bool>(uv_is_active(h))); |
132 |
|
135 |
writer->json_keyvalue("is_referenced", static_cast<bool>(uv_has_ref(h))); |
133 |
|
|
writer->json_keyvalue("address", |
134 |
|
135 |
ValueToHexString(reinterpret_cast<uint64_t>(h))); |
135 |
|
|
|
136 |
✓✓✓✓ ✗✓✓ |
135 |
switch (h->type) { |
137 |
|
|
case UV_FS_EVENT: |
138 |
|
|
case UV_FS_POLL: |
139 |
|
2 |
ReportPath(h, writer); |
140 |
|
2 |
break; |
141 |
|
|
case UV_PROCESS: |
142 |
|
1 |
writer->json_keyvalue("pid", handle->process.pid); |
143 |
|
1 |
break; |
144 |
|
|
case UV_TCP: |
145 |
|
|
case UV_UDP: |
146 |
|
5 |
ReportEndpoints(h, writer); |
147 |
|
5 |
break; |
148 |
|
|
case UV_TIMER: { |
149 |
|
17 |
uint64_t due = handle->timer.timeout; |
150 |
|
17 |
uint64_t now = uv_now(handle->timer.loop); |
151 |
|
17 |
writer->json_keyvalue("repeat", uv_timer_get_repeat(&handle->timer)); |
152 |
|
|
writer->json_keyvalue("firesInMsFromNow", |
153 |
|
17 |
static_cast<int64_t>(due - now)); |
154 |
|
17 |
writer->json_keyvalue("expired", now >= due); |
155 |
|
17 |
break; |
156 |
|
|
} |
157 |
|
|
case UV_TTY: { |
158 |
|
|
int height, width, rc; |
159 |
|
|
rc = uv_tty_get_winsize(&(handle->tty), &width, &height); |
160 |
|
|
if (rc == 0) { |
161 |
|
|
writer->json_keyvalue("width", width); |
162 |
|
|
writer->json_keyvalue("height", height); |
163 |
|
|
} |
164 |
|
|
break; |
165 |
|
|
} |
166 |
|
|
case UV_SIGNAL: |
167 |
|
|
// SIGWINCH is used by libuv so always appears. |
168 |
|
|
// See http://docs.libuv.org/en/v1.x/signal.html |
169 |
|
1 |
writer->json_keyvalue("signum", handle->signal.signum); |
170 |
|
|
writer->json_keyvalue("signal", |
171 |
|
1 |
node::signo_string(handle->signal.signum)); |
172 |
|
1 |
break; |
173 |
|
|
default: |
174 |
|
109 |
break; |
175 |
|
|
} |
176 |
|
|
|
177 |
✓✓✓✓
|
135 |
if (h->type == UV_TCP || h->type == UV_UDP |
178 |
|
|
#ifndef _WIN32 |
179 |
✓✓ |
130 |
|| h->type == UV_NAMED_PIPE |
180 |
|
|
#endif |
181 |
|
|
) { |
182 |
|
|
// These *must* be 0 or libuv will set the buffer sizes to the non-zero |
183 |
|
|
// values they contain. |
184 |
|
9 |
int send_size = 0; |
185 |
|
9 |
int recv_size = 0; |
186 |
|
9 |
uv_send_buffer_size(h, &send_size); |
187 |
|
9 |
uv_recv_buffer_size(h, &recv_size); |
188 |
|
9 |
writer->json_keyvalue("sendBufferSize", send_size); |
189 |
|
9 |
writer->json_keyvalue("recvBufferSize", recv_size); |
190 |
|
|
} |
191 |
|
|
|
192 |
|
|
#ifndef _WIN32 |
193 |
✓✓✓✓ ✓✗✓✓
|
263 |
if (h->type == UV_TCP || h->type == UV_NAMED_PIPE || h->type == UV_TTY || |
194 |
✗✓ |
254 |
h->type == UV_UDP || h->type == UV_POLL) { |
195 |
|
|
uv_os_fd_t fd_v; |
196 |
|
9 |
int rc = uv_fileno(h, &fd_v); |
197 |
|
|
|
198 |
✓✗ |
9 |
if (rc == 0) { |
199 |
|
9 |
writer->json_keyvalue("fd", static_cast<int>(fd_v)); |
200 |
✗✗✗✓
|
9 |
switch (fd_v) { |
201 |
|
|
case STDIN_FILENO: |
202 |
|
|
writer->json_keyvalue("stdio", "stdin"); |
203 |
|
|
break; |
204 |
|
|
case STDOUT_FILENO: |
205 |
|
|
writer->json_keyvalue("stdio", "stdout"); |
206 |
|
|
break; |
207 |
|
|
case STDERR_FILENO: |
208 |
|
|
writer->json_keyvalue("stdio", "stderr"); |
209 |
|
|
break; |
210 |
|
|
default: |
211 |
|
9 |
break; |
212 |
|
|
} |
213 |
|
|
} |
214 |
|
|
} |
215 |
|
|
#endif |
216 |
|
|
|
217 |
✓✓✓✓ ✗✓ |
135 |
if (h->type == UV_TCP || h->type == UV_NAMED_PIPE || h->type == UV_TTY) { |
218 |
|
7 |
writer->json_keyvalue("writeQueueSize", handle->stream.write_queue_size); |
219 |
|
|
writer->json_keyvalue("readable", |
220 |
|
7 |
static_cast<bool>(uv_is_readable(&handle->stream))); |
221 |
|
|
writer->json_keyvalue("writable", |
222 |
|
7 |
static_cast<bool>(uv_is_writable(&handle->stream))); |
223 |
|
|
} |
224 |
|
|
|
225 |
|
135 |
writer->json_end(); |
226 |
|
135 |
} |
227 |
|
|
|
228 |
|
8665 |
std::string EscapeJsonChars(const std::string& str) { |
229 |
|
|
const std::string control_symbols[0x20] = { |
230 |
|
|
"\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", |
231 |
|
|
"\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", |
232 |
|
|
"\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013", |
233 |
|
|
"\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", |
234 |
|
|
"\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f" |
235 |
|
285945 |
}; |
236 |
|
|
|
237 |
|
8665 |
std::string ret; |
238 |
|
8665 |
size_t last_pos = 0; |
239 |
|
8665 |
size_t pos = 0; |
240 |
✓✓ |
126454 |
for (; pos < str.size(); ++pos) { |
241 |
|
117789 |
std::string replace; |
242 |
|
117789 |
char ch = str[pos]; |
243 |
✗✓ |
117789 |
if (ch == '\\') { |
244 |
|
|
replace = "\\\\"; |
245 |
✓✓ |
117789 |
} else if (ch == '\"') { |
246 |
|
4 |
replace = "\\\""; |
247 |
|
|
} else { |
248 |
|
117785 |
size_t num = static_cast<size_t>(ch); |
249 |
✗✓ |
117785 |
if (num < 0x20) replace = control_symbols[num]; |
250 |
|
|
} |
251 |
✓✓ |
117789 |
if (!replace.empty()) { |
252 |
✓✗ |
4 |
if (pos > last_pos) { |
253 |
|
4 |
ret += str.substr(last_pos, pos - last_pos); |
254 |
|
|
} |
255 |
|
4 |
last_pos = pos + 1; |
256 |
|
4 |
ret += replace; |
257 |
|
|
} |
258 |
|
117789 |
} |
259 |
|
|
// Append any remaining symbols. |
260 |
✓✓ |
8665 |
if (last_pos < str.size()) { |
261 |
|
8650 |
ret += str.substr(last_pos, pos - last_pos); |
262 |
|
|
} |
263 |
✓✓ |
285945 |
return ret; |
264 |
|
|
} |
265 |
|
|
|
266 |
✓✗✓✗
|
15114 |
} // namespace report |