pnet 0.4.1

Cross-platform, low level networking using the Rust programming language.
diff --git a/Cargo.toml b/Cargo.toml
index 48a845b..7cf4ccf 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -32,5 +32,14 @@ optional = true
 [dependencies.pnet_macros]
 path = "pnet_macros"
 
-[dev-dependencies]
+[dependencies]
 time = "*"
+
+[[bin]]
+name = "rs_receiver"
+path = "benches/rs_receiver.rs"
+
+[[bin]]
+name = "rs_sender"
+path = "benches/rs_sender.rs"
+
diff --git a/benches/rs_sender.rs b/benches/rs_sender.rs
index 289863b..e6713e3 100644
--- a/benches/rs_sender.rs
+++ b/benches/rs_sender.rs
@@ -10,6 +10,7 @@
 #![feature(str_char)]
 
 extern crate pnet;
+extern crate time;
 
 use pnet::datalink::{datalink_channel};
 use pnet::datalink::DataLinkChannelType::Layer2;
@@ -24,6 +25,7 @@ use pnet::util::get_network_interfaces;
 
 use std::env;
 use std::net::Ipv4Addr;
+use std::thread;
 
 static IPV4_HEADER_LEN: usize = 20;
 static UDP_HEADER_LEN: usize = 8;
@@ -79,8 +81,11 @@ pub fn build_udp4_packet(packet: &mut [u8], msg: &str) {
 }
 
 fn main() {
+    use std::iter::repeat;
+
     let interface_name = env::args().nth(1).unwrap();
     let destination = (&env::args().nth(2).unwrap()[..]).parse().unwrap();
+    let packet_size = (&env::args().nth(3).unwrap()[..]).parse().unwrap();
     // Find the network interface with the provided name
     let interfaces = get_network_interfaces();
     let interface = interfaces.iter()
@@ -94,7 +99,8 @@ fn main() {
         Err(e) => panic!("rs_sender: unable to create channel: {}", e)
     };
 
-    let mut buffer = [0u8; 64];
+    //let mut buffer = [0u8; 60];
+    let mut buffer: Vec<u8> = repeat(0u8).take(packet_size).collect();
     let mut mut_ethernet_header = MutableEthernetPacket::new(&mut buffer[..]);
     {
         mut_ethernet_header.set_destination(destination);
@@ -105,8 +111,19 @@ fn main() {
 
     let ethernet_header = EthernetPacket::new(mut_ethernet_header.packet());
 
-    loop {
-        tx.send_to(&ethernet_header, None);
+    thread::sleep_ms(5000);
+
+//    loop {
+    for i in 0..25 {
+        let start = time::precise_time_ns();
+        tx.build_and_send(10_000_000,
+                          ethernet_header.packet().len(),
+                          &mut |mut eh: MutableEthernetPacket| {
+                              eh.clone_from(&ethernet_header);
+                          });
+        let end = time::precise_time_ns();
+        let duration = (end - start) as f64 / 1_000_000_000.0;
+        println!("{} pps (10_000_000 packets in {} seconds)", 10_000_000.0 / duration, duration);
     }
 }
 
diff --git a/src/bindings/mod.rs b/src/bindings/mod.rs
index 1da0b4d..958f9a3 100644
--- a/src/bindings/mod.rs
+++ b/src/bindings/mod.rs
@@ -9,7 +9,7 @@
 // NOTE Remove this once the next rust nightly is out.
 pub mod libc;
 
-#[cfg(all(not(feature = "netmap"), any(target_os = "freebsd", target_os = "macos", windows)))]
+#[cfg(any(target_os = "freebsd", target_os = "macos", windows))]
 pub mod bpf;
 
 #[cfg(all(not(feature = "netmap"), target_os = "linux"))]
diff --git a/src/datalink/netmap.rs b/src/datalink/netmap.rs
index 57f324e..ff53aae 100644
--- a/src/datalink/netmap.rs
+++ b/src/datalink/netmap.rs
@@ -12,49 +12,96 @@
 extern crate netmap_sys;
 extern crate libc;
 
-use libc::{c_int, c_uint, c_ulong, c_short};
 use self::netmap_sys::netmap_user::{nm_open, nm_close, nm_nextpkt, nm_desc, nm_pkthdr,
                                 nm_ring_next, NETMAP_TXRING, NETMAP_FD, NETMAP_BUF};
-use self::netmap_sys::netmap::{nm_ring_empty, netmap_slot};
+use self::netmap_sys::netmap::{nm_ring_empty, netmap_slot, NS_REPORT, netmap_if, netmap_ring};
+
+use self::libc::funcs::bsd44::sysctlbyname;
 
 use std::ffi::CString;
-use std::path::Path;
-use std::fs::File;
 use std::io;
-use std::io::Read;
 use std::mem;
 use std::num;
 use std::ptr;
 use std::raw;
 use std::sync::Arc;
 
+use bindings::bpf;
 use datalink::DataLinkChannelType;
 use packet::Packet;
 use packet::ethernet::{EthernetPacket, MutableEthernetPacket};
 use util::{NetworkInterface};
 
-#[cfg(target_os = "linux")]
+#[cfg(any(target_os = "linux", target_os = "freebsd"))]
 #[repr(C)]
 struct pollfd {
-    fd: c_int,
-    events: c_short,
-    revents: c_short
+    fd: libc::c_int,
+    events: libc::c_short,
+    revents: libc::c_short
 }
 
+#[cfg(any(target_os = "linux", target_os = "freebsd"))]
+const POLLIN: libc::c_short = 0x0001;
+#[cfg(any(target_os = "linux", target_os = "freebsd"))]
+const POLLOUT: libc::c_short = 0x0004;
+
+#[cfg(target_os = "freebsd")]
+type nfds_t = libc::c_uint;
 #[cfg(target_os = "linux")]
-const POLLIN: c_short = 0x0001;
-#[cfg(target_os = "linux")]
-const POLLOUT: c_short = 0x0004;
+type nfds_t = libc::c_ulong;
 
-type nfds_t = c_ulong;
+extern {
+    fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: libc::c_int) -> libc::c_int;
+}
 
+#[link(name = "nm_helper")]
 extern {
-    fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int;
+    fn netmap_txring(iface: *mut netmap_if, offset: isize) -> *mut netmap_ring;
+    fn netmap_buf(ring: *mut netmap_ring, offset: isize) -> *mut libc::c_void;
 }
 
 struct NmDesc {
     desc: *mut nm_desc,
-    buf_size: c_uint,
+    buf_size: libc::c_uint,
+}
+
+#[cfg(target_os = "linux")]
+fn build_desc(desc: *mut nm_desc) -> io::Result<NmDesc> {
+    use std::fs::File;
+    use std::path::Path;
+    use std::io::Read;
+
+    // FIXME the following try statements leak if they fail
+    let mut f = try!(File::open(&Path::new("/sys/module/netmap/parameters/buf_size")));
+    let mut num_str = String::new();
+    try!(f.read_to_string(&mut num_str));
+    let buf_size = num_str.trim_right().parse().unwrap();
+    
+    Ok(NmDesc {
+        desc: desc,
+        buf_size: buf_size
+    })
+}
+
+#[cfg(target_os = "freebsd")]
+fn build_desc(desc: *mut nm_desc) -> io::Result<NmDesc> {
+    let name = CString::new(&b"dev.netmap.buf_size"[..]).unwrap().as_ptr();
+    let mut buf_size: libc::c_uint = 0;
+    let mut size_of_u32 = mem::size_of::<libc::c_uint>() as u64;
+    if unsafe {
+        sysctlbyname(name,
+                     (&mut buf_size as *mut libc::c_uint) as *mut libc::c_void,
+                     &mut size_of_u32,
+                     ptr::null_mut(),
+                     0)
+    } == -1 {
+        Err(io::Error::last_os_error())
+    } else {
+        Ok(NmDesc {
+            desc: desc,
+            buf_size: buf_size
+        })
+    }
 }
 
 impl NmDesc {
@@ -67,15 +114,7 @@ impl NmDesc {
         if desc.is_null() {
             Err(io::Error::last_os_error())
         } else {
-            let mut f = try!(File::open(&Path::new("/sys/module/netmap/parameters/buf_size")));
-            let mut num_str = String::new();
-            try!(f.read_to_string(&mut num_str));
-            let buf_size = num_str.trim_right().parse().unwrap();
-
-            Ok(NmDesc {
-                desc: desc,
-                buf_size: buf_size
-            })
+            build_desc(desc)
         }
     }
 }
@@ -98,7 +137,7 @@ impl DataLinkSenderImpl {
                           func: &mut F) -> Option<io::Result<()>>
         where F : FnMut(MutableEthernetPacket)
     {
-        assert!(num::cast::<usize, u16>(packet_size).unwrap() as c_uint <= self.desc.buf_size);
+        assert!(num::cast::<usize, u16>(packet_size).unwrap() as libc::c_uint <= self.desc.buf_size);
         let desc = self.desc.desc;
         let mut fds = pollfd {
             fd: unsafe { NETMAP_FD(desc) },
@@ -108,25 +147,42 @@ impl DataLinkSenderImpl {
         let mut packet_idx = 0usize;
         while packet_idx < num_packets {
             unsafe {
-                if poll(&mut fds, 1, -1) < 0 {
+                if poll(&mut fds, 1, 1000) <= 0 {
                     return Some(Err(io::Error::last_os_error()));
                 }
-                let ring = NETMAP_TXRING((*desc).nifp, 0);
-                while !nm_ring_empty(ring) && packet_idx < num_packets {
-                    let i = (*ring).cur;
+                for i in (*desc).first_tx_ring .. (*desc).last_tx_ring + 1 {
+                    if packet_idx >= num_packets {
+                        break;
+                    }
+		    //let ring = NETMAP_TXRING((*desc).nifp, i as isize);
+		    let ring = netmap_txring((*desc).nifp, i as isize);
+                    if nm_ring_empty(ring) {
+                        continue;
+                    }
+                //while !nm_ring_empty(ring) && packet_idx < num_packets {
+                //    let i = (*ring).cur;
                     let slot_ptr: *mut netmap_slot = mem::transmute(&mut (*ring).slot);
-                    let buf = NETMAP_BUF(ring, (*slot_ptr.offset(i as isize)).buf_idx as isize);
+                    let slot_ptr = slot_ptr.offset(i as isize);
+                    let buf = netmap_buf(ring, (*slot_ptr).buf_idx as isize);
                     let slice = raw::Slice { data: buf, len: packet_size };
                     let meh = MutableEthernetPacket::new(mem::transmute(slice));
-                    (*slot_ptr.offset(i as isize)).len = packet_size as u16;
+                    (*slot_ptr).len = packet_size as u16;
+                    if packet_idx == num_packets - 1 {
+                        (*slot_ptr).flags |= NS_REPORT as u16;
+                    }
                     func(meh);
-                    let next = nm_ring_next(ring, i);
+                    let next = nm_ring_next(ring, i as libc::c_uint);
                     (*ring).head = next;
                     (*ring).cur =  next;
                     packet_idx += 1;
                 }
             }
         }
+	unsafe {
+            for i in 0..10 {
+	        bpf::ioctl(fds.fd, 536897940/*NIOCTXSYNC*/, ptr::null::<libc::c_void>());
+            }
+        };
 
         Some(Ok(()))
     }
@@ -186,7 +242,7 @@ impl<'a> DataLinkChannelIteratorImpl<'a> {
                 events: POLLIN,
                 revents: 0,
             };
-            if unsafe { poll(&mut fds, 1, -1) } < 0 {
+            if unsafe { poll(&mut fds, 1, -1) } <= 0 {
                 return Err(io::Error::last_os_error());
             }
             buf = unsafe { nm_nextpkt(desc, &mut h) };