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