1 /* $OpenBSD: gen_traffic.c,v 1.2 2016/10/26 14:06:33 bluhm 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 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 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 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 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 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 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 event_del(&r->ev); 223 close(fd); 224 break; 225 default: 226 total += n; 227 /* warnx("read: %lld - %lld", n, total); */ 228 break; 229 } 230 if (total == 10 * 4096) { 231 /* warnx("done %lld", total); */ 232 exit(0); 233 } 234 } 235 236 void 237 gen_traffic_write(int fd, short events, void *arg) 238 { 239 static int count = 0; 240 struct timeval pause; 241 struct sender *s; 242 uint8_t buf[4096]; 243 244 s = arg; 245 pause.tv_sec = 1; 246 pause.tv_usec = 0; 247 event_del(&s->ev); 248 if (count++ >= 10) { 249 /* warnx("%s", "done writing"); */ 250 close(fd); 251 return; 252 } 253 if (write(fd, buf, 4096) == -1) 254 err(1, "%s", "write"); 255 evtimer_add(&s->pause, &pause); 256 } 257