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