Sorry, wrong diff forgot the bogus SO_RDOMAIN define (old base). I've just remembered I've changed the -r option from miliseconds to seconds I'll fix that and send another patch with miliseconds, the rest should be ok.
Index: tcpbench.c =================================================================== RCS file: /cvs/src/usr.bin/tcpbench/tcpbench.c,v retrieving revision 1.18 diff -d -u -p -w -r1.18 tcpbench.c --- tcpbench.c 28 Sep 2010 12:00:35 -0000 1.18 +++ tcpbench.c 14 Oct 2010 04:26:42 -0000 @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Damien Miller <d...@mindrot.org> + * Copyright (c) 2010 Christiano F. Haesbaert <haesba...@haesbaert.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,6 +20,7 @@ #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/resource.h> +#include <sys/queue.h> #include <net/route.h> @@ -39,6 +41,7 @@ #include <stdio.h> #include <string.h> #include <errno.h> +#include <event.h> #include <netdb.h> #include <signal.h> #include <err.h> @@ -49,30 +52,58 @@ #include <nlist.h> #define DEFAULT_PORT "12345" -#define DEFAULT_STATS_INTERVAL 1000 /* ms */ -#define DEFAULT_BUF 256 * 1024 +#define DEFAULT_STATS_INTERVAL 1 /* seconds */ +#define DEFAULT_BUF (256 * 1024) #define MAX_FD 1024 -sig_atomic_t done = 0; -sig_atomic_t proc_slice = 0; - -static u_int rtableid; -static char **kflag; -static size_t Bflag; +static u_int rdomain; static int Sflag; static int rflag; static int sflag; static int vflag; +static kvm_t *kvmh; +static char **kvars; +static u_long ktcbtab; +static char *dummybuf; +static size_t dummybuf_len; + /* stats for a single connection */ struct statctx { + TAILQ_ENTRY(statctx) entry; struct timeval t_start, t_last; unsigned long long bytes; u_long tcbaddr; - char **kvars; - kvm_t *kh; + int fd; + char *buf; + size_t buflen; + struct event ev; }; +static void signal_handler(int, short, void *); +static void saddr_ntop(const struct sockaddr *, socklen_t, char *, size_t); +static void drop_gid(void); +static void set_slice_timer(int); +static void print_header(void); +static void kget(u_long, void *, size_t); +static u_long kfind_tcb(int); +static void kupdate_stats(u_long, struct inpcb *, struct tcpcb *, + struct socket *); +static void list_kvars(void); +static void check_kvar(const char *); +static char ** check_prepare_kvars(char *); +static void stats_prepare(struct statctx *); +static void stats_update(struct statctx *, ssize_t); +static void stats_cleanslice(void); +static void stats_display(unsigned long long, long double, float, + struct statctx *, struct inpcb *, struct tcpcb *, struct socket *); +static void process_slice(int, short, void *); +static void server_handle_sc(int, short, void *); +static void server_accept(int, short, void *); +static nfds_t server_init(struct addrinfo *); +static void client_handle_sc(int, short, void *); +static void client_init(struct addrinfo *, int); + /* * We account the mainstats here, that is the stats * for all connections, all variables starting with slice @@ -85,6 +116,7 @@ static struct { struct timeval t_start; /* when we started counting */ long double peak_mbps; /* peak mbps so far */ int nconns; /* connected clients */ + struct event timer; /* process timer */ } mainstats; /* When adding variables, also add to stats_display() */ @@ -118,18 +150,7 @@ static const char *allowed_kvars[] = { NULL }; -static void -exitsighand(int signo) -{ - done = signo; -} - -static void -alarmhandler(int signo) -{ - proc_slice = 1; - signal(signo, alarmhandler); -} +TAILQ_HEAD(, statctx) sc_queue; static void __dead usage(void) @@ -137,13 +158,32 @@ usage(void) fprintf(stderr, "usage: tcpbench -l\n" " tcpbench [-v] [-B buf] [-k kvars] [-n connections] [-p port]\n" - " [-r rate] [-S space] [-V rtable] hostname\n" + " [-r rate] [-S space] [-V rdomain] hostname\n" " tcpbench -s [-v] [-B buf] [-k kvars] [-p port]\n" - " [-r rate] [-S space] [-V rtable]\n"); + " [-r rate] [-S space] [-V rdomain]\n"); exit(1); } static void +signal_handler(int sig, short event, void *bula) +{ + /* + * signal handler rules don't apply, libevent decouples for us + */ + switch (sig) { + case SIGINT: + case SIGTERM: + case SIGHUP: + warnx("Terminated by signal %d", sig); + exit(0); + break; /* NOTREACHED */ + default: + errx(1, "unexpected signal %d", sig); + break; /* NOTREACHED */ + } +} + +static void saddr_ntop(const struct sockaddr *addr, socklen_t alen, char *buf, size_t len) { char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; @@ -160,22 +200,33 @@ saddr_ntop(const struct sockaddr *addr, } static void -set_timer(int toggle) +drop_gid(void) { - struct itimerval itv; + gid_t gid; + + gid = getgid(); + if (setresgid(gid, gid, gid) == -1) + err(1, "setresgid"); +} + +static void +set_slice_timer(int on) +{ + struct timeval tv; if (rflag <= 0) return; - if (toggle) { - itv.it_interval.tv_sec = rflag / 1000; - itv.it_interval.tv_usec = (rflag % 1000) * 1000; - itv.it_value = itv.it_interval; + if (on) { + if (evtimer_pending(&mainstats.timer, NULL)) + return; + timerclear(&tv); + tv.tv_sec = rflag; + evtimer_add(&mainstats.timer, &tv); + } else { + if (evtimer_pending(&mainstats.timer, NULL)) + evtimer_del(&mainstats.timer); } - else - bzero(&itv, sizeof(itv)); - - setitimer(ITIMER_REAL, &itv, NULL); } static void @@ -186,21 +237,21 @@ print_header(void) printf("%12s %14s %12s %8s ", "elapsed_ms", "bytes", "mbps", "bwidth"); - for (kv = kflag; kflag != NULL && *kv != NULL; kv++) - printf("%s%s", kv != kflag ? "," : "", *kv); + for (kv = kvars; kvars != NULL && *kv != NULL; kv++) + printf("%s%s", kv != kvars ? "," : "", *kv); printf("\n"); } static void -kget(kvm_t *kh, u_long addr, void *buf, size_t size) +kget(u_long addr, void *buf, size_t size) { - if (kvm_read(kh, addr, buf, size) != (ssize_t)size) - errx(1, "kvm_read: %s", kvm_geterr(kh)); + if (kvm_read(kvmh, addr, buf, size) != (ssize_t)size) + errx(1, "kvm_read: %s", kvm_geterr(kvmh)); } static u_long -kfind_tcb(kvm_t *kh, u_long ktcbtab, int sock) +kfind_tcb(int sock) { struct inpcbtable tcbtab; struct inpcb *head, *next, *prev; @@ -234,7 +285,7 @@ kfind_tcb(kvm_t *kh, u_long ktcbtab, int if (vflag >= 2) fprintf(stderr, "Using PCB table at %lu\n", ktcbtab); retry: - kget(kh, ktcbtab, &tcbtab, sizeof(tcbtab)); + kget(ktcbtab, &tcbtab, sizeof(tcbtab)); prev = head = (struct inpcb *)&CIRCLEQ_FIRST( &((struct inpcbtable *)ktcbtab)->inpt_queue); next = CIRCLEQ_FIRST(&tcbtab.inpt_queue); @@ -244,7 +295,7 @@ retry: while (next != head) { if (vflag >= 2) fprintf(stderr, "Checking PCB %p\n", next); - kget(kh, (u_long)next, &inpcb, sizeof(inpcb)); + kget((u_long)next, &inpcb, sizeof(inpcb)); if (CIRCLEQ_PREV(&inpcb, inp_queue) != prev) { if (nretry--) { warnx("pcb prev pointer insane"); @@ -307,7 +358,7 @@ retry: in6->sin6_port != inpcb.inp_fport) continue; } - kget(kh, (u_long)inpcb.inp_ppcb, &tcpcb, sizeof(tcpcb)); + kget((u_long)inpcb.inp_ppcb, &tcpcb, sizeof(tcpcb)); if (tcpcb.t_state != TCPS_ESTABLISHED) { if (vflag >= 2) fprintf(stderr, "Not established\n"); @@ -315,19 +366,19 @@ retry: } if (vflag >= 2) fprintf(stderr, "Found PCB at %p\n", prev); - return (u_long)prev; + return ((u_long)prev); } errx(1, "No matching PCB found"); } static void -kupdate_stats(kvm_t *kh, u_long tcbaddr, - struct inpcb *inpcb, struct tcpcb *tcpcb, struct socket *sockb) +kupdate_stats(u_long tcbaddr, struct inpcb *inpcb, + struct tcpcb *tcpcb, struct socket *sockb) { - kget(kh, tcbaddr, inpcb, sizeof(*inpcb)); - kget(kh, (u_long)inpcb->inp_ppcb, tcpcb, sizeof(*tcpcb)); - kget(kh, (u_long)inpcb->inp_socket, sockb, sizeof(*sockb)); + kget(tcbaddr, inpcb, sizeof(*inpcb)); + kget((u_long)inpcb->inp_ppcb, tcpcb, sizeof(*tcpcb)); + kget((u_long)inpcb->inp_socket, sockb, sizeof(*sockb)); } static void @@ -365,22 +416,26 @@ check_prepare_kvars(char *list) errx(1, "strdup"); ret[n] = NULL; } - return ret; + return (ret); } static void -stats_prepare(struct statctx *sc, int fd, kvm_t *kh, u_long ktcbtab) +stats_prepare(struct statctx *sc) { if (rflag <= 0) return; - sc->kh = kh; - sc->kvars = kflag; - if (kflag) - sc->tcbaddr = kfind_tcb(kh, ktcbtab, fd); - if (gettimeofday(&sc->t_start, NULL) == -1) - err(1, "gettimeofday"); + sc->buf = dummybuf; + sc->buflen = dummybuf_len; + if (kvars) + sc->tcbaddr = kfind_tcb(sc->fd); sc->t_last = sc->t_start; sc->bytes = 0; + event_set(&sc->ev, sc->fd, EV_READ | EV_PERSIST, + server_handle_sc, sc); + event_add(&sc->ev, NULL); + /* TODO: use clock_gettime() */ + if (gettimeofday(&sc->t_start, NULL) == -1) + err(1, "gettimeofday"); } static void @@ -406,14 +461,14 @@ stats_display(unsigned long long total_e printf("%12llu %14llu %12.3Lf %7.2f%% ", total_elapsed, sc->bytes, mbps, bwperc); - if (sc->kvars != NULL) { - kupdate_stats(sc->kh, sc->tcbaddr, inpcb, tcpcb, + if (kvars != NULL) { + kupdate_stats(sc->tcbaddr, inpcb, tcpcb, sockb); - for (j = 0; sc->kvars[j] != NULL; j++) { + for (j = 0; kvars[j] != NULL; j++) { #define S(a) #a #define P(b, v, f) \ - if (strcmp(sc->kvars[j], S(b.v)) == 0) { \ + if (strcmp(kvars[j], S(b.v)) == 0) { \ printf("%s"f, j > 0 ? "," : "", b->v); \ continue; \ } @@ -451,30 +506,24 @@ stats_display(unsigned long long total_e } static void -mainstats_display(long double slice_mbps, long double avg_mbps) -{ - printf("Conn: %3d Mbps: %12.3Lf Peak Mbps: %12.3Lf Avg Mbps: %12.3Lf\n", - mainstats.nconns, slice_mbps, mainstats.peak_mbps, avg_mbps); -} - -static void -process_slice(struct statctx *sc, size_t nsc) +process_slice(int fd, short event, void *bula) { unsigned long long total_elapsed, since_last; long double mbps, slice_mbps = 0; float bwperc; - nfds_t i; + struct statctx *sc; struct timeval t_cur, t_diff; struct inpcb inpcb; struct tcpcb tcpcb; struct socket sockb; - for (i = 0; i < nsc; i++, sc++) { + TAILQ_FOREACH(sc, &sc_queue, entry) { if (gettimeofday(&t_cur, NULL) == -1) err(1, "gettimeofday"); - if (sc->kvars != NULL) /* process kernel stats */ - kupdate_stats(sc->kh, sc->tcbaddr, &inpcb, &tcpcb, + if (kvars != NULL) /* process kernel stats */ + kupdate_stats(sc->tcbaddr, &inpcb, &tcpcb, &sockb); + timersub(&t_cur, &sc->t_start, &t_diff); total_elapsed = t_diff.tv_sec * 1000 + t_diff.tv_usec / 1000; timersub(&t_cur, &sc->t_last, &t_diff); @@ -488,59 +537,99 @@ process_slice(struct statctx *sc, size_t sc->t_last = t_cur; sc->bytes = 0; - } /* process stats for this slice */ if (slice_mbps > mainstats.peak_mbps) mainstats.peak_mbps = slice_mbps; - mainstats_display(slice_mbps, slice_mbps / mainstats.nconns); + printf("Conn: %3d Mbps: %12.3Lf Peak Mbps: %12.3Lf Avg Mbps: %12.3Lf\n", + mainstats.nconns, slice_mbps, mainstats.peak_mbps, + slice_mbps / mainstats.nconns); + stats_cleanslice(); + set_slice_timer(mainstats.nconns > 0); } -static int -handle_connection(struct statctx *sc, int fd, char *buf, size_t buflen) +static void +server_handle_sc(int fd, short event, void *v_sc) { + struct statctx *sc = v_sc; ssize_t n; again: - n = read(fd, buf, buflen); + n = read(sc->fd, sc->buf, sc->buflen); if (n == -1) { if (errno == EINTR) goto again; else if (errno == EWOULDBLOCK) - return 0; - warn("fd %d read error", fd); - - return -1; - } - else if (n == 0) { + return; + warn("fd %d read error", sc->fd); + return; + } else if (n == 0) { if (vflag) - fprintf(stderr, "%8d closed by remote end\n", fd); - close(fd); - return -1; + fprintf(stderr, "%8d closed by remote end\n", sc->fd); + close(sc->fd); + TAILQ_REMOVE(&sc_queue, sc, entry); + free(sc); + mainstats.nconns--; + set_slice_timer(mainstats.nconns > 0); + return; } if (vflag >= 3) fprintf(stderr, "read: %zd bytes\n", n); - stats_update(sc, n); - return 0; +} + +static void +server_accept(int fd, short event, void *bula) +{ + int sock, r; + struct statctx *sc; + struct sockaddr_storage ss; + socklen_t sslen; + char tmp[128]; + + sslen = sizeof(ss); +again: + if ((sock = accept(fd, (struct sockaddr *)&ss, + &sslen)) == -1) { + if (errno == EINTR) + goto again; + warn("accept"); + return; + } + saddr_ntop((struct sockaddr *)&ss, sslen, + tmp, sizeof(tmp)); + if ((r = fcntl(sock, F_GETFL, 0)) == -1) + err(1, "fcntl(F_GETFL)"); + r |= O_NONBLOCK; + if (fcntl(sock, F_SETFL, r) == -1) + err(1, "fcntl(F_SETFL, O_NONBLOCK)"); + /* Alloc client structure and register reading callback */ + if ((sc = calloc(1, sizeof(*sc))) == NULL) + err(1, "calloc"); + sc->fd = sock; + stats_prepare(sc); + event_set(&sc->ev, sc->fd, EV_READ | EV_PERSIST, + server_handle_sc, sc); + event_add(&sc->ev, NULL); + TAILQ_INSERT_TAIL(&sc_queue, sc, entry); + mainstats.nconns++; + set_slice_timer(mainstats.nconns > 0); + if (vflag) + warnx("Accepted connection from %s, fd = %d\n", tmp, sc->fd); } static nfds_t -serverbind(struct pollfd *pfd, nfds_t max_nfds, struct addrinfo *aitop) +server_init(struct addrinfo *aitop) { char tmp[128]; int sock, on = 1; struct addrinfo *ai; + struct event *ev; nfds_t lnfds; lnfds = 0; for (ai = aitop; ai != NULL; ai = ai->ai_next) { - if (lnfds == max_nfds) { - fprintf(stderr, - "maximum number of listening fds reached\n"); - break; - } saddr_ntop(ai->ai_addr, ai->ai_addrlen, tmp, sizeof(tmp)); if (vflag) fprintf(stderr, "Try to listen on %s\n", tmp); @@ -552,12 +641,12 @@ serverbind(struct pollfd *pfd, nfds_t ma warn("socket"); continue; } - if (rtableid && ai->ai_family == AF_INET) { - if (setsockopt(sock, IPPROTO_IP, SO_RTABLE, - &rtableid, sizeof(rtableid)) == -1) - err(1, "setsockopt SO_RTABLE"); - } else if (rtableid) - warnx("rtable only supported on AF_INET"); + if (rdomain && ai->ai_family == AF_INET) { + if (setsockopt(sock, IPPROTO_IP, SO_RDOMAIN, + &rdomain, sizeof(rdomain)) == -1) + err(1, "setsockopt SO_RDOMAIN"); + } else if (rdomain) + warnx("rdomain only supported on AF_INET"); if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) warn("reuse port"); @@ -582,165 +671,47 @@ serverbind(struct pollfd *pfd, nfds_t ma close(sock); continue; } + if ((ev = calloc(1, sizeof(*ev))) == NULL) + err(1, "calloc"); + event_set(ev, sock, EV_READ | EV_PERSIST, server_accept, NULL); + event_add(ev, NULL); if (vflag >= 3) fprintf(stderr, "listening on fd %d\n", sock); lnfds++; - pfd[lnfds - 1].fd = sock; - pfd[lnfds - 1].events = POLLIN; - } freeaddrinfo(aitop); if (lnfds == 0) errx(1, "No working listen addresses found"); - return lnfds; + return (lnfds); } static void -set_listening(struct pollfd *pfd, nfds_t lfds, int toggle) { - int i; - - for (i = 0; i < (int)lfds; i++) { - if (toggle) - pfd[i].events = POLLIN; - else - pfd[i].events = 0; - } - -} -static void __dead -serverloop(kvm_t *kvmh, u_long ktcbtab, struct addrinfo *aitop) +client_handle_sc(int fd, short event, void *v_sc) { - socklen_t sslen; - struct pollfd *pfd; - char tmp[128], *buf; - struct statctx *psc; - struct sockaddr_storage ss; - nfds_t i, nfds, lfds; - size_t nalloc; - int r, sock, client_id; - - sslen = sizeof(ss); - nalloc = 128; - if ((pfd = calloc(sizeof(*pfd), nalloc)) == NULL) - err(1, "calloc"); - if ((psc = calloc(sizeof(*psc), nalloc)) == NULL) - err(1, "calloc"); - if ((buf = malloc(Bflag)) == NULL) - err(1, "malloc"); - lfds = nfds = serverbind(pfd, nalloc - 1, aitop); - if (vflag >= 3) - fprintf(stderr, "listening on %d fds\n", lfds); - if (setpgid(0, 0) == -1) - err(1, "setpgid"); - - print_header(); - - client_id = 0; - while (!done) { - if (proc_slice) { - process_slice(psc + lfds, nfds - lfds); - stats_cleanslice(); - proc_slice = 0; - } - if (vflag >= 3) - fprintf(stderr, "mainstats.nconns = %u\n", - mainstats.nconns); - if ((r = poll(pfd, nfds, INFTIM)) == -1) { - if (errno == EINTR) - continue; - warn("poll"); - break; - } - - if (vflag >= 3) - fprintf(stderr, "poll: %d\n", r); - for (i = 0 ; r > 0 && i < nfds; i++) { - if ((pfd[i].revents & POLLIN) == 0) - continue; - if (pfd[i].fd == -1) - errx(1, "pfd insane"); - r--; - if (vflag >= 3) - fprintf(stderr, "fd %d active i = %d\n", - pfd[i].fd, i); - /* new connection */ - if (i < lfds) { - if ((sock = accept(pfd[i].fd, - (struct sockaddr *)&ss, - &sslen)) == -1) { - if (errno == EINTR) - continue; - else if (errno == EMFILE || - errno == ENFILE) - set_listening(pfd, lfds, 0); - warn("accept"); - continue; - } - if ((r = fcntl(sock, F_GETFL, 0)) == -1) - err(1, "fcntl(F_GETFL)"); - r |= O_NONBLOCK; - if (fcntl(sock, F_SETFL, r) == -1) - err(1, "fcntl(F_SETFL, O_NONBLOCK)"); - saddr_ntop((struct sockaddr *)&ss, sslen, - tmp, sizeof(tmp)); - if (vflag) - fprintf(stderr, - "Accepted connection %d from " - "%s, fd = %d\n", client_id++, tmp, - sock); - /* alloc more space if we're full */ - if (nfds == nalloc) { - nalloc *= 2; - if ((pfd = realloc(pfd, - sizeof(*pfd) * nalloc)) == NULL) - err(1, "realloc"); - if ((psc = realloc(psc, - sizeof(*psc) * nalloc)) == NULL) - err(1, "realloc"); + struct statctx *sc = v_sc; + ssize_t n; +again: + if ((n = write(sc->fd, sc->buf, sc->buflen)) == -1) { + if (errno == EINTR || errno == EAGAIN) + goto again; + err(1, "write"); } - pfd[nfds].fd = sock; - pfd[nfds].events = POLLIN; - stats_prepare(&psc[nfds], sock, kvmh, ktcbtab); - nfds++; - if (!mainstats.nconns++) - set_timer(1); - continue; + if (n == 0) { + warnx("Remote end closed connection"); + exit(1); } - /* event in fd */ if (vflag >= 3) - fprintf(stderr, - "fd %d active", pfd[i].fd); - while (handle_connection(&psc[i], pfd[i].fd, - buf, Bflag) == -1) { - pfd[i] = pfd[nfds - 1]; - pfd[nfds - 1].fd = -1; - psc[i] = psc[nfds - 1]; - mainstats.nconns--; - nfds--; - /* stop display if no clients */ - if (!mainstats.nconns) { - proc_slice = 1; - set_timer(0); - } - /* if we were full */ - set_listening(pfd, lfds, 1); - - /* is there an event pending on the last fd? */ - if (pfd[i].fd == -1 || - (pfd[i].revents & POLLIN) == 0) - break; - } - } - } - exit(1); + warnx("write: %zd bytes\n", n); + stats_update(sc, n); } -void -clientconnect(struct addrinfo *aitop, struct pollfd *pfd, int nconn) +static void +client_init(struct addrinfo *aitop, int nconn) { - char tmp[128]; + struct statctx *sc; struct addrinfo *ai; + char tmp[128]; int i, r, sock; for (i = 0; i < nconn; i++) { @@ -757,12 +728,12 @@ clientconnect(struct addrinfo *aitop, st warn("socket"); continue; } - if (rtableid && ai->ai_family == AF_INET) { - if (setsockopt(sock, IPPROTO_IP, SO_RTABLE, - &rtableid, sizeof(rtableid)) == -1) - err(1, "setsockopt SO_RTABLE"); - } else if (rtableid) - warnx("rtable only supported on AF_INET"); + if (rdomain && ai->ai_family == AF_INET) { + if (setsockopt(sock, IPPROTO_IP, SO_RDOMAIN, + &rdomain, sizeof(rdomain)) == -1) + err(1, "setsockopt SO_RDOMAIN"); + } else if (rdomain) + warnx("rdomain only supported on AF_INET"); if (Sflag) { if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &Sflag, sizeof(Sflag)) == -1) @@ -781,15 +752,22 @@ clientconnect(struct addrinfo *aitop, st } if (sock == -1) errx(1, "No host found"); - if ((r = fcntl(sock, F_GETFL, 0)) == -1) err(1, "fcntl(F_GETFL)"); r |= O_NONBLOCK; if (fcntl(sock, F_SETFL, r) == -1) err(1, "fcntl(F_SETFL, O_NONBLOCK)"); - - pfd[i].fd = sock; - pfd[i].events = POLLOUT; + /* Alloc and prepare stats */ + if ((sc = calloc(1, sizeof(*sc))) == NULL) + err(1, "calloc"); + sc->fd = sock; + stats_prepare(sc); + event_set(&sc->ev, sc->fd, EV_WRITE | EV_PERSIST, + client_handle_sc, sc); + event_add(&sc->ev, NULL); + TAILQ_INSERT_TAIL(&sc_queue, sc, entry); + mainstats.nconns++; + set_slice_timer(mainstats.nconns > 0); } freeaddrinfo(aitop); @@ -797,102 +775,26 @@ clientconnect(struct addrinfo *aitop, st fprintf(stderr, "%u connections established\n", nconn); } -static void __dead -clientloop(kvm_t *kvmh, u_long ktcbtab, struct addrinfo *aitop, int nconn) -{ - struct statctx *psc; - struct pollfd *pfd; - char *buf; - int i; - ssize_t n; - - if ((pfd = calloc(nconn, sizeof(*pfd))) == NULL) - err(1, "clientloop pfd calloc"); - if ((psc = calloc(nconn, sizeof(*psc))) == NULL) - err(1, "clientloop psc calloc"); - - clientconnect(aitop, pfd, nconn); - - for (i = 0; i < nconn; i++) { - stats_prepare(psc + i, pfd[i].fd, kvmh, ktcbtab); - mainstats.nconns++; - } - - if ((buf = malloc(Bflag)) == NULL) - err(1, "malloc"); - arc4random_buf(buf, Bflag); - - print_header(); - set_timer(1); - - while (!done) { - if (proc_slice) { - process_slice(psc, nconn); - stats_cleanslice(); - proc_slice = 0; - } - if (poll(pfd, nconn, INFTIM) == -1) { - if (errno == EINTR) - continue; - err(1, "poll"); - } - for (i = 0; i < nconn; i++) { - if (pfd[i].revents & POLLOUT) { - if ((n = write(pfd[i].fd, buf, Bflag)) == -1) { - if (errno == EINTR || errno == EAGAIN) - continue; - err(1, "write"); - } - if (n == 0) { - warnx("Remote end closed connection"); - done = -1; - break; - } - if (vflag >= 3) - fprintf(stderr, "write: %zd bytes\n", - n); - stats_update(psc + i, n); - } - } - } - - if (done > 0) - warnx("Terminated by signal %d", done); - - free(buf); - exit(0); -} - -static void -drop_gid(void) -{ - gid_t gid; - - gid = getgid(); - if (setresgid(gid, gid, gid) == -1) - err(1, "setresgid"); -} - int main(int argc, char **argv) { extern int optind; extern char *optarg; - char kerr[_POSIX2_LINE_MAX], *tmp; struct addrinfo *aitop, hints; const char *errstr; - kvm_t *kvmh = NULL; struct rlimit rl; - int ch, herr; + int ch, herr, nconn; struct nlist nl[] = { { "_tcbtable" }, { "" } }; const char *host = NULL, *port = DEFAULT_PORT; - int nconn = 1; + struct event ev_sigint, ev_sigterm, ev_sighup; - Bflag = DEFAULT_BUF; - Sflag = sflag = vflag = rtableid = 0; - kflag = NULL; + dummybuf_len = DEFAULT_BUF; + Sflag = sflag = vflag = rdomain = 0; + kvmh = NULL; + kvars = NULL; rflag = DEFAULT_STATS_INTERVAL; + nconn = 1; while ((ch = getopt(argc, argv, "B:hlk:n:p:r:sS:vV:")) != -1) { switch (ch) { @@ -902,7 +804,7 @@ main(int argc, char **argv) case 'k': if ((tmp = strdup(optarg)) == NULL) errx(1, "strdup"); - kflag = check_prepare_kvars(tmp); + kvars = check_prepare_kvars(tmp); free(tmp); break; case 'r': @@ -926,7 +828,7 @@ main(int argc, char **argv) errstr, optarg); break; case 'B': - Bflag = strtonum(optarg, 0, 1024*1024*1024, + dummybuf_len = strtonum(optarg, 0, 1024*1024*1024, &errstr); if (errstr != NULL) errx(1, "read/write buffer size is %s: %s", @@ -936,10 +838,10 @@ main(int argc, char **argv) vflag++; break; case 'V': - rtableid = (unsigned int)strtonum(optarg, 0, + rdomain = (unsigned int)strtonum(optarg, 0, RT_TABLEID_MAX, &errstr); if (errstr) - errx(1, "rtable value is %s: %s", + errx(1, "rdomain value is %s: %s", errstr, optarg); break; case 'n': @@ -972,23 +874,17 @@ main(int argc, char **argv) else errx(1, "getaddrinfo: %s", gai_strerror(herr)); } - - if (kflag) { + if (kvars) { if ((kvmh = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, kerr)) == NULL) errx(1, "kvm_open: %s", kerr); drop_gid(); if (kvm_nlist(kvmh, nl) < 0 || nl[0].n_type == 0) errx(1, "kvm: no namelist"); + ktcbtab = nl[0].n_value; } else drop_gid(); - signal(SIGINT, exitsighand); - signal(SIGTERM, exitsighand); - signal(SIGHUP, exitsighand); - signal(SIGPIPE, SIG_IGN); - signal(SIGALRM, alarmhandler); - if (getrlimit(RLIMIT_NOFILE, &rl) == -1) err(1, "getrlimit"); if (rl.rlim_cur < MAX_FD) @@ -998,10 +894,36 @@ main(int argc, char **argv) if (getrlimit(RLIMIT_NOFILE, &rl) == -1) err(1, "getrlimit"); - if (sflag) - serverloop(kvmh, nl[0].n_value, aitop); - else - clientloop(kvmh, nl[0].n_value, aitop, nconn); + /* Init world */ + TAILQ_INIT(&sc_queue); + if ((dummybuf = malloc(dummybuf_len)) == NULL) + err(1, "malloc"); + arc4random_buf(dummybuf, dummybuf_len); - return 0; + /* Setup libevent and signals */ + event_init(); + signal_set(&ev_sigterm, SIGTERM, signal_handler, NULL); + signal_set(&ev_sighup, SIGHUP, signal_handler, NULL); + signal_set(&ev_sigint, SIGINT, signal_handler, NULL); + signal_add(&ev_sigint, NULL); + signal_add(&ev_sigterm, NULL); + signal_add(&ev_sighup, NULL); + signal(SIGPIPE, SIG_IGN); + + print_header(); + + /* Slice stats timer */ + evtimer_set(&mainstats.timer, process_slice, NULL); + + if (sflag) { + (void)server_init(aitop); + if (setpgid(0, 0) == -1) + err(1, "setpgid"); + } else + client_init(aitop, nconn); + + /* libevent main loop*/ + event_dispatch(); + + return (0); } Index: Makefile =================================================================== RCS file: /cvs/src/usr.bin/tcpbench/Makefile,v retrieving revision 1.3 diff -d -u -p -w -r1.3 Makefile --- Makefile 26 Jun 2008 07:05:56 -0000 1.3 +++ Makefile 14 Oct 2010 04:26:42 -0000 @@ -15,7 +15,7 @@ CDIAGFLAGS+= -Wshadow PROG=tcpbench -LDADD=-lkvm +LDADD=-lkvm -levent #BINGRP= kmem #BINMODE=2555