1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <fcntl.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <signal.h>
9 
10 #include <arpa/inet.h>
11 #include <sys/socket.h>
12 
13 #define PORT 12345
14 #define RUNTIME 10
15 
16 static struct {
17 	unsigned int timeout;
18 	unsigned int port;
19 } opts = {
20 	.timeout = RUNTIME,
21 	.port = PORT,
22 };
23 
24 static void handler(int sig)
25 {
26 	_exit(sig == SIGALRM ? 0 : 1);
27 }
28 
29 static void set_timeout(void)
30 {
31 	struct sigaction action = {
32 		.sa_handler = handler,
33 	};
34 
35 	sigaction(SIGALRM, &action, NULL);
36 
37 	alarm(opts.timeout);
38 }
39 
40 static void do_connect(const struct sockaddr_in *dst)
41 {
42 	int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
43 
44 	if (s >= 0)
45 		fcntl(s, F_SETFL, O_NONBLOCK);
46 
47 	connect(s, (struct sockaddr *)dst, sizeof(*dst));
48 	close(s);
49 }
50 
51 static void do_accept(const struct sockaddr_in *src)
52 {
53 	int c, one = 1, s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
54 
55 	if (s < 0)
56 		return;
57 
58 	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
59 	setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
60 
61 	bind(s, (struct sockaddr *)src, sizeof(*src));
62 
63 	listen(s, 16);
64 
65 	c = accept(s, NULL, NULL);
66 	if (c >= 0)
67 		close(c);
68 
69 	close(s);
70 }
71 
72 static int accept_loop(void)
73 {
74 	struct sockaddr_in src = {
75 		.sin_family = AF_INET,
76 		.sin_port = htons(opts.port),
77 	};
78 
79 	inet_pton(AF_INET, "127.0.0.1", &src.sin_addr);
80 
81 	set_timeout();
82 
83 	for (;;)
84 		do_accept(&src);
85 
86 	return 1;
87 }
88 
89 static int connect_loop(void)
90 {
91 	struct sockaddr_in dst = {
92 		.sin_family = AF_INET,
93 		.sin_port = htons(opts.port),
94 	};
95 
96 	inet_pton(AF_INET, "127.0.0.1", &dst.sin_addr);
97 
98 	set_timeout();
99 
100 	for (;;)
101 		do_connect(&dst);
102 
103 	return 1;
104 }
105 
106 static void parse_opts(int argc, char **argv)
107 {
108 	int c;
109 
110 	while ((c = getopt(argc, argv, "t:p:")) != -1) {
111 		switch (c) {
112 		case 't':
113 			opts.timeout = atoi(optarg);
114 			break;
115 		case 'p':
116 			opts.port = atoi(optarg);
117 			break;
118 		}
119 	}
120 }
121 
122 int main(int argc, char *argv[])
123 {
124 	pid_t p;
125 
126 	parse_opts(argc, argv);
127 
128 	p = fork();
129 	if (p < 0)
130 		return 111;
131 
132 	if (p > 0)
133 		return accept_loop();
134 
135 	return connect_loop();
136 }
137