aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/net/fin_ack_lat.c
blob: 70187494b57af117f31e92a704b91f52a96682ce (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// SPDX-License-Identifier: GPL-2.0

#include <arpa/inet.h>
#include <errno.h>
#include <error.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>

static int child_pid;

static unsigned long timediff(struct timeval s, struct timeval e)
{
	unsigned long s_us, e_us;

	s_us = s.tv_sec * 1000000 + s.tv_usec;
	e_us = e.tv_sec * 1000000 + e.tv_usec;
	if (s_us > e_us)
		return 0;
	return e_us - s_us;
}

static void client(int port)
{
	int sock = 0;
	struct sockaddr_in addr, laddr;
	socklen_t len = sizeof(laddr);
	struct linger sl;
	int flag = 1;
	int buffer;
	struct timeval start, end;
	unsigned long lat, sum_lat = 0, nr_lat = 0;

	while (1) {
		gettimeofday(&start, NULL);

		sock = socket(AF_INET, SOCK_STREAM, 0);
		if (sock < 0)
			error(-1, errno, "socket creation");

		sl.l_onoff = 1;
		sl.l_linger = 0;
		if (setsockopt(sock, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl)))
			error(-1, errno, "setsockopt(linger)");

		if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
					&flag, sizeof(flag)))
			error(-1, errno, "setsockopt(nodelay)");

		addr.sin_family = AF_INET;
		addr.sin_port = htons(port);

		if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) <= 0)
			error(-1, errno, "inet_pton");

		if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
			error(-1, errno, "connect");

		send(sock, &buffer, sizeof(buffer), 0);
		if (read(sock, &buffer, sizeof(buffer)) == -1)
			error(-1, errno, "waiting read");

		gettimeofday(&end, NULL);
		lat = timediff(start, end);
		sum_lat += lat;
		nr_lat++;
		if (lat < 100000)
			goto close;

		if (getsockname(sock, (struct sockaddr *)&laddr, &len) == -1)
			error(-1, errno, "getsockname");
		printf("port: %d, lat: %lu, avg: %lu, nr: %lu\n",
				ntohs(laddr.sin_port), lat,
				sum_lat / nr_lat, nr_lat);
close:
		fflush(stdout);
		close(sock);
	}
}

static void server(int sock, struct sockaddr_in address)
{
	int accepted;
	int addrlen = sizeof(address);
	int buffer;

	while (1) {
		accepted = accept(sock, (struct sockaddr *)&address,
				(socklen_t *)&addrlen);
		if (accepted < 0)
			error(-1, errno, "accept");

		if (read(accepted, &buffer, sizeof(buffer)) == -1)
			error(-1, errno, "read");
		close(accepted);
	}
}

static void sig_handler(int signum)
{
	kill(SIGTERM, child_pid);
	exit(0);
}

int main(int argc, char const *argv[])
{
	int sock;
	int opt = 1;
	struct sockaddr_in address;
	struct sockaddr_in laddr;
	socklen_t len = sizeof(laddr);

	if (signal(SIGTERM, sig_handler) == SIG_ERR)
		error(-1, errno, "signal");

	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock < 0)
		error(-1, errno, "socket");

	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
				&opt, sizeof(opt)) == -1)
		error(-1, errno, "setsockopt");

	address.sin_family = AF_INET;
	address.sin_addr.s_addr = INADDR_ANY;
	/* dynamically allocate unused port */
	address.sin_port = 0;

	if (bind(sock, (struct sockaddr *)&address, sizeof(address)) < 0)
		error(-1, errno, "bind");

	if (listen(sock, 3) < 0)
		error(-1, errno, "listen");

	if (getsockname(sock, (struct sockaddr *)&laddr, &len) == -1)
		error(-1, errno, "getsockname");

	fprintf(stderr, "server port: %d\n", ntohs(laddr.sin_port));
	child_pid = fork();
	if (!child_pid)
		client(ntohs(laddr.sin_port));
	else
		server(sock, laddr);

	return 0;
}