Skip to content

Commit

Permalink
Begin support for supporting multiple DLTs
Browse files Browse the repository at this point in the history
Wraps existing traits in a macro, creating one for each DLT. Ideally this
would be done using generics, however after multiple attempts to get this
working I have not succeeded.
  • Loading branch information
mrmonday committed Jan 24, 2016
1 parent 10eb740 commit 61f2d8f
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 83 deletions.
2 changes: 1 addition & 1 deletion LICENSE-MIT
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2014 Robert Clipsham
Copyright (c) 2014-2016 Robert Clipsham

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
Expand Down
15 changes: 8 additions & 7 deletions src/datalink/bpf.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2014, 2015 Robert Clipsham <[email protected]>
// Copyright (c) 2014-2016 Robert Clipsham <[email protected]>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
Expand All @@ -19,7 +19,8 @@ use std::sync::Arc;
use bindings::bpf;
use packet::Packet;
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};
use datalink::{DataLinkChannelIterator, DataLinkChannelType, DataLinkReceiver, DataLinkSender};
use datalink::{EthernetDataLinkChannelIterator, DataLinkChannelType, EthernetDataLinkReceiver,
EthernetDataLinkSender};
use datalink::DataLinkChannelType::{Layer2, Layer3};
use internal;
use util::NetworkInterface;
Expand All @@ -30,7 +31,7 @@ pub fn datalink_channel(network_interface: &NetworkInterface,
write_buffer_size: usize,
read_buffer_size: usize,
channel_type: DataLinkChannelType)
-> io::Result<(Box<DataLinkSender>, Box<DataLinkReceiver>)> {
-> io::Result<(Box<EthernetDataLinkSender>, Box<EthernetDataLinkReceiver>)> {
#[cfg(target_os = "freebsd")]
fn get_fd() -> libc::c_int {
unsafe {
Expand Down Expand Up @@ -175,7 +176,7 @@ pub struct DataLinkSenderImpl {
header_size: usize,
}

impl DataLinkSender for DataLinkSenderImpl {
impl EthernetDataLinkSender for DataLinkSenderImpl {
#[inline]
fn build_and_send(&mut self,
num_packets: usize,
Expand Down Expand Up @@ -234,8 +235,8 @@ pub struct DataLinkReceiverImpl {
header_size: usize,
}

impl DataLinkReceiver for DataLinkReceiverImpl {
fn iter<'a>(&'a mut self) -> Box<DataLinkChannelIterator + 'a> {
impl EthernetDataLinkReceiver for DataLinkReceiverImpl {
fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
let buflen = self.read_buffer.len();
Box::new(DataLinkChannelIteratorImpl {
pc: self,
Expand All @@ -250,7 +251,7 @@ pub struct DataLinkChannelIteratorImpl<'a> {
packets: VecDeque<(usize, usize)>,
}

impl<'a> DataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
impl<'a> EthernetDataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
fn next(&mut self) -> io::Result<EthernetPacket> {
if self.packets.is_empty() {
let buflen = match unsafe {
Expand Down
15 changes: 8 additions & 7 deletions src/datalink/linux.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2014, 2015 Robert Clipsham <[email protected]>
// Copyright (c) 2014-2016 Robert Clipsham <[email protected]>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
Expand All @@ -15,7 +15,8 @@ use std::mem;
use std::sync::Arc;

use bindings::linux;
use datalink::{DataLinkChannelIterator, DataLinkChannelType, DataLinkReceiver, DataLinkSender};
use datalink::{EthernetDataLinkChannelIterator, DataLinkChannelType, EthernetDataLinkReceiver,
EthernetDataLinkSender};
use datalink::DataLinkChannelType::{Layer2, Layer3};
use internal;
use packet::Packet;
Expand Down Expand Up @@ -44,7 +45,7 @@ pub fn datalink_channel(network_interface: &NetworkInterface,
write_buffer_size: usize,
read_buffer_size: usize,
channel_type: DataLinkChannelType)
-> io::Result<(Box<DataLinkSender>, Box<DataLinkReceiver>)> {
-> io::Result<(Box<EthernetDataLinkSender>, Box<EthernetDataLinkReceiver>)> {
let eth_p_all = 0x0003;
let (typ, proto) = match channel_type {
Layer2 => (libc::SOCK_RAW, eth_p_all),
Expand Down Expand Up @@ -112,7 +113,7 @@ pub struct DataLinkSenderImpl {
send_addr_len: usize,
}

impl DataLinkSender for DataLinkSenderImpl {
impl EthernetDataLinkSender for DataLinkSenderImpl {
// FIXME Layer 3
#[inline]
fn build_and_send(&mut self,
Expand Down Expand Up @@ -167,9 +168,9 @@ pub struct DataLinkReceiverImpl {
_channel_type: DataLinkChannelType,
}

impl DataLinkReceiver for DataLinkReceiverImpl {
impl EthernetDataLinkReceiver for DataLinkReceiverImpl {
// FIXME Layer 3
fn iter<'a>(&'a mut self) -> Box<DataLinkChannelIterator + 'a> {
fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
Box::new(DataLinkChannelIteratorImpl { pc: self })
}
}
Expand All @@ -178,7 +179,7 @@ pub struct DataLinkChannelIteratorImpl<'a> {
pc: &'a mut DataLinkReceiverImpl,
}

impl<'a> DataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
impl<'a> EthernetDataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
fn next(&mut self) -> io::Result<EthernetPacket> {
let mut caddr: libc::sockaddr_storage = unsafe { mem::zeroed() };
let res = internal::recv_from(self.pc.socket.fd, &mut self.pc.read_buffer, &mut caddr);
Expand Down
93 changes: 52 additions & 41 deletions src/datalink/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2014, 2015 Robert Clipsham <[email protected]>
// Copyright (c) 2014-2016 Robert Clipsham <[email protected]>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
Expand Down Expand Up @@ -64,54 +64,65 @@ pub fn datalink_channel(network_interface: &NetworkInterface,
write_buffer_size: usize,
read_buffer_size: usize,
channel_type: DataLinkChannelType)
-> io::Result<(Box<DataLinkSender>, Box<DataLinkReceiver>)> {
-> io::Result<(Box<EthernetDataLinkSender>, Box<EthernetDataLinkReceiver>)> {
backend::datalink_channel(network_interface,
write_buffer_size,
read_buffer_size,
channel_type)
}

/// Structure for sending packets at the data link layer. Should be constructed using
/// datalink_channel().
pub trait DataLinkSender : Send {
/// Create and send a number of packets
///
/// This will call `func` `num_packets` times. The function will be provided with a mutable
/// packet to manipulate, which will then be sent. This allows packets to be built in-place,
/// avoiding the copy required for `send`. If there is not sufficient capacity in the buffer,
/// None will be returned.
#[inline]
fn build_and_send(&mut self,
num_packets: usize,
packet_size: usize,
func: &mut FnMut(MutableEthernetPacket))
-> Option<io::Result<()>>;
macro_rules! dls {
($name:ident, $mut_packet:ident, $packet:ident) => {
/// Trait to enable sending $packet packets
pub trait $name : Send {
/// Create and send a number of packets
///
/// This will call `func` `num_packets` times. The function will be provided with a
/// mutable packet to manipulate, which will then be sent. This allows packets to be
/// built in-place, avoiding the copy required for `send`. If there is not sufficient
/// capacity in the buffer, None will be returned.
#[inline]
fn build_and_send(&mut self,
num_packets: usize,
packet_size: usize,
func: &mut FnMut($mut_packet))
-> Option<io::Result<()>>;

/// Send a packet
///
/// This may require an additional copy compared to `build_and_send`, depending on the
/// operating system being used. The second parameter is currently ignored, however `None`
/// should be passed.
#[inline]
fn send_to(&mut self,
packet: &EthernetPacket,
dst: Option<NetworkInterface>)
-> Option<io::Result<()>>;
/// Send a packet
///
/// This may require an additional copy compared to `build_and_send`, depending on the
/// operating system being used. The second parameter is currently ignored, however
/// `None` should be passed.
#[inline]
fn send_to(&mut self,
packet: &$packet,
dst: Option<NetworkInterface>)
-> Option<io::Result<()>>;
}
}
}

/// Structure for receiving packets at the data link layer. Should be constructed using
/// datalink_channel().
pub trait DataLinkReceiver : Send {
/// Returns an iterator over `EthernetPacket`s.
///
/// This will likely be removed once other layer two types are supported.
#[inline]
fn iter<'a>(&'a mut self) -> Box<DataLinkChannelIterator + 'a>;
}
dls!(EthernetDataLinkSender, MutableEthernetPacket, EthernetPacket);

macro_rules! dlr {
($recv_name:ident, $iter_name:ident, $packet:ident) => {
/// Structure for receiving packets at the data link layer. Should be constructed using
/// datalink_channel().
pub trait $recv_name : Send {
/// Returns an iterator over `EthernetPacket`s.
///
/// This will likely be removed once other layer two types are supported.
#[inline]
fn iter<'a>(&'a mut self) -> Box<$iter_name + 'a>;
}

/// An iterator over data link layer packets
pub trait DataLinkChannelIterator<'a> {
/// Get the next EthernetPacket in the channel
#[inline]
fn next(&mut self) -> io::Result<EthernetPacket>;
/// An iterator over data link layer packets
pub trait $iter_name<'a> {
/// Get the next EthernetPacket in the channel
#[inline]
fn next(&mut self) -> io::Result<$packet>;
}
}
}

dlr!(EthernetDataLinkReceiver, EthernetDataLinkChannelIterator, EthernetPacket);
34 changes: 14 additions & 20 deletions src/datalink/netmap.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2015, 2015 Robert Clipsham <[email protected]>
// Copyright (c) 2015-2016 Robert Clipsham <[email protected]>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
Expand All @@ -21,12 +21,12 @@ 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::slice;
use std::sync::Arc;

use datalink::{DataLinkChannelIterator, DataLinkChannelType, DataLinkReceiver, DataLinkSender};
use datalink::{EthernetDataLinkChannelIterator, DataLinkChannelType, EthernetDataLinkReceiver,
EthernetDataLinkSender};
use packet::Packet;
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};
use util::NetworkInterface;
Expand Down Expand Up @@ -63,7 +63,7 @@ unsafe impl Sync for NmDesc {}

impl NmDesc {
fn new(iface: &NetworkInterface) -> io::Result<NmDesc> {
let ifname = CString::new(("netmap:".to_string() + &iface.name[..]).as_bytes());
let ifname = CString::new(("netmap:".to_owned() + &iface.name[..]).as_bytes());
let desc = unsafe { nm_open(ifname.unwrap().as_ptr(), ptr::null(), 0, ptr::null()) };

if desc.is_null() {
Expand Down Expand Up @@ -95,7 +95,7 @@ pub fn datalink_channel(network_interface: &NetworkInterface,
_write_buffer_size: usize,
_read_buffer_size: usize,
_channel_type: DataLinkChannelType)
-> io::Result<(Box<DataLinkSender>, Box<DataLinkReceiver>)> {
-> io::Result<(Box<EthernetDataLinkSender>, Box<EthernetDataLinkReceiver>)> {
// FIXME probably want one for each of send/recv
let desc = NmDesc::new(network_interface);
match desc {
Expand All @@ -113,7 +113,7 @@ pub struct DataLinkSenderImpl {
desc: Arc<NmDesc>,
}

impl DataLinkSender for DataLinkSenderImpl {
impl EthernetDataLinkSender for DataLinkSenderImpl {
#[inline]
fn build_and_send(&mut self,
num_packets: usize,
Expand All @@ -138,11 +138,8 @@ impl DataLinkSender for DataLinkSenderImpl {
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 slice = raw::Slice {
data: buf,
len: packet_size,
};
let meh = MutableEthernetPacket::new(mem::transmute(slice)).unwrap();
let slice = slice::from_raw_parts_mut(buf as *mut u8, packet_size);
let meh = MutableEthernetPacket::new(slice).unwrap();
(*slot_ptr.offset(i as isize)).len = packet_size as u16;
func(meh);
let next = nm_ring_next(ring, i);
Expand Down Expand Up @@ -174,9 +171,9 @@ pub struct DataLinkReceiverImpl {
desc: Arc<NmDesc>,
}

impl DataLinkReceiver for DataLinkReceiverImpl {
impl EthernetDataLinkReceiver for DataLinkReceiverImpl {
// FIXME Layer 3
fn iter<'a>(&'a mut self) -> Box<DataLinkChannelIterator + 'a> {
fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
Box::new(DataLinkChannelIteratorImpl { pc: self })
}
}
Expand All @@ -185,8 +182,8 @@ pub struct DataLinkChannelIteratorImpl<'a> {
pc: &'a mut DataLinkReceiverImpl,
}

impl<'a> DataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
fn next<'c>(&'c mut self) -> io::Result<EthernetPacket<'c>> {
impl<'a> EthernetDataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
fn next(&mut self) -> io::Result<EthernetPacket> {
let desc = self.pc.desc.desc;
let mut h: nm_pkthdr = unsafe { mem::uninitialized() };
let mut buf = unsafe { nm_nextpkt(desc, &mut h) };
Expand All @@ -202,10 +199,7 @@ impl<'a> DataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
buf = unsafe { nm_nextpkt(desc, &mut h) };
}
Ok(EthernetPacket::new(unsafe {
mem::transmute(raw::Slice {
data: buf,
len: h.len as usize,
})
slice::from_raw_parts(buf, h.len as usize)
}).unwrap())
}
}
15 changes: 8 additions & 7 deletions src/datalink/winpcap.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2014, 2015 Robert Clipsham <[email protected]>
// Copyright (c) 2014-2016 Robert Clipsham <[email protected]>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
Expand All @@ -17,7 +17,8 @@ use std::slice;
use std::sync::Arc;

use bindings::{bpf, winpcap};
use datalink::{DataLinkChannelIterator, DataLinkChannelType, DataLinkReceiver, DataLinkSender};
use datalink::{EthernetDataLinkChannelIterator, DataLinkChannelType, EthernetDataLinkReceiver,
EthernetDataLinkSender};
use packet::Packet;
use packet::ethernet::{EthernetPacket, MutableEthernetPacket};
use util::NetworkInterface;
Expand Down Expand Up @@ -51,7 +52,7 @@ pub fn datalink_channel(network_interface: &NetworkInterface,
read_buffer_size: usize,
write_buffer_size: usize,
_channel_type: DataLinkChannelType)
-> io::Result<(Box<DataLinkSender>, Box<DataLinkReceiver>)> {
-> io::Result<(Box<EthernetDataLinkSender>, Box<EthernetDataLinkReceiver>)> {
let mut read_buffer = Vec::new();
read_buffer.resize(read_buffer_size, 0u8);

Expand Down Expand Up @@ -137,7 +138,7 @@ pub struct DataLinkSenderImpl {
packet: WinPcapPacket,
}

impl DataLinkSender for DataLinkSenderImpl {
impl EthernetDataLinkSender for DataLinkSenderImpl {
#[inline]
fn build_and_send(&mut self,
num_packets: usize,
Expand Down Expand Up @@ -203,8 +204,8 @@ pub struct DataLinkReceiverImpl {
packet: WinPcapPacket,
}

impl DataLinkReceiver for DataLinkReceiverImpl {
fn iter<'a>(&'a mut self) -> Box<DataLinkChannelIterator + 'a> {
impl EthernetDataLinkReceiver for DataLinkReceiverImpl {
fn iter<'a>(&'a mut self) -> Box<EthernetDataLinkChannelIterator + 'a> {
let buflen = unsafe { (*self.packet.packet).Length } as usize;
Box::new(DataLinkChannelIteratorImpl {
pc: self,
Expand All @@ -222,7 +223,7 @@ pub struct DataLinkChannelIteratorImpl<'a> {
packets: VecDeque<(usize, usize)>,
}

impl<'a> DataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
impl<'a> EthernetDataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> {
fn next(&mut self) -> io::Result<EthernetPacket> {
// NOTE Most of the logic here is identical to FreeBSD/OS X
if self.packets.is_empty() {
Expand Down

0 comments on commit 61f2d8f

Please sign in to comment.