1 ##dhcp-probe-01-pcap-loop.patch - wrap pcap_dispatch in a loop
2 --- src/dhcp_probe.c 2009-08-16 12:24:10.000000000 +0300
3 +++ src/dhcp_probe.c 2009-08-16 11:52:26.000000000 +0300
5 volatile sig_atomic_t reopen_log_file; /* for signal handler */
6 volatile sig_atomic_t reopen_capture_file; /* for signal handler */
7 volatile sig_atomic_t quit_requested; /* for signal requested */
8 +volatile sig_atomic_t alarm_fired; /* for signal requested */
10 pcap_t *pd = NULL; /* libpcap - packet capture descriptor used for actual packet capture */
11 pcap_t *pd_template = NULL; /* libpcap - packet capture descriptor just used as template */
16 +/* capture packets from pcap for timeout seconds */
18 +loop_for_packets(int timeout)
20 + int packets_recv = 0;
26 + int pcap_rc = pcap_dispatch(pd, -1, process_response, NULL);
28 + report(LOG_ERR, "pcap_dispatch(): %s", pcap_geterr(pd));
29 + else if (pcap_rc > 0)
30 + packets_recv += pcap_rc;
31 + } while(! alarm_fired && !quit_requested);
33 + return packets_recv;
38 main(int argc, char **argv)
50 char pcap_errbuf[PCAP_ERRBUF_SIZE], pcap_errbuf2[PCAP_ERRBUF_SIZE];
53 - char libnet_errbuf[LIBNET_ERRBUF_SIZE];
55 /* get progname = last component of argv[0] */
56 prog = strrchr(argv[0], '/');
59 reread_config_file = 0; /* set by signal handler */
60 reopen_log_file = 0; /* set by signal handler */
61 reopen_capture_file = 0; /* set by signal handler */
65 ifname = strdup(argv[optind]); /* interface name is a required final argument */
68 report(LOG_ERR, "sigaction: %s", get_errmsg());
71 + sigemptyset(&sa.sa_mask);
72 + sa.sa_handler = catcher;
74 + if (sigaction(SIGALRM, &sa, NULL) < 0) {
75 + report(LOG_ERR, "sigaction: %s", get_errmsg());
83 for (l = libnet_cq_head(); libnet_cq_last(); l = libnet_cq_next()) { /* write one flavor packet and listen for answers */
87 int pcap_open_retries;
90 /* We set up for packet capture BEFORE writing our packet, to minimize the delay
91 between our writing and when we are able to start capturing. (I cannot tell from
93 report(LOG_DEBUG, "listening for answers for %d milliseconds", GetResponse_wait_time());
96 - /* XXX I often find that pcap_dispatch() returns well before the timeout specified earlier.
97 - I ensure that there's no alarm() still left over before we start, and also ensure we don't
98 - get interrupted by SIGCHLD (possible since process_response() could fork an alert_program or alert_program2 child).
99 - But we STILL often return from pcap_dispatch() too soon!
100 - April 2001: An update to the pcap(3) man page around version 0.6 (?), along with postings
101 - on the tcpdump workers mailing list explains what's going on. The timeout specified in
102 - pcap_open_live() isn't a timeout in the sense one might expect. The pcap_dispatch() call
103 - can return sooner than expected (even immediately), or if no packets are received, might
104 - never return at all; the behavior is platform-dependant. I don't have a way to work
105 - around this issue; it means this program just won't work reliably (or at all) on some
109 - alarm(0); /* just in case a previous alarm was still left */
111 sigemptyset(&new_sigset);
112 sigaddset(&new_sigset, SIGCHLD);
113 sigprocmask(SIG_BLOCK, &new_sigset, &old_sigset); /* block SIGCHLD */
115 - pcap_rc = pcap_dispatch(pd, -1, process_response, NULL);
116 + packets_recv = loop_for_packets(GetResponse_wait_time() / 1000);;
118 sigprocmask(SIG_SETMASK, &old_sigset, NULL); /* unblock SIGCHLD */
121 - report(LOG_ERR, "pcap_dispatch(): %s", pcap_geterr(pd));
122 - else if (debug > 10)
123 - report(LOG_DEBUG, "done listening, captured %d packets", pcap_rc);
125 + report(LOG_DEBUG, "done listening, captured %d packets", packets_recv);
127 /* I was hoping that perhaps pcap_stats() would return a nonzero number of packets dropped when
128 the buffer size specified to pcap_open_live() turns out to be too small -- so we could
130 pcap_close(pd_template);
133 + return 0; /* make gcc happy */
138 /* Perform all necessary functions to handle a request to reconfigure.
139 Must not be called until after initial configuration is complete.
144 if (! read_configfile(config_file)) {
147 @@ -1050,8 +1059,14 @@
149 if ((sig == SIGINT) || (sig == SIGTERM) || (sig == SIGQUIT)) { /* quit gracefully */
151 + /* pcap wraps the socket read inside a loop, so the signal doesn't
152 + interrupt it without an explicit call to pcap_breakloop */
153 + pcap_breakloop(pd);
155 + } else if (sig == SIGALRM) { /* timer */
156 + pcap_breakloop(pd);
160 } else if (sig == SIGHUP) { /* re-read config file */
161 /* Doing the reread while in the signal handler is way too dangerous.
162 We'll do it at the start or end of the next main event loop.