xref: /freebsd/contrib/libpcap/testprogs/nonblocktest.c (revision 9f23cbd6cae82fd77edfad7173432fa8dccd0a95)
1 /*
2  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21 
22 #include "varattrs.h"
23 
24 /*
25  * Tests for pcap_set_nonblock / pcap_get_nonblock:
26  * - idempotency
27  * - set/get are symmetric
28  * - get returns the same before/after activate
29  * - pcap_breakloop works after setting nonblock on and then off
30  *
31  * Really this is meant to
32  * be run manually under strace, to check for extra
33  * calls to eventfd or close.
34  */
35 #include <pcap.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <stdarg.h>
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 
45 static pcap_t *pd;
46 static char *program_name = "nonblocktest";
47 /* Forwards */
48 static void PCAP_NORETURN usage(void);
49 static void PCAP_NORETURN error(const char *, ...) PCAP_PRINTFLIKE(1, 2);
50 static void warning(const char *, ...) PCAP_PRINTFLIKE(1, 2);
51 
52 /* VARARGS */
53 static void
54 error(const char *fmt, ...)
55 {
56 	va_list ap;
57 
58 	(void)fprintf(stderr, "%s: ", program_name);
59 	va_start(ap, fmt);
60 	(void)vfprintf(stderr, fmt, ap);
61 	va_end(ap);
62 	if (*fmt) {
63 		fmt += strlen(fmt);
64 		if (fmt[-1] != '\n')
65 			(void)fputc('\n', stderr);
66 	}
67 	exit(1);
68 	/* NOTREACHED */
69 }
70 
71 /* VARARGS */
72 static void
73 warning(const char *fmt, ...)
74 {
75 	va_list ap;
76 
77 	(void)fprintf(stderr, "%s: WARNING: ", program_name);
78 	va_start(ap, fmt);
79 	(void)vfprintf(stderr, fmt, ap);
80 	va_end(ap);
81 	if (*fmt) {
82 		fmt += strlen(fmt);
83 		if (fmt[-1] != '\n')
84 			(void)fputc('\n', stderr);
85 	}
86 }
87 
88 static void
89 usage(void)
90 {
91 	(void)fprintf(stderr, "Usage: %s [ -i interface ]\n",
92 	    program_name);
93 	exit(1);
94 }
95 
96 static void
97 breakme(u_char *user _U_, const struct pcap_pkthdr *h _U_, const u_char *sp _U_)
98 {
99 	warning("using pcap_breakloop()");
100 	pcap_breakloop(pd);
101 }
102 
103 int
104 main(int argc, char **argv)
105 {
106 	int status, op, i, ret;
107 	char *device;
108 	pcap_if_t *devlist;
109 	char ebuf[PCAP_ERRBUF_SIZE];
110 
111 	device = NULL;
112 	while ((op = getopt(argc, argv, "i:sptnq")) != -1) {
113 		switch (op) {
114 
115 		case 'i':
116 			device = optarg;
117 			break;
118 
119 		default:
120 			usage();
121 			/* NOTREACHED */
122 		}
123 	}
124 	if (device == NULL) {
125 		if (pcap_findalldevs(&devlist, ebuf) == -1)
126 			error("%s", ebuf);
127 		if (devlist == NULL)
128 			error("no interfaces available for capture");
129 		device = strdup(devlist->name);
130 		warning("listening on %s", device);
131 		pcap_freealldevs(devlist);
132 	}
133 	*ebuf = '\0';
134 	pd = pcap_create(device, ebuf);
135 	if (pd == NULL)
136 		error("%s", ebuf);
137 	else if (*ebuf)
138 		warning("%s", ebuf);
139 	/* set nonblock before activate */
140 	if (pcap_setnonblock(pd, 1, ebuf) < 0)
141 		error("pcap_setnonblock failed: %s", ebuf);
142 	/* getnonblock just returns "not activated yet" */
143 	ret = pcap_getnonblock(pd, ebuf);
144 	if (ret != PCAP_ERROR_NOT_ACTIVATED)
145 		error("pcap_getnonblock unexpectedly succeeded");
146 	if ((status = pcap_activate(pd)) < 0)
147 		error("pcap_activate failed");
148 	ret = pcap_getnonblock(pd, ebuf);
149 	if (ret != 1)
150 		error( "pcap_getnonblock did not return nonblocking" );
151 
152 	/* Set nonblock multiple times, ensure with strace that it's a noop */
153 	for (i=0; i<10; i++) {
154 		if (pcap_setnonblock(pd, 1, ebuf) < 0)
155 			error("pcap_setnonblock failed: %s", ebuf);
156 		ret = pcap_getnonblock(pd, ebuf);
157 		if (ret != 1)
158 			error( "pcap_getnonblock did not return nonblocking" );
159 	}
160 	/* Set block multiple times, ensure with strace that it's a noop */
161 	for (i=0; i<10; i++) {
162 		if (pcap_setnonblock(pd, 0, ebuf) < 0)
163 			error("pcap_setnonblock failed: %s", ebuf);
164 		ret = pcap_getnonblock(pd, ebuf);
165 		if (ret != 0)
166 			error( "pcap_getnonblock did not return blocking" );
167 	}
168 
169 	/* Now pcap_loop forever, with a callback that
170 	 * uses pcap_breakloop to get out of forever */
171 	pcap_loop(pd, -1, breakme, NULL);
172 
173         /* Now test that pcap_setnonblock fails if we can't open the
174          * eventfd. */
175         if (pcap_setnonblock(pd, 1, ebuf) < 0)
176                 error("pcap_setnonblock failed: %s", ebuf);
177         while (1) {
178                 ret = open("/dev/null", O_RDONLY);
179                 if (ret < 0)
180                         break;
181         }
182         ret = pcap_setnonblock(pd, 0, ebuf);
183         if (ret == 0)
184                 error("pcap_setnonblock succeeded even though file table is full");
185         else
186                 warning("pcap_setnonblock failed as expected: %s", ebuf);
187 }
188