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+
490577static 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
534716static 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 << " \n Flags 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
0 commit comments