1 /*
2 * Copyright (c) 2014 Oracle and/or its affiliates. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Author: Alexey Kodanev <alexey.kodanev@oracle.com>
19 *
20 */
21
22 #include <pthread.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <netdb.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <poll.h>
29 #include <time.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <errno.h>
33
34 #include "test.h"
35 #include "lapi/posix_clocks.h"
36 #include "safe_macros.h"
37
38 char *TCID = "tcp_fastopen";
39
40 static const int max_msg_len = 1500;
41
42 /* TCP server requiers */
43 #ifndef TCP_FASTOPEN
44 #define TCP_FASTOPEN 23
45 #endif
46
47 #ifndef SO_BUSY_POLL
48 #define SO_BUSY_POLL 46
49 #endif
50
51 /* TCP client requiers */
52 #ifndef MSG_FASTOPEN
53 #define MSG_FASTOPEN 0x20000000 /* Send data in TCP SYN */
54 #endif
55
56 enum {
57 TCP_SERVER = 0,
58 TCP_CLIENT,
59 };
60 static int tcp_mode;
61
62 enum {
63 TFO_ENABLED = 0,
64 TFO_DISABLED,
65 };
66 static int tfo_support;
67 static int fastopen_api;
68
69 static const char tfo_cfg[] = "/proc/sys/net/ipv4/tcp_fastopen";
70 static const char tcp_tw_reuse[] = "/proc/sys/net/ipv4/tcp_tw_reuse";
71 static int tw_reuse_changed;
72 static int tfo_cfg_value;
73 static int tfo_bit_num;
74 static int tfo_cfg_changed;
75 static int tfo_queue_size = 100;
76 static int max_queue_len = 100;
77 static const int client_byte = 0x43;
78 static const int server_byte = 0x53;
79 static const int start_byte = 0x24;
80 static const int start_fin_byte = 0x25;
81 static const int end_byte = 0x0a;
82 static int client_msg_size = 32;
83 static int server_msg_size = 128;
84 static char *client_msg;
85 static char *server_msg;
86
87 /*
88 * The number of requests from client after
89 * which server has to close the connection.
90 */
91 static int server_max_requests = 3;
92 static int client_max_requests = 10;
93 static int clients_num = 2;
94 static char *tcp_port = "61000";
95 static char *server_addr = "localhost";
96 static int busy_poll = -1;
97 /* server socket */
98 static int sfd;
99
100 /* how long a client must wait for the server's reply, microsec */
101 static long wait_timeout = 10000000;
102
103 /* in the end test will save time result in this file */
104 static char *rpath = "./tfo_result";
105
106 static int force_run;
107 static int verbose;
108
109 static char *narg, *Narg, *qarg, *rarg, *Rarg, *aarg, *Targ, *barg;
110
111 static const option_t options[] = {
112 /* server params */
113 {"R:", NULL, &Rarg},
114 {"q:", NULL, &qarg},
115
116 /* client params */
117 {"H:", NULL, &server_addr},
118 {"a:", NULL, &aarg},
119 {"n:", NULL, &narg},
120 {"N:", NULL, &Narg},
121 {"T:", NULL, &Targ},
122 {"r:", NULL, &rarg},
123 {"d:", NULL, &rpath},
124
125 /* common */
126 {"g:", NULL, &tcp_port},
127 {"b:", NULL, &barg},
128 {"F", &force_run, NULL},
129 {"l", &tcp_mode, NULL},
130 {"o", &fastopen_api, NULL},
131 {"O", &tfo_support, NULL},
132 {"v", &verbose, NULL},
133 {NULL, NULL, NULL}
134 };
135
help(void)136 static void help(void)
137 {
138 printf("\n -F Force to run\n");
139 printf(" -v Verbose\n");
140 printf(" -o Use old TCP API, default is new TCP API\n");
141 printf(" -O TFO support is off, default is on\n");
142 printf(" -l Become TCP Client, default is TCP server\n");
143 printf(" -g x x - server port, default is %s\n", tcp_port);
144 printf(" -b x x - low latency busy poll timeout\n");
145
146 printf("\n Client:\n");
147 printf(" -H x x - server name or ip address, default is '%s'\n",
148 server_addr);
149 printf(" -a x x - num of clients running in parallel\n");
150 printf(" -r x x - num of client requests\n");
151 printf(" -n x Client message size, max msg size is '%d'\n",
152 max_msg_len);
153 printf(" -N x Server message size, max msg size is '%d'\n",
154 max_msg_len);
155 printf(" -T x Reply timeout, default is '%ld' (microsec)\n",
156 wait_timeout);
157 printf(" -d x x is a path to the file where results are saved\n");
158
159 printf("\n Server:\n");
160 printf(" -R x x - num of requests, after which conn. closed\n");
161 printf(" -q x x - server's limit on the queue of TFO requests\n");
162 }
163
164 /* common structure for TCP server and TCP client */
165 struct tcp_func {
166 void (*init)(void);
167 void (*run)(void);
168 void (*cleanup)(void);
169 };
170 static struct tcp_func tcp;
171
172 #define MAX_THREADS 10000
173 static pthread_attr_t attr;
174 static pthread_t *thread_ids;
175
176 static struct addrinfo *remote_addrinfo;
177 static struct addrinfo *local_addrinfo;
178 static const struct linger clo = { 1, 3 };
179
do_cleanup(void)180 static void do_cleanup(void)
181 {
182 free(client_msg);
183 free(server_msg);
184
185 tcp.cleanup();
186
187 if (tfo_cfg_changed) {
188 SAFE_FILE_SCANF(NULL, tfo_cfg, "%d", &tfo_cfg_value);
189 tfo_cfg_value &= ~tfo_bit_num;
190 tfo_cfg_value |= !tfo_support << (tfo_bit_num - 1);
191 tst_resm(TINFO, "unset '%s' back to '%d'",
192 tfo_cfg, tfo_cfg_value);
193 SAFE_FILE_PRINTF(NULL, tfo_cfg, "%d", tfo_cfg_value);
194 }
195
196 if (tw_reuse_changed) {
197 SAFE_FILE_PRINTF(NULL, tcp_tw_reuse, "0");
198 tst_resm(TINFO, "unset '%s' back to '0'", tcp_tw_reuse);
199 }
200 }
TST_DECLARE_ONCE_FN(cleanup,do_cleanup)201 TST_DECLARE_ONCE_FN(cleanup, do_cleanup)
202
203 static int sock_recv_poll(int fd, char *buf, int buf_size, int offset)
204 {
205 struct pollfd pfd;
206 pfd.fd = fd;
207 pfd.events = POLLIN;
208 int len = -1;
209 while (1) {
210 errno = 0;
211 int ret = poll(&pfd, 1, wait_timeout / 1000);
212 if (ret == -1) {
213 if (errno == EINTR)
214 continue;
215 break;
216 }
217
218 if (ret == 0) {
219 errno = ETIME;
220 break;
221 }
222
223 if (ret != 1 || !(pfd.revents & POLLIN))
224 break;
225
226 errno = 0;
227 len = recv(fd, buf + offset,
228 buf_size - offset, MSG_DONTWAIT);
229
230 if (len == -1 && errno == EINTR)
231 continue;
232 else
233 break;
234 }
235
236 return len;
237 }
238
client_recv(int * fd,char * buf)239 static int client_recv(int *fd, char *buf)
240 {
241 int len, offset = 0;
242
243 while (1) {
244 errno = 0;
245 len = sock_recv_poll(*fd, buf, server_msg_size, offset);
246
247 /* socket closed or msg is not valid */
248 if (len < 1 || (offset + len) > server_msg_size ||
249 (buf[0] != start_byte && buf[0] != start_fin_byte)) {
250 if (!errno)
251 errno = ENOMSG;
252 break;
253 }
254 offset += len;
255 if (buf[offset - 1] != end_byte)
256 continue;
257
258 if (verbose) {
259 tst_resm_hexd(TINFO, buf, offset,
260 "msg recv from sock %d:", *fd);
261 }
262
263 /* recv last msg, close socket */
264 if (buf[0] == start_fin_byte)
265 break;
266 return 0;
267 }
268
269 shutdown(*fd, SHUT_WR);
270 SAFE_CLOSE(cleanup, *fd);
271 *fd = -1;
272 return (errno) ? -1 : 0;
273 }
274
client_connect_send(const char * msg,int size)275 static int client_connect_send(const char *msg, int size)
276 {
277 int cfd = socket(remote_addrinfo->ai_family, SOCK_STREAM, 0);
278 const int flag = 1;
279
280 if (cfd == -1)
281 return cfd;
282
283 setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
284 if (busy_poll >= 0) {
285 setsockopt(cfd, SOL_SOCKET, SO_BUSY_POLL,
286 &busy_poll, sizeof(busy_poll));
287 }
288
289 if (fastopen_api == TFO_ENABLED) {
290 /* Replaces connect() + send()/write() */
291 if (sendto(cfd, msg, size, MSG_FASTOPEN | MSG_NOSIGNAL,
292 remote_addrinfo->ai_addr,
293 remote_addrinfo->ai_addrlen) != size) {
294 SAFE_CLOSE(cleanup, cfd);
295 return -1;
296 }
297 } else {
298 /* old TCP API */
299 if (connect(cfd, remote_addrinfo->ai_addr,
300 remote_addrinfo->ai_addrlen)) {
301 SAFE_CLOSE(cleanup, cfd);
302 return -1;
303 }
304
305 if (send(cfd, msg, size, MSG_NOSIGNAL) != client_msg_size) {
306 SAFE_CLOSE(cleanup, cfd);
307 return -1;
308 }
309 }
310
311 return cfd;
312 }
313
client_fn(LTP_ATTRIBUTE_UNUSED void * arg)314 void *client_fn(LTP_ATTRIBUTE_UNUSED void *arg)
315 {
316 char buf[server_msg_size];
317 int cfd, i;
318 intptr_t err = 0;
319
320 /* connect & send requests */
321 cfd = client_connect_send(client_msg, client_msg_size);
322 if (cfd == -1) {
323 err = errno;
324 goto out;
325 }
326
327 if (client_recv(&cfd, buf)) {
328 err = errno;
329 goto out;
330 }
331
332 for (i = 1; i < client_max_requests; ++i) {
333
334 /* check connection, it can be closed */
335 int ret = 0;
336 if (cfd != -1)
337 ret = recv(cfd, buf, 1, MSG_DONTWAIT);
338
339 if (ret == 0) {
340 /* try to reconnect and send */
341 if (cfd != -1)
342 SAFE_CLOSE(cleanup, cfd);
343
344 cfd = client_connect_send(client_msg, client_msg_size);
345 if (cfd == -1) {
346 err = errno;
347 goto out;
348 }
349
350 if (client_recv(&cfd, buf)) {
351 err = errno;
352 break;
353 }
354
355 continue;
356
357 } else if (ret > 0) {
358 err = EMSGSIZE;
359 break;
360 }
361
362 if (verbose) {
363 tst_resm_hexd(TINFO, client_msg, client_msg_size,
364 "try to send msg[%d]", i);
365 }
366
367 if (send(cfd, client_msg, client_msg_size,
368 MSG_NOSIGNAL) != client_msg_size) {
369 err = ECOMM;
370 break;
371 }
372 if (client_recv(&cfd, buf)) {
373 err = errno;
374 break;
375 }
376 }
377
378 if (cfd != -1)
379 SAFE_CLOSE(cleanup, cfd);
380
381 out:
382 return (void *) err;
383 }
384
385 union net_size_field {
386 char bytes[2];
387 uint16_t value;
388 };
389
make_client_request(void)390 static void make_client_request(void)
391 {
392 client_msg[0] = start_byte;
393
394 /* set size for reply */
395 union net_size_field net_size;
396 net_size.value = htons(server_msg_size);
397 client_msg[1] = net_size.bytes[0];
398 client_msg[2] = net_size.bytes[1];
399
400 client_msg[client_msg_size - 1] = end_byte;
401 }
402
parse_client_request(const char * msg)403 static int parse_client_request(const char *msg)
404 {
405 union net_size_field net_size;
406 net_size.bytes[0] = msg[1];
407 net_size.bytes[1] = msg[2];
408 int size = ntohs(net_size.value);
409 if (size < 2 || size > max_msg_len)
410 return -1;
411
412 return size;
413 }
414
415 static struct timespec tv_client_start;
416 static struct timespec tv_client_end;
417
client_init(void)418 static void client_init(void)
419 {
420 if (clients_num >= MAX_THREADS) {
421 tst_brkm(TBROK, cleanup,
422 "Unexpected num of clients '%d'",
423 clients_num);
424 }
425
426 thread_ids = SAFE_MALLOC(NULL, sizeof(pthread_t) * clients_num);
427
428 client_msg = SAFE_MALLOC(NULL, client_msg_size);
429 memset(client_msg, client_byte, client_msg_size);
430
431 make_client_request();
432
433 struct addrinfo hints;
434 memset(&hints, 0, sizeof(struct addrinfo));
435 hints.ai_socktype = SOCK_STREAM;
436 int err = getaddrinfo(server_addr, tcp_port, &hints, &remote_addrinfo);
437 if (err) {
438 tst_brkm(TBROK, cleanup, "getaddrinfo of '%s' failed, %s",
439 server_addr, gai_strerror(err));
440 }
441
442 tst_resm(TINFO, "TCP Fast Open over IPv%s",
443 (remote_addrinfo->ai_family == AF_INET6) ? "6" : "4");
444
445 clock_gettime(CLOCK_MONOTONIC_RAW, &tv_client_start);
446 int i;
447 for (i = 0; i < clients_num; ++i) {
448 if (pthread_create(&thread_ids[i], 0, client_fn, NULL) != 0) {
449 tst_brkm(TBROK | TERRNO, cleanup,
450 "pthread_create failed at %s:%d",
451 __FILE__, __LINE__);
452 }
453 }
454 }
455
client_run(void)456 static void client_run(void)
457 {
458 void *res = NULL;
459 long clnt_time = 0;
460 int i;
461 for (i = 0; i < clients_num; ++i) {
462 pthread_join(thread_ids[i], &res);
463 if (res) {
464 tst_brkm(TBROK, cleanup, "client[%d] failed: %s",
465 i, strerror((intptr_t)res));
466 }
467 }
468
469 clock_gettime(CLOCK_MONOTONIC_RAW, &tv_client_end);
470 clnt_time = (tv_client_end.tv_sec - tv_client_start.tv_sec) * 1000 +
471 (tv_client_end.tv_nsec - tv_client_start.tv_nsec) / 1000000;
472
473 tst_resm(TINFO, "total time '%ld' ms", clnt_time);
474
475 /* ask server to terminate */
476 client_msg[0] = start_fin_byte;
477 int cfd = client_connect_send(client_msg, client_msg_size);
478 if (cfd != -1) {
479 shutdown(cfd, SHUT_WR);
480 SAFE_CLOSE(NULL, cfd);
481 }
482 /* the script tcp_fastopen_run.sh will remove it */
483 SAFE_FILE_PRINTF(cleanup, rpath, "%ld", clnt_time);
484 }
485
client_cleanup(void)486 static void client_cleanup(void)
487 {
488 free(thread_ids);
489
490 if (remote_addrinfo)
491 freeaddrinfo(remote_addrinfo);
492 }
493
make_server_reply(int size)494 static char *make_server_reply(int size)
495 {
496 char *send_msg = SAFE_MALLOC(NULL, size);
497 memset(send_msg, server_byte, size - 1);
498 send_msg[0] = start_byte;
499 send_msg[size - 1] = end_byte;
500 return send_msg;
501 }
502
server_fn(void * cfd)503 void *server_fn(void *cfd)
504 {
505 int client_fd = (intptr_t) cfd;
506 int num_requests = 0, offset = 0;
507
508 /* Reply will be constructed from first client request */
509 char *send_msg = NULL;
510 int send_msg_size = 0;
511
512 char recv_msg[max_msg_len];
513
514 setsockopt(client_fd, SOL_SOCKET, SO_LINGER, &clo, sizeof(clo));
515 if (busy_poll >= 0) {
516 setsockopt(client_fd, SOL_SOCKET, SO_BUSY_POLL,
517 &busy_poll, sizeof(busy_poll));
518 }
519
520 ssize_t recv_len;
521
522 while (1) {
523 recv_len = sock_recv_poll(client_fd, recv_msg,
524 max_msg_len, offset);
525
526 if (recv_len == 0)
527 break;
528
529 if (recv_len < 0 || (offset + recv_len) > max_msg_len ||
530 (recv_msg[0] != start_byte &&
531 recv_msg[0] != start_fin_byte)) {
532 tst_resm(TFAIL, "recv failed, sock '%d'", client_fd);
533 goto out;
534 }
535
536 offset += recv_len;
537
538 if (recv_msg[offset - 1] != end_byte) {
539 /* msg is not complete, continue recv */
540 continue;
541 }
542
543 /* client asks to terminate */
544 if (recv_msg[0] == start_fin_byte)
545 goto out;
546
547 if (verbose) {
548 tst_resm_hexd(TINFO, recv_msg, offset,
549 "msg recv from sock %d:", client_fd);
550 }
551
552 /* if we send reply for the first time, construct it here */
553 if (!send_msg) {
554 send_msg_size = parse_client_request(recv_msg);
555 if (send_msg_size < 0) {
556 tst_resm(TFAIL, "wrong msg size '%d'",
557 send_msg_size);
558 goto out;
559 }
560 send_msg = make_server_reply(send_msg_size);
561 }
562
563 /*
564 * It will tell client that server is going
565 * to close this connection.
566 */
567 if (++num_requests >= server_max_requests)
568 send_msg[0] = start_fin_byte;
569
570 if (send(client_fd, send_msg, send_msg_size,
571 MSG_NOSIGNAL) == -1) {
572 tst_resm(TFAIL | TERRNO, "send failed");
573 goto out;
574 }
575
576 offset = 0;
577
578 if (num_requests >= server_max_requests) {
579 /* max reqs, close socket */
580 shutdown(client_fd, SHUT_WR);
581 break;
582 }
583 }
584
585 free(send_msg);
586 SAFE_CLOSE(cleanup, client_fd);
587 return NULL;
588
589 out:
590 free(send_msg);
591 SAFE_CLOSE(cleanup, client_fd);
592 cleanup();
593 tst_exit();
594 }
595
server_thread_add(intptr_t client_fd)596 static void server_thread_add(intptr_t client_fd)
597 {
598 pthread_t id;
599 if (pthread_create(&id, &attr, server_fn, (void *) client_fd)) {
600 tst_brkm(TBROK | TERRNO, cleanup,
601 "pthread_create failed at %s:%d", __FILE__, __LINE__);
602 }
603 }
604
server_init(void)605 static void server_init(void)
606 {
607 struct addrinfo hints;
608 memset(&hints, 0, sizeof(struct addrinfo));
609 hints.ai_family = AF_INET6;
610 hints.ai_socktype = SOCK_STREAM;
611 hints.ai_flags = AI_PASSIVE;
612 if (getaddrinfo(NULL, tcp_port, &hints, &local_addrinfo) != 0)
613 tst_brkm(TBROK | TERRNO, cleanup, "getaddrinfo failed");
614
615 /* IPv6 socket is also able to access IPv4 protocol stack */
616 sfd = SAFE_SOCKET(cleanup, AF_INET6, SOCK_STREAM, 0);
617
618 tst_resm(TINFO, "assigning a name to the server socket...");
619 if (!local_addrinfo)
620 tst_brkm(TBROK, cleanup, "failed to get the address");
621
622 SAFE_BIND(cleanup, sfd, local_addrinfo->ai_addr,
623 local_addrinfo->ai_addrlen);
624
625 freeaddrinfo(local_addrinfo);
626
627 const int flag = 1;
628 setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
629
630 if (fastopen_api == TFO_ENABLED) {
631 if (setsockopt(sfd, IPPROTO_TCP, TCP_FASTOPEN, &tfo_queue_size,
632 sizeof(tfo_queue_size)) == -1)
633 tst_brkm(TBROK, cleanup, "Can't set TFO sock. options");
634 }
635
636 SAFE_LISTEN(cleanup, sfd, max_queue_len);
637 tst_resm(TINFO, "Listen on the socket '%d', port '%s'", sfd, tcp_port);
638 }
639
server_cleanup(void)640 static void server_cleanup(void)
641 {
642 SAFE_CLOSE(NULL, sfd);
643 }
644
server_run(void)645 static void server_run(void)
646 {
647 /* IPv4 source address will be mapped to IPv6 address */
648 struct sockaddr_in6 addr6;
649 socklen_t addr_size = sizeof(addr6);
650
651 pthread_attr_init(&attr);
652
653 /*
654 * detaching threads allow to reclaim thread's resources
655 * once a thread finishes its work.
656 */
657 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
658 tst_brkm(TBROK | TERRNO, cleanup, "setdetachstate failed");
659
660 while (1) {
661 int client_fd = accept(sfd, (struct sockaddr *)&addr6,
662 &addr_size);
663
664 if (client_fd == -1)
665 tst_brkm(TBROK, cleanup, "Can't create client socket");
666
667 if (verbose) {
668 char addr_buf[INET6_ADDRSTRLEN];
669 tst_resm(TINFO, "conn: port '%d', addr '%s'",
670 addr6.sin6_port, inet_ntop(AF_INET6,
671 &addr6.sin6_addr, addr_buf, INET6_ADDRSTRLEN));
672 }
673
674 server_thread_add(client_fd);
675 }
676 }
677
check_opt(const char * name,char * arg,int * val,int lim)678 static void check_opt(const char *name, char *arg, int *val, int lim)
679 {
680 if (arg) {
681 if (sscanf(arg, "%i", val) != 1)
682 tst_brkm(TBROK, NULL, "-%s option arg is not a number",
683 name);
684 if (*val < lim)
685 tst_brkm(TBROK, NULL, "-%s option arg is less than %d",
686 name, lim);
687 }
688 }
689
check_opt_l(const char * name,char * arg,long * val,long lim)690 static void check_opt_l(const char *name, char *arg, long *val, long lim)
691 {
692 if (arg) {
693 if (sscanf(arg, "%ld", val) != 1)
694 tst_brkm(TBROK, NULL, "-%s option arg is not a number",
695 name);
696 if (*val < lim)
697 tst_brkm(TBROK, NULL, "-%s option arg is less than %ld",
698 name, lim);
699 }
700 }
701
setup(int argc,char * argv[])702 static void setup(int argc, char *argv[])
703 {
704 tst_parse_opts(argc, argv, options, help);
705
706 /* if client_num is not set, use num of processors */
707 clients_num = sysconf(_SC_NPROCESSORS_ONLN);
708
709 check_opt("a", aarg, &clients_num, 1);
710 check_opt("r", rarg, &client_max_requests, 1);
711 check_opt("R", Rarg, &server_max_requests, 1);
712 check_opt("n", narg, &client_msg_size, 1);
713 check_opt("N", Narg, &server_msg_size, 1);
714 check_opt("q", qarg, &tfo_queue_size, 1);
715 check_opt_l("T", Targ, &wait_timeout, 0L);
716 check_opt("b", barg, &busy_poll, 0);
717
718 if (!force_run)
719 tst_require_root();
720
721 if (!force_run && tst_kvercmp(3, 7, 0) < 0) {
722 tst_brkm(TCONF, NULL,
723 "Test must be run with kernel 3.7 or newer");
724 }
725
726 if (!force_run && busy_poll >= 0 && tst_kvercmp(3, 11, 0) < 0) {
727 tst_brkm(TCONF, NULL,
728 "Test must be run with kernel 3.11 or newer");
729 }
730
731 /* check tcp fast open knob */
732 if (!force_run && access(tfo_cfg, F_OK) == -1)
733 tst_brkm(TCONF, NULL, "Failed to find '%s'", tfo_cfg);
734
735 if (!force_run) {
736 SAFE_FILE_SCANF(NULL, tfo_cfg, "%d", &tfo_cfg_value);
737 tst_resm(TINFO, "'%s' is %d", tfo_cfg, tfo_cfg_value);
738 }
739
740 tst_sig(FORK, DEF_HANDLER, cleanup);
741
742 tst_resm(TINFO, "TCP %s is using %s TCP API.",
743 (tcp_mode == TCP_SERVER) ? "server" : "client",
744 (fastopen_api == TFO_ENABLED) ? "Fastopen" : "old");
745
746 switch (tcp_mode) {
747 case TCP_SERVER:
748 tst_resm(TINFO, "max requests '%d'",
749 server_max_requests);
750 tcp.init = server_init;
751 tcp.run = server_run;
752 tcp.cleanup = server_cleanup;
753 tfo_bit_num = 2;
754 break;
755 case TCP_CLIENT:
756 tst_resm(TINFO, "connection: addr '%s', port '%s'",
757 server_addr, tcp_port);
758 tst_resm(TINFO, "client max req: %d", client_max_requests);
759 tst_resm(TINFO, "clients num: %d", clients_num);
760 tst_resm(TINFO, "client msg size: %d", client_msg_size);
761 tst_resm(TINFO, "server msg size: %d", server_msg_size);
762
763 tcp.init = client_init;
764 tcp.run = client_run;
765 tcp.cleanup = client_cleanup;
766 tfo_bit_num = 1;
767 break;
768 }
769
770 tfo_support = TFO_ENABLED == tfo_support;
771 if (((tfo_cfg_value & tfo_bit_num) == tfo_bit_num) != tfo_support) {
772 int value = (tfo_cfg_value & ~tfo_bit_num)
773 | (tfo_support << (tfo_bit_num - 1));
774 tst_resm(TINFO, "set '%s' to '%d'", tfo_cfg, value);
775 SAFE_FILE_PRINTF(cleanup, tfo_cfg, "%d", value);
776 tfo_cfg_changed = 1;
777 }
778
779 int reuse_value = 0;
780 SAFE_FILE_SCANF(cleanup, tcp_tw_reuse, "%d", &reuse_value);
781 if (!reuse_value) {
782 SAFE_FILE_PRINTF(cleanup, tcp_tw_reuse, "1");
783 tw_reuse_changed = 1;
784 tst_resm(TINFO, "set '%s' to '1'", tcp_tw_reuse);
785 }
786
787 tst_resm(TINFO, "TFO support %s",
788 (tfo_support) ? "enabled" : "disabled");
789
790 tcp.init();
791 }
792
main(int argc,char * argv[])793 int main(int argc, char *argv[])
794 {
795 setup(argc, argv);
796
797 tcp.run();
798
799 cleanup();
800
801 tst_exit();
802 }
803