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 program WinPcap]

The sample showed in this lesson behaves exacltly like the one of the previous one (Obtaining advanced information about installed devices ), but it uses pcap_next_ex() instead of pcap_loop().

The callback-based capture mechanism of pcap_loop() is elegant and proves to be a good interface in several situations. However, handling a callback is sometimes not practical: it often makes the program more complex and it becomes a pain in situations like multithreaded applications or C++ classes.

In these cases, pcap_next_ex() allows to receive the packets with a direct call. Its parameters are the same of a capture callback: it receives 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 the main of the program, 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 */
        if (pcap_findalldevs(&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 adapter */
        if ( (adhandle= pcap_open_live(d->name, // name of the device
            65536,     // portion of the packet to capture.
            // 65536 grants that the whole packet will be captured on all the MACs.
            1,         // promiscuous mode
            1000,      // read timeout
            errbuf     // error buffer
            ) ) == NULL)
        {
            fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n");
            /* 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;
    }

Note:
  pcap_next_ex() at the moment is available only under Win32, because it's not a part of the original libpcap API. This means that source code that relies on it will not be portable under Unix.

Why we use pcap_next_ex() and not pcap_next(), that is instead available in libpcap as well? Because pcap_next() has some annoying limitations, that discourage its use in most situations. 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 hardly useful when gathering packets from a file.

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

documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.