diff --git a/pcap-bpf.c b/pcap-bpf.c index eb31e34..bcfd556 100644 --- a/pcap-bpf.c +++ b/pcap-bpf.c @@ -20,7 +20,7 @@ */ #ifndef lint static const char rcsid[] = - "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.66 2003-07-25 05:32:02 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.67 2003-11-04 07:05:32 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -143,6 +143,18 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) register u_char *bp, *ep; again: + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it + * has, and return -2 to indicate that we were + * told to break out of the loop. + */ + p->break_loop = 0; + return (-2); + } cc = p->cc; if (p->cc == 0) { cc = read(p->fd, (char *)p->buffer, p->bufsize); @@ -211,6 +223,27 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) ep = bp + cc; while (bp < ep) { register int caplen, hdrlen; + + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + p->bp = bp; + p->cc = ep - bp; + return (n); + } + } + caplen = bhp->bh_caplen; hdrlen = bhp->bh_hdrlen; /* @@ -470,7 +503,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, #endif /* HAVE_DAG_API */ #ifdef BIOCGDLTLIST - bzero(&bdl, sizeof(bdl)); + memset(&bdl, 0, sizeof(bdl)); #endif p = (pcap_t *)malloc(sizeof(*p)); diff --git a/pcap-dag.c b/pcap-dag.c index c1ef389..016a087 100644 --- a/pcap-dag.c +++ b/pcap-dag.c @@ -19,7 +19,7 @@ #ifndef lint static const char rcsid[] = - "@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.9 2003-10-02 07:07:49 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.10 2003-11-04 07:05:33 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -210,8 +210,9 @@ static dag_record_t *get_next_dag_header(pcap_t *p) { /* * Read at most max_packets from the capture stream and call the callback - * for each of them. Returns the number of packets handled or -1 if an - * error occured. A blocking + * for each of them. Returns the number of packets handled, -1 if an + * error occured, or -2 if we were told to break out of the loop. + * A blocking */ static int dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { u_char *dp = NULL; @@ -221,6 +222,18 @@ static int dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { dag_record_t *header; register unsigned long long ts; + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it has, and return -2 + * to indicate that we were told to break out of the loop. + */ + p->break_loop = 0; + return -2; + } + /* Receive a single packet from the kernel */ header = get_next_dag_header(p); dp = ((u_char *)header) + dag_record_size; diff --git a/pcap-dlpi.c b/pcap-dlpi.c index 46bf708..51cc1e9 100644 --- a/pcap-dlpi.c +++ b/pcap-dlpi.c @@ -38,7 +38,7 @@ #ifndef lint static const char rcsid[] = - "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.90 2003-07-25 05:32:03 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap-dlpi.c,v 1.91 2003-11-04 07:05:33 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -207,6 +207,19 @@ pcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user) data.maxlen = p->bufsize; data.len = 0; do { + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates + * that it has, and return -2 to + * indicate that we were told to + * break out of the loop. + */ + p->break_loop = 0; + return (-2); + } if (getmsg(p->fd, &ctl, &data, &flags) < 0) { /* Don't choke when we get ptraced */ if (errno == EINTR) { @@ -229,6 +242,25 @@ pcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user) n = 0; #ifdef HAVE_SYS_BUFMOD_H while (bp < ep) { + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + p->bp = bp; + p->cc = ep - bp; + return (n); + } + } #ifdef LBL_ALIGN if ((long)bp & 3) { sbp = &sbhdr; diff --git a/pcap-int.h b/pcap-int.h index 4e97649..7fc288e 100644 --- a/pcap-int.h +++ b/pcap-int.h @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.54 2003-10-24 23:55:06 guy Exp $ (LBL) + * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.55 2003-11-04 07:05:34 guy Exp $ (LBL) */ #ifndef pcap_int_h @@ -106,6 +106,8 @@ struct pcap { int tzoff; /* timezone offset */ int offset; /* offset for proper alignment */ + int break_loop; /* flag set to force break from packet-reading loop */ + struct pcap_sf sf; struct pcap_md md; diff --git a/pcap-linux.c b/pcap-linux.c index 9828d13..6120b67 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -27,7 +27,7 @@ #ifndef lint static const char rcsid[] = - "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.96 2003-10-06 07:04:55 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.97 2003-11-04 07:05:34 guy Exp $ (LBL)"; #endif /* @@ -462,6 +462,18 @@ pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata) bp = handle->buffer + handle->offset; do { + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it + * has, and return -2 as an indication that we + * were told to break out of the loop. + */ + p->break_loop = 0; + return -2; + } fromlen = sizeof(from); packet_len = recvfrom( handle->fd, bp + offset, diff --git a/pcap-nit.c b/pcap-nit.c index 44db9af..b5fbb42 100644 --- a/pcap-nit.c +++ b/pcap-nit.c @@ -20,7 +20,7 @@ */ #ifndef lint static const char rcsid[] = - "@(#) $Header: /tcpdump/master/libpcap/pcap-nit.c,v 1.49 2003-07-25 05:32:04 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap-nit.c,v 1.50 2003-11-04 07:05:35 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -126,6 +126,26 @@ pcap_read_nit(pcap_t *p, int cnt, pcap_handler callback, u_char *user) n = 0; ep = bp + cc; while (bp < ep) { + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + p->cc = ep - bp; + p->bp = bp; + return (n); + } + } + nh = (struct nit_hdr *)bp; cp = bp + sizeof(*nh); diff --git a/pcap-pf.c b/pcap-pf.c index d3f3b7f..1e735d6 100644 --- a/pcap-pf.c +++ b/pcap-pf.c @@ -24,7 +24,7 @@ #ifndef lint static const char rcsid[] = - "@(#) $Header: /tcpdump/master/libpcap/pcap-pf.c,v 1.78 2003-07-25 05:32:05 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap-pf.c,v 1.79 2003-11-04 07:05:36 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -135,6 +135,25 @@ pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user) pad = 0; #endif while (cc > 0) { + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (pc->break_loop) { + if (n == 0) { + pc->break_loop = 0; + return (-2); + } else { + pc->cc = cc; + pc->bp = bp; + return (n); + } + } if (cc < sizeof(*sp)) { snprintf(pc->errbuf, sizeof(pc->errbuf), "pf short read (%d)", cc); diff --git a/pcap-snit.c b/pcap-snit.c index 1b7bae5..b150e33 100644 --- a/pcap-snit.c +++ b/pcap-snit.c @@ -25,7 +25,7 @@ #ifndef lint static const char rcsid[] = - "@(#) $Header: /tcpdump/master/libpcap/pcap-snit.c,v 1.65 2003-07-25 05:32:05 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap-snit.c,v 1.66 2003-11-04 07:05:36 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -141,6 +141,26 @@ pcap_read_snit(pcap_t *p, int cnt, pcap_handler callback, u_char *user) n = 0; ep = bp + cc; while (bp < ep) { + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + p->bp = bp; + p->cc = ep - bp; + return (n); + } + } + ++p->md.stat.ps_recv; cp = bp; diff --git a/pcap-snoop.c b/pcap-snoop.c index 69c6569..a1b530e 100644 --- a/pcap-snoop.c +++ b/pcap-snoop.c @@ -20,7 +20,7 @@ */ #ifndef lint static const char rcsid[] = - "@(#) $Header: /tcpdump/master/libpcap/pcap-snoop.c,v 1.44 2003-07-25 05:32:05 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap-snoop.c,v 1.45 2003-11-04 07:05:37 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -68,13 +68,25 @@ pcap_read_snoop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) register u_char *cp; again: + /* + * Has "pcap_breakloop()" been called? + */ + if (p->break_loop) { + /* + * Yes - clear the flag that indicates that it + * has, and return -2 to indicate that we were + * told to break out of the loop. + */ + p->break_loop = 0; + return (-2); + } cc = read(p->fd, (char *)p->buffer, p->bufsize); if (cc < 0) { /* Don't choke when we get ptraced */ switch (errno) { case EINTR: - goto again; + goto again; case EWOULDBLOCK: return (0); /* XXX */ diff --git a/pcap-win32.c b/pcap-win32.c index 1bf18af..3ad6277 100644 --- a/pcap-win32.c +++ b/pcap-win32.c @@ -32,7 +32,7 @@ #ifndef lint static const char rcsid[] = - "@(#) $Header: /tcpdump/master/libpcap/pcap-win32.c,v 1.14 2003-09-22 11:48:40 risso Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap-win32.c,v 1.15 2003-11-04 07:05:37 guy Exp $ (LBL)"; #endif #include @@ -119,6 +119,27 @@ pcap_read_win32(pcap_t *p, int cnt, pcap_handler callback, u_char *user) ep = bp + cc; while (bp < ep) { register int caplen, hdrlen; + + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else { + p->bp = bp; + p->cc = ep - bp; + return (n); + } + } + caplen = bhp->bh_caplen; hdrlen = bhp->bh_hdrlen; diff --git a/pcap.3 b/pcap.3 index 011fc19..f3d6de4 100644 --- a/pcap.3 +++ b/pcap.3 @@ -1,4 +1,4 @@ -.\" @(#) $Header: /tcpdump/master/libpcap/Attic/pcap.3,v 1.49 2003-10-10 00:27:45 guy Exp $ +.\" @(#) $Header: /tcpdump/master/libpcap/Attic/pcap.3,v 1.50 2003-11-04 07:05:38 guy Exp $ .\" .\" Copyright (c) 1994, 1996, 1997 .\" The Regents of the University of California. All rights reserved. @@ -84,6 +84,10 @@ const u_char **pkt_data) .ft .LP .ft B +void pcap_breakloop(pcap_t *) +.ft +.LP +.ft B int pcap_datalink(pcap_t *p) int pcap_list_datalinks(pcap_t *p, int **dlt_buf); int pcap_set_datalink(pcap_t *p, int dlt); @@ -455,6 +459,9 @@ an error in which case or .B pcap_geterr() may be used to display the error text. +A return of \-2 indicates that the loop terminated due to a call to +.B pcap_breakloop() +before any packets were processed. .PP .BR NOTE : when reading a live capture, @@ -489,10 +496,12 @@ A negative .I cnt causes .B pcap_loop() -to loop forever (or at least until an error occurs). A negative number -is returned on an error; 0 is returned if +to loop forever (or at least until an error occurs). \-1 is returned on +an error; 0 is returned if .I cnt -is exhausted. +is exhausted; \-2 is returned if the loop terminated due to a call to +.B pcap_breakloop() +before any packets were processed. .PP .B pcap_next() reads the next packet (by calling @@ -541,6 +550,45 @@ pointer pointed to by the .I pkt_data argument is set to point to the data in the packet. .PP +.B pcap_breakloop() +sets a flag that will force +.B pcap_dispatch() +or +.B pcap_loop() +to return rather than looping; they will return the number of packets +that have been processed so far, or \-2 if no packets have been +processed so far. +.PP +This routine is safe to use inside a signal handler on UNIX or a console +control handler on Windows, as it merely sets a flag that is checked +within the loop. +.PP +The flag is checked in loops reading packets from the OS - a signal by +itself will not necessarily terminate those loops - as well as in loops +processing a set of packets returned by the OS. Note that +.B pcap_next() +will, on some platforms, loop reading packets from the OS; that loop +will not necessarily be terminated by a signal, so +.B pcap_breakloop() +should be used to terminate packet processing even if +.B pcap_next() +is being used. +.PP +.B pcap_breakloop() +does not guarantee that no further packets will be processed by +.B pcap_dispatch() +or +.B pcap_loop() +after it is called; at most one more packet might be processed. +.PP +If \-2 is returned from +.B pcap_dispatch() +or +.BR pcap_loop() , +the flag is cleared, so a subsequent call will resume reading packets. +If a positive number is returned, the flag is not cleared, so a +subsequent call will return \-2 and clear the flag. +.PP .B pcap_dump() outputs a packet to the ``savefile'' opened with .BR pcap_dump_open() . diff --git a/pcap.c b/pcap.c index cfda3cb..620e4d2 100644 --- a/pcap.c +++ b/pcap.c @@ -33,7 +33,7 @@ #ifndef lint static const char rcsid[] = - "@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.62 2003-10-31 21:49:18 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.63 2003-11-04 07:05:39 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -189,6 +189,7 @@ pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, * Return codes for pcap_read() are: * - 0: timeout * - -1: error + * - -2: loop was broken out of with pcap_breakloop() * - >1: OK * The first one ('0') conflicts with the return code of 0 from * pcap_offline_read() meaning "end of file". @@ -196,6 +197,15 @@ pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, return (p->read_op(p, 1, pcap_fakecallback, (u_char *)&s)); } +/* + * Force the loop in "pcap_read()" or "pcap_read_offline()" to terminate. + */ +void +pcap_breakloop(pcap_t *p) +{ + p->break_loop = 1; +} + int pcap_datalink(pcap_t *p) { diff --git a/pcap.h b/pcap.h index 7b0778d..3277b98 100644 --- a/pcap.h +++ b/pcap.h @@ -31,7 +31,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.44 2003-04-10 06:08:06 guy Exp $ (LBL) + * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.45 2003-11-04 07:05:39 guy Exp $ (LBL) */ #ifndef lib_pcap_h @@ -178,6 +178,7 @@ int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); const u_char* pcap_next(pcap_t *, struct pcap_pkthdr *); int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); +void pcap_breakloop(pcap_t *); int pcap_stats(pcap_t *, struct pcap_stat *); int pcap_setfilter(pcap_t *, struct bpf_program *); int pcap_getnonblock(pcap_t *, char *); diff --git a/savefile.c b/savefile.c index 13fe6f8..390bc60 100644 --- a/savefile.c +++ b/savefile.c @@ -30,7 +30,7 @@ #ifndef lint static const char rcsid[] = - "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.91 2003-11-04 01:49:08 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.92 2003-11-04 07:05:40 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -742,6 +742,23 @@ pcap_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) while (status == 0) { struct pcap_pkthdr h; + /* + * Has "pcap_breakloop()" been called? + * If so, return immediately - if we haven't read any + * packets, clear the flag and return -2 to indicate + * that we were told to break out of the loop, otherwise + * leave the flag set, so that the *next* call will break + * out of the loop without having read any packets, and + * return the number of packets we've processed so far. + */ + if (p->break_loop) { + if (n == 0) { + p->break_loop = 0; + return (-2); + } else + return (n); + } + status = sf_next_packet(p, &h, p->buffer, p->bufsize); if (status) { if (status == 1)