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: &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: &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

source code of linux/tools/testing/selftests/netfilter/connect_close.c