1 /* $OpenBSD: gen_traffic.c,v 1.1 2013/08/23 08:25:58 florian 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 err(1, "%s", "connect"); 131 event_set(&sender->ev, s, EV_WRITE | EV_PERSIST, gen_traffic_write, 132 sender); 133 event_add(&sender->ev, NULL); 134 evtimer_set(&sender->pause, gen_traffic_sender_paused, sender); 135 event_dispatch(); 136 exit(0); 137 } 138 139 void 140 gen_traffic_paused(int fd, short events, void *arg) 141 { 142 struct listener *l = arg; 143 event_add(&l->ev, NULL); 144 } 145 146 void 147 gen_traffic_sender_paused(int fd, short events, void *arg) 148 { 149 struct sender *s = arg; 150 event_add(&s->ev, NULL); 151 } 152 153 void 154 gen_traffic_accept(int fd, short events, void *arg) 155 { 156 struct listener *l; 157 struct sockaddr_storage ss; 158 struct timeval pause; 159 struct reader *r; 160 socklen_t len; 161 int s; 162 163 l = arg; 164 pause.tv_sec = 1; pause.tv_usec = 0; 165 166 len = sizeof(ss); 167 s = accept(fd, (struct sockaddr *)&ss, &len); 168 if (s == -1) { 169 switch (errno) { 170 case EINTR: 171 case EWOULDBLOCK: 172 case ECONNABORTED: 173 return; 174 case EMFILE: 175 case ENFILE: 176 event_del(&l->ev); 177 evtimer_add(&l->pause, &pause); 178 return; 179 default: 180 err(1, "%s", "accept"); 181 } 182 } 183 184 if (ioctl(s, FIONBIO, &on) == -1) 185 err(1, "%s", "reader ioctl(FIONBIO)"); 186 187 r = calloc(1, sizeof(*r)); 188 if (r == NULL) 189 errx(1, "%s", "cannot calloc reader"); 190 191 r->fd = s; 192 193 event_set(&r->ev, s, EV_READ | EV_PERSIST, gen_traffic_request, r); 194 event_add(&r->ev, NULL); 195 } 196 197 void 198 gen_traffic_request(int fd, short events, void *arg) 199 { 200 static size_t total = 0; 201 struct reader *r; 202 size_t n; 203 uint8_t buf[4096]; 204 205 r = arg; 206 207 n = read(fd, buf, 4096); 208 209 switch (n) { 210 case -1: 211 switch (errno) { 212 case EINTR: 213 case EAGAIN: 214 return; 215 default: 216 err(1, "%s", "read"); 217 } 218 break; 219 220 case 0: 221 event_del(&r->ev); 222 close(fd); 223 break; 224 default: 225 total += n; 226 /* warnx("read: %lld - %lld", n, total); */ 227 break; 228 } 229 if (total == 10 * 4096) { 230 /* warnx("done %lld", total); */ 231 exit(0); 232 } 233 } 234 235 void 236 gen_traffic_write(int fd, short events, void *arg) 237 { 238 static int count = 0; 239 struct timeval pause; 240 struct sender *s; 241 uint8_t buf[4096]; 242 243 s = arg; 244 pause.tv_sec = 1; 245 pause.tv_usec = 0; 246 event_del(&s->ev); 247 if (count++ >= 10) { 248 /* warnx("%s", "done writing"); */ 249 close(fd); 250 return; 251 } 252 if (write(fd, buf, 4096) == -1) 253 err(1, "%s", "write"); 254 evtimer_add(&s->pause, &pause); 255 } 256