func (p *Handle) LinkType() layers.LinkType {
	return layers.LinkType(C.pcap_datalink(p.cptr))
}
LinkType returns pcap_datalink, as a layers.LinkType.
package pcap
import "C"
import (
	"errors"
	"fmt"
	"io"
	"net"
	"reflect"
	"runtime"
	"strconv"
	"sync"
	"syscall"
	"time"
	"unsafe"
	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
)
const errorBufferSize = 256
const MaxBpfInstructions = 4096
const bpfInstructionBufferSize = 8 * MaxBpfInstructions
type Handle struct {
	cptr         *C.pcap_t
	blockForever bool
	device       string
	mu           sync.Mutex
	pkthdr  *C.struct_pcap_pkthdr
	buf_ptr *C.u_char
}
type Stats struct {
	PacketsReceived  int
	PacketsDropped   int
	PacketsIfDropped int
}
type Interface struct {
	Name        string
	Description string
	Addresses   []InterfaceAddress
}
type Datalink struct {
	Name        string
	Description string
}
type InterfaceAddress struct {
	IP      net.IP
	Netmask net.IPMask  
}
type BPF struct {
	orig string
	bpf  _Ctype_struct_bpf_program  
}
type BPFInstruction struct {
	Code uint16
	Jt   uint8
	Jf   uint8
	K    uint32
}
const BlockForever = -time.Millisecond * 10
func timeoutMillis(timeout time.Duration) C.int {
	if timeout < 0 {
		timeout *= -1
	}
	if timeout != 0 && timeout < time.Millisecond {
		timeout = time.Millisecond
	}
	return C.int(timeout / time.Millisecond)
}
func OpenLive(device string, snaplen int32, promisc bool, timeout time.Duration) (handle *Handle, _ error) {
	buf := (*C.char)(C.calloc(errorBufferSize, 1))
	defer C.free(unsafe.Pointer(buf))
	var pro C.int
	if promisc {
		pro = 1
	}
	p := &Handle{}
	p.blockForever = timeout < 0
	p.device = device
	dev := C.CString(device)
	defer C.free(unsafe.Pointer(dev))
	p.cptr = C.pcap_open_live(dev, C.int(snaplen), pro, timeoutMillis(timeout), buf)
	if p.cptr == nil {
		return nil, errors.New(C.GoString(buf))
	}
	return p, nil
}
func OpenOffline(file string) (handle *Handle, err error) {
	buf := (*C.char)(C.calloc(errorBufferSize, 1))
	defer C.free(unsafe.Pointer(buf))
	cf := C.CString(file)
	defer C.free(unsafe.Pointer(cf))
	cptr := C.pcap_open_offline(cf, buf)
	if cptr == nil {
		return nil, errors.New(C.GoString(buf))
	}
	return &Handle{cptr: cptr}, nil
}
type NextError int32
func (n NextError) Error() string {
	switch n {
	case NextErrorOk:
		return "OK"
	case NextErrorTimeoutExpired:
		return "Timeout Expired"
	case NextErrorReadError:
		return "Read Error"
	case NextErrorNoMorePackets:
		return "No More Packets In File"
	case NextErrorNotActivated:
		return "Not Activated"
	}
	return strconv.Itoa(int(n))
}
const (
	NextErrorOk             NextError = 1
	NextErrorTimeoutExpired NextError = 0
	NextErrorReadError      NextError = -1
	NextErrorNoMorePackets NextError = -2
	NextErrorNotActivated  NextError = -3
)
func (p *Handle) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
	p.mu.Lock()
	err = p.getNextBufPtrLocked(&ci)
	if err == nil {
		data = C.GoBytes(unsafe.Pointer(p.buf_ptr), C.int(ci.CaptureLength))
	}
	p.mu.Unlock()
	return
}
type activateError C.int
const (
	aeNoError      = 0
	aeActivated    = C.PCAP_ERROR_ACTIVATED
	aePromisc      = C.PCAP_WARNING_PROMISC_NOTSUP
	aeNoSuchDevice = C.PCAP_ERROR_NO_SUCH_DEVICE
	aeDenied       = C.PCAP_ERROR_PERM_DENIED
	aeNotUp        = C.PCAP_ERROR_IFACE_NOT_UP
)
func (a activateError) Error() string {
	switch a {
	case aeNoError:
		return "No Error"
	case aeActivated:
		return "Already Activated"
	case aePromisc:
		return "Cannot set as promisc"
	case aeNoSuchDevice:
		return "No Such Device"
	case aeDenied:
		return "Permission Denied"
	case aeNotUp:
		return "Interface Not Up"
	default:
		return fmt.Sprintf("unknown activated error: %d", a)
	}
}
func (p *Handle) getNextBufPtrLocked(ci *gopacket.CaptureInfo) error {
	if p.cptr == nil {
		return io.EOF
	}
	var result NextError
	for {
		result = NextError(C.pcap_next_ex(p.cptr, &p.pkthdr, &p.buf_ptr))
		if p.blockForever && result == NextErrorTimeoutExpired {
			continue
		}
		break
	}
	if result != NextErrorOk {
		if result == NextErrorNoMorePackets {
			return io.EOF
		} else {
			return result
		}
	}
	ci.Timestamp = time.Unix(int64(p.pkthdr.ts.tv_sec),
		int64(p.pkthdr.ts.tv_usec)*1000)  
	ci.CaptureLength = int(p.pkthdr.caplen)
	ci.Length = int(p.pkthdr.len)
	return nil
}
func (p *Handle) ZeroCopyReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
	p.mu.Lock()
	err = p.getNextBufPtrLocked(&ci)
	if err == nil {
		slice := (*reflect.SliceHeader)(unsafe.Pointer(&data))
		slice.Data = uintptr(unsafe.Pointer(p.buf_ptr))
		slice.Len = ci.CaptureLength
		slice.Cap = ci.CaptureLength
	}
	p.mu.Unlock()
	return
}
func (p *Handle) Close() {
	p.mu.Lock()
	if p.cptr == nil {
		return
	}
	C.pcap_close(p.cptr)
	p.cptr = nil
	p.mu.Unlock()
}
func (p *Handle) Error() error {
	return errors.New(C.GoString(C.pcap_geterr(p.cptr)))
}
func (p *Handle) Stats() (stat *Stats, err error) {
	var cstats _Ctype_struct_pcap_stat
	if -1 == C.pcap_stats(p.cptr, &cstats) {
		return nil, p.Error()
	}
	return &Stats{
		PacketsReceived:  int(cstats.ps_recv),
		PacketsDropped:   int(cstats.ps_drop),
		PacketsIfDropped: int(cstats.ps_ifdrop),
	}, nil
}
func (p *Handle) ListDataLinks() (datalinks []Datalink, err error) {
	var dlt_buf *C.int
	n := int(C.pcap_list_datalinks(p.cptr, &dlt_buf))
	if -1 == n {
		return nil, p.Error()
	}
	defer C.pcap_free_datalinks(dlt_buf)
	datalinks = make([]Datalink, n)
	dltArray := (*[100]C.int)(unsafe.Pointer(dlt_buf))
	for i := 0; i < n; i++ {
		expr := C.pcap_datalink_val_to_name((*dltArray)[i])
		datalinks[i].Name = C.GoString(expr)
		expr = C.pcap_datalink_val_to_description((*dltArray)[i])
		datalinks[i].Description = C.GoString(expr)
	}
	return datalinks, nil
}
func (p *Handle) compileBPFFilter(expr string) (_Ctype_struct_bpf_program, error) {
	errorBuf := (*C.char)(C.calloc(errorBufferSize, 1))
	defer C.free(unsafe.Pointer(errorBuf))
	var netp uint32
	var maskp uint32
	if len(p.device) > 0 {
		dev := C.CString(p.device)
		defer C.free(unsafe.Pointer(dev))
		if -1 == C.pcap_lookupnet(
			dev,
			(*C.bpf_u_int32)(unsafe.Pointer(&netp)),
			(*C.bpf_u_int32)(unsafe.Pointer(&maskp)),
			errorBuf,
		) {
		}
	}
	var bpf _Ctype_struct_bpf_program
	cexpr := C.CString(expr)
	defer C.free(unsafe.Pointer(cexpr))
	if -1 == C.pcap_compile(p.cptr, &bpf, cexpr, 1, C.bpf_u_int32(maskp)) {
		return bpf, p.Error()
	}
	return bpf, nil
}
func (p *Handle) CompileBPFFilter(expr string) ([]BPFInstruction, error) {
	bpf, err := p.compileBPFFilter(expr)
	defer C.pcap_freecode(&bpf)
	if err != nil {
		return nil, err
	}
	bpfInsn := (*[bpfInstructionBufferSize]_Ctype_struct_bpf_insn)(unsafe.Pointer(bpf.bf_insns))[0:bpf.bf_len:bpf.bf_len]
	bpfInstruction := make([]BPFInstruction, len(bpfInsn), len(bpfInsn))
	for i, v := range bpfInsn {
		bpfInstruction[i].Code = uint16(v.code)
		bpfInstruction[i].Jt = uint8(v.jt)
		bpfInstruction[i].Jf = uint8(v.jf)
		bpfInstruction[i].K = uint32(v.k)
	}
	return bpfInstruction, nil
}
func (p *Handle) SetBPFFilter(expr string) (err error) {
	bpf, err := p.compileBPFFilter(expr)
	defer C.pcap_freecode(&bpf)
	if err != nil {
		return err
	}
	if -1 == C.pcap_setfilter(p.cptr, &bpf) {
		C.pcap_freecode(&bpf)
		return p.Error()
	}
	return nil
}
func (p *Handle) SetBPFInstructionFilter(bpfInstructions []BPFInstruction) (err error) {
	bpf, err := bpfInstructionFilter(bpfInstructions)
	if err != nil {
		return err
	}
	if -1 == C.pcap_setfilter(p.cptr, &bpf) {
		C.pcap_freecode(&bpf)
		return p.Error()
	}
	C.pcap_freecode(&bpf)
	return nil
}
func bpfInstructionFilter(bpfInstructions []BPFInstruction) (bpf _Ctype_struct_bpf_program, err error) {
	if len(bpfInstructions) < 1 {
		return bpf, errors.New("bpfInstructions must not be empty")
	}
	if len(bpfInstructions) > MaxBpfInstructions {
		return bpf, fmt.Errorf("bpfInstructions must not be larger than %d", MaxBpfInstructions)
	}
	bpf.bf_len = C.u_int(len(bpfInstructions))
	cbpfInsns := C.calloc(C.size_t(len(bpfInstructions)), C.size_t(unsafe.Sizeof(bpfInstructions[0])))
	copy((*[bpfInstructionBufferSize]BPFInstruction)(cbpfInsns)[0:len(bpfInstructions)], bpfInstructions)
	bpf.bf_insns = (*_Ctype_struct_bpf_insn)(cbpfInsns)
	return
}
func (p *Handle) NewBPF(expr string) (*BPF, error) {
	bpf := &BPF{orig: expr}
	cexpr := C.CString(expr)
	defer C.free(unsafe.Pointer(cexpr))
	if C.pcap_compile(p.cptr, &bpf.bpf, cexpr  , 1, C.PCAP_NETMASK_UNKNOWN) != 0 {
		return nil, p.Error()
	}
	runtime.SetFinalizer(bpf, destroyBPF)
	return bpf, nil
}
func (p *Handle) NewBPFInstructionFilter(bpfInstructions []BPFInstruction) (*BPF, error) {
	var err error
	bpf := &BPF{orig: "BPF Instruction Filter"}
	bpf.bpf, err = bpfInstructionFilter(bpfInstructions)
	if err != nil {
		return nil, err
	}
	runtime.SetFinalizer(bpf, destroyBPF)
	return bpf, nil
}
func destroyBPF(bpf *BPF) {
	C.pcap_freecode(&bpf.bpf)
}
func (b *BPF) String() string {
	return b.orig
}
func (b *BPF) Matches(ci gopacket.CaptureInfo, data []byte) bool {
	var hdr C.struct_pcap_pkthdr
	hdr.ts.tv_sec = C.gopacket_time_secs_t(ci.Timestamp.Unix())
	hdr.ts.tv_usec = C.gopacket_time_usecs_t(ci.Timestamp.Nanosecond() / 1000)
	hdr.caplen = C.bpf_u_int32(len(data))  
	hdr.len = C.bpf_u_int32(ci.Length)
	dataptr := (*C.u_char)(unsafe.Pointer(&data[0]))
	return C.pcap_offline_filter(&b.bpf, &hdr, dataptr) != 0
}
func Version() string {
	return C.GoString(C.pcap_lib_version())
}