Hi Christiano, Thanks very much for doing this. Unfortunately I won't have time to look at your patch for a couple more weeks, but I certainly have no philosophical objections to using libevent.
-d On Thu, 14 Oct 2010, Christiano F. Haesbaert wrote: > 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 <[email protected]> > + * Copyright (c) 2010 Christiano F. Haesbaert <[email protected]> > * > * 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
