1 /* $OpenBSD: gen_traffic.c,v 1.3 2022/05/31 19:01:46 mbuhl Exp $ */
2 /*
3 * Copyright (c) 2013 Florian Obser <florian@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/types.h>
19 #include <sys/ioctl.h>
20 #include <sys/queue.h>
21 #include <sys/socket.h>
22 #include <sys/socketvar.h>
23 #include <sys/stat.h>
24 #include <sys/un.h>
25 #include <sys/wait.h>
26 #include <err.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #include <event.h>
30 #include <netdb.h>
31 #include <pwd.h>
32 #include <signal.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <syslog.h>
37 #include <unistd.h>
38
39 __dead void usage(void);
40 void gen_traffic_paused(int, short, void*);
41 void gen_traffic_accept(int, short, void*);
42 void gen_traffic_request(int, short, void*);
43 void gen_traffic_write(int, short, void*);
44 void gen_traffic_sender_paused(int, short, void*);
45
46 struct listener {
47 struct event ev, pause;
48 };
49
50 struct reader {
51 struct event ev;
52 int fd;
53 };
54
55 struct sender {
56 struct event ev, pause;
57 int fd;
58 };
59
60 __dead void
usage(void)61 usage(void)
62 {
63 extern char *__progname;
64 fprintf(stderr, "usage: %s 4|6\n", __progname);
65 exit(1);
66 }
67
68
69 int on = 1;
70
71 int
main(int argc,char * argv[])72 main(int argc, char *argv[])
73 {
74 struct addrinfo hints, *sender_res, *server_res;
75 struct listener *l;
76 struct sender *sender;
77 char *ip;
78 int error, s;
79
80 if (argc != 2)
81 usage();
82 if (strncmp(argv[1], "4", 1) == 0)
83 ip = "10.11.12.13";
84 else if (strncmp(argv[1], "6", 1) == 0)
85 ip = "2001:db8::13";
86 else
87 usage();
88
89 event_init();
90
91 memset(&hints, 0, sizeof(hints));
92 hints.ai_family = PF_UNSPEC;
93 hints.ai_socktype = SOCK_STREAM;
94 error = getaddrinfo(ip, "12346", &hints, &server_res);
95 if (error)
96 errx(1, "%s", gai_strerror(error));
97 s = socket(server_res->ai_family, server_res->ai_socktype,
98 server_res->ai_protocol);
99 if (s == -1)
100 err(1, "%s", "bind");
101 if (bind(s, server_res->ai_addr, server_res->ai_addrlen) < 0)
102 err(1, "%s", "bind");
103 if (ioctl(s, FIONBIO, &on) == -1)
104 err(1, "%s", "listener ioctl(FIONBIO)");
105 if (listen(s, 5) == -1)
106 err(1, "%s", "listen");
107
108 l = calloc(1, sizeof(*l));
109 if (l == NULL)
110 errx(1, "calloc");
111 event_set(&l->ev, s, EV_READ | EV_PERSIST, gen_traffic_accept, l);
112 event_add(&l->ev, NULL);
113 evtimer_set(&l->pause, gen_traffic_paused, l);
114
115 error = getaddrinfo(ip, "12345", &hints, &sender_res);
116 if (error)
117 errx(1, "%s", gai_strerror(error));
118 s = socket(sender_res->ai_family, sender_res->ai_socktype,
119 sender_res->ai_protocol);
120 if (s == -1)
121 err(1, "%s", "bind");
122 if (bind(s, sender_res->ai_addr, sender_res->ai_addrlen) < 0)
123 err(1, "%s", "bind");
124 if (ioctl(s, FIONBIO, &on) == -1)
125 err(1, "%s", "sender ioctl(FIONBIO)");
126 sender = calloc(1, sizeof(*sender));
127 if (sender == NULL)
128 errx(1, "calloc");
129 if (connect(s, server_res->ai_addr, server_res->ai_addrlen) == -1 &&
130 errno != EINPROGRESS)
131 err(1, "%s", "connect");
132 event_set(&sender->ev, s, EV_WRITE | EV_PERSIST, gen_traffic_write,
133 sender);
134 event_add(&sender->ev, NULL);
135 evtimer_set(&sender->pause, gen_traffic_sender_paused, sender);
136 event_dispatch();
137 exit(0);
138 }
139
140 void
gen_traffic_paused(int fd,short events,void * arg)141 gen_traffic_paused(int fd, short events, void *arg)
142 {
143 struct listener *l = arg;
144 event_add(&l->ev, NULL);
145 }
146
147 void
gen_traffic_sender_paused(int fd,short events,void * arg)148 gen_traffic_sender_paused(int fd, short events, void *arg)
149 {
150 struct sender *s = arg;
151 event_add(&s->ev, NULL);
152 }
153
154 void
gen_traffic_accept(int fd,short events,void * arg)155 gen_traffic_accept(int fd, short events, void *arg)
156 {
157 struct listener *l;
158 struct sockaddr_storage ss;
159 struct timeval pause;
160 struct reader *r;
161 socklen_t len;
162 int s;
163
164 l = arg;
165 pause.tv_sec = 1; pause.tv_usec = 0;
166
167 len = sizeof(ss);
168 s = accept(fd, (struct sockaddr *)&ss, &len);
169 if (s == -1) {
170 switch (errno) {
171 case EINTR:
172 case EWOULDBLOCK:
173 case ECONNABORTED:
174 return;
175 case EMFILE:
176 case ENFILE:
177 event_del(&l->ev);
178 evtimer_add(&l->pause, &pause);
179 return;
180 default:
181 err(1, "%s", "accept");
182 }
183 }
184
185 if (ioctl(s, FIONBIO, &on) == -1)
186 err(1, "%s", "reader ioctl(FIONBIO)");
187
188 r = calloc(1, sizeof(*r));
189 if (r == NULL)
190 errx(1, "%s", "cannot calloc reader");
191
192 r->fd = s;
193
194 event_set(&r->ev, s, EV_READ | EV_PERSIST, gen_traffic_request, r);
195 event_add(&r->ev, NULL);
196 }
197
198 void
gen_traffic_request(int fd,short events,void * arg)199 gen_traffic_request(int fd, short events, void *arg)
200 {
201 static size_t total = 0;
202 struct reader *r;
203 size_t n;
204 uint8_t buf[4096];
205
206 r = arg;
207
208 n = read(fd, buf, 4096);
209
210 switch (n) {
211 case -1:
212 switch (errno) {
213 case EINTR:
214 case EAGAIN:
215 return;
216 default:
217 err(1, "%s", "read");
218 }
219 break;
220
221 case 0:
222 exit(0);
223 default:
224 total += n;
225 /* warnx("read: %lld - %lld", n, total); */
226 break;
227 }
228 }
229
230 void
gen_traffic_write(int fd,short events,void * arg)231 gen_traffic_write(int fd, short events, void *arg)
232 {
233 static int count = 0;
234 struct timeval pause;
235 struct sender *s;
236 uint8_t buf[4096];
237
238 s = arg;
239 pause.tv_sec = 1;
240 pause.tv_usec = 0;
241 event_del(&s->ev);
242 if (count++ >= 10) {
243 /* warnx("%s", "done writing"); */
244 close(fd);
245 return;
246 }
247 if (write(fd, buf, 4096) == -1)
248 err(1, "%s", "write");
249 evtimer_add(&s->pause, &pause);
250 }
251