xref: /linux/tools/testing/selftests/net/tfo.c (revision 5c8013ae2e86ec36b07500ba4cacb14ab4d6f728)
1*c65b5bb2SDavid Wei // SPDX-License-Identifier: GPL-2.0
2*c65b5bb2SDavid Wei #include <error.h>
3*c65b5bb2SDavid Wei #include <fcntl.h>
4*c65b5bb2SDavid Wei #include <limits.h>
5*c65b5bb2SDavid Wei #include <stdbool.h>
6*c65b5bb2SDavid Wei #include <stdint.h>
7*c65b5bb2SDavid Wei #include <stdio.h>
8*c65b5bb2SDavid Wei #include <stdlib.h>
9*c65b5bb2SDavid Wei #include <string.h>
10*c65b5bb2SDavid Wei #include <unistd.h>
11*c65b5bb2SDavid Wei #include <arpa/inet.h>
12*c65b5bb2SDavid Wei #include <sys/socket.h>
13*c65b5bb2SDavid Wei #include <netinet/tcp.h>
14*c65b5bb2SDavid Wei #include <errno.h>
15*c65b5bb2SDavid Wei 
16*c65b5bb2SDavid Wei static int cfg_server;
17*c65b5bb2SDavid Wei static int cfg_client;
18*c65b5bb2SDavid Wei static int cfg_port = 8000;
19*c65b5bb2SDavid Wei static struct sockaddr_in6 cfg_addr;
20*c65b5bb2SDavid Wei static char *cfg_outfile;
21*c65b5bb2SDavid Wei 
parse_address(const char * str,int port,struct sockaddr_in6 * sin6)22*c65b5bb2SDavid Wei static int parse_address(const char *str, int port, struct sockaddr_in6 *sin6)
23*c65b5bb2SDavid Wei {
24*c65b5bb2SDavid Wei 	int ret;
25*c65b5bb2SDavid Wei 
26*c65b5bb2SDavid Wei 	sin6->sin6_family = AF_INET6;
27*c65b5bb2SDavid Wei 	sin6->sin6_port = htons(port);
28*c65b5bb2SDavid Wei 
29*c65b5bb2SDavid Wei 	ret = inet_pton(sin6->sin6_family, str, &sin6->sin6_addr);
30*c65b5bb2SDavid Wei 	if (ret != 1) {
31*c65b5bb2SDavid Wei 		/* fallback to plain IPv4 */
32*c65b5bb2SDavid Wei 		ret = inet_pton(AF_INET, str, &sin6->sin6_addr.s6_addr32[3]);
33*c65b5bb2SDavid Wei 		if (ret != 1)
34*c65b5bb2SDavid Wei 			return -1;
35*c65b5bb2SDavid Wei 
36*c65b5bb2SDavid Wei 		/* add ::ffff prefix */
37*c65b5bb2SDavid Wei 		sin6->sin6_addr.s6_addr32[0] = 0;
38*c65b5bb2SDavid Wei 		sin6->sin6_addr.s6_addr32[1] = 0;
39*c65b5bb2SDavid Wei 		sin6->sin6_addr.s6_addr16[4] = 0;
40*c65b5bb2SDavid Wei 		sin6->sin6_addr.s6_addr16[5] = 0xffff;
41*c65b5bb2SDavid Wei 	}
42*c65b5bb2SDavid Wei 
43*c65b5bb2SDavid Wei 	return 0;
44*c65b5bb2SDavid Wei }
45*c65b5bb2SDavid Wei 
run_server(void)46*c65b5bb2SDavid Wei static void run_server(void)
47*c65b5bb2SDavid Wei {
48*c65b5bb2SDavid Wei 	unsigned long qlen = 32;
49*c65b5bb2SDavid Wei 	int fd, opt, connfd;
50*c65b5bb2SDavid Wei 	socklen_t len;
51*c65b5bb2SDavid Wei 	char buf[64];
52*c65b5bb2SDavid Wei 	FILE *outfile;
53*c65b5bb2SDavid Wei 
54*c65b5bb2SDavid Wei 	outfile = fopen(cfg_outfile, "w");
55*c65b5bb2SDavid Wei 	if (!outfile)
56*c65b5bb2SDavid Wei 		error(1, errno, "fopen() outfile");
57*c65b5bb2SDavid Wei 
58*c65b5bb2SDavid Wei 	fd = socket(AF_INET6, SOCK_STREAM, 0);
59*c65b5bb2SDavid Wei 	if (fd == -1)
60*c65b5bb2SDavid Wei 		error(1, errno, "socket()");
61*c65b5bb2SDavid Wei 
62*c65b5bb2SDavid Wei 	opt = 1;
63*c65b5bb2SDavid Wei 	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
64*c65b5bb2SDavid Wei 		error(1, errno, "setsockopt(SO_REUSEADDR)");
65*c65b5bb2SDavid Wei 
66*c65b5bb2SDavid Wei 	if (setsockopt(fd, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen)) < 0)
67*c65b5bb2SDavid Wei 		error(1, errno, "setsockopt(TCP_FASTOPEN)");
68*c65b5bb2SDavid Wei 
69*c65b5bb2SDavid Wei 	if (bind(fd, (struct sockaddr *)&cfg_addr, sizeof(cfg_addr)) < 0)
70*c65b5bb2SDavid Wei 		error(1, errno, "bind()");
71*c65b5bb2SDavid Wei 
72*c65b5bb2SDavid Wei 	if (listen(fd, 5) < 0)
73*c65b5bb2SDavid Wei 		error(1, errno, "listen()");
74*c65b5bb2SDavid Wei 
75*c65b5bb2SDavid Wei 	len = sizeof(cfg_addr);
76*c65b5bb2SDavid Wei 	connfd = accept(fd, (struct sockaddr *)&cfg_addr, &len);
77*c65b5bb2SDavid Wei 	if (connfd < 0)
78*c65b5bb2SDavid Wei 		error(1, errno, "accept()");
79*c65b5bb2SDavid Wei 
80*c65b5bb2SDavid Wei 	len = sizeof(opt);
81*c65b5bb2SDavid Wei 	if (getsockopt(connfd, SOL_SOCKET, SO_INCOMING_NAPI_ID, &opt, &len) < 0)
82*c65b5bb2SDavid Wei 		error(1, errno, "getsockopt(SO_INCOMING_NAPI_ID)");
83*c65b5bb2SDavid Wei 
84*c65b5bb2SDavid Wei 	read(connfd, buf, 64);
85*c65b5bb2SDavid Wei 	fprintf(outfile, "%d\n", opt);
86*c65b5bb2SDavid Wei 
87*c65b5bb2SDavid Wei 	fclose(outfile);
88*c65b5bb2SDavid Wei 	close(connfd);
89*c65b5bb2SDavid Wei 	close(fd);
90*c65b5bb2SDavid Wei }
91*c65b5bb2SDavid Wei 
run_client(void)92*c65b5bb2SDavid Wei static void run_client(void)
93*c65b5bb2SDavid Wei {
94*c65b5bb2SDavid Wei 	int fd;
95*c65b5bb2SDavid Wei 	char *msg = "Hello, world!";
96*c65b5bb2SDavid Wei 
97*c65b5bb2SDavid Wei 	fd = socket(AF_INET6, SOCK_STREAM, 0);
98*c65b5bb2SDavid Wei 	if (fd == -1)
99*c65b5bb2SDavid Wei 		error(1, errno, "socket()");
100*c65b5bb2SDavid Wei 
101*c65b5bb2SDavid Wei 	sendto(fd, msg, strlen(msg), MSG_FASTOPEN, (struct sockaddr *)&cfg_addr, sizeof(cfg_addr));
102*c65b5bb2SDavid Wei 
103*c65b5bb2SDavid Wei 	close(fd);
104*c65b5bb2SDavid Wei }
105*c65b5bb2SDavid Wei 
usage(const char * filepath)106*c65b5bb2SDavid Wei static void usage(const char *filepath)
107*c65b5bb2SDavid Wei {
108*c65b5bb2SDavid Wei 	error(1, 0, "Usage: %s (-s|-c) -h<server_ip> -p<port> -o<outfile> ", filepath);
109*c65b5bb2SDavid Wei }
110*c65b5bb2SDavid Wei 
parse_opts(int argc,char ** argv)111*c65b5bb2SDavid Wei static void parse_opts(int argc, char **argv)
112*c65b5bb2SDavid Wei {
113*c65b5bb2SDavid Wei 	struct sockaddr_in6 *addr6 = (void *) &cfg_addr;
114*c65b5bb2SDavid Wei 	char *addr = NULL;
115*c65b5bb2SDavid Wei 	int ret;
116*c65b5bb2SDavid Wei 	int c;
117*c65b5bb2SDavid Wei 
118*c65b5bb2SDavid Wei 	if (argc <= 1)
119*c65b5bb2SDavid Wei 		usage(argv[0]);
120*c65b5bb2SDavid Wei 
121*c65b5bb2SDavid Wei 	while ((c = getopt(argc, argv, "sch:p:o:")) != -1) {
122*c65b5bb2SDavid Wei 		switch (c) {
123*c65b5bb2SDavid Wei 		case 's':
124*c65b5bb2SDavid Wei 			if (cfg_client)
125*c65b5bb2SDavid Wei 				error(1, 0, "Pass one of -s or -c");
126*c65b5bb2SDavid Wei 			cfg_server = 1;
127*c65b5bb2SDavid Wei 			break;
128*c65b5bb2SDavid Wei 		case 'c':
129*c65b5bb2SDavid Wei 			if (cfg_server)
130*c65b5bb2SDavid Wei 				error(1, 0, "Pass one of -s or -c");
131*c65b5bb2SDavid Wei 			cfg_client = 1;
132*c65b5bb2SDavid Wei 			break;
133*c65b5bb2SDavid Wei 		case 'h':
134*c65b5bb2SDavid Wei 			addr = optarg;
135*c65b5bb2SDavid Wei 			break;
136*c65b5bb2SDavid Wei 		case 'p':
137*c65b5bb2SDavid Wei 			cfg_port = strtoul(optarg, NULL, 0);
138*c65b5bb2SDavid Wei 			break;
139*c65b5bb2SDavid Wei 		case 'o':
140*c65b5bb2SDavid Wei 			cfg_outfile = strdup(optarg);
141*c65b5bb2SDavid Wei 			if (!cfg_outfile)
142*c65b5bb2SDavid Wei 				error(1, 0, "outfile invalid");
143*c65b5bb2SDavid Wei 			break;
144*c65b5bb2SDavid Wei 		}
145*c65b5bb2SDavid Wei 	}
146*c65b5bb2SDavid Wei 
147*c65b5bb2SDavid Wei 	if (cfg_server && addr)
148*c65b5bb2SDavid Wei 		error(1, 0, "Server cannot have -h specified");
149*c65b5bb2SDavid Wei 
150*c65b5bb2SDavid Wei 	memset(addr6, 0, sizeof(*addr6));
151*c65b5bb2SDavid Wei 	addr6->sin6_family = AF_INET6;
152*c65b5bb2SDavid Wei 	addr6->sin6_port = htons(cfg_port);
153*c65b5bb2SDavid Wei 	addr6->sin6_addr = in6addr_any;
154*c65b5bb2SDavid Wei 	if (addr) {
155*c65b5bb2SDavid Wei 		ret = parse_address(addr, cfg_port, addr6);
156*c65b5bb2SDavid Wei 		if (ret)
157*c65b5bb2SDavid Wei 			error(1, 0, "Client address parse error: %s", addr);
158*c65b5bb2SDavid Wei 	}
159*c65b5bb2SDavid Wei }
160*c65b5bb2SDavid Wei 
main(int argc,char ** argv)161*c65b5bb2SDavid Wei int main(int argc, char **argv)
162*c65b5bb2SDavid Wei {
163*c65b5bb2SDavid Wei 	parse_opts(argc, argv);
164*c65b5bb2SDavid Wei 
165*c65b5bb2SDavid Wei 	if (cfg_server)
166*c65b5bb2SDavid Wei 		run_server();
167*c65b5bb2SDavid Wei 	else if (cfg_client)
168*c65b5bb2SDavid Wei 		run_client();
169*c65b5bb2SDavid Wei 
170*c65b5bb2SDavid Wei 	return 0;
171*c65b5bb2SDavid Wei }
172