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
handler(int sig)24 static void handler(int sig)
25 {
26 _exit(sig == SIGALRM ? 0 : 1);
27 }
28
set_timeout(void)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
do_connect(const struct sockaddr_in * dst)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
do_accept(const struct sockaddr_in * src)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
accept_loop(void)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
connect_loop(void)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
parse_opts(int argc,char ** argv)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
main(int argc,char * argv[])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