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

Commit 324eeae

Browse files
committed
Additional information for libuv handles
1 parent 1b62e31 commit 324eeae

4 files changed

Lines changed: 358 additions & 25 deletions

File tree

binding.gyp

Lines changed: 2 additions & 2 deletions
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

Lines changed: 213 additions & 22 deletions
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>
@@ -487,48 +490,227 @@ void GetNodeReport(Isolate* isolate, DumpEvent event, const char* message, const
487490
WriteNodeReport(isolate, event, message, location, nullptr, out, &tm_struct);
488491
}
489492

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

496583
// List all the types so we get a compile warning if we've missed one,
497-
// (using default: supresses the compiler warning.)
584+
// (using default: supresses the compiler warning).
498585
switch (h->type) {
499586
case UV_UNKNOWN_HANDLE: type = "unknown"; break;
500587
case UV_ASYNC: type = "async"; break;
501588
case UV_CHECK: type = "check"; break;
502-
case UV_FS_EVENT: type = "fs_event"; break;
503-
case UV_FS_POLL: type = "fs_poll"; break;
589+
case UV_FS_EVENT: {
590+
type = "fs_event";
591+
reportPath(h, data);
592+
break;
593+
}
594+
case UV_FS_POLL: {
595+
type = "fs_poll";
596+
reportPath(h, data);
597+
break;
598+
}
504599
case UV_HANDLE: type = "handle"; break;
505600
case UV_IDLE: type = "idle"; break;
506601
case UV_NAMED_PIPE: type = "pipe"; break;
507602
case UV_POLL: type = "poll"; break;
508603
case UV_PREPARE: type = "prepare"; break;
509-
case UV_PROCESS: type = "process"; break;
604+
case UV_PROCESS: {
605+
type = "process";
606+
data << "pid: " << handle->process.pid;
607+
break;
608+
}
510609
case UV_STREAM: type = "stream"; break;
511-
case UV_TCP: type = "tcp"; break;
512-
case UV_TIMER: type = "timer"; break;
513-
case UV_TTY: type = "tty"; break;
514-
case UV_UDP: type = "udp"; break;
515-
case UV_SIGNAL: type = "signal"; break;
610+
case UV_TCP: {
611+
type = "tcp";
612+
reportEndpoints(h, data);
613+
break;
614+
}
615+
case UV_TIMER: {
616+
type = "timer";
617+
data << "repeat: " << uv_timer_get_repeat(&(handle->timer));
618+
// TODO timeout is not actually public however it is present in
619+
// 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+
data << ", timeout in: "
623+
<< (handle->timer.timeout - uv_now(handle->timer.loop)) << " ms";
624+
break;
625+
}
626+
case UV_TTY: {
627+
int height, width, rc;
628+
type = "tty";
629+
rc = uv_tty_get_winsize(&(handle->tty), &width, &height);
630+
if (rc == 0) {
631+
data << "width: " << width << ", height: " << height;
632+
}
633+
break;
634+
}
635+
case UV_UDP: {
636+
type = "udp";
637+
reportEndpoints(h, data);
638+
break;
639+
}
640+
case UV_SIGNAL: {
641+
// SIGWINCH is used by libuv so always appears.
642+
// See http://docs.libuv.org/en/v1.x/signal.html
643+
type = "signal";
644+
data << "signum: " << handle->signal.signum
645+
// node::signo_string() is not exported by Node.js on Windows.
646+
#ifndef _WIN32
647+
<< " (" << node::signo_string(handle->signal.signum) << ")"
648+
#endif
649+
;
650+
break;
651+
}
516652
case UV_FILE: type = "file"; break;
517653
// We shouldn't see "max" type
518-
case UV_HANDLE_TYPE_MAX : break;
654+
case UV_HANDLE_TYPE_MAX : type = "max"; break;
519655
}
520656

521-
snprintf(buf, sizeof(buf),
522-
#ifdef _WIN32
523-
"[%c%c] %-10s0x%p\n",
524-
#else
525-
"[%c%c] %-10s%p\n",
657+
if (h->type == UV_TCP || h->type == UV_UDP
658+
#ifndef _WIN32
659+
|| h->type == UV_NAMED_PIPE
660+
#endif
661+
) {
662+
// These *must* be 0 or libuv will set the buffer sizes to the non-zero
663+
// values they contain.
664+
int send_size = 0;
665+
int recv_size = 0;
666+
if (h->type == UV_TCP || h->type == UV_UDP) {
667+
data << ", ";
668+
}
669+
uv_send_buffer_size(h, &send_size);
670+
uv_recv_buffer_size(h, &recv_size);
671+
data << "send buffer size: " << send_size
672+
<< ", recv buffer size: " << recv_size;
673+
}
674+
675+
if (h->type == UV_TCP || h->type == UV_NAMED_PIPE || h->type == UV_TTY ||
676+
h->type == UV_UDP || h->type == UV_POLL) {
677+
uv_os_fd_t fd_v;
678+
uv_os_fd_t* fd = &fd_v;
679+
int rc = uv_fileno(h, fd);
680+
// uv_os_fd_t is an int on Unix and HANDLE on Windows.
681+
#ifndef _WIN32
682+
if (rc == 0) {
683+
switch (fd_v) {
684+
case 0:
685+
data << ", stdin"; break;
686+
case 1:
687+
data << ", stdout"; break;
688+
case 2:
689+
data << ", stderr"; break;
690+
default:
691+
data << ", file descriptor: " << static_cast<int>(fd_v);
692+
break;
693+
}
694+
}
526695
#endif
527-
uv_has_ref(h)?'R':'-',
528-
uv_is_active(h)?'A':'-',
529-
type.c_str(), (void*)h);
696+
}
697+
698+
if (h->type == UV_TCP || h->type == UV_NAMED_PIPE || h->type == UV_TTY) {
699+
700+
data << ", write queue size "
701+
<< handle->stream.write_queue_size;
702+
data << (uv_is_readable(&handle->stream) ? ", readable" : "")
703+
<< (uv_is_writable(&handle->stream) ? ", writable": "");
530704

531-
*out << buf;
705+
}
706+
707+
*out << std::left << "[" << (uv_has_ref(h) ? 'R' : '-')
708+
<< (uv_is_active(h) ? 'A' : '-') << "] " << std::setw(10) << type
709+
<< std::internal << std::setw(2 + 2 * sizeof(void*));
710+
char prev_fill = out->fill('0');
711+
*out << static_cast<void*>(h) << std::left;
712+
out->fill(prev_fill);
713+
*out << " " << std::left << data.str() << std::endl;
532714
}
533715

534716
static void WriteNodeReport(Isolate* isolate, DumpEvent event, const char* message, const char* location, char* filename, std::ostream &out, TIME_TYPE* tm_struct) {
@@ -539,6 +721,10 @@ static void WriteNodeReport(Isolate* isolate, DumpEvent event, const char* messa
539721
pid_t pid = getpid();
540722
#endif
541723

724+
// Save formatting for output stream.
725+
std::ios oldState(nullptr);
726+
oldState.copyfmt(out);
727+
542728
// File stream opened OK, now start printing the report content, starting with the title
543729
// and header information (event, filename, timestamp and pid)
544730
out << "================================================================================\n";
@@ -603,7 +789,9 @@ static void WriteNodeReport(Isolate* isolate, DumpEvent event, const char* messa
603789
out << "\n================================================================================";
604790
out << "\n==== Node.js libuv Handle Summary ==============================================\n";
605791
out << "\n(Flags: R=Ref, A=Active)\n";
606-
out << "\nFlags Type Address\n";
792+
out << std::left << std::setw(7) << "Flags" << std::setw(10) << "Type"
793+
<< std::setw(4 + 2 * sizeof(void*)) << "Address" << "Details"
794+
<< std::endl;
607795
uv_walk(uv_default_loop(), walkHandle, (void*)&out);
608796

609797
// Print operating system information
@@ -612,6 +800,9 @@ static void WriteNodeReport(Isolate* isolate, DumpEvent event, const char* messa
612800
out << "\n================================================================================\n";
613801
out << std::flush;
614802

803+
// Restore output stream formatting.
804+
out.copyfmt(oldState);
805+
615806
report_active = false;
616807
}
617808

test/common.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ const getLibcVersion = (path) => {
174174
return (match != null ? match[1] : undefined);
175175
};
176176

177-
const getSection = (report, section) => {
177+
const getSection = exports.getSection = (report, section) => {
178178
const re = new RegExp('==== ' + section + ' =+' + reNewline + '+([\\S\\s]+?)'
179179
+ reNewline + '+={80}' + reNewline);
180180
const match = re.exec(report);

0 commit comments

Comments
 (0)