The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
/*
 * Pcap.xs
 *
 * XS wrapper for LBL pcap(3) library.
 *
 * Copyright (C) 2005, 2006, 2007, 2008 Sebastien Aperghis-Tramoni with code by 
 *      Jean-Louis Morel. All rights reserved.
 * Copyright (C) 2003 Marco Carnut. All rights reserved. 
 * Copyright (C) 1999 Tim Potter. All rights reserved. 
 *
 * This program is free software; you can redistribute it and/or modify it 
 * under the same terms as Perl itself.
 *
 */

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _CYGWIN
#include <windows.h>
#endif

#ifdef _WIN32
#include <malloc.h>
#endif

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#define NEED_PL_signals 1
#define NEED_sv_2pv_nolen 1
#include "ppport.h"

#include <pcap.h>

#ifdef _CYGWIN
#include <Win32-Extensions.h>
#endif

#include "const-c.inc"
#include "stubs.inc"

#ifdef __cplusplus
}
#endif


typedef struct bpf_program  pcap_bpf_program_t;

/* Wrapper for callback function */

SV *callback_fn;

void callback_wrapper(u_char *user, const struct pcap_pkthdr *h, const u_char *pkt) {
    SV *packet  = newSVpv((u_char *)pkt, h->caplen);
    HV *hdr     = newHV();
    SV *ref_hdr = newRV_inc((SV*)hdr);

    /* Fill the hash fields */
    hv_store(hdr, "tv_sec",  strlen("tv_sec"),  newSViv(h->ts.tv_sec),  0);
    hv_store(hdr, "tv_usec", strlen("tv_usec"), newSViv(h->ts.tv_usec), 0);
    hv_store(hdr, "caplen",  strlen("caplen"),  newSVuv(h->caplen),     0);
    hv_store(hdr, "len",     strlen("len"),     newSVuv(h->len),        0);	

    /* Push arguments onto stack */
    dSP;
    PUSHMARK(sp);
    XPUSHs((SV*)user);
    XPUSHs(ref_hdr);
    XPUSHs(packet);
    PUTBACK;

    /* Call perl function */
    call_sv (callback_fn, G_DISCARD);

    /* Decrement refcount to temp SVs */
    SvREFCNT_dec(packet);
    SvREFCNT_dec(hdr);
    SvREFCNT_dec(ref_hdr);
}


MODULE = Net::Pcap      PACKAGE = Net::Pcap     PREFIX = pcap_

INCLUDE: const-xs.inc

PROTOTYPES: DISABLE


char *
pcap_lookupdev(err)
	SV *err

	CODE:
		if (SvROK(err)) {
			char *errbuf = safemalloc(PCAP_ERRBUF_SIZE+1);
			SV *err_sv = SvRV(err);

			RETVAL = pcap_lookupdev(errbuf);
#ifdef WPCAP
			{
				int length = lstrlenW((PWSTR)RETVAL) + 2;
				char *r = safemalloc(length);  /* Conversion from Unicode to ANSI */
				WideCharToMultiByte(CP_ACP, 0, (PWSTR)RETVAL, -1, r, length, NULL, NULL);	
				lstrcpyA(RETVAL, r);
				safefree(r);
			}
#endif /* WPCAP */
			if (RETVAL == NULL) {
				sv_setpv(err_sv, errbuf);
			} else {
				err_sv = &PL_sv_undef;
			}

			safefree(errbuf);

		} else
			croak("arg1 not a hash ref");

	OUTPUT:
		RETVAL
		err


int
pcap_lookupnet(device, net, mask, err)
	const char *device
	SV *net
	SV *mask
	SV *err

	CODE:
		if (SvROK(net) && SvROK(mask) && SvROK(err)) {
			char *errbuf = safemalloc(PCAP_ERRBUF_SIZE+1);
			bpf_u_int32 netp, maskp;
			SV *net_sv  = SvRV(net);
			SV *mask_sv = SvRV(mask);
			SV *err_sv  = SvRV(err);

			RETVAL = pcap_lookupnet(device, &netp, &maskp, errbuf);

			netp = ntohl(netp);
			maskp = ntohl(maskp);

			if (RETVAL != -1) {
				sv_setuv(net_sv, netp);
				sv_setuv(mask_sv, maskp);
				err_sv = &PL_sv_undef;
			} else {
				sv_setpv(err_sv, errbuf);
			}

			safefree(errbuf);

		} else {
			RETVAL = -1;
			if (!SvROK(net )) croak("arg2 not a reference");
			if (!SvROK(mask)) croak("arg3 not a reference");
			if (!SvROK(err )) croak("arg4 not a reference");
		}

	OUTPUT:
		net
		mask
		err
		RETVAL


void
pcap_findalldevs_xs(devinfo, err)
    SV * devinfo
    SV * err
 
    PREINIT:
        char *errbuf = safemalloc(PCAP_ERRBUF_SIZE+1);
    
    PPCODE:
        if ( SvROK(err) && SvROK(devinfo) && (SvTYPE(SvRV(devinfo)) == SVt_PVHV) ) {
            int r;
            pcap_if_t *alldevs, *d;
            HV *hv;
            SV *err_sv = SvRV(err);
            
            hv = (HV *)SvRV(devinfo);
            
            r = pcap_findalldevs(&alldevs, errbuf);

            switch(r) {
                case 0: /* normal case */
                    for (d=alldevs; d; d=d->next) {
                        XPUSHs(sv_2mortal(newSVpv(d->name, 0)));

                        if (d->description)
                            hv_store(hv, d->name, strlen(d->name), newSVpv(d->description, 0), 0);
                        else
                            if( (strcmp(d->name,"lo") == 0) || (strcmp(d->name,"lo0") == 0)) 
                                hv_store(hv, d->name, strlen(d->name), 
                                        newSVpv("Loopback device", 0), 0);
                            else
                                hv_store(hv, d->name, strlen(d->name), 
                                        newSVpv("No description available", 0), 0);
                    }
            
                    pcap_freealldevs(alldevs);
                    err_sv = &PL_sv_undef;
                    break;

                case 3: { /* function is not available */
                    char *dev = pcap_lookupdev(errbuf);

                    if(dev == NULL) {
                        sv_setpv(err_sv, errbuf);
                        break;
                    }

                    XPUSHs(sv_2mortal(newSVpv(dev, 0)));
                    if( (strcmp(dev,"lo") == 0) || (strcmp(dev,"lo0") == 0)) 
                        hv_store(hv, dev, strlen(dev), newSVpv("", 0), 0);
                    else
                        hv_store(hv, dev, strlen(dev), newSVpv("No description available", 0), 0);
                    break;
                }

                case -1: /* error */
                    sv_setpv(err_sv, errbuf); 
                    break;
            }
        } else {
            if ( !SvROK(devinfo) || (SvTYPE(SvRV(devinfo)) != SVt_PVHV) ) 
                croak("arg1 not a hash ref");
            if ( !SvROK(err) )
                croak("arg2 not a scalar ref");
        }
        safefree(errbuf);


pcap_t *
pcap_open_live(device, snaplen, promisc, to_ms, err)
	const char *device
	int snaplen
	int promisc
	int to_ms
	SV *err;

	CODE:
		if (SvROK(err)) {
			char *errbuf = safemalloc(PCAP_ERRBUF_SIZE+1);
			SV *err_sv = SvRV(err);
#ifdef _MSC_VER
            /* Net::Pcap hangs when to_ms == 0 under ActivePerl/MSVC */
            if(to_ms == 0) to_ms = 1;
#endif
			RETVAL = pcap_open_live(device, snaplen, promisc, to_ms, errbuf);

			if (RETVAL == NULL) {
				sv_setpv(err_sv, errbuf);
			} else {
				err_sv = &PL_sv_undef;
			}

			safefree(errbuf);

		} else
			croak("arg5 not a reference");

	OUTPUT:
		err
		RETVAL


pcap_t *
pcap_open_dead(linktype, snaplen)
    int linktype
    int snaplen

    OUTPUT:
        RETVAL


pcap_t *
pcap_open_offline(fname, err)
	const char *fname
	SV *err

	CODE:
		if (SvROK(err)) {
			char *errbuf = safemalloc(PCAP_ERRBUF_SIZE+1);
			SV *err_sv = SvRV(err);

			RETVAL = pcap_open_offline(fname, errbuf);

			if (RETVAL == NULL) {
				sv_setpv(err_sv, errbuf);
			} else {
				err_sv = &PL_sv_undef;
			}

			safefree(errbuf);

		} else
			croak("arg2 not a reference");	

	OUTPUT:
		err
		RETVAL


pcap_dumper_t *
pcap_dump_open(p, fname)
	pcap_t *p
	const char *fname


int
pcap_setnonblock(p, nb, err)
	pcap_t *p
	int nb
	SV *err

	CODE:
		if (SvROK(err)) {
			char *errbuf = safemalloc(PCAP_ERRBUF_SIZE+1);
			SV *err_sv = SvRV(err);

			RETVAL = pcap_setnonblock(p, nb, errbuf);

			if (RETVAL == -1) {
				sv_setpv(err_sv, errbuf);
			} else {
				err_sv = &PL_sv_undef;
			}

			safefree(errbuf);

		} else
			croak("arg3 not a reference");	

	OUTPUT:
		err
		RETVAL


int
pcap_getnonblock(p, err)
    pcap_t *p
    SV *err

    CODE:
        if (SvROK(err)) {
            char *errbuf = safemalloc(PCAP_ERRBUF_SIZE+1);
            SV *err_sv = SvRV(err);

            RETVAL = pcap_getnonblock(p, errbuf);

            if (RETVAL == -1) {
                sv_setpv(err_sv, errbuf);
            } else {
                err_sv = &PL_sv_undef;
            }

            safefree(errbuf);

		} else
			croak("arg2 not a reference");	

  OUTPUT:
    err
    RETVAL


int
pcap_dispatch(p, cnt, callback, user)
	pcap_t *p
	int cnt
	SV *callback
	SV *user

	CODE:
    {
		U32 SAVE_signals;
		callback_fn = newSVsv(callback);
		user = newSVsv(user);

		*(pcap_geterr(p)) = '\0';   /* reset error string */

		SAVE_signals = PL_signals;  /* Allow the call to be interrupted by signals */
		PL_signals |= PERL_SIGNALS_UNSAFE_FLAG;
		RETVAL = pcap_dispatch(p, cnt, callback_wrapper, (u_char *)user);
		PL_signals = SAVE_signals;

		SvREFCNT_dec(user);
		SvREFCNT_dec(callback_fn);
    }	
	OUTPUT:
		RETVAL


int
pcap_loop(p, cnt, callback, user)
	pcap_t *p
	int cnt
	SV *callback
	SV *user

	CODE:
    {
		U32 SAVE_signals;
		callback_fn = newSVsv(callback);
		user = newSVsv(user);

		SAVE_signals = PL_signals;  /* Allow the call to be interrupted by signals */
		PL_signals |= PERL_SIGNALS_UNSAFE_FLAG;
		RETVAL = pcap_loop(p, cnt, callback_wrapper, (u_char *)user);
		PL_signals = SAVE_signals;

		SvREFCNT_dec(user);
		SvREFCNT_dec(callback_fn);
    }
	OUTPUT:
		RETVAL


SV *
pcap_next(p, pkt_header)
	pcap_t *p
	SV *pkt_header

	CODE:
		if (SvROK(pkt_header) && (SvTYPE(SvRV(pkt_header)) == SVt_PVHV)) {
			struct pcap_pkthdr real_h;
			const u_char *result;
			U32 SAVE_signals;
			HV *hv;

			memset(&real_h, '\0', sizeof(real_h));

			SAVE_signals = PL_signals;  /* Allow the call to be interrupted by signals */
			PL_signals |= PERL_SIGNALS_UNSAFE_FLAG;
			result = pcap_next(p, &real_h);
			PL_signals = SAVE_signals;

			hv = (HV *)SvRV(pkt_header);	
	
			if (result != NULL) {
				hv_store(hv, "tv_sec",  strlen("tv_sec"),  newSViv(real_h.ts.tv_sec),  0);
				hv_store(hv, "tv_usec", strlen("tv_usec"), newSViv(real_h.ts.tv_usec), 0);
				hv_store(hv, "caplen",  strlen("caplen"),  newSVuv(real_h.caplen),     0);
				hv_store(hv, "len",     strlen("len"),     newSVuv(real_h.len),        0);	

				RETVAL = newSVpv((char *)result, real_h.caplen);

			} else 
				RETVAL = &PL_sv_undef;

		} else
            croak("arg2 not a hash ref");	

    OUTPUT:
        pkt_header
        RETVAL     


int
pcap_next_ex(p, pkt_header, pkt_data)
    pcap_t *p
    SV *pkt_header
    SV *pkt_data

    CODE:
        /* Check if pkt_header is a hashref and pkt_data a scalarref */
        if (SvROK(pkt_header) && (SvTYPE(SvRV(pkt_header)) == SVt_PVHV) && SvROK(pkt_data)) {
			struct pcap_pkthdr *header;
			const u_char *data;
			U32 SAVE_signals;
			HV *hv;

			memset(&header, '\0', sizeof(header));

			SAVE_signals = PL_signals;  /* Allow the call to be interrupted by signals */
			PL_signals |= PERL_SIGNALS_UNSAFE_FLAG;
			RETVAL = pcap_next_ex(p, &header, &data);
			PL_signals = SAVE_signals;

			hv = (HV *)SvRV(pkt_header);	

			if (RETVAL == 1) {
                hv_store(hv, "tv_sec",  strlen("tv_sec"),  newSViv(header->ts.tv_sec),  0);
                hv_store(hv, "tv_usec", strlen("tv_usec"), newSViv(header->ts.tv_usec), 0);
                hv_store(hv, "caplen",  strlen("caplen"),  newSVuv(header->caplen),     0);
                hv_store(hv, "len",     strlen("len"),     newSVuv(header->len),        0);	

                sv_setpvn((SV *)SvRV(pkt_data), data, header->caplen);
            }

        } else {
            RETVAL = -1;
            if (!SvROK(pkt_header) || (SvTYPE(SvRV(pkt_header)) != SVt_PVHV))
                croak("arg2 not a hash ref");
            if (!SvROK(pkt_data))
                croak("arg3 not a scalar ref");
        }

    OUTPUT:
        pkt_header
        pkt_data
        RETVAL


void 
pcap_dump(p, pkt_header, sp)
	pcap_dumper_t *p
	SV *pkt_header
	SV *sp

	CODE:
		/* Check if pkt_header is a hashref */
		if (SvROK(pkt_header) && (SvTYPE(SvRV(pkt_header)) == SVt_PVHV)) {
		        struct pcap_pkthdr real_h;
			char *real_sp;
			HV *hv;
			SV **sv;

			memset(&real_h, '\0', sizeof(real_h));

			/* Copy from hash to pcap_pkthdr */
			hv = (HV *)SvRV(pkt_header);

			sv = hv_fetch(hv, "tv_sec", strlen("tv_sec"), 0);
			if (sv != NULL) {
				real_h.ts.tv_sec = SvIV(*sv);
			}

			sv = hv_fetch(hv, "tv_usec", strlen("tv_usec"), 0);
			if (sv != NULL) {
				real_h.ts.tv_usec = SvIV(*sv);
			}

			sv = hv_fetch(hv, "caplen", strlen("caplen"), 0);
			if (sv != NULL) {
			        real_h.caplen = SvIV(*sv);
		        }

			sv = hv_fetch(hv, "len", strlen("len"), 0);
			if (sv != NULL) {
			        real_h.len = SvIV(*sv);
			}

			real_sp = SvPV(sp, PL_na);

			/* Call pcap_dump() */
			pcap_dump((u_char *)p, &real_h, real_sp);

		} else
            croak("arg2 not a hash ref");


int 
pcap_compile(p, fp, str, optimize, mask)
	pcap_t *p
	SV *fp
	char *str
	int optimize
	bpf_u_int32 mask

	CODE:
		if (SvROK(fp)) {
			pcap_bpf_program_t *real_fp = safemalloc(sizeof(pcap_bpf_program_t));
			*(pcap_geterr(p)) = '\0';   /* reset error string */
			RETVAL = pcap_compile(p, real_fp, str, optimize, mask);
			sv_setref_pv(SvRV(fp), "pcap_bpf_program_tPtr", (void *)real_fp);

		} else
			croak("arg2 not a reference");

	OUTPUT:
		fp
		RETVAL


int
pcap_compile_nopcap(snaplen, linktype, fp, str, optimize, mask)
    int snaplen
    int linktype
	SV *fp
	char *str
	int optimize
	bpf_u_int32 mask

    CODE:
		if (SvROK(fp)) {
			pcap_bpf_program_t *real_fp = safemalloc(sizeof(pcap_bpf_program_t));
			RETVAL = pcap_compile_nopcap(snaplen, linktype, real_fp, str, optimize, mask);
			sv_setref_pv(SvRV(fp), "pcap_bpf_program_tPtr", (void *)real_fp);

		} else
			croak("arg3 not a reference");

    OUTPUT:
        fp
        RETVAL


int 
pcap_setfilter(p, fp)
	pcap_t *p
	pcap_bpf_program_t *fp


void
pcap_freecode(fp)
	pcap_bpf_program_t *fp


void
pcap_breakloop(p)
    pcap_t *p


void
pcap_close(p)
	pcap_t *p


void
pcap_dump_close(p)
	pcap_dumper_t *p


FILE *
pcap_dump_file(p)
	pcap_dumper_t *p


int
pcap_dump_flush(p)
	pcap_dumper_t *p


int 
pcap_datalink(p)
	pcap_t *p


int
pcap_set_datalink(p, linktype)
    pcap_t *p
    int linktype


int
pcap_datalink_name_to_val(name)
    const char *name


const char *
pcap_datalink_val_to_name(linktype)
    int linktype


const char *
pcap_datalink_val_to_description(linktype)
    int linktype


int 
pcap_snapshot(p)
	pcap_t *p


int 
pcap_is_swapped(p)
	pcap_t *p


int 
pcap_major_version(p)
	pcap_t *p


int 
pcap_minor_version(p)
	pcap_t *p


void
pcap_perror(p, prefix)
	pcap_t *p
	char *prefix
 

char *
pcap_geterr(p)
	pcap_t *p


char *
pcap_strerror(error)
	int error


const char *
pcap_lib_version()


FILE *
pcap_file(p)
	pcap_t *p


int
pcap_fileno(p)
	pcap_t *p


int
pcap_get_selectable_fd(p)
	pcap_t *p


int
pcap_stats(p, ps)
	pcap_t *p;
	SV *ps;

	CODE:
		/* Call pcap_stats() function */

		if (SvROK(ps) && (SvTYPE(SvRV(ps)) == SVt_PVHV)) {
			struct pcap_stat real_ps;
			HV *hv;

			*(pcap_geterr(p)) = '\0';   /* reset error string */

			RETVAL = pcap_stats(p, &real_ps);

			/* Copy pcap_stats fields into hash */

			hv = (HV *)SvRV(ps);

			hv_store(hv, "ps_recv", strlen("ps_recv"), 
						newSVuv(real_ps.ps_recv), 0);
			hv_store(hv, "ps_drop", strlen("ps_drop"), 
						newSVuv(real_ps.ps_drop), 0);
			hv_store(hv, "ps_ifdrop", strlen("ps_ifdrop"), 
						newSVuv(real_ps.ps_ifdrop), 0);

		} else
            croak("arg2 not a hash ref");

	OUTPUT:
		RETVAL


int
pcap_createsrcstr(source, type, host, port, name, err)
    SV *    source 
    int     type  
    char *  host 
    char *  port  
    char *  name
    SV *    err

    CODE:
        if (SvROK(source) && SvROK(err)) {
            char *errbuf = safemalloc(PCAP_ERRBUF_SIZE);
            char *sourcebuf = safemalloc(PCAP_BUF_SIZE);
            SV *err_sv = SvRV(err);
            SV *source_sv = SvRV(source);

            RETVAL = pcap_createsrcstr(sourcebuf, type, host, port, name, errbuf);

            if (RETVAL != -1) {
                sv_setpv(source_sv, sourcebuf);
                err_sv = &PL_sv_undef;
            } else {
                sv_setpv(err_sv, errbuf);
            }

            safefree(errbuf);
            safefree(sourcebuf);

        } else {
            RETVAL = -1;
            if (!SvROK(source)) croak("arg1 not a reference");
            if (!SvROK(err)) croak("arg6 not a reference");
        }

    OUTPUT:
        source
        err
        RETVAL


int
pcap_parsesrcstr(source, type, host, port, name, err)
    char * source  
    SV *   type 
    SV *   host 
    SV *   port  
    SV *   name 
    SV *   err 

    CODE:
        if ( !SvROK(type) ) croak("arg2 not a reference");   
        if ( !SvROK(host) ) croak("arg3 not a reference");  
        if ( !SvROK(port) ) croak("arg4 not a reference");
        if ( !SvROK(name) ) croak("arg5 not a reference");

        if ( !SvROK(err) )
            croak("arg6 not a reference");

        else {  
            int rtype;
            char *hostbuf = safemalloc(PCAP_BUF_SIZE);
            char *portbuf = safemalloc(PCAP_BUF_SIZE);
            char *namebuf = safemalloc(PCAP_BUF_SIZE);
            char *errbuf  = safemalloc(PCAP_ERRBUF_SIZE);
            SV *type_sv = SvRV(type);
            SV *host_sv = SvRV(host);
            SV *port_sv = SvRV(port);
            SV *name_sv = SvRV(name);    
            SV *err_sv = SvRV(err);    

            RETVAL = pcap_parsesrcstr(source, &rtype, hostbuf, portbuf, namebuf, errbuf);

            if (RETVAL != -1) {
                sv_setiv(type_sv, rtype);
                sv_setpv(host_sv, hostbuf);
                sv_setpv(port_sv, portbuf);
                sv_setpv(name_sv, namebuf);				
                err_sv = &PL_sv_undef;
            } else {
                sv_setpv(err_sv, errbuf);
            }

            safefree(hostbuf);
            safefree(portbuf);
            safefree(namebuf);
            safefree(errbuf);
        }

    OUTPUT:
        type
        host
        port
        name
        err
        RETVAL


pcap_t *
pcap_open(source, snaplen, flags, read_timeout, auth, err)
    char *source
    int snaplen
    int flags
    int read_timeout
    SV *auth
    SV *err

    CODE:
        if (!SvROK(err))
            croak("arg6 not a reference");

        if ( !SvOK(auth) || (SvOK(auth) && SvROK(auth) && (SvTYPE(SvRV(auth)) == SVt_PVHV)) ) {
            struct pcap_rmtauth real_auth;
            struct pcap_rmtauth * preal_auth;
            char *errbuf = safemalloc(PCAP_ERRBUF_SIZE);
            SV *err_sv = SvRV(err);

            if (!SvOK(auth)) {      /* if auth (struct pcap_rmtauth) is undef */
                preal_auth = NULL;

            } else {                    /* auth (struct pcap_rmtauth) is a hashref */  
                HV *hv;
                SV **sv;

                memset(&real_auth, '\0', sizeof(real_auth));

                /* Copy from hash to pcap_rmtauth */
                hv = (HV *)SvRV(auth);
                sv = hv_fetch(hv, "type", strlen("type"), 0);

                if (sv != NULL)
                    real_auth.type = SvIV(*sv);

                sv = hv_fetch(hv, "username", strlen("username"), 0);

                if (sv != NULL)
                    real_auth.username = SvPV(*sv, PL_na);

                sv = hv_fetch(hv, "password", strlen("password"), 0);

                if (sv != NULL)
                    real_auth.password = SvPV(*sv, PL_na);

                preal_auth = &real_auth;
            }

            RETVAL = pcap_open(source, snaplen, flags, read_timeout, preal_auth, errbuf); 

            if (RETVAL == NULL) {
                sv_setpv(err_sv, errbuf);				
            } else {
                err_sv = &PL_sv_undef;
            }  	  

            safefree(errbuf);

        } else
            croak("arg5 not a hash ref");

    OUTPUT:
        RETVAL
        err


int
pcap_setuserbuffer(p, size)
    pcap_t *p
    int size


int
pcap_setbuff(p, dim)
    pcap_t *p
    int dim


int
pcap_setmode (p, mode)
    pcap_t *p
    int mode


int
pcap_setmintocopy(p, size) 
    pcap_t *p
    int size


void
pcap_getevent(p)
    pcap_t *p

    PREINIT:
        unsigned int h;

    PPCODE:
        h = (unsigned int) pcap_getevent(p);  
        ST(0) = sv_newmortal();
        sv_setref_iv(ST(0), "Win32::Event", h);
        XSRETURN(1);

 
int 
pcap_sendpacket(p, buf)
    pcap_t *p
    SV *buf

    CODE:
        RETVAL = pcap_sendpacket(p, SvPVX(buf), sv_len(buf));  

    OUTPUT:
        RETVAL


pcap_send_queue * 
pcap_sendqueue_alloc(memsize)
    u_int memsize


MODULE = Net::Pcap      PACKAGE = pcap_send_queuePtr

void
DESTROY(queue)
    pcap_send_queue * queue

    CODE:
        pcap_sendqueue_destroy(queue);


MODULE = Net::Pcap      PACKAGE = Net::Pcap     PREFIX = pcap_

int
pcap_sendqueue_queue(queue, header, p)
    pcap_send_queue * queue
    SV *header
    SV *p

    CODE:
        /* Check that header is a hashref */
        if (SvROK(header) && (SvTYPE(SvRV(header)) == SVt_PVHV)) {
            struct pcap_pkthdr real_h;
            char *real_p;
            HV *hv;
            SV **sv;

            memset(&real_h, '\0', sizeof(real_h));

            /* Copy from hash to pcap_pkthdr */
            hv = (HV *)SvRV(header);

            sv = hv_fetch(hv, "tv_sec", strlen("tv_sec"), 0);
            if (sv != NULL) {
                real_h.ts.tv_sec = SvIV(*sv);
            }

            sv = hv_fetch(hv, "tv_usec", strlen("tv_usec"), 0);
            if (sv != NULL) {
                real_h.ts.tv_usec = SvIV(*sv);
            }

            sv = hv_fetch(hv, "caplen", strlen("caplen"), 0);
            if (sv != NULL) {
                real_h.caplen = SvIV(*sv);
            }

            sv = hv_fetch(hv, "len", strlen("len"), 0);
            if (sv != NULL) {
                real_h.len = SvIV(*sv);
            }

            real_p = SvPV(p, PL_na);

            /* Call pcap_sendqueue_queue() */
            RETVAL = pcap_sendqueue_queue(queue, &real_h, (unsigned char *) real_p);

        } else
            croak("arg2 not a hash ref");

    OUTPUT:
        RETVAL	


u_int
pcap_sendqueue_transmit(p, queue, sync)
    pcap_t *p
    pcap_send_queue * queue
    int sync