16
16
#include <unistd.h>
17
17
#include <time.h>
18
18
19
+ #include <sys/ioctl.h>
19
20
#include <sys/poll.h>
20
21
#include <sys/sendfile.h>
21
22
#include <sys/stat.h>
28
29
29
30
#include <linux/tcp.h>
30
31
#include <linux/time_types.h>
32
+ #include <linux/sockios.h>
31
33
32
34
extern int optind ;
33
35
@@ -68,6 +70,8 @@ static unsigned int cfg_time;
68
70
static unsigned int cfg_do_w ;
69
71
static int cfg_wait ;
70
72
static uint32_t cfg_mark ;
73
+ static char * cfg_input ;
74
+ static int cfg_repeat = 1 ;
71
75
72
76
struct cfg_cmsg_types {
73
77
unsigned int cmsg_enabled :1 ;
@@ -91,22 +95,31 @@ static struct cfg_sockopt_types cfg_sockopt_types;
91
95
92
96
static void die_usage (void )
93
97
{
94
- fprintf (stderr , "Usage: mptcp_connect [-6] [-u] [-s MPTCP|TCP] [-p port] [-m mode]"
95
- "[-l] [-w sec] [-t num] [-T num] connect_address\n" );
98
+ fprintf (stderr , "Usage: mptcp_connect [-6] [-c cmsg] [-i file] [-I num] [-j] [-l] "
99
+ "[-m mode] [-M mark] [-o option] [-p port] [-P mode] [-j] [-l] [-r num] "
100
+ "[-s MPTCP|TCP] [-S num] [-r num] [-t num] [-T num] [-u] [-w sec] connect_address\n" );
96
101
fprintf (stderr , "\t-6 use ipv6\n" );
97
- fprintf (stderr , "\t-t num -- set poll timeout to num\n" );
98
- fprintf (stderr , "\t-T num -- set expected runtime to num ms\n" );
99
- fprintf (stderr , "\t-S num -- set SO_SNDBUF to num\n" );
100
- fprintf (stderr , "\t-R num -- set SO_RCVBUF to num\n" );
101
- fprintf (stderr , "\t-p num -- use port num\n" );
102
- fprintf (stderr , "\t-s [MPTCP|TCP] -- use mptcp(default) or tcp sockets\n" );
102
+ fprintf (stderr , "\t-c cmsg -- test cmsg type <cmsg>\n" );
103
+ fprintf (stderr , "\t-i file -- read the data to send from the given file instead of stdin" );
104
+ fprintf (stderr , "\t-I num -- repeat the transfer 'num' times. In listen mode accepts num "
105
+ "incoming connections, in client mode, disconnect and reconnect to the server\n" );
106
+ fprintf (stderr , "\t-j -- add additional sleep at connection start and tear down "
107
+ "-- for MPJ tests\n" );
108
+ fprintf (stderr , "\t-l -- listens mode, accepts incoming connection\n" );
103
109
fprintf (stderr , "\t-m [poll|mmap|sendfile] -- use poll(default)/mmap+write/sendfile\n" );
104
110
fprintf (stderr , "\t-M mark -- set socket packet mark\n" );
105
- fprintf (stderr , "\t-w num -- wait num sec before closing the socket\n" );
106
- fprintf (stderr , "\t-c cmsg -- test cmsg type <cmsg>\n" );
107
111
fprintf (stderr , "\t-o option -- test sockopt <option>\n" );
112
+ fprintf (stderr , "\t-p num -- use port num\n" );
108
113
fprintf (stderr ,
109
114
"\t-P [saveWithPeek|saveAfterPeek] -- save data with/after MSG_PEEK form tcp socket\n" );
115
+ fprintf (stderr , "\t-t num -- set poll timeout to num\n" );
116
+ fprintf (stderr , "\t-T num -- set expected runtime to num ms\n" );
117
+ fprintf (stderr , "\t-r num -- enable slow mode, limiting each write to num bytes "
118
+ "-- for remove addr tests\n" );
119
+ fprintf (stderr , "\t-R num -- set SO_RCVBUF to num\n" );
120
+ fprintf (stderr , "\t-s [MPTCP|TCP] -- use mptcp(default) or tcp sockets\n" );
121
+ fprintf (stderr , "\t-S num -- set SO_SNDBUF to num\n" );
122
+ fprintf (stderr , "\t-w num -- wait num sec before closing the socket\n" );
110
123
exit (1 );
111
124
}
112
125
@@ -310,7 +323,8 @@ static int sock_listen_mptcp(const char * const listenaddr,
310
323
}
311
324
312
325
static int sock_connect_mptcp (const char * const remoteaddr ,
313
- const char * const port , int proto )
326
+ const char * const port , int proto ,
327
+ struct addrinfo * * peer )
314
328
{
315
329
struct addrinfo hints = {
316
330
.ai_protocol = IPPROTO_TCP ,
@@ -334,8 +348,10 @@ static int sock_connect_mptcp(const char * const remoteaddr,
334
348
if (cfg_mark )
335
349
set_mark (sock , cfg_mark );
336
350
337
- if (connect (sock , a -> ai_addr , a -> ai_addrlen ) == 0 )
351
+ if (connect (sock , a -> ai_addr , a -> ai_addrlen ) == 0 ) {
352
+ * peer = a ;
338
353
break ; /* success */
354
+ }
339
355
340
356
perror ("connect()" );
341
357
close (sock );
@@ -524,14 +540,17 @@ static ssize_t do_rnd_read(const int fd, char *buf, const size_t len)
524
540
return ret ;
525
541
}
526
542
527
- static void set_nonblock (int fd )
543
+ static void set_nonblock (int fd , bool nonblock )
528
544
{
529
545
int flags = fcntl (fd , F_GETFL );
530
546
531
547
if (flags == -1 )
532
548
return ;
533
549
534
- fcntl (fd , F_SETFL , flags | O_NONBLOCK );
550
+ if (nonblock )
551
+ fcntl (fd , F_SETFL , flags | O_NONBLOCK );
552
+ else
553
+ fcntl (fd , F_SETFL , flags & ~O_NONBLOCK );
535
554
}
536
555
537
556
static int copyfd_io_poll (int infd , int peerfd , int outfd , bool * in_closed_after_out )
@@ -543,7 +562,7 @@ static int copyfd_io_poll(int infd, int peerfd, int outfd, bool *in_closed_after
543
562
unsigned int woff = 0 , wlen = 0 ;
544
563
char wbuf [8192 ];
545
564
546
- set_nonblock (peerfd );
565
+ set_nonblock (peerfd , true );
547
566
548
567
for (;;) {
549
568
char rbuf [8192 ];
@@ -638,7 +657,6 @@ static int copyfd_io_poll(int infd, int peerfd, int outfd, bool *in_closed_after
638
657
if (cfg_remove )
639
658
usleep (cfg_wait );
640
659
641
- close (peerfd );
642
660
return 0 ;
643
661
}
644
662
@@ -780,7 +798,7 @@ static int copyfd_io_sendfile(int infd, int peerfd, int outfd,
780
798
return err ;
781
799
}
782
800
783
- static int copyfd_io (int infd , int peerfd , int outfd )
801
+ static int copyfd_io (int infd , int peerfd , int outfd , bool close_peerfd )
784
802
{
785
803
bool in_closed_after_out = false;
786
804
struct timespec start , end ;
@@ -819,6 +837,9 @@ static int copyfd_io(int infd, int peerfd, int outfd)
819
837
if (ret )
820
838
return ret ;
821
839
840
+ if (close_peerfd )
841
+ close (peerfd );
842
+
822
843
if (cfg_time ) {
823
844
unsigned int delta_ms ;
824
845
@@ -930,7 +951,7 @@ static void maybe_close(int fd)
930
951
{
931
952
unsigned int r = rand ();
932
953
933
- if (!(cfg_join || cfg_remove ) && (r & 1 ))
954
+ if (!(cfg_join || cfg_remove || cfg_repeat > 1 ) && (r & 1 ))
934
955
close (fd );
935
956
}
936
957
@@ -940,7 +961,9 @@ int main_loop_s(int listensock)
940
961
struct pollfd polls ;
941
962
socklen_t salen ;
942
963
int remotesock ;
964
+ int fd = 0 ;
943
965
966
+ again :
944
967
polls .fd = listensock ;
945
968
polls .events = POLLIN ;
946
969
@@ -961,14 +984,27 @@ int main_loop_s(int listensock)
961
984
check_sockaddr (pf , & ss , salen );
962
985
check_getpeername (remotesock , & ss , salen );
963
986
987
+ if (cfg_input ) {
988
+ fd = open (cfg_input , O_RDONLY );
989
+ if (fd < 0 )
990
+ xerror ("can't open %s: %d" , cfg_input , errno );
991
+ }
992
+
964
993
SOCK_TEST_TCPULP (remotesock , 0 );
965
994
966
- return copyfd_io (0 , remotesock , 1 );
995
+ copyfd_io (fd , remotesock , 1 , true);
996
+ } else {
997
+ perror ("accept" );
998
+ return 1 ;
967
999
}
968
1000
969
- perror ("accept" );
1001
+ if (-- cfg_repeat > 0 ) {
1002
+ if (cfg_input )
1003
+ close (fd );
1004
+ goto again ;
1005
+ }
970
1006
971
- return 1 ;
1007
+ return 0 ;
972
1008
}
973
1009
974
1010
static void init_rng (void )
@@ -1057,15 +1093,47 @@ static void parse_setsock_options(const char *name)
1057
1093
exit (1 );
1058
1094
}
1059
1095
1096
+ void xdisconnect (int fd , int addrlen )
1097
+ {
1098
+ struct sockaddr_storage empty ;
1099
+ int msec_sleep = 10 ;
1100
+ int queued = 1 ;
1101
+ int i ;
1102
+
1103
+ shutdown (fd , SHUT_WR );
1104
+
1105
+ /* while until the pending data is completely flushed, the later
1106
+ * disconnect will bypass/ignore/drop any pending data.
1107
+ */
1108
+ for (i = 0 ; ; i += msec_sleep ) {
1109
+ if (ioctl (fd , SIOCOUTQ , & queued ) < 0 )
1110
+ xerror ("can't query out socket queue: %d" , errno );
1111
+
1112
+ if (!queued )
1113
+ break ;
1114
+
1115
+ if (i > poll_timeout )
1116
+ xerror ("timeout while waiting for spool to complete" );
1117
+ usleep (msec_sleep * 1000 );
1118
+ }
1119
+
1120
+ memset (& empty , 0 , sizeof (empty ));
1121
+ empty .ss_family = AF_UNSPEC ;
1122
+ if (connect (fd , (struct sockaddr * )& empty , addrlen ) < 0 )
1123
+ xerror ("can't disconnect: %d" , errno );
1124
+ }
1125
+
1060
1126
int main_loop (void )
1061
1127
{
1062
- int fd ;
1128
+ int fd , ret , fd_in = 0 ;
1129
+ struct addrinfo * peer ;
1063
1130
1064
1131
/* listener is ready. */
1065
- fd = sock_connect_mptcp (cfg_host , cfg_port , cfg_sock_proto );
1132
+ fd = sock_connect_mptcp (cfg_host , cfg_port , cfg_sock_proto , & peer );
1066
1133
if (fd < 0 )
1067
1134
return 2 ;
1068
1135
1136
+ again :
1069
1137
check_getpeername_connect (fd );
1070
1138
1071
1139
SOCK_TEST_TCPULP (fd , cfg_sock_proto );
@@ -1077,7 +1145,31 @@ int main_loop(void)
1077
1145
if (cfg_cmsg_types .cmsg_enabled )
1078
1146
apply_cmsg_types (fd , & cfg_cmsg_types );
1079
1147
1080
- return copyfd_io (0 , fd , 1 );
1148
+ if (cfg_input ) {
1149
+ fd_in = open (cfg_input , O_RDONLY );
1150
+ if (fd < 0 )
1151
+ xerror ("can't open %s:%d" , cfg_input , errno );
1152
+ }
1153
+
1154
+ /* close the client socket open only if we are not going to reconnect */
1155
+ ret = copyfd_io (fd_in , fd , 1 , cfg_repeat == 1 );
1156
+ if (ret )
1157
+ return ret ;
1158
+
1159
+ if (-- cfg_repeat > 0 ) {
1160
+ xdisconnect (fd , peer -> ai_addrlen );
1161
+
1162
+ /* the socket could be unblocking at this point, we need the
1163
+ * connect to be blocking
1164
+ */
1165
+ set_nonblock (fd , false);
1166
+ if (connect (fd , peer -> ai_addr , peer -> ai_addrlen ))
1167
+ xerror ("can't reconnect: %d" , errno );
1168
+ if (cfg_input )
1169
+ close (fd_in );
1170
+ goto again ;
1171
+ }
1172
+ return 0 ;
1081
1173
}
1082
1174
1083
1175
int parse_proto (const char * proto )
@@ -1162,7 +1254,7 @@ static void parse_opts(int argc, char **argv)
1162
1254
{
1163
1255
int c ;
1164
1256
1165
- while ((c = getopt (argc , argv , "6jr:lp:s:ht:T:m:S:R:w:M:P:c:o :" )) != -1 ) {
1257
+ while ((c = getopt (argc , argv , "6c:hi:I:jlm:M:o:p:P:r:R:s:S:t:T:w :" )) != -1 ) {
1166
1258
switch (c ) {
1167
1259
case 'j' :
1168
1260
cfg_join = true;
@@ -1176,6 +1268,12 @@ static void parse_opts(int argc, char **argv)
1176
1268
if (cfg_do_w <= 0 )
1177
1269
cfg_do_w = 50 ;
1178
1270
break ;
1271
+ case 'i' :
1272
+ cfg_input = optarg ;
1273
+ break ;
1274
+ case 'I' :
1275
+ cfg_repeat = atoi (optarg );
1276
+ break ;
1179
1277
case 'l' :
1180
1278
listen_mode = true;
1181
1279
break ;
0 commit comments