aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tools/testing/selftests/netfilter/connect_close.c
blob: 1c3b0add54c4193282c148acc7e62ef9ae0cae47 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// SPDX-License-Identifier: GPL-2.0

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

#include <arpa/inet.h>
#include <sys/socket.h>

#define PORT 12345
#define RUNTIME 10

static struct {
	unsigned int timeout;
	unsigned int port;
} opts = {
	.timeout = RUNTIME,
	.port = PORT,
};

static void handler(int sig)
{
	_exit(sig == SIGALRM ? 0 : 1);
}

static void set_timeout(void)
{
	struct sigaction action = {
		.sa_handler = handler,
	};

	sigaction(SIGALRM, &action, NULL);

	alarm(opts.timeout);
}

static void do_connect(const struct sockaddr_in *dst)
{
	int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	if (s >= 0)
		fcntl(s, F_SETFL, O_NONBLOCK);

	connect(s, (struct sockaddr *)dst, sizeof(*dst));
	close(s);
}

static void do_accept(const struct sockaddr_in *src)
{
	int c, one = 1, s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	if (s < 0)
		return;

	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
	setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));

	bind(s, (struct sockaddr *)src, sizeof(*src));

	listen(s, 16);

	c = accept(s, NULL, NULL);
	if (c >= 0)
		close(c);

	close(s);
}

static int accept_loop(void)
{
	struct sockaddr_in src = {
		.sin_family = AF_INET,
		.sin_port = htons(opts.port),
	};

	inet_pton(AF_INET, "127.0.0.1", &src.sin_addr);

	set_timeout();

	for (;;)
		do_accept(&src);

	return 1;
}

static int connect_loop(void)
{
	struct sockaddr_in dst = {
		.sin_family = AF_INET,
		.sin_port = htons(opts.port),
	};

	inet_pton(AF_INET, "127.0.0.1", &dst.sin_addr);

	set_timeout();

	for (;;)
		do_connect(&dst);

	return 1;
}

static void parse_opts(int argc, char **argv)
{
	int c;

	while ((c = getopt(argc, argv, "t:p:")) != -1) {
		switch (c) {
		case 't':
			opts.timeout = atoi(optarg);
			break;
		case 'p':
			opts.port = atoi(optarg);
			break;
		}
	}
}

int main(int argc, char *argv[])
{
	pid_t p;

	parse_opts(argc, argv);

	p = fork();
	if (p < 0)
		return 111;

	if (p > 0)
		return accept_loop();

	return connect_loop();
}