From 61f2d8f8e39977c854959ef76fcc78963eead9be Mon Sep 17 00:00:00 2001 From: Robert Clipsham Date: Sun, 24 Jan 2016 17:13:19 +0000 Subject: [PATCH] Begin support for supporting multiple DLTs 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. --- LICENSE-MIT | 2 +- src/datalink/bpf.rs | 15 +++---- src/datalink/linux.rs | 15 +++---- src/datalink/mod.rs | 93 +++++++++++++++++++++++------------------ src/datalink/netmap.rs | 34 +++++++-------- src/datalink/winpcap.rs | 15 +++---- 6 files changed, 91 insertions(+), 83 deletions(-) diff --git a/LICENSE-MIT b/LICENSE-MIT index 85a25ff..e3a68ac 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -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 diff --git a/src/datalink/bpf.rs b/src/datalink/bpf.rs index eaf8c9a..2415f9b 100644 --- a/src/datalink/bpf.rs +++ b/src/datalink/bpf.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2014, 2015 Robert Clipsham +// Copyright (c) 2014-2016 Robert Clipsham // // Licensed under the Apache License, Version 2.0 or the MIT license @@ -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; @@ -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, Box)> { + -> io::Result<(Box, Box)> { #[cfg(target_os = "freebsd")] fn get_fd() -> libc::c_int { unsafe { @@ -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, @@ -234,8 +235,8 @@ pub struct DataLinkReceiverImpl { header_size: usize, } -impl DataLinkReceiver for DataLinkReceiverImpl { - fn iter<'a>(&'a mut self) -> Box { +impl EthernetDataLinkReceiver for DataLinkReceiverImpl { + fn iter<'a>(&'a mut self) -> Box { let buflen = self.read_buffer.len(); Box::new(DataLinkChannelIteratorImpl { pc: self, @@ -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 { if self.packets.is_empty() { let buflen = match unsafe { diff --git a/src/datalink/linux.rs b/src/datalink/linux.rs index de8995c..33947d9 100644 --- a/src/datalink/linux.rs +++ b/src/datalink/linux.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2014, 2015 Robert Clipsham +// Copyright (c) 2014-2016 Robert Clipsham // // Licensed under the Apache License, Version 2.0 or the MIT license @@ -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; @@ -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, Box)> { + -> io::Result<(Box, Box)> { let eth_p_all = 0x0003; let (typ, proto) = match channel_type { Layer2 => (libc::SOCK_RAW, eth_p_all), @@ -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, @@ -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 { + fn iter<'a>(&'a mut self) -> Box { Box::new(DataLinkChannelIteratorImpl { pc: self }) } } @@ -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 { 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); diff --git a/src/datalink/mod.rs b/src/datalink/mod.rs index d2630e3..918067f 100644 --- a/src/datalink/mod.rs +++ b/src/datalink/mod.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2014, 2015 Robert Clipsham +// Copyright (c) 2014-2016 Robert Clipsham // // Licensed under the Apache License, Version 2.0 or the MIT license @@ -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, Box)> { + -> io::Result<(Box, Box)> { 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>; +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>; - /// 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) - -> Option>; + /// 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) + -> Option>; + } + } } -/// 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; -} +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; + /// 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); diff --git a/src/datalink/netmap.rs b/src/datalink/netmap.rs index f2ad750..1449d49 100644 --- a/src/datalink/netmap.rs +++ b/src/datalink/netmap.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2015, 2015 Robert Clipsham +// Copyright (c) 2015-2016 Robert Clipsham // // Licensed under the Apache License, Version 2.0 or the MIT license @@ -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; @@ -63,7 +63,7 @@ unsafe impl Sync for NmDesc {} impl NmDesc { fn new(iface: &NetworkInterface) -> io::Result { - 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() { @@ -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, Box)> { + -> io::Result<(Box, Box)> { // FIXME probably want one for each of send/recv let desc = NmDesc::new(network_interface); match desc { @@ -113,7 +113,7 @@ pub struct DataLinkSenderImpl { desc: Arc, } -impl DataLinkSender for DataLinkSenderImpl { +impl EthernetDataLinkSender for DataLinkSenderImpl { #[inline] fn build_and_send(&mut self, num_packets: usize, @@ -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); @@ -174,9 +171,9 @@ pub struct DataLinkReceiverImpl { desc: Arc, } -impl DataLinkReceiver for DataLinkReceiverImpl { +impl EthernetDataLinkReceiver for DataLinkReceiverImpl { // FIXME Layer 3 - fn iter<'a>(&'a mut self) -> Box { + fn iter<'a>(&'a mut self) -> Box { Box::new(DataLinkChannelIteratorImpl { pc: self }) } } @@ -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> { +impl<'a> EthernetDataLinkChannelIterator<'a> for DataLinkChannelIteratorImpl<'a> { + fn next(&mut self) -> io::Result { let desc = self.pc.desc.desc; let mut h: nm_pkthdr = unsafe { mem::uninitialized() }; let mut buf = unsafe { nm_nextpkt(desc, &mut h) }; @@ -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()) } } diff --git a/src/datalink/winpcap.rs b/src/datalink/winpcap.rs index d797eb1..93c27fc 100644 --- a/src/datalink/winpcap.rs +++ b/src/datalink/winpcap.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2014, 2015 Robert Clipsham +// Copyright (c) 2014-2016 Robert Clipsham // // Licensed under the Apache License, Version 2.0 or the MIT license @@ -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; @@ -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, Box)> { + -> io::Result<(Box, Box)> { let mut read_buffer = Vec::new(); read_buffer.resize(read_buffer_size, 0u8); @@ -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, @@ -203,8 +204,8 @@ pub struct DataLinkReceiverImpl { packet: WinPcapPacket, } -impl DataLinkReceiver for DataLinkReceiverImpl { - fn iter<'a>(&'a mut self) -> Box { +impl EthernetDataLinkReceiver for DataLinkReceiverImpl { + fn iter<'a>(&'a mut self) -> Box { let buflen = unsafe { (*self.packet.packet).Length } as usize; Box::new(DataLinkChannelIteratorImpl { pc: self, @@ -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 { // NOTE Most of the logic here is identical to FreeBSD/OS X if self.packets.is_empty() {