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
16static struct {
17	unsigned int timeout;
18	unsigned int port;
19} opts = {
20	.timeout = RUNTIME,
21	.port = PORT,
22};
23
24static void handler(int sig)
25{
26	_exit(sig == SIGALRM ? 0 : 1);
27}
28
29static 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
40static 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
51static 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
72static 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
89static 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
106static 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
122int 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