From 229eb085a6ca4d291a3b273504e479a72afb5d0f Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 27 Mar 2025 13:18:50 +0100 Subject: [PATCH 1/2] set break_loop in pcap.c when PCAP_ERROR_BREAK is returned The code is the same everywhere anyway, and there are just a few callers of read_op that need to deal with this. So let the caller handle it. This should be a bit nicer overall and will simplify the implementation to permit breaking the loop in a way that also flushes out the queue. --- dlpisubs.c | 3 +-- pcap-bpf.c | 15 ++++----------- pcap-bt-linux.c | 4 +--- pcap-bt-monitor-linux.c | 4 +--- pcap-dag.c | 18 ++---------------- pcap-dbus.c | 6 ++---- pcap-dlpi.c | 13 +++---------- pcap-dpdk.c | 3 --- pcap-haiku.c | 1 - pcap-hurd.c | 4 +--- pcap-libdlpi.c | 11 ++--------- pcap-linux.c | 16 ++++------------ pcap-netfilter-linux.c | 8 -------- pcap-netmap.c | 5 ++--- pcap-npf.c | 10 +--------- pcap-rdmasniff.c | 2 -- pcap-rpcap.c | 17 +++-------------- pcap-snf.c | 1 - pcap-usb-linux.c | 10 ++-------- pcap.c | 14 ++++++++++++-- savefile.c | 7 +++---- 21 files changed, 44 insertions(+), 128 deletions(-) diff --git a/dlpisubs.c b/dlpisubs.c index e1a64492d4..632b0c94c6 100644 --- a/dlpisubs.c +++ b/dlpisubs.c @@ -166,8 +166,7 @@ pcap_process_pkts(pcap_t *p, pcap_handler callback, u_char *user, */ if (p->break_loop) { if (n == 0) { - p->break_loop = 0; - return (-2); + return PCAP_ERROR_BREAK; } else { p->bp = bufp; p->cc = ep - bufp; diff --git a/pcap-bpf.c b/pcap-bpf.c index 7d29be2017..5d9e72a5f9 100644 --- a/pcap-bpf.c +++ b/pcap-bpf.c @@ -1190,15 +1190,9 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) /* * Has "pcap_breakloop()" been called? */ - if (p->break_loop) { - /* - * Yes - clear the flag that indicates that it - * has, and return PCAP_ERROR_BREAK to indicate - * that we were told to break out of the loop. - */ - p->break_loop = 0; + if (p->break_loop) return (PCAP_ERROR_BREAK); - } + cc = p->cc; if (p->cc == 0) { /* @@ -1348,10 +1342,9 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) if (p->break_loop) { p->bp = bp; p->cc = (u_int)(ep - bp); - if (n == 0) { - p->break_loop = 0; + if (n == 0) return (PCAP_ERROR_BREAK); - } else + else return (n); } diff --git a/pcap-bt-linux.c b/pcap-bt-linux.c index 67d357c4d8..c22c9773ac 100644 --- a/pcap-bt-linux.c +++ b/pcap-bt-linux.c @@ -338,10 +338,8 @@ bt_read_linux(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char /* ignore interrupt system call error */ do { if (handle->break_loop) - { - handle->break_loop = 0; return PCAP_ERROR_BREAK; - } + ret = recvmsg(handle->fd, &msg, 0); } while ((ret == -1) && (errno == EINTR)); diff --git a/pcap-bt-monitor-linux.c b/pcap-bt-monitor-linux.c index 44d40e2efc..2e1f614e84 100644 --- a/pcap-bt-monitor-linux.c +++ b/pcap-bt-monitor-linux.c @@ -118,10 +118,8 @@ bt_monitor_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_ch do { if (handle->break_loop) - { - handle->break_loop = 0; return PCAP_ERROR_BREAK; - } + ret = recvmsg(handle->fd, &msg, 0); } while ((ret == -1) && (errno == EINTR)); diff --git a/pcap-dag.c b/pcap-dag.c index 147479ca01..20fc15e099 100644 --- a/pcap-dag.c +++ b/pcap-dag.c @@ -334,15 +334,8 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) /* * Has "pcap_breakloop()" been called? */ - if (p->break_loop) { - /* - * Yes - clear the flag that indicates that - * it has, and return PCAP_ERROR_BREAK to indicate that - * we were told to break out of the loop. - */ - p->break_loop = 0; + if (p->break_loop) return PCAP_ERROR_BREAK; - } /* dag_advance_stream() will block (unless nonblock is called) * until 64kB of data has accumulated. @@ -395,15 +388,8 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) /* * Has "pcap_breakloop()" been called? */ - if (p->break_loop) { - /* - * Yes - clear the flag that indicates that - * it has, and return PCAP_ERROR_BREAK to indicate that - * we were told to break out of the loop. - */ - p->break_loop = 0; + if (p->break_loop) return PCAP_ERROR_BREAK; - } rlen = ntohs(header->rlen); if (rlen < dag_record_size) diff --git a/pcap-dbus.c b/pcap-dbus.c index d29fb81d36..31c204d1ef 100644 --- a/pcap-dbus.c +++ b/pcap-dbus.c @@ -70,10 +70,8 @@ dbus_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *us return -1; } - if (handle->break_loop) { - handle->break_loop = 0; - return -2; - } + if (handle->break_loop) + return PCAP_ERROR_BREAK; message = dbus_connection_pop_message(handlep->conn); } diff --git a/pcap-dlpi.c b/pcap-dlpi.c index 1cb680bb11..51bf5f8eec 100644 --- a/pcap-dlpi.c +++ b/pcap-dlpi.c @@ -180,16 +180,9 @@ pcap_read_dlpi(pcap_t *p, int cnt, pcap_handler callback, u_char *user) /* * 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 (p->break_loop) + return PCAP_ERROR_BREAK; + /* * XXX - check for the DLPI primitive, which * would be DL_HP_RAWDATA_IND on HP-UX diff --git a/pcap-dpdk.c b/pcap-dpdk.c index 76de9b7690..3c2f6e6512 100644 --- a/pcap-dpdk.c +++ b/pcap-dpdk.c @@ -353,7 +353,6 @@ static int pcap_dpdk_dispatch(pcap_t *p, int max_cnt, pcap_handler cb, u_char *c while( pkt_cnt < max_cnt){ if (p->break_loop){ - p->break_loop = 0; return PCAP_ERROR_BREAK; } // read once in non-blocking mode, or try many times waiting for timeout_ms. @@ -365,9 +364,7 @@ static int pcap_dpdk_dispatch(pcap_t *p, int max_cnt, pcap_handler cb, u_char *c }else{ if (p->break_loop){ RTE_LOG(DEBUG, USER1, "dpdk: no packets available and break_loop is set in blocking mode.\n"); - p->break_loop = 0; return PCAP_ERROR_BREAK; - } RTE_LOG(DEBUG, USER1, "dpdk: no packets available for timeout %d ms in blocking mode.\n", timeout_ms); } diff --git a/pcap-haiku.c b/pcap-haiku.c index 9a2d6cf4c2..54509dc67e 100644 --- a/pcap-haiku.c +++ b/pcap-haiku.c @@ -62,7 +62,6 @@ pcap_read_haiku(pcap_t* handle, int maxPackets _U_, pcap_handler callback, ssize_t bytesReceived; do { if (handle->break_loop) { - handle->break_loop = 0; return PCAP_ERROR_BREAK; } bytesReceived = recvfrom(handle->fd, buffer, handle->bufsize, MSG_TRUNC, diff --git a/pcap-hurd.c b/pcap-hurd.c index 134a109b35..fc527c1076 100644 --- a/pcap-hurd.c +++ b/pcap-hurd.c @@ -134,10 +134,8 @@ pcap_read_hurd(pcap_t *p, int cnt _U_, pcap_handler callback, u_char *user) msg = (struct net_rcv_msg *)p->buffer; retry: - if (p->break_loop) { - p->break_loop = 0; + if (p->break_loop) return PCAP_ERROR_BREAK; - } kr = mach_msg(&msg->msg_hdr, MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0, p->bufsize, ph->rcv_port, MACH_MSG_TIMEOUT_NONE, diff --git a/pcap-libdlpi.c b/pcap-libdlpi.c index 67cb58580b..474b4d7c2d 100644 --- a/pcap-libdlpi.c +++ b/pcap-libdlpi.c @@ -410,15 +410,8 @@ pcap_read_libdlpi(pcap_t *p, int count, pcap_handler callback, u_char *user) } 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 (p->break_loop) + return PCAP_ERROR_BREAK; msglen = p->bufsize; bufp = p->buffer + p->offset; diff --git a/pcap-linux.c b/pcap-linux.c index fc459ece10..bee66e3cee 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -3676,10 +3676,8 @@ static int pcap_wait_for_frames_mmap(pcap_t *handle) * It's EINTR; if we were told to break out of * the loop, do so. */ - if (handle->break_loop) { - handle->break_loop = 0; + if (handle->break_loop) return PCAP_ERROR_BREAK; - } } else if (ret > 0) { /* * OK, some descriptor is ready. @@ -3826,10 +3824,8 @@ static int pcap_wait_for_frames_mmap(pcap_t *handle) * pcap_breakloop() call; if we were told * to break out of the loop, do so. */ - if (handle->break_loop) { - handle->break_loop = 0; + if (handle->break_loop) return PCAP_ERROR_BREAK; - } } } @@ -4423,10 +4419,8 @@ pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback, handle->offset = 0; /* check for break loop condition*/ - if (handle->break_loop) { - handle->break_loop = 0; + if (handle->break_loop) return PCAP_ERROR_BREAK; - } } return pkts; } @@ -4557,10 +4551,8 @@ pcap_read_linux_mmap_v3(pcap_t *handle, int max_packets, pcap_handler callback, } /* check for break loop condition*/ - if (handle->break_loop) { - handle->break_loop = 0; + if (handle->break_loop) return PCAP_ERROR_BREAK; - } } if (pkts == 0 && handlep->timeout == 0) { /* Block until we see a packet. */ diff --git a/pcap-netfilter-linux.c b/pcap-netfilter-linux.c index 90296be71b..16b6738238 100644 --- a/pcap-netfilter-linux.c +++ b/pcap-netfilter-linux.c @@ -92,12 +92,6 @@ netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_c * Has "pcap_breakloop()" been called? */ if (handle->break_loop) { - /* - * Yes - clear the flag that indicates that it - * has, and return PCAP_ERROR_BREAK to indicate - * that we were told to break out of the loop. - */ - handle->break_loop = 0; return PCAP_ERROR_BREAK; } cc = handle->cc; @@ -116,7 +110,6 @@ netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_c do { read_ret = recv(handle->fd, handle->buffer, handle->bufsize, 0); if (handle->break_loop) { - handle->break_loop = 0; return PCAP_ERROR_BREAK; } if (read_ret == -1 && errno == ENOBUFS) @@ -165,7 +158,6 @@ netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_c handle->bp = bp; handle->cc = (u_int)(ep - bp); if (count == 0) { - handle->break_loop = 0; return PCAP_ERROR_BREAK; } else return count; diff --git a/pcap-netmap.c b/pcap-netmap.c index 56a6bc4180..227a75f57c 100644 --- a/pcap-netmap.c +++ b/pcap-netmap.c @@ -97,10 +97,9 @@ pcap_netmap_dispatch(pcap_t *p, int cnt, pcap_handler cb, u_char *user) pn->cb_arg = user; for (;;) { - if (p->break_loop) { - p->break_loop = 0; + if (p->break_loop) return PCAP_ERROR_BREAK; - } + /* nm_dispatch won't run forever */ ret = nm_dispatch((void *)d, cnt, (void *)pcap_netmap_filter, (void *)p); diff --git a/pcap-npf.c b/pcap-npf.c index 4feee30cfd..b2fa1f807f 100644 --- a/pcap-npf.c +++ b/pcap-npf.c @@ -555,15 +555,8 @@ pcap_read_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) /* * Has "pcap_breakloop()" been called? */ - if (p->break_loop) { - /* - * Yes - clear the flag that indicates that it - * has, and return PCAP_ERROR_BREAK to indicate - * that we were told to break out of the loop. - */ - p->break_loop = 0; + if (p->break_loop) return (PCAP_ERROR_BREAK); - } /* * Capture the packets. @@ -668,7 +661,6 @@ pcap_read_npf(pcap_t *p, int cnt, pcap_handler callback, u_char *user) */ if (p->break_loop) { if (n == 0) { - p->break_loop = 0; return (PCAP_ERROR_BREAK); } else { p->bp = bp; diff --git a/pcap-rdmasniff.c b/pcap-rdmasniff.c index ba4705b71a..022350c28f 100644 --- a/pcap-rdmasniff.c +++ b/pcap-rdmasniff.c @@ -126,7 +126,6 @@ rdmasniff_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *u return PCAP_ERROR; } if (handle->break_loop) { - handle->break_loop = 0; return PCAP_ERROR_BREAK; } } @@ -179,7 +178,6 @@ rdmasniff_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *u rdmasniff_post_recv(handle, wc.wr_id); if (handle->break_loop) { - handle->break_loop = 0; return PCAP_ERROR_BREAK; } } diff --git a/pcap-rpcap.c b/pcap-rpcap.c index fd3cf6abb9..a5eaf3a9f4 100644 --- a/pcap-rpcap.c +++ b/pcap-rpcap.c @@ -671,15 +671,8 @@ static int pcap_read_rpcap(pcap_t *p, int cnt, pcap_handler callback, u_char *us /* * Has "pcap_breakloop()" been called? */ - if (p->break_loop) { - /* - * Yes - clear the flag that indicates that it - * has, and return PCAP_ERROR_BREAK to indicate - * that we were told to break out of the loop. - */ - p->break_loop = 0; + if (p->break_loop) return (PCAP_ERROR_BREAK); - } /* * Read some packets. @@ -713,13 +706,9 @@ static int pcap_read_rpcap(pcap_t *p, int cnt, pcap_handler callback, u_char *us * * Were we told to break out of the loop? */ - if (p->break_loop) { - /* - * Yes. - */ - p->break_loop = 0; + if (p->break_loop) return (PCAP_ERROR_BREAK); - } + /* No - return the number of packets we've processed. */ return n; } diff --git a/pcap-snf.c b/pcap-snf.c index 72ed13d62a..2adc772867 100644 --- a/pcap-snf.c +++ b/pcap-snf.c @@ -151,7 +151,6 @@ snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) */ if (p->break_loop) { if (n == 0) { - p->break_loop = 0; return PCAP_ERROR_BREAK; } else { return (n); diff --git a/pcap-usb-linux.c b/pcap-usb-linux.c index 4287585f15..eba19696ef 100644 --- a/pcap-usb-linux.c +++ b/pcap-usb-linux.c @@ -670,10 +670,7 @@ usb_read_linux_bin(pcap_t *handle, int max_packets _U_, pcap_handler callback, u do { ret = ioctl(handle->fd, MON_IOCX_GET, &info); if (handle->break_loop) - { - handle->break_loop = 0; - return -2; - } + return PCAP_ERROR_BREAK; } while ((ret == -1) && (errno == EINTR)); if (ret < 0) { @@ -800,10 +797,7 @@ usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_ch do { ret = ioctl(handle->fd, MON_IOCX_MFETCH, &fetch); if (handle->break_loop) - { - handle->break_loop = 0; - return -2; - } + return PCAP_ERROR_BREAK; } while ((ret == -1) && (errno == EINTR)); if (ret < 0) { diff --git a/pcap.c b/pcap.c index ebb0c9e978..2f34c51a72 100644 --- a/pcap.c +++ b/pcap.c @@ -569,6 +569,7 @@ pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, const u_char **pkt_data) { struct oneshot_userdata s; + int ret; s.hdr = &p->pcap_header; s.pkt = pkt_data; @@ -615,7 +616,9 @@ pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, * The first one ('0') conflicts with the return code of 0 from * pcapint_offline_read() meaning "end of file". */ - return (p->read_op(p, 1, p->oneshot_callback, (u_char *)&s)); + ret = p->read_op(p, 1, p->oneshot_callback, (u_char *)&s); + if (ret == PCAP_ERROR_BREAK) + p->break_loop = 0; } /* @@ -2892,7 +2895,12 @@ pcapint_open_offline_common(char *ebuf, size_t total_size, size_t private_offset int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { - return (p->read_op(p, cnt, callback, user)); + int ret = p->read_op(p, cnt, callback, user); + + if (ret == PCAP_ERROR_BREAK) + p->break_loop = 0; + + return ret; } int @@ -2915,6 +2923,8 @@ pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) n = p->read_op(p, cnt, callback, user); } while (n == 0); } + if (n == PCAP_ERROR_BREAK) + p->break_loop = 0; if (n <= 0) return (n); if (!PACKET_COUNT_IS_UNLIMITED(cnt)) { diff --git a/savefile.c b/savefile.c index 17cf98722d..ed12900050 100644 --- a/savefile.c +++ b/savefile.c @@ -645,10 +645,9 @@ pcapint_offline_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) * return the number of packets we've processed so far. */ if (p->break_loop) { - if (n == 0) { - p->break_loop = 0; - return (-2); - } else + if (n == 0) + return (PCAP_ERROR_BREAK); + else return (n); } From de3a961dc6c7fb3c9289953a349313b20d95da2b Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 27 Mar 2025 14:41:38 +0100 Subject: [PATCH 2/2] add pcap_breakloop_flush API and implement it on linux It is useful to get all the packets up to the current point in time. Due to input buffering this may not be the case. On Linux with tcpdump, one can get up to a second worth of packets that are not processed. Add a new pcap_breakloop_flush and set the internal break_loop variable to separate values depending on which version of pcap_breakloop was used. Then, on Linux, keep processing packets without polling if the break_loop variable is set to PCAPINT_BREAK_FLUSH, but abort immediately in the PCAPINT_BREAK_IMMEDIATE case. --- pcap-int.h | 13 ++++++++++--- pcap-linux.c | 34 +++++++++++++++++++++++----------- pcap-npf.c | 4 ++-- pcap.c | 14 ++++++++++---- pcap/pcap.h | 3 +++ 5 files changed, 48 insertions(+), 20 deletions(-) diff --git a/pcap-int.h b/pcap-int.h index d154f00e5d..6bce067ae6 100644 --- a/pcap-int.h +++ b/pcap-int.h @@ -183,7 +183,7 @@ typedef int (*set_datalink_op_t)(pcap_t *, int); typedef int (*getnonblock_op_t)(pcap_t *); typedef int (*setnonblock_op_t)(pcap_t *, int); typedef int (*stats_op_t)(pcap_t *, struct pcap_stat *); -typedef void (*breakloop_op_t)(pcap_t *); +typedef void (*breakloop_op_t)(pcap_t *, int); #ifdef _WIN32 typedef struct pcap_stat *(*stats_ex_op_t)(pcap_t *, int *); typedef int (*setbuff_op_t)(pcap_t *, int); @@ -199,6 +199,12 @@ typedef int (*live_dump_ended_op_t)(pcap_t *, int); #endif typedef void (*cleanup_op_t)(pcap_t *); +enum { + PCAPINT_BREAK_RUN = 0, + PCAPINT_BREAK_IMMEDIATE, + PCAPINT_BREAK_FLUSH, +}; + /* * We put all the stuff used in the read code path at the beginning, * to try to keep it together in the same cache line or lines. @@ -228,7 +234,8 @@ struct pcap { u_char *bp; u_int cc; - sig_atomic_t break_loop; /* flag set to force break from packet-reading loop */ + /* break packet-reading loop, will be set to one of PCAPINT_BREAK_* */ + sig_atomic_t break_loop; void *priv; /* private data for methods */ @@ -433,7 +440,7 @@ void pcapint_add_to_pcaps_to_close(pcap_t *); void pcapint_remove_from_pcaps_to_close(pcap_t *); void pcapint_cleanup_live_common(pcap_t *); int pcapint_check_activated(pcap_t *); -void pcapint_breakloop_common(pcap_t *); +void pcapint_breakloop_common(pcap_t *, int mode); /* * Internal interfaces for "pcap_findalldevs()". diff --git a/pcap-linux.c b/pcap-linux.c index bee66e3cee..6d407357df 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -1106,9 +1106,9 @@ set_poll_timeout(struct pcap_linux *handlep) } } -static void pcap_breakloop_linux(pcap_t *handle) +static void pcap_breakloop_linux(pcap_t *handle, int mode) { - pcapint_breakloop_common(handle); + pcapint_breakloop_common(handle, mode); struct pcap_linux *handlep = handle->priv; uint64_t value = 1; @@ -3677,7 +3677,7 @@ static int pcap_wait_for_frames_mmap(pcap_t *handle) * the loop, do so. */ if (handle->break_loop) - return PCAP_ERROR_BREAK; + return 0; } else if (ret > 0) { /* * OK, some descriptor is ready. @@ -3825,7 +3825,7 @@ static int pcap_wait_for_frames_mmap(pcap_t *handle) * to break out of the loop, do so. */ if (handle->break_loop) - return PCAP_ERROR_BREAK; + return 0; } } @@ -4340,17 +4340,24 @@ pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback, int pkts = 0; int ret; + /* Stop processing if we should break out immediately */ + if (handle->break_loop == PCAPINT_BREAK_IMMEDIATE) + return PCAP_ERROR_BREAK; + /* wait for frames availability.*/ h.raw = RING_GET_CURRENT_FRAME(handle); - if (!packet_mmap_acquire(h.h2)) { + if (!handle->break_loop && !packet_mmap_acquire(h.h2)) { /* * The current frame is owned by the kernel; wait for * a frame to be handed to us. */ ret = pcap_wait_for_frames_mmap(handle); - if (ret) { + if (ret) return ret; - } + + /* We may have received an immediate break while polling */ + if (handle->break_loop == PCAPINT_BREAK_IMMEDIATE) + return PCAP_ERROR_BREAK; } /* @@ -4418,10 +4425,15 @@ pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback, if (++handle->offset >= handle->cc) handle->offset = 0; - /* check for break loop condition*/ - if (handle->break_loop) - return PCAP_ERROR_BREAK; + /* Abort processing if requested */ + if (handle->break_loop == PCAPINT_BREAK_IMMEDIATE) + break; } + + /* All packets are drained, report loop break */ + if (pkts == 0 && handle->break_loop) + return PCAP_ERROR_BREAK; + return pkts; } @@ -4445,7 +4457,7 @@ pcap_read_linux_mmap_v3(pcap_t *handle, int max_packets, pcap_handler callback, * for a frame to be handed to us. */ ret = pcap_wait_for_frames_mmap(handle); - if (ret) { + if (ret && ret != PCAP_ERROR_BREAK) { return ret; } } diff --git a/pcap-npf.c b/pcap-npf.c index b2fa1f807f..f54ad545c4 100644 --- a/pcap-npf.c +++ b/pcap-npf.c @@ -804,9 +804,9 @@ pcap_cleanup_npf(pcap_t *p) } static void -pcap_breakloop_npf(pcap_t *p) +pcap_breakloop_npf(pcap_t *p, int mode) { - pcapint_breakloop_common(p); + pcapint_breakloop_common(p, mode); struct pcap_win *pw = p->priv; /* XXX - what if this fails? */ diff --git a/pcap.c b/pcap.c index 2f34c51a72..62fe0f7872 100644 --- a/pcap.c +++ b/pcap.c @@ -2941,7 +2941,13 @@ pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) void pcap_breakloop(pcap_t *p) { - p->breakloop_op(p); + p->breakloop_op(p, PCAPINT_BREAK_IMMEDIATE); +} + +void +pcap_breakloop_flush(pcap_t *p) +{ + p->breakloop_op(p, PCAPINT_BREAK_FLUSH); } int @@ -4074,9 +4080,9 @@ pcapint_remove_from_pcaps_to_close(pcap_t *p) } void -pcapint_breakloop_common(pcap_t *p) +pcapint_breakloop_common(pcap_t *p, int mode) { - p->break_loop = 1; + p->break_loop = mode; } @@ -4293,7 +4299,7 @@ pcap_read_dead(pcap_t *p, int cnt _U_, pcap_handler callback _U_, } static void -pcap_breakloop_dead(pcap_t *p _U_) +pcap_breakloop_dead(pcap_t *p _U_, int mode) { /* * A "dead" pcap_t is just a placeholder to use in order to diff --git a/pcap/pcap.h b/pcap/pcap.h index a023fde6c6..ac30e048b3 100644 --- a/pcap/pcap.h +++ b/pcap/pcap.h @@ -608,6 +608,9 @@ PCAP_API int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); PCAP_AVAILABLE_0_8 PCAP_API void pcap_breakloop(pcap_t *); +PCAP_AVAILABLE_1_11 +PCAP_API void pcap_breakloop_flush(pcap_t *); + PCAP_AVAILABLE_0_4 PCAP_API int pcap_stats(pcap_t *, struct pcap_stat *) PCAP_WARN_UNUSED_RESULT;