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 it could be a good choice in some 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. Using pcap_next_ex() gives the complete control of the code to the programmer because the packets are received only when the programmer wants them.

The parameters of this function 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 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 annoying limitations. 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.

<<< Previous Next >>>

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