14
14
#include <strings.h>
15
15
#include <signal.h>
16
16
#include <unistd.h>
17
+ #include <time.h>
17
18
18
19
#include <sys/poll.h>
19
20
#include <sys/sendfile.h>
@@ -64,6 +65,7 @@ static int cfg_sndbuf;
64
65
static int cfg_rcvbuf ;
65
66
static bool cfg_join ;
66
67
static bool cfg_remove ;
68
+ static unsigned int cfg_time ;
67
69
static unsigned int cfg_do_w ;
68
70
static int cfg_wait ;
69
71
static uint32_t cfg_mark ;
@@ -78,9 +80,10 @@ static struct cfg_cmsg_types cfg_cmsg_types;
78
80
static void die_usage (void )
79
81
{
80
82
fprintf (stderr , "Usage: mptcp_connect [-6] [-u] [-s MPTCP|TCP] [-p port] [-m mode]"
81
- "[-l] [-w sec] connect_address\n" );
83
+ "[-l] [-w sec] [-t num] [-T num] connect_address\n" );
82
84
fprintf (stderr , "\t-6 use ipv6\n" );
83
85
fprintf (stderr , "\t-t num -- set poll timeout to num\n" );
86
+ fprintf (stderr , "\t-T num -- set expected runtime to num ms\n" );
84
87
fprintf (stderr , "\t-S num -- set SO_SNDBUF to num\n" );
85
88
fprintf (stderr , "\t-R num -- set SO_RCVBUF to num\n" );
86
89
fprintf (stderr , "\t-p num -- use port num\n" );
@@ -448,7 +451,7 @@ static void set_nonblock(int fd)
448
451
fcntl (fd , F_SETFL , flags | O_NONBLOCK );
449
452
}
450
453
451
- static int copyfd_io_poll (int infd , int peerfd , int outfd )
454
+ static int copyfd_io_poll (int infd , int peerfd , int outfd , bool * in_closed_after_out )
452
455
{
453
456
struct pollfd fds = {
454
457
.fd = peerfd ,
@@ -487,9 +490,11 @@ static int copyfd_io_poll(int infd, int peerfd, int outfd)
487
490
*/
488
491
fds .events &= ~POLLIN ;
489
492
490
- if ((fds .events & POLLOUT ) == 0 )
493
+ if ((fds .events & POLLOUT ) == 0 ) {
494
+ * in_closed_after_out = true;
491
495
/* and nothing more to send */
492
496
break ;
497
+ }
493
498
494
499
/* Else, still have data to transmit */
495
500
} else if (len < 0 ) {
@@ -547,7 +552,7 @@ static int copyfd_io_poll(int infd, int peerfd, int outfd)
547
552
}
548
553
549
554
/* leave some time for late join/announce */
550
- if (cfg_join || cfg_remove )
555
+ if (cfg_remove )
551
556
usleep (cfg_wait );
552
557
553
558
close (peerfd );
@@ -646,7 +651,7 @@ static int do_sendfile(int infd, int outfd, unsigned int count)
646
651
}
647
652
648
653
static int copyfd_io_mmap (int infd , int peerfd , int outfd ,
649
- unsigned int size )
654
+ unsigned int size , bool * in_closed_after_out )
650
655
{
651
656
int err ;
652
657
@@ -664,13 +669,14 @@ static int copyfd_io_mmap(int infd, int peerfd, int outfd,
664
669
shutdown (peerfd , SHUT_WR );
665
670
666
671
err = do_recvfile (peerfd , outfd );
672
+ * in_closed_after_out = true;
667
673
}
668
674
669
675
return err ;
670
676
}
671
677
672
678
static int copyfd_io_sendfile (int infd , int peerfd , int outfd ,
673
- unsigned int size )
679
+ unsigned int size , bool * in_closed_after_out )
674
680
{
675
681
int err ;
676
682
@@ -685,34 +691,70 @@ static int copyfd_io_sendfile(int infd, int peerfd, int outfd,
685
691
if (err )
686
692
return err ;
687
693
err = do_recvfile (peerfd , outfd );
694
+ * in_closed_after_out = true;
688
695
}
689
696
690
697
return err ;
691
698
}
692
699
693
700
static int copyfd_io (int infd , int peerfd , int outfd )
694
701
{
702
+ bool in_closed_after_out = false;
703
+ struct timespec start , end ;
695
704
int file_size ;
705
+ int ret ;
706
+
707
+ if (cfg_time && (clock_gettime (CLOCK_MONOTONIC , & start ) < 0 ))
708
+ xerror ("can not fetch start time %d" , errno );
696
709
697
710
switch (cfg_mode ) {
698
711
case CFG_MODE_POLL :
699
- return copyfd_io_poll (infd , peerfd , outfd );
712
+ ret = copyfd_io_poll (infd , peerfd , outfd , & in_closed_after_out );
713
+ break ;
714
+
700
715
case CFG_MODE_MMAP :
701
716
file_size = get_infd_size (infd );
702
717
if (file_size < 0 )
703
718
return file_size ;
704
- return copyfd_io_mmap (infd , peerfd , outfd , file_size );
719
+ ret = copyfd_io_mmap (infd , peerfd , outfd , file_size , & in_closed_after_out );
720
+ break ;
721
+
705
722
case CFG_MODE_SENDFILE :
706
723
file_size = get_infd_size (infd );
707
724
if (file_size < 0 )
708
725
return file_size ;
709
- return copyfd_io_sendfile (infd , peerfd , outfd , file_size );
726
+ ret = copyfd_io_sendfile (infd , peerfd , outfd , file_size , & in_closed_after_out );
727
+ break ;
728
+
729
+ default :
730
+ fprintf (stderr , "Invalid mode %d\n" , cfg_mode );
731
+
732
+ die_usage ();
733
+ return 1 ;
710
734
}
711
735
712
- fprintf (stderr , "Invalid mode %d\n" , cfg_mode );
736
+ if (ret )
737
+ return ret ;
713
738
714
- die_usage ();
715
- return 1 ;
739
+ if (cfg_time ) {
740
+ unsigned int delta_ms ;
741
+
742
+ if (clock_gettime (CLOCK_MONOTONIC , & end ) < 0 )
743
+ xerror ("can not fetch end time %d" , errno );
744
+ delta_ms = (end .tv_sec - start .tv_sec ) * 1000 + (end .tv_nsec - start .tv_nsec ) / 1000000 ;
745
+ if (delta_ms > cfg_time ) {
746
+ xerror ("transfer slower than expected! runtime %d ms, expected %d ms" ,
747
+ delta_ms , cfg_time );
748
+ }
749
+
750
+ /* show the runtime only if this end shutdown(wr) before receiving the EOF,
751
+ * (that is, if this end got the longer runtime)
752
+ */
753
+ if (in_closed_after_out )
754
+ fprintf (stderr , "%d" , delta_ms );
755
+ }
756
+
757
+ return 0 ;
716
758
}
717
759
718
760
static void check_sockaddr (int pf , struct sockaddr_storage * ss ,
@@ -1005,12 +1047,11 @@ static void parse_opts(int argc, char **argv)
1005
1047
{
1006
1048
int c ;
1007
1049
1008
- while ((c = getopt (argc , argv , "6jr:lp:s:hut:m:S:R:w:M:P:c:" )) != -1 ) {
1050
+ while ((c = getopt (argc , argv , "6jr:lp:s:hut:T: m:S:R:w:M:P:c:" )) != -1 ) {
1009
1051
switch (c ) {
1010
1052
case 'j' :
1011
1053
cfg_join = true;
1012
1054
cfg_mode = CFG_MODE_POLL ;
1013
- cfg_wait = 400000 ;
1014
1055
break ;
1015
1056
case 'r' :
1016
1057
cfg_remove = true;
@@ -1043,6 +1084,9 @@ static void parse_opts(int argc, char **argv)
1043
1084
if (poll_timeout <= 0 )
1044
1085
poll_timeout = -1 ;
1045
1086
break ;
1087
+ case 'T' :
1088
+ cfg_time = atoi (optarg );
1089
+ break ;
1046
1090
case 'm' :
1047
1091
cfg_mode = parse_mode (optarg );
1048
1092
break ;
0 commit comments