tcpdump mailing list archives
Re: Portable way to "block" on pcap_next_ex()
From: Fernando Gont <fernando () gont com ar>
Date: Mon, 16 Jan 2012 19:20:40 -0300
Hi, Guy, On 01/16/2012 05:25 PM, Guy Harris wrote:
If you have a system where select() works as it should, i.e.:[....]select() will block until either 1) a bufferful of packets arrives or 2) the timer, started when the select() is done, expires, regardless of whether any packets are available to read.This doesn't seem to agree with my tests. I've just checked this on FreeBSD-8.2-release and on a current Ubuntu system,Sorry, I didn't make it clear enough that, when I said that, I was speaking only of systems using BPF, so it wouldn't apply to Ubuntu (or any other Linux distribution), for example.
But it does work in the same way on FreeBSD and OpenBSD, too. -- just tested this...
and in both cases select() returns "readable" only for each packet that is received.What do you mean by "only for each packet that is received"? Do you mean that it doesn't return "readable" if there are no packets to read?
Both on Linux and on BSDs, each time a packet is received, select() returns readable (without waiting for the entire buffer to fill up). -- my understanding is that you were expecting select() to block till the buffer filled up, or when the timer expired. But everytime select() returns, there's a packet to read, and it seems it never returns when there are no packets to read. FWIW, this is my test program: /* * Testing select() and pcap_next_ex() * * Please send any bug reports to Fernando Gont <fgont () si6networks com> */ #include <errno.h> #include <stdlib.h> #include <stdio.h> #include <time.h> #include <getopt.h> #include <unistd.h> #include <string.h> #include <pcap.h> #include <sys/types.h> #include <sys/param.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netinet/ip6.h> #include <netinet/icmp6.h> #include <sys/socket.h> #include <sys/select.h> /* Constants used with the libpcap functions */ #define PCAP_ICMPV6_FILTER "icmp6 and ip6[40]==128" #define PCAP_SNAP_LEN 65535 #define PCAP_TIMEOUT 1 #define PCAP_PROMISC 1 #define PCAP_OPT 1 #ifndef PCAP_NETMASK_UNKNOWN #define PCAP_NETMASK_UNKNOWN 0xffffffff #endif #define IFACE_LENGTH 255 pcap_t *pfd; bpf_u_int32 my_netmask; bpf_u_int32 my_ip; struct bpf_program pcap_filter; char dev[64], errbuf[PCAP_ERRBUF_SIZE]; char iface[IFACE_LENGTH]; char *lasts, *rpref, *endptr; char *charptr; int main(int argc, char **argv){ extern char *optarg; extern int optind; int r, sel, fd; fd_set sset, rset; struct pcap_pkthdr *pkthdr; const u_char *pktdata; unsigned char iface_f=0; static struct option longopts[] = { {"interface", required_argument, 0, 'i'}, }; char shortopts[]= "i:"; char option; if(argc<=1){ puts("Missing parameters"); exit(1); } while((option=getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch(option) { case 'i': /* Interface */ strncpy(iface, optarg, IFACE_LENGTH-1); iface_f=1; break; default: puts("Unsuported option"); exit(1); break; } /* switch */ } /* while(getopt) */ if(geteuid()) { puts("tool needs root privileges to run."); exit(1); } if(!iface_f){ puts("Must specify the network interface with the -i option"); exit(1); } if( (pfd= pcap_open_live(iface, PCAP_SNAP_LEN, PCAP_PROMISC, PCAP_TIMEOUT, errbuf)) == NULL){ printf("pcap_open_live(): %s\n", errbuf); exit(1); } if( pcap_datalink(pfd) != DLT_EN10MB){ printf("Error: Interface %s is not an Ethernet interface", iface); exit(1); } if(pcap_compile(pfd, &pcap_filter, PCAP_ICMPV6_FILTER, PCAP_OPT, PCAP_NETMASK_UNKNOWN) == -1){ printf("pcap_compile(): %s", pcap_geterr(pfd)); exit(1); } if(pcap_setfilter(pfd, &pcap_filter) == -1){ printf("pcap_setfilter(): %s", pcap_geterr(pfd)); exit(1); } pcap_freecode(&pcap_filter); if( (fd= pcap_fileno(pfd)) == -1){ puts("Error obtaining descriptor number for pcap_t"); exit(1); } FD_ZERO(&sset); FD_SET(fd, &sset); while(1){ rset= sset; if((sel=select(fd+1, &rset, NULL, NULL, NULL)) == -1){ if(errno == EINTR){ puts("select() was interrupted"); continue; } else{ puts("Error in select()"); exit(1); } } puts("Descriptor was readable"); if((r=pcap_next_ex(pfd, &pkthdr, &pktdata)) == -1){ printf("pcap_next_ex(): %s", pcap_geterr(pfd)); exit(1); } else if(r == 0){ puts("pcap_next_ex() returned 0"); continue; } puts("pcap_next_ex() returned a packet"); } exit(0); } P.S.: The filter above expects ICMPv6 echo requests, so you can test the program with "ping6 IPV6ADDRESS". Thanks! Best regards, -- Fernando Gont e-mail: fernando () gont com ar || fgont () si6networks com PGP Fingerprint: 7809 84F5 322E 45C7 F1C9 3945 96EE A9EF D076 FFF1 - This is the tcpdump-workers list. Visit https://cod.sandelman.ca/ to unsubscribe.
Current thread:
- Portable way to "block" on pcap_next_ex() Fernando Gont (Jan 15)
- Re: Portable way to "block" on pcap_next_ex() Guy Harris (Jan 15)
- Re: Portable way to "block" on pcap_next_ex() Fernando Gont (Jan 15)
- Re: Portable way to "block" on pcap_next_ex() Guy Harris (Jan 15)
- Re: Portable way to "block" on pcap_next_ex() Fernando Gont (Jan 16)
- Re: Portable way to "block" on pcap_next_ex() Guy Harris (Jan 16)
- Re: Portable way to "block" on pcap_next_ex() Fernando Gont (Jan 16)
- Re: Portable way to "block" on pcap_next_ex() Guy Harris (Jan 16)
- Re: Portable way to "block" on pcap_next_ex() Fernando Gont (Jan 15)
- Re: Portable way to "block" on pcap_next_ex() Guy Harris (Jan 15)