/**
 * Sample libpcap client demonstrating buffer integrity problem.
 */

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>

#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/if_tun.h>

#include <pcap/pcap.h>
#include <assert.h>

//** uncomment to enable debugging
// #define DBGPRINTF(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
#define DBGPRINTF(fmt, ...)

pcap_t*
pcapAlloc(const char *dev) {
    pcap_t *handle;
    char errbuf[PCAP_ERRBUF_SIZE];

    handle = pcap_open_live(dev, 64 * 1024 /* snaplen */, 1 /* promisc */, 1 /* timeout */, errbuf);
    if (handle == NULL) {
        fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
        exit(EXIT_FAILURE);
    }

    return handle;
}

void
processPacket(const unsigned char *p, bpf_u_int32 caplen) {
    static unsigned char backup[64 * 1024];

    assert(caplen <= sizeof (backup));
    memcpy(backup, p, caplen);

    usleep(2000); // this helps making the problem worse

    assert(memcmp(backup, p, caplen) == 0);
}

void
processPcap(pcap_t *pcap) {
    struct pcap_pkthdr *hp;
    const unsigned char *pp;

    if (pcap_next_ex(pcap, &hp, &pp) < 0) {
        pcap_perror(pcap, "pcap_next_ex");
    } else {
        DBGPRINTF("got %d bytes from pcap1\n", hp->caplen);
        
        processPacket(pp, hp->caplen);
    }
}

int
main(int argc, char *argv[]) {
    assert(argc == 2);
    pcap_t *pcap = pcapAlloc(argv[1]);

    for (;;) {
        processPcap(pcap);
    }
}
