1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun #include <arpa/inet.h>
4*4882a593Smuzhiyun #include <errno.h>
5*4882a593Smuzhiyun #include <error.h>
6*4882a593Smuzhiyun #include <netinet/in.h>
7*4882a593Smuzhiyun #include <netinet/tcp.h>
8*4882a593Smuzhiyun #include <signal.h>
9*4882a593Smuzhiyun #include <stdio.h>
10*4882a593Smuzhiyun #include <stdlib.h>
11*4882a593Smuzhiyun #include <sys/socket.h>
12*4882a593Smuzhiyun #include <sys/time.h>
13*4882a593Smuzhiyun #include <unistd.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun static int child_pid;
16*4882a593Smuzhiyun
timediff(struct timeval s,struct timeval e)17*4882a593Smuzhiyun static unsigned long timediff(struct timeval s, struct timeval e)
18*4882a593Smuzhiyun {
19*4882a593Smuzhiyun unsigned long s_us, e_us;
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun s_us = s.tv_sec * 1000000 + s.tv_usec;
22*4882a593Smuzhiyun e_us = e.tv_sec * 1000000 + e.tv_usec;
23*4882a593Smuzhiyun if (s_us > e_us)
24*4882a593Smuzhiyun return 0;
25*4882a593Smuzhiyun return e_us - s_us;
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun
client(int port)28*4882a593Smuzhiyun static void client(int port)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun int sock = 0;
31*4882a593Smuzhiyun struct sockaddr_in addr, laddr;
32*4882a593Smuzhiyun socklen_t len = sizeof(laddr);
33*4882a593Smuzhiyun struct linger sl;
34*4882a593Smuzhiyun int flag = 1;
35*4882a593Smuzhiyun int buffer;
36*4882a593Smuzhiyun struct timeval start, end;
37*4882a593Smuzhiyun unsigned long lat, sum_lat = 0, nr_lat = 0;
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun while (1) {
40*4882a593Smuzhiyun gettimeofday(&start, NULL);
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun sock = socket(AF_INET, SOCK_STREAM, 0);
43*4882a593Smuzhiyun if (sock < 0)
44*4882a593Smuzhiyun error(-1, errno, "socket creation");
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun sl.l_onoff = 1;
47*4882a593Smuzhiyun sl.l_linger = 0;
48*4882a593Smuzhiyun if (setsockopt(sock, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl)))
49*4882a593Smuzhiyun error(-1, errno, "setsockopt(linger)");
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
52*4882a593Smuzhiyun &flag, sizeof(flag)))
53*4882a593Smuzhiyun error(-1, errno, "setsockopt(nodelay)");
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun addr.sin_family = AF_INET;
56*4882a593Smuzhiyun addr.sin_port = htons(port);
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) <= 0)
59*4882a593Smuzhiyun error(-1, errno, "inet_pton");
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
62*4882a593Smuzhiyun error(-1, errno, "connect");
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun send(sock, &buffer, sizeof(buffer), 0);
65*4882a593Smuzhiyun if (read(sock, &buffer, sizeof(buffer)) == -1)
66*4882a593Smuzhiyun error(-1, errno, "waiting read");
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun gettimeofday(&end, NULL);
69*4882a593Smuzhiyun lat = timediff(start, end);
70*4882a593Smuzhiyun sum_lat += lat;
71*4882a593Smuzhiyun nr_lat++;
72*4882a593Smuzhiyun if (lat < 100000)
73*4882a593Smuzhiyun goto close;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun if (getsockname(sock, (struct sockaddr *)&laddr, &len) == -1)
76*4882a593Smuzhiyun error(-1, errno, "getsockname");
77*4882a593Smuzhiyun printf("port: %d, lat: %lu, avg: %lu, nr: %lu\n",
78*4882a593Smuzhiyun ntohs(laddr.sin_port), lat,
79*4882a593Smuzhiyun sum_lat / nr_lat, nr_lat);
80*4882a593Smuzhiyun close:
81*4882a593Smuzhiyun fflush(stdout);
82*4882a593Smuzhiyun close(sock);
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
server(int sock,struct sockaddr_in address)86*4882a593Smuzhiyun static void server(int sock, struct sockaddr_in address)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun int accepted;
89*4882a593Smuzhiyun int addrlen = sizeof(address);
90*4882a593Smuzhiyun int buffer;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun while (1) {
93*4882a593Smuzhiyun accepted = accept(sock, (struct sockaddr *)&address,
94*4882a593Smuzhiyun (socklen_t *)&addrlen);
95*4882a593Smuzhiyun if (accepted < 0)
96*4882a593Smuzhiyun error(-1, errno, "accept");
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun if (read(accepted, &buffer, sizeof(buffer)) == -1)
99*4882a593Smuzhiyun error(-1, errno, "read");
100*4882a593Smuzhiyun close(accepted);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
sig_handler(int signum)104*4882a593Smuzhiyun static void sig_handler(int signum)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun kill(SIGTERM, child_pid);
107*4882a593Smuzhiyun exit(0);
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
main(int argc,char const * argv[])110*4882a593Smuzhiyun int main(int argc, char const *argv[])
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun int sock;
113*4882a593Smuzhiyun int opt = 1;
114*4882a593Smuzhiyun struct sockaddr_in address;
115*4882a593Smuzhiyun struct sockaddr_in laddr;
116*4882a593Smuzhiyun socklen_t len = sizeof(laddr);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun if (signal(SIGTERM, sig_handler) == SIG_ERR)
119*4882a593Smuzhiyun error(-1, errno, "signal");
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun sock = socket(AF_INET, SOCK_STREAM, 0);
122*4882a593Smuzhiyun if (sock < 0)
123*4882a593Smuzhiyun error(-1, errno, "socket");
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
126*4882a593Smuzhiyun &opt, sizeof(opt)) == -1)
127*4882a593Smuzhiyun error(-1, errno, "setsockopt");
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun address.sin_family = AF_INET;
130*4882a593Smuzhiyun address.sin_addr.s_addr = INADDR_ANY;
131*4882a593Smuzhiyun /* dynamically allocate unused port */
132*4882a593Smuzhiyun address.sin_port = 0;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun if (bind(sock, (struct sockaddr *)&address, sizeof(address)) < 0)
135*4882a593Smuzhiyun error(-1, errno, "bind");
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun if (listen(sock, 3) < 0)
138*4882a593Smuzhiyun error(-1, errno, "listen");
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun if (getsockname(sock, (struct sockaddr *)&laddr, &len) == -1)
141*4882a593Smuzhiyun error(-1, errno, "getsockname");
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun fprintf(stderr, "server port: %d\n", ntohs(laddr.sin_port));
144*4882a593Smuzhiyun child_pid = fork();
145*4882a593Smuzhiyun if (!child_pid)
146*4882a593Smuzhiyun client(ntohs(laddr.sin_port));
147*4882a593Smuzhiyun else
148*4882a593Smuzhiyun server(sock, laddr);
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun return 0;
151*4882a593Smuzhiyun }
152