Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b62e228

Browse filesBrowse files
richardlauaddaleax
authored andcommitted
report: add fallback for uv_getnameinfo() failures
Attempt to report the host and port in the case that uv_getnameinfo() fails. PR-URL: #26140 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
1 parent 06d592c commit b62e228
Copy full SHA for b62e228

File tree

Expand file treeCollapse file tree

2 files changed

+98
-61
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

2 files changed

+98
-61
lines changed
Open diff view settings
Collapse file

‎src/node_report_utils.cc‎

Copy file name to clipboardExpand all lines: src/node_report_utils.cc
+41-29Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,52 @@ using node::MallocedBuffer;
77

88
static constexpr auto null = JSONWriter::Null{};
99

10+
// Utility function to format socket information.
11+
static void ReportEndpoint(uv_handle_t* h,
12+
struct sockaddr* addr,
13+
const char* name,
14+
JSONWriter* writer) {
15+
if (addr == nullptr) {
16+
writer->json_keyvalue(name, null);
17+
return;
18+
}
19+
20+
uv_getnameinfo_t endpoint;
21+
char* host = nullptr;
22+
char hostbuf[INET6_ADDRSTRLEN];
23+
const int family = addr->sa_family;
24+
const int port = ntohs(family == AF_INET ?
25+
reinterpret_cast<sockaddr_in*>(addr)->sin_port :
26+
reinterpret_cast<sockaddr_in6*>(addr)->sin6_port);
27+
28+
if (uv_getnameinfo(h->loop, &endpoint, nullptr, addr, NI_NUMERICSERV) == 0) {
29+
host = endpoint.host;
30+
DCHECK_EQ(port, std::stoi(endpoint.service));
31+
} else {
32+
const void* src = family == AF_INET ?
33+
static_cast<void*>(
34+
&(reinterpret_cast<sockaddr_in*>(addr)->sin_addr)) :
35+
static_cast<void*>(
36+
&(reinterpret_cast<sockaddr_in6*>(addr)->sin6_addr));
37+
if (uv_inet_ntop(family, src, hostbuf, sizeof(hostbuf)) == 0) {
38+
host = hostbuf;
39+
}
40+
}
41+
writer->json_objectstart(name);
42+
if (host != nullptr) {
43+
writer->json_keyvalue("host", host);
44+
}
45+
writer->json_keyvalue("port", port);
46+
writer->json_objectend();
47+
}
48+
1049
// Utility function to format libuv socket information.
1150
static void ReportEndpoints(uv_handle_t* h, JSONWriter* writer) {
1251
struct sockaddr_storage addr_storage;
1352
struct sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage);
1453
uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
1554
int addr_size = sizeof(addr_storage);
1655
int rc = -1;
17-
bool wrote_local_endpoint = false;
18-
bool wrote_remote_endpoint = false;
1956

2057
switch (h->type) {
2158
case UV_UDP:
@@ -27,38 +64,13 @@ static void ReportEndpoints(uv_handle_t* h, JSONWriter* writer) {
2764
default:
2865
break;
2966
}
30-
if (rc == 0) {
31-
// uv_getnameinfo will format host and port and handle IPv4/IPv6.
32-
uv_getnameinfo_t local;
33-
rc = uv_getnameinfo(h->loop, &local, nullptr, addr, NI_NUMERICSERV);
34-
35-
if (rc == 0) {
36-
writer->json_objectstart("localEndpoint");
37-
writer->json_keyvalue("host", local.host);
38-
writer->json_keyvalue("port", local.service);
39-
writer->json_objectend();
40-
wrote_local_endpoint = true;
41-
}
42-
}
43-
if (!wrote_local_endpoint) writer->json_keyvalue("localEndpoint", null);
67+
ReportEndpoint(h, rc == 0 ? addr : nullptr, "localEndpoint", writer);
4468

4569
if (h->type == UV_TCP) {
4670
// Get the remote end of the connection.
4771
rc = uv_tcp_getpeername(&handle->tcp, addr, &addr_size);
48-
if (rc == 0) {
49-
uv_getnameinfo_t remote;
50-
rc = uv_getnameinfo(h->loop, &remote, nullptr, addr, NI_NUMERICSERV);
51-
52-
if (rc == 0) {
53-
writer->json_objectstart("remoteEndpoint");
54-
writer->json_keyvalue("host", remote.host);
55-
writer->json_keyvalue("port", remote.service);
56-
writer->json_objectend();
57-
wrote_local_endpoint = true;
58-
}
59-
}
72+
ReportEndpoint(h, rc == 0 ? addr : nullptr, "remoteEndpoint", writer);
6073
}
61-
if (!wrote_remote_endpoint) writer->json_keyvalue("remoteEndpoint", null);
6274
}
6375

6476
// Utility function to format libuv path information.
Collapse file

‎test/node-report/test-api-uvhandles.js‎

Copy file name to clipboardExpand all lines: test/node-report/test-api-uvhandles.js
+57-32Lines changed: 57 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,7 @@ if (process.argv[2] === 'child') {
6060
const data = { pid: child_process.pid,
6161
tcp_address: server.address(),
6262
udp_address: udp_socket.address(),
63-
skip_fs_watch: (watcher === undefined ?
64-
'fs.watch() unavailable' :
65-
false) };
63+
skip_fs_watch: (watcher === undefined) };
6664
process.send(data);
6765
http.get({ port: server.address().port });
6866
});
@@ -74,6 +72,8 @@ if (process.argv[2] === 'child') {
7472
tmpdir.refresh();
7573
const options = { encoding: 'utf8', silent: true, cwd: tmpdir.path };
7674
const child = fork('--experimental-report', [__filename, 'child'], options);
75+
let child_data;
76+
child.on('message', (data) => { child_data = data; });
7777
let stderr = '';
7878
child.stderr.on('data', (chunk) => { stderr += chunk; });
7979
let stdout = '';
@@ -94,36 +94,61 @@ if (process.argv[2] === 'child') {
9494
assert.deepStrictEqual(reports, [], report_msg, reports);
9595

9696
const report = JSON.parse(stdout);
97-
let fs = 0;
98-
let poll = 0;
99-
let process = 0;
100-
let timer = 0;
101-
let pipe = 0;
102-
let tcp = 0;
103-
let udp = 0;
104-
const fs_msg = 'fs_event not found';
105-
const poll_msg = 'poll_event not found';
106-
const process_msg = 'process event not found';
107-
const timer_msg = 'timer event not found';
108-
const pipe_msg = 'pipe event not found';
109-
const tcp_msg = 'tcp event not found';
110-
const udp_msg = 'udp event not found';
111-
for (const entry in report.libuv) {
112-
if (report.libuv[entry].type === 'fs_event') fs = 1;
113-
else if (report.libuv[entry].type === 'fs_poll') poll = 1;
114-
else if (report.libuv[entry].type === 'process') process = 1;
115-
else if (report.libuv[entry].type === 'timer') timer = 1;
116-
else if (report.libuv[entry].type === 'pipe') pipe = 1;
117-
else if (report.libuv[entry].type === 'tcp') tcp = 1;
118-
else if (report.libuv[entry].type === 'udp') udp = 1;
97+
const prefix = common.isWindows ? '\\\\?\\' : '';
98+
const expected_filename = `${prefix}${__filename}`;
99+
const found_tcp = [];
100+
// Functions are named to aid debugging when they are not called.
101+
const validators = {
102+
fs_event: common.mustCall(function fs_event_validator(handle) {
103+
if (!child_data.skip_fs_watch) {
104+
assert.strictEqual(handle.filename, expected_filename);
105+
assert(handle.is_referenced);
106+
}
107+
}),
108+
fs_poll: common.mustCall(function fs_poll_validator(handle) {
109+
assert.strictEqual(handle.filename, expected_filename);
110+
assert(handle.is_referenced);
111+
}),
112+
pipe: common.mustCallAtLeast(function pipe_validator(handle) {
113+
assert(handle.is_referenced);
114+
}),
115+
process: common.mustCall(function process_validator(handle) {
116+
assert.strictEqual(handle.pid, child_data.pid);
117+
assert(handle.is_referenced);
118+
}),
119+
tcp: common.mustCall(function tcp_validator(handle) {
120+
// TCP handles. The report should contain three sockets:
121+
// 1. The server's listening socket.
122+
// 2. The inbound socket making the request.
123+
// 3. The outbound socket sending the response.
124+
const port = child_data.tcp_address.port;
125+
if (handle.localEndpoint.port === port) {
126+
if (handle.remoteEndpoint === null) {
127+
found_tcp.push('listening');
128+
} else {
129+
found_tcp.push('inbound');
130+
}
131+
} else if (handle.remoteEndpoint.port === port) {
132+
found_tcp.push('outbound');
133+
}
134+
assert(handle.is_referenced);
135+
}, 3),
136+
timer: common.mustCall(function timer_validator(handle) {
137+
assert(!handle.is_referenced);
138+
assert.strictEqual(handle.repeat, 0);
139+
}),
140+
udp: common.mustCall(function udp_validator(handle) {
141+
assert.strictEqual(handle.localEndpoint.port,
142+
child_data.udp_address.port);
143+
assert(handle.is_referenced);
144+
}),
145+
};
146+
for (const entry of report.libuv) {
147+
if (validators[entry.type]) validators[entry.type](entry);
148+
}
149+
for (const socket of ['listening', 'inbound', 'outbound']) {
150+
assert(found_tcp.includes(socket), `${socket} TCP socket was not found`);
119151
}
120-
assert.deepStrictEqual(fs, 1, fs_msg);
121-
assert.deepStrictEqual(poll, 1, poll_msg);
122-
assert.deepStrictEqual(process, 1, process_msg);
123-
assert.deepStrictEqual(timer, 1, timer_msg);
124-
assert.deepStrictEqual(pipe, 1, pipe_msg);
125-
assert.deepStrictEqual(tcp, 1, tcp_msg);
126-
assert.deepStrictEqual(udp, 1, udp_msg);
127152

128153
// Common report tests.
129154
helper.validateContent(stdout);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.