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