1
1
#include " node_report.h"
2
2
#include " v8.h"
3
+ #include " uv.h"
3
4
#include " time.h"
4
5
5
6
#include < fcntl.h>
6
7
#include < map>
7
8
#include < string.h>
8
9
#include < stdio.h>
9
10
#include < stdlib.h>
11
+ #include < iomanip>
10
12
#include < iostream>
11
13
#include < fstream>
14
+ #include < sstream>
12
15
13
16
#if !defined(_MSC_VER)
14
17
#include < strings.h>
@@ -489,48 +492,236 @@ void GetNodeReport(Isolate* isolate, DumpEvent event, const char* message, const
489
492
WriteNodeReport (isolate, event, message, location, nullptr , out, error, &tm_struct);
490
493
}
491
494
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
+
492
579
static void walkHandle (uv_handle_t * h, void * arg) {
493
580
std::string type;
494
- std::string data = " " ;
581
+ std::ostringstream data;
495
582
std::ostream* out = reinterpret_cast <std::ostream*>(arg);
496
- char buf[ 64 ] ;
583
+ uv_any_handle* handle = (uv_any_handle*)h ;
497
584
498
585
// 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).
500
587
switch (h->type ) {
501
588
case UV_UNKNOWN_HANDLE: type = " unknown" ; break ;
502
589
case UV_ASYNC: type = " async" ; break ;
503
590
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
+ }
506
601
case UV_HANDLE: type = " handle" ; break ;
507
602
case UV_IDLE: type = " idle" ; break ;
508
603
case UV_NAMED_PIPE: type = " pipe" ; break ;
509
604
case UV_POLL: type = " poll" ; break ;
510
605
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
+ }
512
611
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
+ }
518
663
case UV_FILE: type = " file" ; break ;
519
664
// We shouldn't see "max" type
520
- case UV_HANDLE_TYPE_MAX : break ;
665
+ case UV_HANDLE_TYPE_MAX : type = " max " ; break ;
521
666
}
522
667
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
528
671
#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
+ }
532
685
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;
534
725
}
535
726
536
727
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
541
732
pid_t pid = getpid ();
542
733
#endif
543
734
735
+ // Save formatting for output stream.
736
+ std::ios oldState (nullptr );
737
+ oldState.copyfmt (out);
738
+
544
739
// File stream opened OK, now start printing the report content, starting with the title
545
740
// and header information (event, filename, timestamp and pid)
546
741
out << " ================================================================================\n " ;
@@ -610,7 +805,9 @@ static void WriteNodeReport(Isolate* isolate, DumpEvent event, const char* messa
610
805
out << " \n ================================================================================" ;
611
806
out << " \n ==== Node.js libuv Handle Summary ==============================================\n " ;
612
807
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;
614
811
uv_walk (uv_default_loop (), walkHandle, (void *)&out);
615
812
616
813
// Print operating system information
@@ -619,6 +816,9 @@ static void WriteNodeReport(Isolate* isolate, DumpEvent event, const char* messa
619
816
out << " \n ================================================================================\n " ;
620
817
out << std::flush;
621
818
819
+ // Restore output stream formatting.
820
+ out.copyfmt (oldState);
821
+
622
822
report_active = false ;
623
823
}
624
824
0 commit comments