/* $OpenBSD: gen_traffic.c,v 1.1 2013/08/23 08:25:58 florian Exp $ */ /* * Copyright (c) 2013 Florian Obser * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include __dead void usage(void); void gen_traffic_paused(int, short, void*); void gen_traffic_accept(int, short, void*); void gen_traffic_request(int, short, void*); void gen_traffic_write(int, short, void*); void gen_traffic_sender_paused(int, short, void*); struct listener { struct event ev, pause; }; struct reader { struct event ev; int fd; }; struct sender { struct event ev, pause; int fd; }; __dead void usage(void) { extern char *__progname; fprintf(stderr, "usage: %s 4|6\n", __progname); exit(1); } int on = 1; int main(int argc, char *argv[]) { struct addrinfo hints, *sender_res, *server_res; struct listener *l; struct sender *sender; char *ip; int error, s; if (argc != 2) usage(); if (strncmp(argv[1], "4", 1) == 0) ip = "10.11.12.13"; else if (strncmp(argv[1], "6", 1) == 0) ip = "2001:db8::13"; else usage(); event_init(); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; error = getaddrinfo(ip, "12346", &hints, &server_res); if (error) errx(1, "%s", gai_strerror(error)); s = socket(server_res->ai_family, server_res->ai_socktype, server_res->ai_protocol); if (s == -1) err(1, "%s", "bind"); if (bind(s, server_res->ai_addr, server_res->ai_addrlen) < 0) err(1, "%s", "bind"); if (ioctl(s, FIONBIO, &on) == -1) err(1, "%s", "listener ioctl(FIONBIO)"); if (listen(s, 5) == -1) err(1, "%s", "listen"); l = calloc(1, sizeof(*l)); if (l == NULL) errx(1, "calloc"); event_set(&l->ev, s, EV_READ | EV_PERSIST, gen_traffic_accept, l); event_add(&l->ev, NULL); evtimer_set(&l->pause, gen_traffic_paused, l); error = getaddrinfo(ip, "12345", &hints, &sender_res); if (error) errx(1, "%s", gai_strerror(error)); s = socket(sender_res->ai_family, sender_res->ai_socktype, sender_res->ai_protocol); if (s == -1) err(1, "%s", "bind"); if (bind(s, sender_res->ai_addr, sender_res->ai_addrlen) < 0) err(1, "%s", "bind"); if (ioctl(s, FIONBIO, &on) == -1) err(1, "%s", "sender ioctl(FIONBIO)"); sender = calloc(1, sizeof(*sender)); if (sender == NULL) errx(1, "calloc"); if (connect(s, server_res->ai_addr, server_res->ai_addrlen) == -1) err(1, "%s", "connect"); event_set(&sender->ev, s, EV_WRITE | EV_PERSIST, gen_traffic_write, sender); event_add(&sender->ev, NULL); evtimer_set(&sender->pause, gen_traffic_sender_paused, sender); event_dispatch(); exit(0); } void gen_traffic_paused(int fd, short events, void *arg) { struct listener *l = arg; event_add(&l->ev, NULL); } void gen_traffic_sender_paused(int fd, short events, void *arg) { struct sender *s = arg; event_add(&s->ev, NULL); } void gen_traffic_accept(int fd, short events, void *arg) { struct listener *l; struct sockaddr_storage ss; struct timeval pause; struct reader *r; socklen_t len; int s; l = arg; pause.tv_sec = 1; pause.tv_usec = 0; len = sizeof(ss); s = accept(fd, (struct sockaddr *)&ss, &len); if (s == -1) { switch (errno) { case EINTR: case EWOULDBLOCK: case ECONNABORTED: return; case EMFILE: case ENFILE: event_del(&l->ev); evtimer_add(&l->pause, &pause); return; default: err(1, "%s", "accept"); } } if (ioctl(s, FIONBIO, &on) == -1) err(1, "%s", "reader ioctl(FIONBIO)"); r = calloc(1, sizeof(*r)); if (r == NULL) errx(1, "%s", "cannot calloc reader"); r->fd = s; event_set(&r->ev, s, EV_READ | EV_PERSIST, gen_traffic_request, r); event_add(&r->ev, NULL); } void gen_traffic_request(int fd, short events, void *arg) { static size_t total = 0; struct reader *r; size_t n; uint8_t buf[4096]; r = arg; n = read(fd, buf, 4096); switch (n) { case -1: switch (errno) { case EINTR: case EAGAIN: return; default: err(1, "%s", "read"); } break; case 0: event_del(&r->ev); close(fd); break; default: total += n; /* warnx("read: %lld - %lld", n, total); */ break; } if (total == 10 * 4096) { /* warnx("done %lld", total); */ exit(0); } } void gen_traffic_write(int fd, short events, void *arg) { static int count = 0; struct timeval pause; struct sender *s; uint8_t buf[4096]; s = arg; pause.tv_sec = 1; pause.tv_usec = 0; event_del(&s->ev); if (count++ >= 10) { /* warnx("%s", "done writing"); */ close(fd); return; } if (write(fd, buf, 4096) == -1) err(1, "%s", "write"); evtimer_add(&s->pause, &pause); }