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.