Documentation
#![allow(non_camel_case_types)]
#![allow(warnings, unused)]
#![allow(dead_code)]

use std::ffi::{self, CStr, CString};
use libc::{c_char,c_uchar,c_int,c_uint};
use std::ptr;
use std::time;
use std::fmt;
use std::mem;
mod clib;

use clib::{pcap_t,pcap_pkthdr};

pub struct Packet {
    pub handle: *mut pcap_t,
    pub head: pcap_pkthdr,
    pub data: *const u8,
}

impl Packet {
    fn new(handle: *mut pcap_t) -> Packet {
        let mut head = make_pkthdr();
        let mut p = Packet { 
            handle: handle,
            head: head, 
            data: ptr::null() ,
         };
        p
    }
}

impl fmt::Debug for Packet{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ret = write!(
            f,
            "Packet {{ ts: {}.{:06}, caplen: {}, len: {} }}",
            self.head.ts.tv_sec, self.head.ts.tv_usec, self.head.caplen, self.head.len
        );
        println!("Data  {:?},Length {:?}",self.data,self.head.len);
	unsafe {
		for i in 0..self.head.len{
			let a = self.data.offset(i as isize);
			print!("0x{:02x}, ",*a);		
		}
	}
		println!();
		ret
    }
}

#[inline]
unsafe fn cstr_to_string(ptr: *const libc::c_char) -> String {

    CStr::from_ptr(ptr as _).to_str().unwrap().to_owned()
}

pub fn make_pkthdr( ) -> clib::pcap_pkthdr {

    let duration = time::Duration::new(10,0);

    clib::pcap_pkthdr{
        ts:
            libc::timeval {
            tv_sec: duration.as_secs() as i64,
            tv_usec: duration.subsec_micros() as libc::suseconds_t,
            },
        caplen : 0,
        len :0,
    }
}



pub fn lookup( ) -> String{

	let mut errbuf = [0i8; 256];
	let devs = unsafe {
		let devices = clib::pcap_lookupdev(errbuf.as_mut_ptr());
		cstr_to_string(devices)
	};

	devs	
}

pub fn lookupnet(interface_name: &str,netp:&mut c_uint,maskp:&mut c_uint)->c_int{
 
    let mut errbuf = [0i8; 256];
    let interface_name = CString::new(interface_name).unwrap();

    let ret = unsafe{

        let ret = clib::pcap_lookupnet(interface_name.as_ptr(), netp, maskp, errbuf.as_mut_ptr());
        if (ret == -1){
            println!("{:?}",errbuf);
        }
        ret
    };
    ret 
}


pub fn findalldevs() -> Vec<String> {

        let mut errbuf = [0i8; 256];
        let devices = unsafe {
            let mut dev_buf: *mut clib::pcap_if_t = ptr::null_mut();
            if clib::pcap_findalldevs(&mut dev_buf, errbuf.as_mut_ptr()) != 0 {
                panic!("Not Find any devices!");
            }

           let mut devices = vec![];
            let mut cur = dev_buf;
            while !cur.is_null() {
                let dev = &*cur;
                let name = cstr_to_string(dev.name);                 
                devices.push(name);

                cur = dev.next;
            }
            clib::pcap_freealldevs(dev_buf);
            devices
        };
        devices

}

pub fn setfilter(p:&mut Packet,s:&str){
    let program = CString::new(s).unwrap();
    unsafe {
        let mut bpf_program: clib::bpf_program = mem::zeroed();
        let ret = clib::pcap_compile(
            (*p).handle,
            &mut bpf_program,
            program.as_ptr(),
            1,
            0,
        );
        if (ret == -1){
            println!("Set filter Failed!");
        }
        let ret = clib::pcap_setfilter((*p).handle, &mut bpf_program);
        clib::pcap_freecode(&mut bpf_program);
         
    }

}

pub fn open(interface_name: &str)->Packet{

	let snaplen :i32 = 5000;
	let promisc   = true;
	let read_timeout_ms :i32 = 2000;

	open_live(interface_name,snaplen,promisc,read_timeout_ms).unwrap()

}

pub fn close(p:&mut Packet){
    unsafe {
        clib::pcap_close((*p).handle);
    }
}

pub fn open_live(
    interface_name: &str,
    snaplen: i32,
    promisc: bool,
    read_timeout_ms: i32,
    ) -> Result<Packet, bool> {

    let interface_name = CString::new(interface_name).unwrap();
    let mut err_buf = [0i8; 256];
    let handle = unsafe {
        clib::pcap_open_live(
            interface_name.as_ptr(),
            snaplen,
            promisc as i32,
            read_timeout_ms,
            err_buf.as_mut_ptr(),
        )
    };
    if handle.is_null() {
		Err(false)
    } else {
        Ok(Packet::new(handle))
    }

}


pub fn create(interface_name:&str) ->Packet{


    let mut err_buf = [0i8; 256];
    let interface_name = CString::new(interface_name).unwrap();
    let handle = unsafe {
        let handle1 = clib::pcap_create(interface_name.as_ptr(),err_buf.as_mut_ptr());
        if handle1.is_null(){
            panic!("Open device error;");
        }

        let ret = clib::pcap_activate(handle1);
        if (ret < 0){
            panic!("Activate device error!");
        }
        handle1
    };

    Packet::new(handle)
}


pub fn next(p:&mut Packet)-> *const libc::c_uchar{


    let data = unsafe {

        let d = clib::pcap_next((*p).handle,&mut p.head);
        p.data = d;
        d
    };
    data
}

pub fn next_ex(p:&mut Packet)->i32{
        
    let mut header: *mut clib::pcap_pkthdr = ptr::null_mut();
    let mut data: *const libc::c_uchar = ptr::null();
    
    let data = unsafe {

        
        let d = clib::pcap_next_ex((*p).handle ,&mut header,&mut (*p).data);
        p.head = *header;
        d
    };
    data
}