Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

Capturing the packets without the callback
[WinPcap tutorial: a step by step guide to using WinPcap]

The example program in this lesson behaves exactly like the previous program (Opening an adapter and capturing the packets), but it uses pcap_next_ex() instead of pcap_loop().

The callback-based capture mechanism of pcap_loop() is elegant and it could be a good choice in some situations. However, handling a callback is sometimes not practical -- it often makes the program more complex especially in situations with multithreaded applications or C++ classes.

In these cases, pcap_next_ex() retrievs a packet with a direct call -- using pcap_next_ex() packets are received only when the programmer wants them.

The parameters of this function are the same as a capture callback -- it takes an adapter descriptor and a couple of pointers that will be initialized and returned to the user (one to a pcap_pkthdr structure and another to a buffer with the packet data).

In the following program, we recycle the callback code of the previous lesson's example and move it inside main() right after the call to pcap_next_ex().

#include "pcap.h" main() { pcap_if_t *alldevs; pcap_if_t *d; int inum; int i=0; pcap_t *adhandle; int res; char errbuf[PCAP_ERRBUF_SIZE]; struct tm *ltime; char timestr[16]; struct pcap_pkthdr *header; u_char *pkt_data; /* Retrieve the device list on the local machine */ if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) { fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); exit(1); } /* Print the list */ for(d=alldevs; d; d=d->next) { printf("%d. %s", ++i, d->name); if (d->description) printf(" (%s)\n", d->description); else printf(" (No description available)\n"); } if(i==0) { printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); return -1; } printf("Enter the interface number (1-%d):",i); scanf("%d", &inum); if(inum < 1 || inum > i) { printf("\nInterface number out of range.\n"); /* Free the device list */ pcap_freealldevs(alldevs); return -1; } /* Jump to the selected adapter */ for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); /* Open the device */ if ( (adhandle= pcap_open(d->name, // name of the device 65536, // portion of the packet to capture. // 65536 guarantees that the whole packet will be captured on all the link layers PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode 1000, // read timeout NULL, // authentication on the remote machine errbuf // error buffer ) ) == NULL) { fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name); /* Free the device list */ pcap_freealldevs(alldevs); return -1; } printf("\nlistening on %s...\n", d->description); /* At this point, we don't need any more the device list. Free it */ pcap_freealldevs(alldevs); /* Retrieve the packets */ while((res = pcap_next_ex( adhandle, &header, &pkt_data)) >= 0){ if(res == 0) /* Timeout elapsed */ continue; /* convert the timestamp to readable format */ ltime=localtime(&header->ts.tv_sec); strftime( timestr, sizeof timestr, "%H:%M:%S", ltime); printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len); } if(res == -1){ printf("Error reading the packets: %s\n", pcap_geterr(adhandle)); return -1; } return 0; }
00001 #include "pcap.h" 00002 00003 00004 main() 00005 { 00006 pcap_if_t *alldevs; 00007 pcap_if_t *d; 00008 int inum; 00009 int i=0; 00010 pcap_t *adhandle; 00011 int res; 00012 char errbuf[PCAP_ERRBUF_SIZE]; 00013 struct tm *ltime; 00014 char timestr[16]; 00015 struct pcap_pkthdr *header; 00016 u_char *pkt_data; 00017 00018 00019 /* Retrieve the device list on the local machine */ 00020 if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) 00021 { 00022 fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); 00023 exit(1); 00024 } 00025 00026 /* Print the list */ 00027 for(d=alldevs; d; d=d->next) 00028 { 00029 printf("%d. %s", ++i, d->name); 00030 if (d->description) 00031 printf(" (%s)\n", d->description); 00032 else 00033 printf(" (No description available)\n"); 00034 } 00035 00036 if(i==0) 00037 { 00038 printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); 00039 return -1; 00040 } 00041 00042 printf("Enter the interface number (1-%d):",i); 00043 scanf("%d", &inum); 00044 00045 if(inum < 1 || inum > i) 00046 { 00047 printf("\nInterface number out of range.\n"); 00048 /* Free the device list */ 00049 pcap_freealldevs(alldevs); 00050 return -1; 00051 } 00052 00053 /* Jump to the selected adapter */ 00054 for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); 00055 00056 /* Open the device */ 00057 if ( (adhandle= pcap_open(d->name, // name of the device 00058 65536, // portion of the packet to capture. 00059 // 65536 guarantees that the whole packet will be captured on all the link layers 00060 PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode 00061 1000, // read timeout 00062 NULL, // authentication on the remote machine 00063 errbuf // error buffer 00064 ) ) == NULL) 00065 { 00066 fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name); 00067 /* Free the device list */ 00068 pcap_freealldevs(alldevs); 00069 return -1; 00070 } 00071 00072 printf("\nlistening on %s...\n", d->description); 00073 00074 /* At this point, we don't need any more the device list. Free it */ 00075 pcap_freealldevs(alldevs); 00076 00077 /* Retrieve the packets */ 00078 while((res = pcap_next_ex( adhandle, &header, &pkt_data)) >= 0){ 00079 00080 if(res == 0) 00081 /* Timeout elapsed */ 00082 continue; 00083 00084 /* convert the timestamp to readable format */ 00085 ltime=localtime(&header->ts.tv_sec); 00086 strftime( timestr, sizeof timestr, "%H:%M:%S", ltime); 00087 00088 printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len); 00089 } 00090 00091 if(res == -1){ 00092 printf("Error reading the packets: %s\n", pcap_geterr(adhandle)); 00093 return -1; 00094 } 00095 00096 return 0; 00097 }

Why do we use pcap_next_ex() instead of the old pcap_next()? Because pcap_next() has some drawbacks. First of all, it is inefficient because it hides the callback method but still relies on pcap_dispatch(). Second, it is not able to detect EOF, so it's not very useful when gathering packets from a file.

Notice also that pcap_next_ex() returns different values for success, timeout elapsed, error and EOF conditions.

<<< Previous Next >>>


documentation. Copyright (c) 2002-2005 Politecnico di Torino. Copyright (c) 2005 CACE technologies. All rights reserved.