Skip to content
This repository was archived by the owner on Jun 18, 2021. It is now read-only.

Commit 076c729

Browse files
committed
Additional information for libuv handles
1 parent b20b236 commit 076c729

File tree

4 files changed

+367
-25
lines changed

4 files changed

+367
-25
lines changed

binding.gyp

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
"cflags": [ "-g", "-O2", "-std=c++11", ],
1111
}],
1212
["OS=='win'", {
13-
"libraries": [ "dbghelp.lib", "Netapi32.lib", "PsApi.lib" ],
14-
"dll_files": [ "dbghelp.dll", "Netapi32.dll", "PsApi.dll" ],
13+
"libraries": [ "dbghelp.lib", "Netapi32.lib", "PsApi.lib", "Ws2_32.lib" ],
14+
"dll_files": [ "dbghelp.dll", "Netapi32.dll", "PsApi.dll", "Ws2_32.dll" ],
1515
}],
1616
],
1717
"defines": [

src/node_report.cc

+222-22
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
#include "node_report.h"
22
#include "v8.h"
3+
#include "uv.h"
34
#include "time.h"
45

56
#include <fcntl.h>
67
#include <map>
78
#include <string.h>
89
#include <stdio.h>
910
#include <stdlib.h>
11+
#include <iomanip>
1012
#include <iostream>
1113
#include <fstream>
14+
#include <sstream>
1215

1316
#if !defined(_MSC_VER)
1417
#include <strings.h>
@@ -489,48 +492,236 @@ void GetNodeReport(Isolate* isolate, DumpEvent event, const char* message, const
489492
WriteNodeReport(isolate, event, message, location, nullptr, out, error, &tm_struct);
490493
}
491494

495+
static void reportEndpoints(uv_handle_t* h, std::ostringstream& out) {
496+
struct sockaddr_storage addr_storage;
497+
struct sockaddr* addr = (sockaddr*)&addr_storage;
498+
char hostbuf[NI_MAXHOST];
499+
char portbuf[NI_MAXSERV];
500+
uv_any_handle* handle = (uv_any_handle*)h;
501+
int addr_size = sizeof(addr_storage);
502+
int rc = -1;
503+
504+
switch (h->type) {
505+
case UV_UDP: {
506+
rc = uv_udp_getsockname(&(handle->udp), addr, &addr_size);
507+
break;
508+
}
509+
case UV_TCP: {
510+
rc = uv_tcp_getsockname(&(handle->tcp), addr, &addr_size);
511+
break;
512+
}
513+
default: break;
514+
}
515+
if (rc == 0) {
516+
// getnameinfo will format host and port and handle IPv4/IPv6.
517+
rc = getnameinfo(addr, addr_size, hostbuf, sizeof(hostbuf), portbuf,
518+
sizeof(portbuf), NI_NUMERICSERV);
519+
if (rc == 0) {
520+
out << std::string(hostbuf) << ":" << std::string(portbuf);
521+
}
522+
523+
if (h->type == UV_TCP) {
524+
// Get the remote end of the connection.
525+
rc = uv_tcp_getpeername(&(handle->tcp), addr, &addr_size);
526+
if (rc == 0) {
527+
rc = getnameinfo(addr, addr_size, hostbuf, sizeof(hostbuf), portbuf,
528+
sizeof(portbuf), NI_NUMERICSERV);
529+
if (rc == 0) {
530+
out << " connected to ";
531+
out << std::string(hostbuf) << ":" << std::string(portbuf);
532+
}
533+
} else if (rc == UV_ENOTCONN) {
534+
out << " (not connected)";
535+
}
536+
}
537+
}
538+
}
539+
540+
static void reportPath(uv_handle_t* h, std::ostringstream& out) {
541+
char *buffer = nullptr;
542+
int rc = -1;
543+
size_t size = 0;
544+
uv_any_handle* handle = (uv_any_handle*)h;
545+
// First call to get required buffer size.
546+
switch (h->type) {
547+
case UV_FS_EVENT: {
548+
rc = uv_fs_event_getpath(&(handle->fs_event), buffer, &size);
549+
break;
550+
}
551+
case UV_FS_POLL: {
552+
rc = uv_fs_poll_getpath(&(handle->fs_poll), buffer, &size);
553+
break;
554+
}
555+
default: break;
556+
}
557+
if (rc == UV_ENOBUFS) {
558+
buffer = static_cast<char *>(malloc(size));
559+
switch (h->type) {
560+
case UV_FS_EVENT: {
561+
rc = uv_fs_event_getpath(&(handle->fs_event), buffer, &size);
562+
break;
563+
}
564+
case UV_FS_POLL: {
565+
rc = uv_fs_poll_getpath(&(handle->fs_poll), buffer, &size);
566+
break;
567+
}
568+
default: break;
569+
}
570+
if (rc == 0) {
571+
// buffer is not null terminated.
572+
std::string name(buffer, size);
573+
out << "filename: " << name;
574+
}
575+
free(buffer);
576+
}
577+
}
578+
492579
static void walkHandle(uv_handle_t* h, void* arg) {
493580
std::string type;
494-
std::string data = "";
581+
std::ostringstream data;
495582
std::ostream* out = reinterpret_cast<std::ostream*>(arg);
496-
char buf[64];
583+
uv_any_handle* handle = (uv_any_handle*)h;
497584

498585
// List all the types so we get a compile warning if we've missed one,
499-
// (using default: supresses the compiler warning.)
586+
// (using default: supresses the compiler warning).
500587
switch (h->type) {
501588
case UV_UNKNOWN_HANDLE: type = "unknown"; break;
502589
case UV_ASYNC: type = "async"; break;
503590
case UV_CHECK: type = "check"; break;
504-
case UV_FS_EVENT: type = "fs_event"; break;
505-
case UV_FS_POLL: type = "fs_poll"; break;
591+
case UV_FS_EVENT: {
592+
type = "fs_event";
593+
reportPath(h, data);
594+
break;
595+
}
596+
case UV_FS_POLL: {
597+
type = "fs_poll";
598+
reportPath(h, data);
599+
break;
600+
}
506601
case UV_HANDLE: type = "handle"; break;
507602
case UV_IDLE: type = "idle"; break;
508603
case UV_NAMED_PIPE: type = "pipe"; break;
509604
case UV_POLL: type = "poll"; break;
510605
case UV_PREPARE: type = "prepare"; break;
511-
case UV_PROCESS: type = "process"; break;
606+
case UV_PROCESS: {
607+
type = "process";
608+
data << "pid: " << handle->process.pid;
609+
break;
610+
}
512611
case UV_STREAM: type = "stream"; break;
513-
case UV_TCP: type = "tcp"; break;
514-
case UV_TIMER: type = "timer"; break;
515-
case UV_TTY: type = "tty"; break;
516-
case UV_UDP: type = "udp"; break;
517-
case UV_SIGNAL: type = "signal"; break;
612+
case UV_TCP: {
613+
type = "tcp";
614+
reportEndpoints(h, data);
615+
break;
616+
}
617+
case UV_TIMER: {
618+
// TODO timeout/due is not actually public however it is present
619+
// in all current versions of libuv. Once uv_timer_get_timeout is
620+
// in a supported level of libuv we should test for it with dlsym
621+
// and use it instead, in case timeout moves in the future.
622+
#ifdef _WIN32
623+
uint64_t due = handle->timer.due;
624+
#else
625+
uint64_t due = handle->timer.timeout;
626+
#endif
627+
uint64_t now = uv_now(handle->timer.loop);
628+
type = "timer";
629+
data << "repeat: " << uv_timer_get_repeat(&(handle->timer));
630+
if (due > now) {
631+
data << ", timeout in: " << (due - now) << " ms";
632+
} else {
633+
data << ", timeout expired: " << (now - due) << " ms ago";
634+
}
635+
break;
636+
}
637+
case UV_TTY: {
638+
int height, width, rc;
639+
type = "tty";
640+
rc = uv_tty_get_winsize(&(handle->tty), &width, &height);
641+
if (rc == 0) {
642+
data << "width: " << width << ", height: " << height;
643+
}
644+
break;
645+
}
646+
case UV_UDP: {
647+
type = "udp";
648+
reportEndpoints(h, data);
649+
break;
650+
}
651+
case UV_SIGNAL: {
652+
// SIGWINCH is used by libuv so always appears.
653+
// See http://docs.libuv.org/en/v1.x/signal.html
654+
type = "signal";
655+
data << "signum: " << handle->signal.signum
656+
// node::signo_string() is not exported by Node.js on Windows.
657+
#ifndef _WIN32
658+
<< " (" << node::signo_string(handle->signal.signum) << ")"
659+
#endif
660+
;
661+
break;
662+
}
518663
case UV_FILE: type = "file"; break;
519664
// We shouldn't see "max" type
520-
case UV_HANDLE_TYPE_MAX : break;
665+
case UV_HANDLE_TYPE_MAX : type = "max"; break;
521666
}
522667

523-
snprintf(buf, sizeof(buf),
524-
#ifdef _WIN32
525-
"[%c%c] %-10s0x%p\n",
526-
#else
527-
"[%c%c] %-10s%p\n",
668+
if (h->type == UV_TCP || h->type == UV_UDP
669+
#ifndef _WIN32
670+
|| h->type == UV_NAMED_PIPE
528671
#endif
529-
uv_has_ref(h)?'R':'-',
530-
uv_is_active(h)?'A':'-',
531-
type.c_str(), (void*)h);
672+
) {
673+
// These *must* be 0 or libuv will set the buffer sizes to the non-zero
674+
// values they contain.
675+
int send_size = 0;
676+
int recv_size = 0;
677+
if (h->type == UV_TCP || h->type == UV_UDP) {
678+
data << ", ";
679+
}
680+
uv_send_buffer_size(h, &send_size);
681+
uv_recv_buffer_size(h, &recv_size);
682+
data << "send buffer size: " << send_size
683+
<< ", recv buffer size: " << recv_size;
684+
}
532685

533-
*out << buf;
686+
if (h->type == UV_TCP || h->type == UV_NAMED_PIPE || h->type == UV_TTY ||
687+
h->type == UV_UDP || h->type == UV_POLL) {
688+
uv_os_fd_t fd_v;
689+
uv_os_fd_t* fd = &fd_v;
690+
int rc = uv_fileno(h, fd);
691+
// uv_os_fd_t is an int on Unix and HANDLE on Windows.
692+
#ifndef _WIN32
693+
if (rc == 0) {
694+
switch (fd_v) {
695+
case 0:
696+
data << ", stdin"; break;
697+
case 1:
698+
data << ", stdout"; break;
699+
case 2:
700+
data << ", stderr"; break;
701+
default:
702+
data << ", file descriptor: " << static_cast<int>(fd_v);
703+
break;
704+
}
705+
}
706+
#endif
707+
}
708+
709+
if (h->type == UV_TCP || h->type == UV_NAMED_PIPE || h->type == UV_TTY) {
710+
711+
data << ", write queue size: "
712+
<< handle->stream.write_queue_size;
713+
data << (uv_is_readable(&handle->stream) ? ", readable" : "")
714+
<< (uv_is_writable(&handle->stream) ? ", writable": "");
715+
716+
}
717+
718+
*out << std::left << "[" << (uv_has_ref(h) ? 'R' : '-')
719+
<< (uv_is_active(h) ? 'A' : '-') << "] " << std::setw(10) << type
720+
<< std::internal << std::setw(2 + 2 * sizeof(void*));
721+
char prev_fill = out->fill('0');
722+
*out << static_cast<void*>(h) << std::left;
723+
out->fill(prev_fill);
724+
*out << " " << std::left << data.str() << std::endl;
534725
}
535726

536727
static void WriteNodeReport(Isolate* isolate, DumpEvent event, const char* message, const char* location, char* filename, std::ostream &out, MaybeLocal<Value> error, TIME_TYPE* tm_struct) {
@@ -541,6 +732,10 @@ static void WriteNodeReport(Isolate* isolate, DumpEvent event, const char* messa
541732
pid_t pid = getpid();
542733
#endif
543734

735+
// Save formatting for output stream.
736+
std::ios oldState(nullptr);
737+
oldState.copyfmt(out);
738+
544739
// File stream opened OK, now start printing the report content, starting with the title
545740
// and header information (event, filename, timestamp and pid)
546741
out << "================================================================================\n";
@@ -610,7 +805,9 @@ static void WriteNodeReport(Isolate* isolate, DumpEvent event, const char* messa
610805
out << "\n================================================================================";
611806
out << "\n==== Node.js libuv Handle Summary ==============================================\n";
612807
out << "\n(Flags: R=Ref, A=Active)\n";
613-
out << "\nFlags Type Address\n";
808+
out << std::left << std::setw(7) << "Flags" << std::setw(10) << "Type"
809+
<< std::setw(4 + 2 * sizeof(void*)) << "Address" << "Details"
810+
<< std::endl;
614811
uv_walk(uv_default_loop(), walkHandle, (void*)&out);
615812

616813
// Print operating system information
@@ -619,6 +816,9 @@ static void WriteNodeReport(Isolate* isolate, DumpEvent event, const char* messa
619816
out << "\n================================================================================\n";
620817
out << std::flush;
621818

819+
// Restore output stream formatting.
820+
out.copyfmt(oldState);
821+
622822
report_active = false;
623823
}
624824

test/common.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ const getLibcVersion = (path) => {
185185
return (match != null ? match[1] : undefined);
186186
};
187187

188-
const getSection = (report, section) => {
188+
const getSection = exports.getSection = (report, section) => {
189189
const re = new RegExp('==== ' + section + ' =+' + reNewline + '+([\\S\\s]+?)'
190190
+ reNewline + '+={80}' + reNewline);
191191
const match = re.exec(report);

0 commit comments

Comments
 (0)