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