xref: /openbsd-src/usr.bin/tcpbench/tcpbench.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: tcpbench.c,v 1.61 2020/02/12 14:46:36 schwarze Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Damien Miller <djm@mindrot.org>
5  * Copyright (c) 2011 Christiano F. Haesbaert <haesbaert@haesbaert.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/time.h>
22 #include <sys/socket.h>
23 #include <sys/socketvar.h>
24 #include <sys/resource.h>
25 #include <sys/queue.h>
26 #include <sys/un.h>
27 
28 #include <net/route.h>
29 
30 #include <netinet/in.h>
31 #include <netinet/ip.h>
32 #include <netinet/tcp.h>
33 #include <netinet/tcp_timer.h>
34 #include <netinet/tcp_fsm.h>
35 #include <netinet/in_pcb.h>
36 #include <netinet/tcp_var.h>
37 
38 #include <arpa/inet.h>
39 
40 #include <unistd.h>
41 #include <limits.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <event.h>
47 #include <netdb.h>
48 #include <signal.h>
49 #include <err.h>
50 #include <fcntl.h>
51 #include <poll.h>
52 #include <paths.h>
53 
54 #include <kvm.h>
55 #include <nlist.h>
56 
57 #define DEFAULT_PORT "12345"
58 #define DEFAULT_STATS_INTERVAL 1000 /* ms */
59 #define DEFAULT_BUF (256 * 1024)
60 #define DEFAULT_UDP_PKT (1500 - 28) /* TODO don't hardcode this */
61 #define TCP_MODE !ptb->uflag
62 #define UDP_MODE ptb->uflag
63 #define MAX_FD 1024
64 
65 /* Our tcpbench globals */
66 struct {
67 	int	  Sflag;	/* Socket buffer size */
68 	u_int	  rflag;	/* Report rate (ms) */
69 	int	  sflag;	/* True if server */
70 	int	  Tflag;	/* ToS if != -1 */
71 	int	  vflag;	/* Verbose */
72 	int	  uflag;	/* UDP mode */
73 	int	  Uflag;	/* UNIX (AF_LOCAL) mode */
74 	int	  Rflag;	/* randomize client write size */
75 	kvm_t	 *kvmh;		/* Kvm handler */
76 	char	**kvars;	/* Kvm enabled vars */
77 	u_long	  ktcbtab;	/* Ktcb */
78 	char	 *dummybuf;	/* IO buffer */
79 	size_t	  dummybuf_len;	/* IO buffer len */
80 } tcpbench, *ptb;
81 
82 struct tcpservsock {
83 	struct event ev;
84 	struct event evt;
85 	int fd;
86 };
87 
88 /* stats for a single tcp connection, udp uses only one  */
89 struct statctx {
90 	TAILQ_ENTRY(statctx) entry;
91 	struct timeval t_start, t_last;
92 	unsigned long long bytes;
93 	int fd;
94 	char *buf;
95 	size_t buflen;
96 	struct event ev;
97 	/* TCP only */
98 	struct tcpservsock *tcp_ts;
99 	u_long tcp_tcbaddr;
100 	/* UDP only */
101 	u_long udp_slice_pkts;
102 };
103 
104 static void	signal_handler(int, short, void *);
105 static void	saddr_ntop(const struct sockaddr *, socklen_t, char *, size_t);
106 static void	drop_gid(void);
107 static void	set_slice_timer(int);
108 static void	print_tcp_header(void);
109 static void	kget(u_long, void *, size_t);
110 static u_long	kfind_tcb(int);
111 static void	kupdate_stats(u_long, struct inpcb *, struct tcpcb *,
112     struct socket *);
113 static void	list_kvars(void);
114 static void	check_kvar(const char *);
115 static char **	check_prepare_kvars(char *);
116 static void	stats_prepare(struct statctx *);
117 static void	tcp_stats_display(unsigned long long, long double, float,
118     struct statctx *, struct inpcb *, struct tcpcb *, struct socket *);
119 static void	tcp_process_slice(int, short, void *);
120 static void	tcp_server_handle_sc(int, short, void *);
121 static void	tcp_server_accept(int, short, void *);
122 static void	server_init(struct addrinfo *, struct statctx *);
123 static void	client_handle_sc(int, short, void *);
124 static void	client_init(struct addrinfo *, int, struct statctx *,
125     struct addrinfo *);
126 static int	clock_gettime_tv(clockid_t, struct timeval *);
127 static void	udp_server_handle_sc(int, short, void *);
128 static void	udp_process_slice(int, short, void *);
129 static int	map_tos(char *, int *);
130 /*
131  * We account the mainstats here, that is the stats
132  * for all connections, all variables starting with slice
133  * are used to account information for the timeslice
134  * between each output. Peak variables record the highest
135  * between all slices so far.
136  */
137 static struct {
138 	unsigned long long slice_bytes; /* bytes for last slice */
139 	long double peak_mbps;		/* peak mbps so far */
140 	int nconns;		        /* connected clients */
141 	struct event timer;		/* process timer */
142 } mainstats;
143 
144 /* When adding variables, also add to tcp_stats_display() */
145 static const char *allowed_kvars[] = {
146 	"inpcb.inp_flags",
147 	"sockb.so_rcv.sb_cc",
148 	"sockb.so_rcv.sb_hiwat",
149 	"sockb.so_rcv.sb_wat",
150 	"sockb.so_snd.sb_cc",
151 	"sockb.so_snd.sb_hiwat",
152 	"sockb.so_snd.sb_wat",
153 	"tcpcb.last_ack_sent",
154 	"tcpcb.max_sndwnd",
155 	"tcpcb.rcv_adv",
156 	"tcpcb.rcv_nxt",
157 	"tcpcb.rcv_scale",
158 	"tcpcb.rcv_wnd",
159 	"tcpcb.rfbuf_cnt",
160 	"tcpcb.rfbuf_ts",
161 	"tcpcb.snd_cwnd",
162 	"tcpcb.snd_max",
163 	"tcpcb.snd_nxt",
164 	"tcpcb.snd_scale",
165 	"tcpcb.snd_ssthresh",
166 	"tcpcb.snd_una",
167 	"tcpcb.snd_wl1",
168 	"tcpcb.snd_wl2",
169 	"tcpcb.snd_wnd",
170 	"tcpcb.t_rcvtime",
171 	"tcpcb.t_rtseq",
172 	"tcpcb.t_rttmin",
173 	"tcpcb.t_rtttime",
174 	"tcpcb.t_rttvar",
175 	"tcpcb.t_srtt",
176 	"tcpcb.ts_recent",
177 	"tcpcb.ts_recent_age",
178 	NULL
179 };
180 
181 TAILQ_HEAD(, statctx) sc_queue;
182 
183 static void __dead
184 usage(void)
185 {
186 	fprintf(stderr,
187 	    "usage: tcpbench -l\n"
188 	    "       tcpbench [-46RUuv] [-B buf] [-b sourceaddr] [-k kvars] [-n connections]\n"
189 	    "                [-p port] [-r interval] [-S space] [-T toskeyword]\n"
190 	    "                [-t secs] [-V rtable] hostname\n"
191 	    "       tcpbench -s [-46Uuv] [-B buf] [-k kvars] [-p port] [-r interval]\n"
192 	    "                [-S space] [-T toskeyword] [-V rtable] [hostname]\n");
193 	exit(1);
194 }
195 
196 static void
197 signal_handler(int sig, short event, void *bula)
198 {
199 	/*
200 	 * signal handler rules don't apply, libevent decouples for us
201 	 */
202 	switch (sig) {
203 	case SIGINT:
204 	case SIGTERM:
205 	case SIGHUP:
206 		warnx("Terminated by signal %d", sig);
207 		exit(0);
208 		break;		/* NOTREACHED */
209 	default:
210 		errx(1, "unexpected signal %d", sig);
211 		break;		/* NOTREACHED */
212 	}
213 }
214 
215 static void
216 saddr_ntop(const struct sockaddr *addr, socklen_t alen, char *buf, size_t len)
217 {
218 	char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
219 	int herr;
220 
221 	if (addr->sa_family == AF_UNIX) {
222 		struct sockaddr_un *sun = (struct sockaddr_un *)addr;
223 		snprintf(buf, len, "%s", sun->sun_path);
224 		return;
225 	}
226 	if ((herr = getnameinfo(addr, alen, hbuf, sizeof(hbuf),
227 	    pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
228 		if (herr == EAI_SYSTEM)
229 			err(1, "getnameinfo");
230 		else
231 			errx(1, "getnameinfo: %s", gai_strerror(herr));
232 	}
233 	snprintf(buf, len, "[%s]:%s", hbuf, pbuf);
234 }
235 
236 static void
237 drop_gid(void)
238 {
239 	gid_t gid;
240 
241 	gid = getgid();
242 	if (setresgid(gid, gid, gid) == -1)
243 		err(1, "setresgid");
244 }
245 
246 static void
247 set_slice_timer(int on)
248 {
249 	struct timeval tv;
250 
251 	if (ptb->rflag == 0)
252 		return;
253 
254 	if (on) {
255 		if (evtimer_pending(&mainstats.timer, NULL))
256 			return;
257 		/* XXX Is there a better way to do this ? */
258 		tv.tv_sec = ptb->rflag / 1000;
259 		tv.tv_usec = (ptb->rflag % 1000) * 1000;
260 
261 		evtimer_add(&mainstats.timer, &tv);
262 	} else if (evtimer_pending(&mainstats.timer, NULL))
263 		evtimer_del(&mainstats.timer);
264 }
265 
266 static int
267 clock_gettime_tv(clockid_t clock_id, struct timeval *tv)
268 {
269 	struct timespec ts;
270 
271 	if (clock_gettime(clock_id, &ts) == -1)
272 		return (-1);
273 
274 	TIMESPEC_TO_TIMEVAL(tv, &ts);
275 
276 	return (0);
277 }
278 
279 static void
280 print_tcp_header(void)
281 {
282 	char **kv;
283 
284 	if (ptb->rflag == 0)
285 		return;
286 
287 	printf("%12s %14s %12s %8s ", "elapsed_ms", "bytes", "mbps",
288 	    "bwidth");
289 	for (kv = ptb->kvars;  ptb->kvars != NULL && *kv != NULL; kv++)
290 		printf("%s%s", kv != ptb->kvars ? "," : "", *kv);
291 	printf("\n");
292 }
293 
294 static void
295 kget(u_long addr, void *buf, size_t size)
296 {
297 	if (kvm_read(ptb->kvmh, addr, buf, size) != (ssize_t)size)
298 		errx(1, "kvm_read: %s", kvm_geterr(ptb->kvmh));
299 }
300 
301 static u_long
302 kfind_tcb(int sock)
303 {
304 	struct inpcbtable tcbtab;
305 	struct inpcb *next, *prev;
306 	struct inpcb inpcb, prevpcb;
307 	struct tcpcb tcpcb;
308 
309 	struct sockaddr_storage me, them;
310 	socklen_t melen, themlen;
311 	struct sockaddr_in *in4;
312 	struct sockaddr_in6 *in6;
313 	char tmp1[64], tmp2[64];
314 	int nretry;
315 
316 	nretry = 10;
317 	melen = themlen = sizeof(struct sockaddr_storage);
318 	if (getsockname(sock, (struct sockaddr *)&me, &melen) == -1)
319 		err(1, "getsockname");
320 	if (getpeername(sock, (struct sockaddr *)&them, &themlen) == -1)
321 		err(1, "getpeername");
322 	if (me.ss_family != them.ss_family)
323 		errx(1, "%s: me.ss_family != them.ss_family", __func__);
324 	if (me.ss_family != AF_INET && me.ss_family != AF_INET6)
325 		errx(1, "%s: unknown socket family", __func__);
326 	if (ptb->vflag >= 2) {
327 		saddr_ntop((struct sockaddr *)&me, me.ss_len,
328 		    tmp1, sizeof(tmp1));
329 		saddr_ntop((struct sockaddr *)&them, them.ss_len,
330 		    tmp2, sizeof(tmp2));
331 		fprintf(stderr, "Our socket local %s remote %s\n", tmp1, tmp2);
332 	}
333 	if (ptb->vflag >= 2)
334 		fprintf(stderr, "Using PCB table at %lu\n", ptb->ktcbtab);
335 retry:
336 	kget(ptb->ktcbtab, &tcbtab, sizeof(tcbtab));
337 	prev = NULL;
338 	next = TAILQ_FIRST(&tcbtab.inpt_queue);
339 
340 	if (ptb->vflag >= 2)
341 		fprintf(stderr, "PCB start at %p\n", next);
342 	while (next != NULL) {
343 		if (ptb->vflag >= 2)
344 			fprintf(stderr, "Checking PCB %p\n", next);
345 		kget((u_long)next, &inpcb, sizeof(inpcb));
346 		if (prev != NULL) {
347 			kget((u_long)prev, &prevpcb, sizeof(prevpcb));
348 			if (TAILQ_NEXT(&prevpcb, inp_queue) != next) {
349 				if (nretry--) {
350 					warnx("PCB prev pointer insane");
351 					goto retry;
352 				} else
353 					errx(1, "PCB prev pointer insane,"
354 					    " all attempts exhaused");
355 			}
356 		}
357 		prev = next;
358 		next = TAILQ_NEXT(&inpcb, inp_queue);
359 
360 		if (me.ss_family == AF_INET) {
361 			if ((inpcb.inp_flags & INP_IPV6) != 0) {
362 				if (ptb->vflag >= 2)
363 					fprintf(stderr, "Skip: INP_IPV6");
364 				continue;
365 			}
366 			if (ptb->vflag >= 2) {
367 				inet_ntop(AF_INET, &inpcb.inp_laddr,
368 				    tmp1, sizeof(tmp1));
369 				inet_ntop(AF_INET, &inpcb.inp_faddr,
370 				    tmp2, sizeof(tmp2));
371 				fprintf(stderr, "PCB %p local: [%s]:%d "
372 				    "remote: [%s]:%d\n", prev,
373 				    tmp1, inpcb.inp_lport,
374 				    tmp2, inpcb.inp_fport);
375 			}
376 			in4 = (struct sockaddr_in *)&me;
377 			if (memcmp(&in4->sin_addr, &inpcb.inp_laddr,
378 			    sizeof(struct in_addr)) != 0 ||
379 			    in4->sin_port != inpcb.inp_lport)
380 				continue;
381 			in4 = (struct sockaddr_in *)&them;
382 			if (memcmp(&in4->sin_addr, &inpcb.inp_faddr,
383 			    sizeof(struct in_addr)) != 0 ||
384 			    in4->sin_port != inpcb.inp_fport)
385 				continue;
386 		} else {
387 			if ((inpcb.inp_flags & INP_IPV6) == 0)
388 				continue;
389 			if (ptb->vflag >= 2) {
390 				inet_ntop(AF_INET6, &inpcb.inp_laddr6,
391 				    tmp1, sizeof(tmp1));
392 				inet_ntop(AF_INET6, &inpcb.inp_faddr6,
393 				    tmp2, sizeof(tmp2));
394 				fprintf(stderr, "PCB %p local: [%s]:%d "
395 				    "remote: [%s]:%d\n", prev,
396 				    tmp1, inpcb.inp_lport,
397 				    tmp2, inpcb.inp_fport);
398 			}
399 			in6 = (struct sockaddr_in6 *)&me;
400 			if (memcmp(&in6->sin6_addr, &inpcb.inp_laddr6,
401 			    sizeof(struct in6_addr)) != 0 ||
402 			    in6->sin6_port != inpcb.inp_lport)
403 				continue;
404 			in6 = (struct sockaddr_in6 *)&them;
405 			if (memcmp(&in6->sin6_addr, &inpcb.inp_faddr6,
406 			    sizeof(struct in6_addr)) != 0 ||
407 			    in6->sin6_port != inpcb.inp_fport)
408 				continue;
409 		}
410 		kget((u_long)inpcb.inp_ppcb, &tcpcb, sizeof(tcpcb));
411 		if (tcpcb.t_state != TCPS_ESTABLISHED) {
412 			if (ptb->vflag >= 2)
413 				fprintf(stderr, "Not established\n");
414 			continue;
415 		}
416 		if (ptb->vflag >= 2)
417 			fprintf(stderr, "Found PCB at %p\n", prev);
418 		return ((u_long)prev);
419 	}
420 
421 	errx(1, "No matching PCB found");
422 }
423 
424 static void
425 kupdate_stats(u_long tcbaddr, struct inpcb *inpcb,
426     struct tcpcb *tcpcb, struct socket *sockb)
427 {
428 	kget(tcbaddr, inpcb, sizeof(*inpcb));
429 	kget((u_long)inpcb->inp_ppcb, tcpcb, sizeof(*tcpcb));
430 	kget((u_long)inpcb->inp_socket, sockb, sizeof(*sockb));
431 }
432 
433 static void
434 check_kvar(const char *var)
435 {
436 	u_int i;
437 
438 	for (i = 0; allowed_kvars[i] != NULL; i++)
439 		if (strcmp(allowed_kvars[i], var) == 0)
440 			return;
441 	errx(1, "Unrecognised kvar: %s", var);
442 }
443 
444 static void
445 list_kvars(void)
446 {
447 	u_int i;
448 
449 	printf("Supported kernel variables:\n");
450 	for (i = 0; allowed_kvars[i] != NULL; i++)
451 		printf("\t%s\n", allowed_kvars[i]);
452 }
453 
454 static char **
455 check_prepare_kvars(char *list)
456 {
457 	char *item, **ret = NULL;
458 	u_int n = 0;
459 
460 	while ((item = strsep(&list, ", \t\n")) != NULL) {
461 		check_kvar(item);
462 		if ((ret = reallocarray(ret, (++n + 1), sizeof(*ret))) == NULL)
463 			err(1, "reallocarray(kvars)");
464 		if ((ret[n - 1] = strdup(item)) == NULL)
465 			err(1, "strdup");
466 		ret[n] = NULL;
467 	}
468 	return (ret);
469 }
470 
471 static void
472 stats_prepare(struct statctx *sc)
473 {
474 	sc->buf = ptb->dummybuf;
475 	sc->buflen = ptb->dummybuf_len;
476 
477 	if (ptb->kvars)
478 		sc->tcp_tcbaddr = kfind_tcb(sc->fd);
479 	if (clock_gettime_tv(CLOCK_MONOTONIC, &sc->t_start) == -1)
480 		err(1, "clock_gettime_tv");
481 	sc->t_last = sc->t_start;
482 
483 }
484 
485 static void
486 tcp_stats_display(unsigned long long total_elapsed, long double mbps,
487     float bwperc, struct statctx *sc, struct inpcb *inpcb,
488     struct tcpcb *tcpcb, struct socket *sockb)
489 {
490 	int j;
491 
492 	printf("%12llu %14llu %12.3Lf %7.2f%% ", total_elapsed, sc->bytes,
493 	    mbps, bwperc);
494 
495 	if (ptb->kvars != NULL) {
496 		kupdate_stats(sc->tcp_tcbaddr, inpcb, tcpcb,
497 		    sockb);
498 
499 		for (j = 0; ptb->kvars[j] != NULL; j++) {
500 #define S(a) #a
501 #define P(b, v, f)							\
502 			if (strcmp(ptb->kvars[j], S(b.v)) == 0) {	\
503 				printf("%s"f, j > 0 ? "," : "", b->v);	\
504 				continue;				\
505 			}
506 			P(inpcb, inp_flags, "0x%08x")
507 			P(sockb, so_rcv.sb_cc, "%lu")
508 			P(sockb, so_rcv.sb_hiwat, "%lu")
509 			P(sockb, so_rcv.sb_wat, "%lu")
510 			P(sockb, so_snd.sb_cc, "%lu")
511 			P(sockb, so_snd.sb_hiwat, "%lu")
512 			P(sockb, so_snd.sb_wat, "%lu")
513 			P(tcpcb, last_ack_sent, "%u")
514 			P(tcpcb, max_sndwnd, "%lu")
515 			P(tcpcb, rcv_adv, "%u")
516 			P(tcpcb, rcv_nxt, "%u")
517 			P(tcpcb, rcv_scale, "%u")
518 			P(tcpcb, rcv_wnd, "%lu")
519 			P(tcpcb, rfbuf_cnt, "%u")
520 			P(tcpcb, rfbuf_ts, "%u")
521 			P(tcpcb, snd_cwnd, "%lu")
522 			P(tcpcb, snd_max, "%u")
523 			P(tcpcb, snd_nxt, "%u")
524 			P(tcpcb, snd_scale, "%u")
525 			P(tcpcb, snd_ssthresh, "%lu")
526 			P(tcpcb, snd_una, "%u")
527 			P(tcpcb, snd_wl1, "%u")
528 			P(tcpcb, snd_wl2, "%u")
529 			P(tcpcb, snd_wnd, "%lu")
530 			P(tcpcb, t_rcvtime, "%u")
531 			P(tcpcb, t_rtseq, "%u")
532 			P(tcpcb, t_rttmin, "%hu")
533 			P(tcpcb, t_rtttime, "%u")
534 			P(tcpcb, t_rttvar, "%hu")
535 			P(tcpcb, t_srtt, "%hu")
536 			P(tcpcb, ts_recent, "%u")
537 			P(tcpcb, ts_recent_age, "%u")
538 #undef S
539 #undef P
540 		}
541 	}
542 	printf("\n");
543 }
544 
545 static void
546 tcp_process_slice(int fd, short event, void *bula)
547 {
548 	unsigned long long total_elapsed, since_last;
549 	long double mbps, slice_mbps = 0;
550 	float bwperc;
551 	struct statctx *sc;
552 	struct timeval t_cur, t_diff;
553 	struct inpcb inpcb;
554 	struct tcpcb tcpcb;
555 	struct socket sockb;
556 
557 	TAILQ_FOREACH(sc, &sc_queue, entry) {
558 		if (clock_gettime_tv(CLOCK_MONOTONIC, &t_cur) == -1)
559 			err(1, "clock_gettime_tv");
560 		if (ptb->kvars != NULL) /* process kernel stats */
561 			kupdate_stats(sc->tcp_tcbaddr, &inpcb, &tcpcb,
562 			    &sockb);
563 
564 		timersub(&t_cur, &sc->t_start, &t_diff);
565 		total_elapsed = t_diff.tv_sec * 1000 + t_diff.tv_usec / 1000;
566 		timersub(&t_cur, &sc->t_last, &t_diff);
567 		since_last = t_diff.tv_sec * 1000 + t_diff.tv_usec / 1000;
568 		if (since_last == 0)
569 			continue;
570 		bwperc = (sc->bytes * 100.0) / mainstats.slice_bytes;
571 		mbps = (sc->bytes * 8) / (since_last * 1000.0);
572 		slice_mbps += mbps;
573 
574 		tcp_stats_display(total_elapsed, mbps, bwperc, sc,
575 		    &inpcb, &tcpcb, &sockb);
576 
577 		sc->t_last = t_cur;
578 		sc->bytes = 0;
579 	}
580 
581 	/* process stats for this slice */
582 	if (slice_mbps > mainstats.peak_mbps)
583 		mainstats.peak_mbps = slice_mbps;
584 	printf("Conn: %3d Mbps: %12.3Lf Peak Mbps: %12.3Lf Avg Mbps: %12.3Lf\n",
585 	    mainstats.nconns, slice_mbps, mainstats.peak_mbps,
586 	    mainstats.nconns ? slice_mbps / mainstats.nconns : 0);
587 	mainstats.slice_bytes = 0;
588 
589 	set_slice_timer(mainstats.nconns > 0);
590 }
591 
592 static void
593 udp_process_slice(int fd, short event, void *v_sc)
594 {
595 	struct statctx *sc = v_sc;
596 	unsigned long long total_elapsed, since_last, pps;
597 	long double slice_mbps;
598 	struct timeval t_cur, t_diff;
599 
600 	if (clock_gettime_tv(CLOCK_MONOTONIC, &t_cur) == -1)
601 		err(1, "clock_gettime_tv");
602 	/* Calculate pps */
603 	timersub(&t_cur, &sc->t_start, &t_diff);
604 	total_elapsed = t_diff.tv_sec * 1000 + t_diff.tv_usec / 1000;
605 	timersub(&t_cur, &sc->t_last, &t_diff);
606 	since_last = t_diff.tv_sec * 1000 + t_diff.tv_usec / 1000;
607 	if (since_last == 0)
608 		return;
609 	slice_mbps = (sc->bytes * 8) / (since_last * 1000.0);
610 	pps = (sc->udp_slice_pkts * 1000) / since_last;
611 	if (slice_mbps > mainstats.peak_mbps)
612 		mainstats.peak_mbps = slice_mbps;
613 	printf("Elapsed: %11llu Mbps: %11.3Lf Peak Mbps: %11.3Lf %s PPS: %7llu\n",
614 	    total_elapsed, slice_mbps, mainstats.peak_mbps,
615 	    ptb->sflag ? "Rx" : "Tx", pps);
616 
617 	/* Clean up this slice time */
618 	sc->t_last = t_cur;
619 	sc->bytes = 0;
620 	sc->udp_slice_pkts = 0;
621 	set_slice_timer(1);
622 }
623 
624 static void
625 udp_server_handle_sc(int fd, short event, void *v_sc)
626 {
627 	ssize_t n;
628 	struct statctx *sc = v_sc;
629 
630 	n = read(fd, ptb->dummybuf, ptb->dummybuf_len);
631 	if (n == 0)
632 		return;
633 	else if (n == -1) {
634 		if (errno != EINTR && errno != EWOULDBLOCK)
635 			warn("fd %d read error", fd);
636 		return;
637 	}
638 
639 	if (ptb->vflag >= 3)
640 		fprintf(stderr, "read: %zd bytes\n", n);
641 	/* If this was our first packet, start slice timer */
642 	if (mainstats.peak_mbps == 0)
643 		set_slice_timer(1);
644 	/* Account packet */
645 	sc->udp_slice_pkts++;
646 	sc->bytes += n;
647 }
648 
649 static void
650 tcp_server_handle_sc(int fd, short event, void *v_sc)
651 {
652 	struct statctx *sc = v_sc;
653 	ssize_t n;
654 
655 	n = read(sc->fd, sc->buf, sc->buflen);
656 	if (n == -1) {
657 		if (errno != EINTR && errno != EWOULDBLOCK)
658 			warn("fd %d read error", sc->fd);
659 		return;
660 	} else if (n == 0) {
661 		if (ptb->vflag)
662 			fprintf(stderr, "%8d closed by remote end\n", sc->fd);
663 
664 		TAILQ_REMOVE(&sc_queue, sc, entry);
665 
666 		event_del(&sc->ev);
667 		close(sc->fd);
668 
669 		/* Some file descriptors are available again. */
670 		if (evtimer_pending(&sc->tcp_ts->evt, NULL)) {
671 			evtimer_del(&sc->tcp_ts->evt);
672 			event_add(&sc->tcp_ts->ev, NULL);
673 		}
674 
675 		free(sc);
676 		mainstats.nconns--;
677 		return;
678 	}
679 	if (ptb->vflag >= 3)
680 		fprintf(stderr, "read: %zd bytes\n", n);
681 	sc->bytes += n;
682 	mainstats.slice_bytes += n;
683 }
684 
685 static void
686 tcp_server_accept(int fd, short event, void *arg)
687 {
688 	struct tcpservsock *ts = arg;
689 	int sock;
690 	struct statctx *sc;
691 	struct sockaddr_storage ss;
692 	socklen_t sslen;
693 	char tmp[128];
694 
695 	sslen = sizeof(ss);
696 
697 	event_add(&ts->ev, NULL);
698 	if (event & EV_TIMEOUT)
699 		return;
700 	if ((sock = accept4(fd, (struct sockaddr *)&ss, &sslen, SOCK_NONBLOCK))
701 	    == -1) {
702 		/*
703 		 * Pause accept if we are out of file descriptors, or
704 		 * libevent will haunt us here too.
705 		 */
706 		if (errno == ENFILE || errno == EMFILE) {
707 			struct timeval evtpause = { 1, 0 };
708 
709 			event_del(&ts->ev);
710 			evtimer_add(&ts->evt, &evtpause);
711 		} else if (errno != EWOULDBLOCK && errno != EINTR &&
712 		    errno != ECONNABORTED)
713 			warn("accept");
714 		return;
715 	}
716 	saddr_ntop((struct sockaddr *)&ss, sslen,
717 	    tmp, sizeof(tmp));
718 	if (ptb->Tflag != -1 && ss.ss_family == AF_INET) {
719 		if (setsockopt(sock, IPPROTO_IP, IP_TOS,
720 		    &ptb->Tflag, sizeof(ptb->Tflag)))
721 			err(1, "setsockopt IP_TOS");
722 	}
723 	if (ptb->Tflag != -1 && ss.ss_family == AF_INET6) {
724 		if (setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS,
725 		    &ptb->Tflag, sizeof(ptb->Tflag)))
726 			err(1, "setsockopt IPV6_TCLASS");
727 	}
728 	/* Alloc client structure and register reading callback */
729 	if ((sc = calloc(1, sizeof(*sc))) == NULL)
730 		err(1, "calloc");
731 	sc->tcp_ts = ts;
732 	sc->fd = sock;
733 	stats_prepare(sc);
734 	event_set(&sc->ev, sc->fd, EV_READ | EV_PERSIST,
735 	    tcp_server_handle_sc, sc);
736 	event_add(&sc->ev, NULL);
737 	TAILQ_INSERT_TAIL(&sc_queue, sc, entry);
738 	mainstats.nconns++;
739 	if (mainstats.nconns == 1)
740 		set_slice_timer(1);
741 	if (ptb->vflag)
742 		fprintf(stderr, "Accepted connection from %s, fd = %d\n",
743 		    tmp, sc->fd);
744 }
745 
746 static void
747 server_init(struct addrinfo *aitop, struct statctx *udp_sc)
748 {
749 	char tmp[128];
750 	int sock, on = 1;
751 	struct addrinfo *ai;
752 	struct event *ev;
753 	struct tcpservsock *ts;
754 	nfds_t lnfds;
755 
756 	lnfds = 0;
757 	for (ai = aitop; ai != NULL; ai = ai->ai_next) {
758 		saddr_ntop(ai->ai_addr, ai->ai_addrlen, tmp, sizeof(tmp));
759 		if (ptb->vflag)
760 			fprintf(stderr, "Try to bind to %s\n", tmp);
761 		if ((sock = socket(ai->ai_family, ai->ai_socktype,
762 		    ai->ai_protocol)) == -1) {
763 			if (ai->ai_next == NULL)
764 				err(1, "socket");
765 			if (ptb->vflag)
766 				warn("socket");
767 			continue;
768 		}
769 		if (ptb->Tflag != -1 && ai->ai_family == AF_INET) {
770 			if (setsockopt(sock, IPPROTO_IP, IP_TOS,
771 			    &ptb->Tflag, sizeof(ptb->Tflag)))
772 				err(1, "setsockopt IP_TOS");
773 		}
774 		if (ptb->Tflag != -1 && ai->ai_family == AF_INET6) {
775 			if (setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS,
776 			    &ptb->Tflag, sizeof(ptb->Tflag)))
777 				err(1, "setsockopt IPV6_TCLASS");
778 		}
779 		if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
780 		    &on, sizeof(on)) == -1)
781 			warn("reuse port");
782 		if (bind(sock, ai->ai_addr, ai->ai_addrlen) != 0) {
783 			if (ai->ai_next == NULL)
784 				err(1, "bind");
785 			if (ptb->vflag)
786 				warn("bind");
787 			close(sock);
788 			continue;
789 		}
790 		if (ptb->Sflag) {
791 			if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
792 			    &ptb->Sflag, sizeof(ptb->Sflag)) == -1)
793 				warn("set receive socket buffer size");
794 		}
795 		if (TCP_MODE) {
796 			if (listen(sock, 64) == -1) {
797 				if (ai->ai_next == NULL)
798 					err(1, "listen");
799 				if (ptb->vflag)
800 					warn("listen");
801 				close(sock);
802 				continue;
803 			}
804 		}
805 		if (UDP_MODE) {
806 			if ((ev = calloc(1, sizeof(*ev))) == NULL)
807 				err(1, "calloc");
808 			event_set(ev, sock, EV_READ | EV_PERSIST,
809 			    udp_server_handle_sc, udp_sc);
810 			event_add(ev, NULL);
811 		} else {
812 			if ((ts = calloc(1, sizeof(*ts))) == NULL)
813 				err(1, "calloc");
814 
815 			ts->fd = sock;
816 			evtimer_set(&ts->evt, tcp_server_accept, ts);
817 			event_set(&ts->ev, ts->fd, EV_READ,
818 			    tcp_server_accept, ts);
819 			event_add(&ts->ev, NULL);
820 		}
821 		if (ptb->vflag >= 3)
822 			fprintf(stderr, "bound to fd %d\n", sock);
823 		lnfds++;
824 	}
825 	if (!ptb->Uflag)
826 		freeaddrinfo(aitop);
827 	if (lnfds == 0)
828 		errx(1, "No working listen addresses found");
829 }
830 
831 static void
832 client_handle_sc(int fd, short event, void *v_sc)
833 {
834 	struct statctx *sc = v_sc;
835 	ssize_t n;
836 	size_t blen = sc->buflen;
837 
838 	if (ptb->Rflag)
839 		blen = arc4random_uniform(blen) + 1;
840 	if ((n = write(sc->fd, sc->buf, blen)) == -1) {
841 		if (errno == EINTR || errno == EWOULDBLOCK ||
842 		    (UDP_MODE && errno == ENOBUFS))
843 			return;
844 		err(1, "write");
845 	}
846 	if (TCP_MODE && n == 0) {
847 		fprintf(stderr, "Remote end closed connection");
848 		exit(1);
849 	}
850 	if (ptb->vflag >= 3)
851 		fprintf(stderr, "write: %zd bytes\n", n);
852 	sc->bytes += n;
853 	mainstats.slice_bytes += n;
854 	if (UDP_MODE)
855 		sc->udp_slice_pkts++;
856 }
857 
858 static void
859 client_init(struct addrinfo *aitop, int nconn, struct statctx *udp_sc,
860     struct addrinfo *aib)
861 {
862 	struct statctx *sc;
863 	struct addrinfo *ai;
864 	char tmp[128];
865 	int i, r, sock;
866 
867 	sc = udp_sc;
868 	for (i = 0; i < nconn; i++) {
869 		for (sock = -1, ai = aitop; ai != NULL; ai = ai->ai_next) {
870 			saddr_ntop(ai->ai_addr, ai->ai_addrlen, tmp,
871 			    sizeof(tmp));
872 			if (ptb->vflag && i == 0)
873 				fprintf(stderr, "Trying %s\n", tmp);
874 			if ((sock = socket(ai->ai_family, ai->ai_socktype,
875 			    ai->ai_protocol)) == -1) {
876 				if (ai->ai_next == NULL)
877 					err(1, "socket");
878 				if (ptb->vflag)
879 					warn("socket");
880 				continue;
881 			}
882 			if (aib != NULL) {
883 				saddr_ntop(aib->ai_addr, aib->ai_addrlen,
884 				    tmp, sizeof(tmp));
885 				if (ptb->vflag)
886 					fprintf(stderr,
887 					    "Try to bind to %s\n", tmp);
888 				if (bind(sock, (struct sockaddr *)aib->ai_addr,
889 				    aib->ai_addrlen) == -1)
890 					err(1, "bind");
891 			}
892 			if (ptb->Tflag != -1 && ai->ai_family == AF_INET) {
893 				if (setsockopt(sock, IPPROTO_IP, IP_TOS,
894 				    &ptb->Tflag, sizeof(ptb->Tflag)))
895 					err(1, "setsockopt IP_TOS");
896 			}
897 			if (ptb->Tflag != -1 && ai->ai_family == AF_INET6) {
898 				if (setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS,
899 				    &ptb->Tflag, sizeof(ptb->Tflag)))
900 					err(1, "setsockopt IPV6_TCLASS");
901 			}
902 			if (ptb->Sflag) {
903 				if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
904 				    &ptb->Sflag, sizeof(ptb->Sflag)) == -1)
905 					warn("set send socket buffer size");
906 			}
907 			if (connect(sock, ai->ai_addr, ai->ai_addrlen) != 0) {
908 				if (ai->ai_next == NULL)
909 					err(1, "connect");
910 				if (ptb->vflag)
911 					warn("connect");
912 				close(sock);
913 				sock = -1;
914 				continue;
915 			}
916 			break;
917 		}
918 		if (sock == -1)
919 			errx(1, "No host found");
920 		if ((r = fcntl(sock, F_GETFL)) == -1)
921 			err(1, "fcntl(F_GETFL)");
922 		r |= O_NONBLOCK;
923 		if (fcntl(sock, F_SETFL, r) == -1)
924 			err(1, "fcntl(F_SETFL, O_NONBLOCK)");
925 		/* Alloc and prepare stats */
926 		if (TCP_MODE) {
927 			if ((sc = calloc(1, sizeof(*sc))) == NULL)
928 				err(1, "calloc");
929 		}
930 		sc->fd = sock;
931 		stats_prepare(sc);
932 		event_set(&sc->ev, sc->fd, EV_WRITE | EV_PERSIST,
933 		    client_handle_sc, sc);
934 		event_add(&sc->ev, NULL);
935 		TAILQ_INSERT_TAIL(&sc_queue, sc, entry);
936 		mainstats.nconns++;
937 		if (mainstats.nconns == 1)
938 			set_slice_timer(1);
939 	}
940 	if (!ptb->Uflag)
941 		freeaddrinfo(aitop);
942 	if (aib != NULL)
943 		freeaddrinfo(aib);
944 
945 	if (ptb->vflag && nconn > 1)
946 		fprintf(stderr, "%d connections established\n",
947 		    mainstats.nconns);
948 }
949 
950 static int
951 map_tos(char *s, int *val)
952 {
953 	/* DiffServ Codepoints and other TOS mappings */
954 	const struct toskeywords {
955 		const char	*keyword;
956 		int		 val;
957 	} *t, toskeywords[] = {
958 		{ "af11",		IPTOS_DSCP_AF11 },
959 		{ "af12",		IPTOS_DSCP_AF12 },
960 		{ "af13",		IPTOS_DSCP_AF13 },
961 		{ "af21",		IPTOS_DSCP_AF21 },
962 		{ "af22",		IPTOS_DSCP_AF22 },
963 		{ "af23",		IPTOS_DSCP_AF23 },
964 		{ "af31",		IPTOS_DSCP_AF31 },
965 		{ "af32",		IPTOS_DSCP_AF32 },
966 		{ "af33",		IPTOS_DSCP_AF33 },
967 		{ "af41",		IPTOS_DSCP_AF41 },
968 		{ "af42",		IPTOS_DSCP_AF42 },
969 		{ "af43",		IPTOS_DSCP_AF43 },
970 		{ "critical",		IPTOS_PREC_CRITIC_ECP },
971 		{ "cs0",		IPTOS_DSCP_CS0 },
972 		{ "cs1",		IPTOS_DSCP_CS1 },
973 		{ "cs2",		IPTOS_DSCP_CS2 },
974 		{ "cs3",		IPTOS_DSCP_CS3 },
975 		{ "cs4",		IPTOS_DSCP_CS4 },
976 		{ "cs5",		IPTOS_DSCP_CS5 },
977 		{ "cs6",		IPTOS_DSCP_CS6 },
978 		{ "cs7",		IPTOS_DSCP_CS7 },
979 		{ "ef",			IPTOS_DSCP_EF },
980 		{ "inetcontrol",	IPTOS_PREC_INTERNETCONTROL },
981 		{ "lowdelay",		IPTOS_LOWDELAY },
982 		{ "netcontrol",		IPTOS_PREC_NETCONTROL },
983 		{ "reliability",	IPTOS_RELIABILITY },
984 		{ "throughput",		IPTOS_THROUGHPUT },
985 		{ NULL,			-1 },
986 	};
987 
988 	for (t = toskeywords; t->keyword != NULL; t++) {
989 		if (strcmp(s, t->keyword) == 0) {
990 			*val = t->val;
991 			return (1);
992 		}
993 	}
994 
995 	return (0);
996 }
997 
998 static void
999 quit(int sig, short event, void *arg)
1000 {
1001 	exit(0);
1002 }
1003 
1004 int
1005 main(int argc, char **argv)
1006 {
1007 	struct timeval tv;
1008 	unsigned int secs, rtable;
1009 
1010 	char kerr[_POSIX2_LINE_MAX], *tmp;
1011 	struct addrinfo *aitop, *aib, hints;
1012 	const char *errstr;
1013 	struct rlimit rl;
1014 	int ch, herr, nconn;
1015 	int family = PF_UNSPEC;
1016 	struct nlist nl[] = { { "_tcbtable" }, { "" } };
1017 	const char *host = NULL, *port = DEFAULT_PORT, *srcbind = NULL;
1018 	struct event ev_sigint, ev_sigterm, ev_sighup, ev_progtimer;
1019 	struct statctx *udp_sc = NULL;
1020 	struct sockaddr_un sock_un;
1021 
1022 	/* Init world */
1023 	setvbuf(stdout, NULL, _IOLBF, 0);
1024 	ptb = &tcpbench;
1025 	ptb->dummybuf_len = 0;
1026 	ptb->Sflag = ptb->sflag = ptb->vflag = ptb->Rflag = ptb->Uflag = 0;
1027 	ptb->kvmh  = NULL;
1028 	ptb->kvars = NULL;
1029 	ptb->rflag = DEFAULT_STATS_INTERVAL;
1030 	ptb->Tflag = -1;
1031 	nconn = 1;
1032 	aib = NULL;
1033 	secs = 0;
1034 
1035 	while ((ch = getopt(argc, argv, "46b:B:hlk:n:p:Rr:sS:t:T:uUvV:")) != -1) {
1036 		switch (ch) {
1037 		case '4':
1038 			family = PF_INET;
1039 			break;
1040 		case '6':
1041 			family = PF_INET6;
1042 			break;
1043 		case 'b':
1044 			srcbind = optarg;
1045 			break;
1046 		case 'l':
1047 			list_kvars();
1048 			exit(0);
1049 		case 'k':
1050 			if ((tmp = strdup(optarg)) == NULL)
1051 				err(1, "strdup");
1052 			ptb->kvars = check_prepare_kvars(tmp);
1053 			free(tmp);
1054 			break;
1055 		case 'R':
1056 			ptb->Rflag = 1;
1057 			break;
1058 		case 'r':
1059 			ptb->rflag = strtonum(optarg, 0, 60 * 60 * 24 * 1000,
1060 			    &errstr);
1061 			if (errstr != NULL)
1062 				errx(1, "statistics interval is %s: %s",
1063 				    errstr, optarg);
1064 			break;
1065 		case 'p':
1066 			port = optarg;
1067 			break;
1068 		case 's':
1069 			ptb->sflag = 1;
1070 			break;
1071 		case 'S':
1072 			ptb->Sflag = strtonum(optarg, 0, 1024*1024*1024,
1073 			    &errstr);
1074 			if (errstr != NULL)
1075 				errx(1, "socket buffer size is %s: %s",
1076 				    errstr, optarg);
1077 			break;
1078 		case 'B':
1079 			ptb->dummybuf_len = strtonum(optarg, 0, 1024*1024*1024,
1080 			    &errstr);
1081 			if (errstr != NULL)
1082 				errx(1, "read/write buffer size is %s: %s",
1083 				    errstr, optarg);
1084 			break;
1085 		case 'v':
1086 			ptb->vflag++;
1087 			break;
1088 		case 'V':
1089 			rtable = (unsigned int)strtonum(optarg, 0,
1090 			    RT_TABLEID_MAX, &errstr);
1091 			if (errstr)
1092 				errx(1, "rtable value is %s: %s",
1093 				    errstr, optarg);
1094 			if (setrtable(rtable) == -1)
1095 				err(1, "setrtable");
1096 			break;
1097 		case 'n':
1098 			nconn = strtonum(optarg, 0, 65535, &errstr);
1099 			if (errstr != NULL)
1100 				errx(1, "number of connections is %s: %s",
1101 				    errstr, optarg);
1102 			break;
1103 		case 'u':
1104 			ptb->uflag = 1;
1105 			break;
1106 		case 'U':
1107 			ptb->Uflag = 1;
1108 			break;
1109 		case 'T':
1110 			if (map_tos(optarg, &ptb->Tflag))
1111 				break;
1112 			errstr = NULL;
1113 			if (strlen(optarg) > 1 && optarg[0] == '0' &&
1114 			    optarg[1] == 'x')
1115 				ptb->Tflag = (int)strtol(optarg, NULL, 16);
1116 			else
1117 				ptb->Tflag = (int)strtonum(optarg, 0, 255,
1118 				    &errstr);
1119 			if (ptb->Tflag == -1 || ptb->Tflag > 255 || errstr)
1120 				errx(1, "illegal tos value %s", optarg);
1121 			break;
1122 		case 't':
1123 			secs = strtonum(optarg, 1, UINT_MAX, &errstr);
1124 			if (errstr != NULL)
1125 				errx(1, "secs is %s: %s",
1126 				    errstr, optarg);
1127 			break;
1128 		case 'h':
1129 		default:
1130 			usage();
1131 		}
1132 	}
1133 
1134 	if (pledge("stdio unveil rpath dns inet unix id proc", NULL) == -1)
1135 		err(1, "pledge");
1136 
1137 	argv += optind;
1138 	argc -= optind;
1139 	if ((argc != (ptb->sflag && !ptb->Uflag ? 0 : 1)) ||
1140 	    (UDP_MODE && (ptb->kvars || nconn != 1)))
1141 		usage();
1142 
1143 	if (ptb->kvars) {
1144 		if (unveil(_PATH_MEM, "r") == -1)
1145 			err(1, "unveil");
1146 		if (unveil(_PATH_KMEM, "r") == -1)
1147 			err(1, "unveil");
1148 		if (unveil(_PATH_KSYMS, "r") == -1)
1149 			err(1, "unveil");
1150 
1151 		if ((ptb->kvmh = kvm_openfiles(NULL, NULL, NULL,
1152 		    O_RDONLY, kerr)) == NULL)
1153 			errx(1, "kvm_open: %s", kerr);
1154 		drop_gid();
1155 		if (kvm_nlist(ptb->kvmh, nl) < 0 || nl[0].n_type == 0)
1156 			errx(1, "kvm: no namelist");
1157 		ptb->ktcbtab = nl[0].n_value;
1158 	} else
1159 		drop_gid();
1160 
1161 	if (!ptb->sflag || ptb->Uflag)
1162 		host = argv[0];
1163 
1164 	if (ptb->Uflag)
1165 		if (unveil(host, "rwc") == -1)
1166 			err(1, "unveil");
1167 
1168 	if (pledge("stdio id dns inet unix", NULL) == -1)
1169 		err(1, "pledge");
1170 
1171 	/*
1172 	 * Rationale,
1173 	 * If TCP, use a big buffer with big reads/writes.
1174 	 * If UDP, use a big buffer in server and a buffer the size of a
1175 	 * ethernet packet.
1176 	 */
1177 	if (!ptb->dummybuf_len) {
1178 		if (ptb->sflag || TCP_MODE)
1179 			ptb->dummybuf_len = DEFAULT_BUF;
1180 		else
1181 			ptb->dummybuf_len = DEFAULT_UDP_PKT;
1182 	}
1183 
1184 	bzero(&hints, sizeof(hints));
1185 	hints.ai_family = family;
1186 	if (UDP_MODE) {
1187 		hints.ai_socktype = SOCK_DGRAM;
1188 		hints.ai_protocol = IPPROTO_UDP;
1189 	} else {
1190 		hints.ai_socktype = SOCK_STREAM;
1191 		hints.ai_protocol = IPPROTO_TCP;
1192 	}
1193 	if (ptb->Uflag) {
1194 		hints.ai_family = AF_UNIX;
1195 		hints.ai_protocol = 0;
1196 		sock_un.sun_family = AF_UNIX;
1197 		if (strlcpy(sock_un.sun_path, host, sizeof(sock_un.sun_path)) >=
1198 		    sizeof(sock_un.sun_path))
1199 			errx(1, "socket name '%s' too long", host);
1200 		hints.ai_addr = (struct sockaddr *)&sock_un;
1201 		hints.ai_addrlen = sizeof(sock_un);
1202 		aitop = &hints;
1203 	} else {
1204 		if (ptb->sflag)
1205 			hints.ai_flags = AI_PASSIVE;
1206 		if (srcbind != NULL) {
1207 			hints.ai_flags |= AI_NUMERICHOST;
1208 			herr = getaddrinfo(srcbind, NULL, &hints, &aib);
1209 			hints.ai_flags &= ~AI_NUMERICHOST;
1210 			if (herr != 0) {
1211 				if (herr == EAI_SYSTEM)
1212 					err(1, "getaddrinfo");
1213 				else
1214 					errx(1, "getaddrinfo: %s",
1215 					    gai_strerror(herr));
1216 			}
1217 		}
1218 		if ((herr = getaddrinfo(host, port, &hints, &aitop)) != 0) {
1219 			if (herr == EAI_SYSTEM)
1220 				err(1, "getaddrinfo");
1221 			else
1222 				errx(1, "getaddrinfo: %s", gai_strerror(herr));
1223 		}
1224 	}
1225 
1226 	if (pledge("stdio id inet unix", NULL) == -1)
1227 		err(1, "pledge");
1228 
1229 	if (getrlimit(RLIMIT_NOFILE, &rl) == -1)
1230 		err(1, "getrlimit");
1231 	if (rl.rlim_cur < MAX_FD)
1232 		rl.rlim_cur = MAX_FD;
1233 	if (setrlimit(RLIMIT_NOFILE, &rl))
1234 		err(1, "setrlimit");
1235 	if (getrlimit(RLIMIT_NOFILE, &rl) == -1)
1236 		err(1, "getrlimit");
1237 
1238 	if (pledge("stdio inet unix", NULL) == -1)
1239 		err(1, "pledge");
1240 
1241 	/* Init world */
1242 	TAILQ_INIT(&sc_queue);
1243 	if ((ptb->dummybuf = malloc(ptb->dummybuf_len)) == NULL)
1244 		err(1, "malloc");
1245 	arc4random_buf(ptb->dummybuf, ptb->dummybuf_len);
1246 
1247 	/* Setup libevent and signals */
1248 	event_init();
1249 	signal_set(&ev_sigterm, SIGTERM, signal_handler, NULL);
1250 	signal_set(&ev_sighup, SIGHUP, signal_handler, NULL);
1251 	signal_set(&ev_sigint, SIGINT, signal_handler, NULL);
1252 	signal_add(&ev_sigint, NULL);
1253 	signal_add(&ev_sigterm, NULL);
1254 	signal_add(&ev_sighup, NULL);
1255 	signal(SIGPIPE, SIG_IGN);
1256 
1257 	if (UDP_MODE) {
1258 		if ((udp_sc = calloc(1, sizeof(*udp_sc))) == NULL)
1259 			err(1, "calloc");
1260 		udp_sc->fd = -1;
1261 		stats_prepare(udp_sc);
1262 		evtimer_set(&mainstats.timer, udp_process_slice, udp_sc);
1263 	} else {
1264 		print_tcp_header();
1265 		evtimer_set(&mainstats.timer, tcp_process_slice, NULL);
1266 	}
1267 
1268 	if (ptb->sflag)
1269 		server_init(aitop, udp_sc);
1270 	else {
1271 		if (secs > 0) {
1272 			timerclear(&tv);
1273 			tv.tv_sec = secs + 1;
1274 			evtimer_set(&ev_progtimer, quit, NULL);
1275 			evtimer_add(&ev_progtimer, &tv);
1276 		}
1277 		client_init(aitop, nconn, udp_sc, aib);
1278 
1279 		if (pledge("stdio", NULL) == -1)
1280 			err(1, "pledge");
1281 	}
1282 
1283 	/* libevent main loop*/
1284 	event_dispatch();
1285 
1286 	return (0);
1287 }
1288