Split scheme.rs.

This commit is contained in:
Egor Karavaev
2017-09-19 00:42:37 +03:00
parent 203fa64580
commit 05650efcb1
6 changed files with 536 additions and 479 deletions
+6 -5
View File
@@ -1,9 +1,10 @@
use std::rc::Rc;
use std::fs::File;
use std::cell::RefCell;
use std::io::Write;
use std::collections::VecDeque;
use smoltcp;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::fs::File;
use std::io::Write;
use std::rc::Rc;
use buffer_pool::Buffer;
pub struct NetworkDevice {
+6 -5
View File
@@ -5,20 +5,21 @@ extern crate netutils;
extern crate smoltcp;
extern crate syscall;
use error::{Error, Result};
use event::EventQueue;
use scheme::Smolnetd;
use std::cell::RefCell;
use std::fs::File;
use std::os::unix::io::{FromRawFd, RawFd};
use std::process;
use std::rc::Rc;
mod error;
use error::{Error, Result};
use event::EventQueue;
use scheme::Smolnetd;
mod buffer_pool;
mod device;
mod scheme;
mod error;
mod logger;
mod scheme;
fn run() -> Result<()> {
use syscall::flag::*;
-469
View File
@@ -1,469 +0,0 @@
use netutils::{getcfg, MacAddr};
use smoltcp;
use std::collections::{BTreeMap, VecDeque};
use std::fs::File;
use std::io::{Read, Write};
use std::mem;
use std::net::Ipv4Addr;
use std::str::FromStr;
use std::time::Instant;
use std::rc::Rc;
use std::cell::RefCell;
use smoltcp::socket::AsSocket;
use syscall::SchemeMut;
use syscall;
use device::NetworkDevice;
use error::{Error, Result};
use buffer_pool::{Buffer, BufferPool};
struct RawHandle {
flags: usize,
events: usize,
socket_handle: smoltcp::socket::SocketHandle,
}
struct UdpHandle {
flags: usize,
events: usize,
remote_endpoint: smoltcp::wire::IpEndpoint,
socket_handle: smoltcp::socket::SocketHandle,
}
pub struct Smolnetd {
network_file: Rc<RefCell<File>>,
ip_file: File,
udp_file: File,
time_file: File,
iface: smoltcp::iface::EthernetInterface<'static, 'static, 'static, NetworkDevice>,
socket_set: smoltcp::socket::SocketSet<'static, 'static, 'static>,
startup_time: Instant,
next_fd: usize,
raw_sockets: BTreeMap<usize, RawHandle>,
udp_sockets: BTreeMap<usize, UdpHandle>,
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
input_buffer_pool: BufferPool,
}
struct IpScheme<'a>(&'a mut Smolnetd);
struct UdpScheme<'a>(&'a mut Smolnetd);
impl Smolnetd {
const INGRESS_PACKET_SIZE: usize = 2048;
const SOCKET_BUFFER_SIZE: usize = 128; //packets
const CHECK_TIMEOUT_MS: i64 = 1000;
pub fn new(network_file: File, ip_file: File, udp_file: File, time_file: File) -> Smolnetd {
let arp_cache = smoltcp::iface::SliceArpCache::new(vec![Default::default(); 8]);
//TODO Use smoltcp::wire::EthernetAddress::from_str
let mac_addr = MacAddr::from_str(&getcfg("mac").unwrap().trim());
let hardware_addr = smoltcp::wire::EthernetAddress(mac_addr.bytes);
//TODO Use smoltcp::wire::Ipv4Addr::from_str
let ip_bytes = Ipv4Addr::from_str(&getcfg("ip").unwrap().trim())
.unwrap()
.octets();
let protocol_addrs = [
smoltcp::wire::IpAddress::Ipv4(smoltcp::wire::Ipv4Address::from_bytes(&ip_bytes)),
];
let default_gw = smoltcp::wire::IpAddress::Ipv4(smoltcp::wire::Ipv4Address::from_bytes(
&Ipv4Addr::from_str(&getcfg("ip_router").unwrap().trim())
.unwrap()
.octets(),
));
trace!("mac {:?} ip {:?}", hardware_addr, protocol_addrs);
let input_queue = Rc::new(RefCell::new(VecDeque::new()));
let network_file = Rc::new(RefCell::new(network_file));
let network_device = NetworkDevice::new(network_file.clone(), input_queue.clone());
let mut iface = smoltcp::iface::EthernetInterface::new(
Box::new(network_device),
Box::new(arp_cache) as Box<smoltcp::iface::ArpCache>,
hardware_addr,
protocol_addrs,
);
iface.set_default_gateway(24, Some(default_gw));
Smolnetd {
iface,
socket_set: smoltcp::socket::SocketSet::new(vec![]),
startup_time: Instant::now(),
ip_file,
udp_file,
time_file,
raw_sockets: BTreeMap::new(),
udp_sockets: BTreeMap::new(),
next_fd: 0,
input_queue,
network_file,
input_buffer_pool: BufferPool::new(Self::INGRESS_PACKET_SIZE),
}
}
pub fn on_network_scheme_event(&mut self) -> Result<Option<()>> {
if self.read_frames()? > 0 {
self.poll().map(Some)?;
}
Ok(None)
}
pub fn on_ip_scheme_event(&mut self) -> Result<Option<()>> {
loop {
let mut packet = syscall::Packet::default();
if self.ip_file.read(&mut packet)? == 0 {
break;
}
IpScheme(self).handle(&mut packet);
self.ip_file.write_all(&packet)?;
}
Ok(None)
}
pub fn on_udp_scheme_event(&mut self) -> Result<Option<()>> {
loop {
let mut packet = syscall::Packet::default();
if self.udp_file.read(&mut packet)? == 0 {
break;
}
UdpScheme(self).handle(&mut packet);
self.udp_file.write_all(&packet)?;
}
Ok(None)
}
pub fn on_time_event(&mut self) -> Result<Option<()>> {
let mut time = syscall::data::TimeSpec::default();
if self.time_file.read(&mut time)? < mem::size_of::<syscall::data::TimeSpec>() {
panic!();
}
let mut time_ms = time.tv_sec * 1000i64 + (time.tv_nsec as i64) / 1_000_000i64;
time_ms += Smolnetd::CHECK_TIMEOUT_MS;
time.tv_sec = time_ms / 1000;
time.tv_nsec = ((time_ms % 1000) * 1_000_00) as i32;
self.time_file
.write_all(&time)
.map_err(|e| Error::from_io_error(e, "Failed to write to time file"))?;
self.poll().map(Some)?;
Ok(None)
}
fn poll(&mut self) -> Result<()> {
let timestamp = self.get_timestamp();
self.iface
.poll(&mut self.socket_set, timestamp)
.expect("poll error");
self.notify_raw_sockets()
}
fn read_frames(&mut self) -> Result<usize> {
let mut total_frames = 0;
loop {
let mut buffer = self.input_buffer_pool.get_buffer();
let count = self.network_file
.borrow_mut()
.read(&mut buffer)
.map_err(|e| {
Error::from_io_error(e, "Failed to read from network file")
})?;
if count == 0 {
break;
}
trace!("got frame {}", count);
buffer.resize(count);
self.input_queue.borrow_mut().push_back(buffer);
total_frames += 1;
}
Ok(total_frames)
}
fn get_timestamp(&self) -> u64 {
let duration = Instant::now().duration_since(self.startup_time);
let duration_ms = (duration.as_secs() * 1000) + (duration.subsec_nanos() / 1000000) as u64;
duration_ms
}
fn network_fsync(&mut self) -> syscall::Result<usize> {
use std::os::unix::io::AsRawFd;
syscall::fsync(self.network_file.borrow_mut().as_raw_fd() as usize)
}
fn notify_raw_sockets(&mut self) -> Result<()> {
for (&fd, ref handle) in &self.raw_sockets {
let socket: &mut smoltcp::socket::RawSocket =
self.socket_set.get_mut(handle.socket_handle).as_socket();
if socket.can_send() {
post_fevent(&mut self.ip_file, fd, syscall::EVENT_READ, 1)?;
}
}
Ok(())
}
}
impl<'a> syscall::SchemeMut for IpScheme<'a> {
fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> syscall::Result<usize> {
use std::str;
if uid != 0 {
return Err(syscall::Error::new(syscall::EACCES));
}
let path = str::from_utf8(url).or_else(|_| Err(syscall::Error::new(syscall::EINVAL)))?;
let proto = u8::from_str_radix(path, 16).or(Err(syscall::Error::new(syscall::ENOENT)))?;
let mut rx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE);
let mut tx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE);
for _ in 0..Smolnetd::SOCKET_BUFFER_SIZE {
rx_packets.push(smoltcp::socket::RawPacketBuffer::new(
vec![0; NetworkDevice::MTU],
));
tx_packets.push(smoltcp::socket::RawPacketBuffer::new(
vec![0; NetworkDevice::MTU],
));
}
let rx_buffer = smoltcp::socket::RawSocketBuffer::new(rx_packets);
let tx_buffer = smoltcp::socket::RawSocketBuffer::new(tx_packets);
let raw_socket = smoltcp::socket::RawSocket::new(
smoltcp::wire::IpVersion::Ipv4,
smoltcp::wire::IpProtocol::from(proto),
rx_buffer,
tx_buffer,
);
let socket_handle = self.0.socket_set.add(raw_socket);
let id = self.0.next_fd;
trace!("Open {} -> {}", path, id);
self.0.raw_sockets.insert(
id,
RawHandle {
flags,
events: 0,
socket_handle,
},
);
self.0.next_fd += 1;
Ok(id)
}
fn close(&mut self, fd: usize) -> syscall::Result<usize> {
trace!("Close {}", fd);
let socket_handle = {
let handle = self.0
.raw_sockets
.get(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
handle.socket_handle
};
self.0.raw_sockets.remove(&fd);
self.0.socket_set.remove(socket_handle);
Ok(0)
}
fn write(&mut self, fd: usize, buf: &[u8]) -> syscall::Result<usize> {
trace!("Write {} len {}", fd, buf.len());
let handle = self.0
.raw_sockets
.get(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
let socket: &mut smoltcp::socket::RawSocket =
self.0.socket_set.get_mut(handle.socket_handle).as_socket();
socket.send_slice(buf).expect("Can't send slice");
Ok(buf.len())
}
fn read(&mut self, fd: usize, buf: &mut [u8]) -> syscall::Result<usize> {
use smoltcp::socket::AsSocket;
let handle = self.0
.raw_sockets
.get(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
let socket: &mut smoltcp::socket::RawSocket =
self.0.socket_set.get_mut(handle.socket_handle).as_socket();
if socket.can_recv() {
let length = socket.recv_slice(buf).expect("Can't receive slice");
trace!("Read fd {} len {}", fd, length);
Ok(length)
} else if handle.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
Ok(0)
} else {
Err(syscall::Error::new(syscall::EWOULDBLOCK))
}
}
fn fevent(&mut self, fd: usize, events: usize) -> syscall::Result<usize> {
trace!("fevent {}", fd);
let handle = self.0
.raw_sockets
.get_mut(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
handle.events = events;
Ok(fd)
}
fn fsync(&mut self, fd: usize) -> syscall::Result<usize> {
trace!("fsync {}", fd);
{
let _handle = self.0
.raw_sockets
.get_mut(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
}
self.0.network_fsync()
}
}
impl<'a> syscall::SchemeMut for UdpScheme<'a> {
fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> syscall::Result<usize> {
use std::str;
if uid != 0 {
return Err(syscall::Error::new(syscall::EACCES));
}
let path = str::from_utf8(url).or_else(|_| Err(syscall::Error::new(syscall::EINVAL)))?;
let mut parts = path.split("/");
let (remote_ip, remote_port) = parse_socket(parts.next().unwrap_or(""));
let (local_ip, local_port) = parse_socket(parts.next().unwrap_or(""));
let mut rx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE);
let mut tx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE);
for _ in 0..Smolnetd::SOCKET_BUFFER_SIZE {
rx_packets.push(smoltcp::socket::UdpPacketBuffer::new(
vec![0; NetworkDevice::MTU],
));
tx_packets.push(smoltcp::socket::UdpPacketBuffer::new(
vec![0; NetworkDevice::MTU],
));
}
let rx_buffer = smoltcp::socket::UdpSocketBuffer::new(rx_packets);
let tx_buffer = smoltcp::socket::UdpSocketBuffer::new(tx_packets);
let mut udp_socket = smoltcp::socket::UdpSocket::new(rx_buffer, tx_buffer);
if !local_ip.is_unspecified() && local_port != 0 {
let udp_socket: &mut smoltcp::socket::UdpSocket = udp_socket.as_socket();
udp_socket.bind(smoltcp::wire::IpEndpoint::new(
smoltcp::wire::IpAddress::Ipv4(
smoltcp::wire::Ipv4Address::from_bytes(&local_ip.octets()),
),
local_port,
)).unwrap();
}
let socket_handle = self.0.socket_set.add(udp_socket);
let id = self.0.next_fd;
trace!("Open {} -> {}", path, id);
self.0.udp_sockets.insert(
id,
UdpHandle {
flags,
events: 0,
socket_handle,
remote_endpoint: smoltcp::wire::IpEndpoint::new(
smoltcp::wire::IpAddress::Ipv4(
smoltcp::wire::Ipv4Address::from_bytes(&remote_ip.octets()),
),
remote_port,
),
},
);
self.0.next_fd += 1;
Ok(id)
}
fn close(&mut self, fd: usize) -> syscall::Result<usize> {
trace!("Close {}", fd);
let socket_handle = {
let handle = self.0
.udp_sockets
.get(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
handle.socket_handle
};
self.0.udp_sockets.remove(&fd);
self.0.socket_set.remove(socket_handle);
Ok(0)
}
fn write(&mut self, fd: usize, buf: &[u8]) -> syscall::Result<usize> {
trace!("Write {} len {}", fd, buf.len());
let handle = self.0
.udp_sockets
.get(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
let socket: &mut smoltcp::socket::UdpSocket =
self.0.socket_set.get_mut(handle.socket_handle).as_socket();
socket.send_slice(buf, handle.remote_endpoint).expect("Can't send slice");
Ok(buf.len())
}
fn read(&mut self, fd: usize, buf: &mut [u8]) -> syscall::Result<usize> {
trace!("Read {}", fd);
let handle = self.0
.udp_sockets
.get(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
let socket: &mut smoltcp::socket::UdpSocket =
self.0.socket_set.get_mut(handle.socket_handle).as_socket();
if socket.can_recv() {
let (length, _) = socket.recv_slice(buf).expect("Can't receive slice");
Ok(length)
} else if handle.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
Ok(0)
} else {
Err(syscall::Error::new(syscall::EWOULDBLOCK))
}
}
fn fevent(&mut self, fd: usize, events: usize) -> syscall::Result<usize> {
trace!("fevent {}", fd);
let handle = self.0
.udp_sockets
.get_mut(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
handle.events = events;
Ok(fd)
}
fn fsync(&mut self, fd: usize) -> syscall::Result<usize> {
trace!("fsync {}", fd);
{
let _handle = self.0
.udp_sockets
.get_mut(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
}
self.0.network_fsync()
}
}
fn post_fevent(scheme_file: &mut File, fd: usize, event: usize, data_len: usize) -> Result<()> {
scheme_file
.write(&syscall::Packet {
id: 0,
pid: 0,
uid: 0,
gid: 0,
a: syscall::number::SYS_FEVENT,
b: fd,
c: event,
d: data_len,
})
.map(|_| ())
.map_err(|e| Error::from_io_error(e, "failed to post fevent"))
}
fn parse_socket(socket: &str) -> (Ipv4Addr, u16) {
let mut socket_parts = socket.split(":");
let host = Ipv4Addr::from_str(socket_parts.next().unwrap_or("")).unwrap();
let port = socket_parts
.next()
.unwrap_or("")
.parse::<u16>()
.unwrap_or(0);
(host, port)
}
+148
View File
@@ -0,0 +1,148 @@
use smoltcp::socket::{AsSocket, RawPacketBuffer, RawSocket, RawSocketBuffer, SocketHandle};
use smoltcp::wire::{IpProtocol, IpVersion};
use std::collections::BTreeMap;
use syscall;
use device::NetworkDevice;
use error::Result;
use super::{Smolnetd, SocketSet};
pub struct RawHandle {
flags: usize,
events: usize,
socket_handle: SocketHandle,
}
pub struct IpScheme {
next_ip_fd: usize,
raw_sockets: BTreeMap<usize, RawHandle>,
socket_set: SocketSet,
}
impl IpScheme {
pub fn new(socket_set: SocketSet) -> IpScheme {
IpScheme {
next_ip_fd: 1,
raw_sockets: BTreeMap::new(),
socket_set,
}
}
pub fn notify_ready_sockets<F: FnMut(usize) -> Result<()>>(&self, mut f: F) -> Result<()> {
for (&fd, ref handle) in &self.raw_sockets {
let mut socket_set = self.socket_set.borrow_mut();
let socket: &mut RawSocket = socket_set.get_mut(handle.socket_handle).as_socket();
if socket.can_send() {
f(fd)?
}
}
Ok(())
}
}
impl<'a> syscall::SchemeMut for IpScheme {
fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> syscall::Result<usize> {
use std::str;
if uid != 0 {
return Err(syscall::Error::new(syscall::EACCES));
}
let path = str::from_utf8(url).or_else(|_| Err(syscall::Error::new(syscall::EINVAL)))?;
let proto = u8::from_str_radix(path, 16).or(Err(syscall::Error::new(syscall::ENOENT)))?;
let mut rx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE);
let mut tx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE);
for _ in 0..Smolnetd::SOCKET_BUFFER_SIZE {
rx_packets.push(RawPacketBuffer::new(vec![0; NetworkDevice::MTU]));
tx_packets.push(RawPacketBuffer::new(vec![0; NetworkDevice::MTU]));
}
let rx_buffer = RawSocketBuffer::new(rx_packets);
let tx_buffer = RawSocketBuffer::new(tx_packets);
let raw_socket = RawSocket::new(
IpVersion::Ipv4,
IpProtocol::from(proto),
rx_buffer,
tx_buffer,
);
let socket_handle = self.socket_set.borrow_mut().add(raw_socket);
let id = self.next_ip_fd;
trace!("IP Open {} -> {}", path, id);
self.raw_sockets.insert(
id,
RawHandle {
flags,
events: 0,
socket_handle,
},
);
self.next_ip_fd += 1;
Ok(id)
}
fn close(&mut self, fd: usize) -> syscall::Result<usize> {
trace!("IP Close {}", fd);
let socket_handle = {
let handle = self.raw_sockets
.get(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
handle.socket_handle
};
self.raw_sockets.remove(&fd);
self.socket_set.borrow_mut().remove(socket_handle);
Ok(0)
}
fn write(&mut self, fd: usize, buf: &[u8]) -> syscall::Result<usize> {
trace!("IP Write {} len {}", fd, buf.len());
let handle = self.raw_sockets
.get(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
let mut socket_set = self.socket_set.borrow_mut();
let socket: &mut RawSocket = socket_set.get_mut(handle.socket_handle).as_socket();
socket.send_slice(buf).expect("Can't send slice");
Ok(buf.len())
}
fn read(&mut self, fd: usize, buf: &mut [u8]) -> syscall::Result<usize> {
use smoltcp::socket::AsSocket;
let handle = self.raw_sockets
.get(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
let mut socket_set = self.socket_set.borrow_mut();
let socket: &mut RawSocket = socket_set.get_mut(handle.socket_handle).as_socket();
if socket.can_recv() {
let length = socket.recv_slice(buf).expect("Can't receive slice");
trace!("IP Read fd {} len {}", fd, length);
Ok(length)
} else if handle.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
Ok(0)
} else {
Err(syscall::Error::new(syscall::EWOULDBLOCK))
}
}
fn fevent(&mut self, fd: usize, events: usize) -> syscall::Result<usize> {
trace!("IP fevent {}", fd);
let handle = self.raw_sockets
.get_mut(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
handle.events = events;
Ok(fd)
}
fn fsync(&mut self, fd: usize) -> syscall::Result<usize> {
trace!("IP fsync {}", fd);
{
let _handle = self.raw_sockets
.get_mut(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
}
Ok(0)
// TODO Implement fsyncing
// self.0.network_fsync()
}
}
+205
View File
@@ -0,0 +1,205 @@
use netutils::{getcfg, MacAddr};
use smoltcp;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::fs::File;
use std::io::{Read, Write};
use std::mem;
use std::net::Ipv4Addr;
use std::rc::Rc;
use std::str::FromStr;
use std::time::Instant;
use syscall::SchemeMut;
use syscall;
use buffer_pool::{Buffer, BufferPool};
use device::NetworkDevice;
use error::{Error, Result};
use self::ip::IpScheme;
use self::udp::UdpScheme;
mod ip;
mod udp;
type SocketSet = Rc<RefCell<smoltcp::socket::SocketSet<'static, 'static, 'static>>>;
pub struct Smolnetd {
network_file: Rc<RefCell<File>>,
ip_file: File,
udp_file: File,
time_file: File,
iface: smoltcp::iface::EthernetInterface<'static, 'static, 'static, NetworkDevice>,
socket_set: SocketSet,
startup_time: Instant,
ip_scheme: IpScheme,
udp_scheme: UdpScheme,
input_queue: Rc<RefCell<VecDeque<Buffer>>>,
input_buffer_pool: BufferPool,
}
impl Smolnetd {
const INGRESS_PACKET_SIZE: usize = 2048;
const SOCKET_BUFFER_SIZE: usize = 128; //packets
const CHECK_TIMEOUT_MS: i64 = 1000;
pub fn new(network_file: File, ip_file: File, udp_file: File, time_file: File) -> Smolnetd {
let arp_cache = smoltcp::iface::SliceArpCache::new(vec![Default::default(); 8]);
//TODO Use smoltcp::wire::EthernetAddress::from_str
let mac_addr = MacAddr::from_str(&getcfg("mac").unwrap().trim());
let hardware_addr = smoltcp::wire::EthernetAddress(mac_addr.bytes);
//TODO Use smoltcp::wire::Ipv4Addr::from_str
let ip_bytes = Ipv4Addr::from_str(&getcfg("ip").unwrap().trim())
.unwrap()
.octets();
let protocol_addrs = [
smoltcp::wire::IpAddress::Ipv4(smoltcp::wire::Ipv4Address::from_bytes(&ip_bytes)),
];
let default_gw = smoltcp::wire::IpAddress::Ipv4(smoltcp::wire::Ipv4Address::from_bytes(
&Ipv4Addr::from_str(&getcfg("ip_router").unwrap().trim())
.unwrap()
.octets(),
));
trace!("mac {:?} ip {:?}", hardware_addr, protocol_addrs);
let input_queue = Rc::new(RefCell::new(VecDeque::new()));
let network_file = Rc::new(RefCell::new(network_file));
let network_device = NetworkDevice::new(network_file.clone(), input_queue.clone());
let mut iface = smoltcp::iface::EthernetInterface::new(
Box::new(network_device),
Box::new(arp_cache) as Box<smoltcp::iface::ArpCache>,
hardware_addr,
protocol_addrs,
);
iface.set_default_gateway(24, Some(default_gw));
let socket_set = Rc::new(RefCell::new(smoltcp::socket::SocketSet::new(vec![])));
Smolnetd {
iface,
socket_set: socket_set.clone(),
startup_time: Instant::now(),
ip_file,
udp_file,
time_file,
ip_scheme: IpScheme::new(socket_set.clone()),
udp_scheme: UdpScheme::new(socket_set.clone()),
input_queue,
network_file,
input_buffer_pool: BufferPool::new(Self::INGRESS_PACKET_SIZE),
}
}
pub fn on_network_scheme_event(&mut self) -> Result<Option<()>> {
if self.read_frames()? > 0 {
self.poll().map(Some)?;
}
Ok(None)
}
pub fn on_ip_scheme_event(&mut self) -> Result<Option<()>> {
loop {
let mut packet = syscall::Packet::default();
if self.ip_file.read(&mut packet)? == 0 {
break;
}
self.ip_scheme.handle(&mut packet);
self.ip_file.write_all(&packet)?;
}
Ok(None)
}
pub fn on_udp_scheme_event(&mut self) -> Result<Option<()>> {
loop {
let mut packet = syscall::Packet::default();
if self.udp_file.read(&mut packet)? == 0 {
break;
}
self.udp_scheme.handle(&mut packet);
self.udp_file.write_all(&packet)?;
}
Ok(None)
}
pub fn on_time_event(&mut self) -> Result<Option<()>> {
let mut time = syscall::data::TimeSpec::default();
if self.time_file.read(&mut time)? < mem::size_of::<syscall::data::TimeSpec>() {
panic!();
}
let mut time_ms = time.tv_sec * 1000i64 + (time.tv_nsec as i64) / 1_000_000i64;
time_ms += Smolnetd::CHECK_TIMEOUT_MS;
time.tv_sec = time_ms / 1000;
time.tv_nsec = ((time_ms % 1000) * 1_000_00) as i32;
self.time_file
.write_all(&time)
.map_err(|e| Error::from_io_error(e, "Failed to write to time file"))?;
self.poll().map(Some)?;
Ok(None)
}
fn poll(&mut self) -> Result<()> {
let timestamp = self.get_timestamp();
self.iface
.poll(&mut *self.socket_set.borrow_mut(), timestamp)
.expect("poll error");
self.notify_raw_sockets()
}
fn read_frames(&mut self) -> Result<usize> {
let mut total_frames = 0;
loop {
let mut buffer = self.input_buffer_pool.get_buffer();
let count = self.network_file
.borrow_mut()
.read(&mut buffer)
.map_err(|e| {
Error::from_io_error(e, "Failed to read from network file")
})?;
if count == 0 {
break;
}
trace!("got frame {}", count);
buffer.resize(count);
self.input_queue.borrow_mut().push_back(buffer);
total_frames += 1;
}
Ok(total_frames)
}
fn get_timestamp(&self) -> u64 {
let duration = Instant::now().duration_since(self.startup_time);
let duration_ms = (duration.as_secs() * 1000) + (duration.subsec_nanos() / 1000000) as u64;
duration_ms
}
fn network_fsync(&mut self) -> syscall::Result<usize> {
use std::os::unix::io::AsRawFd;
syscall::fsync(self.network_file.borrow_mut().as_raw_fd() as usize)
}
fn notify_raw_sockets(&mut self) -> Result<()> {
let ip_file = &mut self.ip_file;
self.ip_scheme
.notify_ready_sockets(|fd| post_fevent(ip_file, fd, syscall::EVENT_READ, 1))?;
let udp_file = &mut self.udp_file;
self.udp_scheme
.notify_ready_sockets(|fd| post_fevent(udp_file, fd, syscall::EVENT_READ, 1))
}
}
fn post_fevent(scheme_file: &mut File, fd: usize, event: usize, data_len: usize) -> Result<()> {
scheme_file
.write(&syscall::Packet {
id: 0,
pid: 0,
uid: 0,
gid: 0,
a: syscall::number::SYS_FEVENT,
b: fd,
c: event,
d: data_len,
})
.map(|_| ())
.map_err(|e| Error::from_io_error(e, "failed to post fevent"))
}
+171
View File
@@ -0,0 +1,171 @@
use netutils::Ipv4Addr;
use smoltcp::socket::{AsSocket, SocketHandle, UdpPacketBuffer, UdpSocket, UdpSocketBuffer};
use smoltcp::wire::{IpAddress, IpEndpoint, Ipv4Address};
use std::collections::BTreeMap;
use syscall;
use device::NetworkDevice;
use error::Result;
use super::{Smolnetd, SocketSet};
pub struct UdpHandle {
flags: usize,
events: usize,
remote_endpoint: IpEndpoint,
pub socket_handle: SocketHandle,
}
pub struct UdpScheme {
next_udp_fd: usize,
udp_sockets: BTreeMap<usize, UdpHandle>,
socket_set: SocketSet,
}
impl UdpScheme {
pub fn new(socket_set: SocketSet) -> UdpScheme {
UdpScheme {
next_udp_fd: 1,
udp_sockets: BTreeMap::new(),
socket_set,
}
}
pub fn notify_ready_sockets<F: FnMut(usize) -> Result<()>>(&self, mut f: F) -> Result<()> {
for (&fd, ref handle) in &self.udp_sockets {
let mut socket_set = self.socket_set.borrow_mut();
let socket: &mut UdpSocket = socket_set.get_mut(handle.socket_handle).as_socket();
if socket.can_send() {
f(fd)?
}
}
Ok(())
}
}
impl syscall::SchemeMut for UdpScheme {
fn open(&mut self, url: &[u8], flags: usize, _uid: u32, _gid: u32) -> syscall::Result<usize> {
use std::str;
let path = str::from_utf8(url).or_else(|_| Err(syscall::Error::new(syscall::EINVAL)))?;
trace!("Udp open {} ", path);
let mut parts = path.split("/");
let (remote_ip, remote_port) = parse_socket(parts.next().unwrap_or(""));
let (local_ip, local_port) = parse_socket(parts.next().unwrap_or(""));
let mut rx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE);
let mut tx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE);
for _ in 0..Smolnetd::SOCKET_BUFFER_SIZE {
rx_packets.push(UdpPacketBuffer::new(vec![0; NetworkDevice::MTU]));
tx_packets.push(UdpPacketBuffer::new(vec![0; NetworkDevice::MTU]));
}
let rx_buffer = UdpSocketBuffer::new(rx_packets);
let tx_buffer = UdpSocketBuffer::new(tx_packets);
let mut udp_socket = UdpSocket::new(rx_buffer, tx_buffer);
if local_ip != Ipv4Addr::NULL && local_port != 0 {
let udp_socket: &mut UdpSocket = udp_socket.as_socket();
udp_socket
.bind(IpEndpoint::new(
IpAddress::Ipv4(Ipv4Address::from_bytes(&local_ip.bytes)),
local_port,
))
.unwrap();
}
let socket_handle = self.socket_set.borrow_mut().add(udp_socket);
let id = self.next_udp_fd;
self.udp_sockets.insert(
id,
UdpHandle {
flags,
events: 0,
socket_handle,
remote_endpoint: IpEndpoint::new(
IpAddress::Ipv4(Ipv4Address::from_bytes(&remote_ip.bytes)),
remote_port,
),
},
);
self.next_udp_fd += 1;
trace!("Udp open fd {} ", id);
Ok(id)
}
fn close(&mut self, fd: usize) -> syscall::Result<usize> {
trace!("Upd close {}", fd);
let socket_handle = {
let handle = self.udp_sockets
.get(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
handle.socket_handle
};
self.udp_sockets.remove(&fd);
self.socket_set.borrow_mut().remove(socket_handle);
Ok(0)
}
fn write(&mut self, fd: usize, buf: &[u8]) -> syscall::Result<usize> {
trace!("Upd write {} len {}", fd, buf.len());
let handle = self.udp_sockets
.get(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
let mut socket_set = self.socket_set.borrow_mut();
let socket: &mut UdpSocket = socket_set.get_mut(handle.socket_handle).as_socket();
socket
.send_slice(buf, handle.remote_endpoint)
.expect("Can't send slice");
Ok(buf.len())
}
fn read(&mut self, fd: usize, buf: &mut [u8]) -> syscall::Result<usize> {
let handle = self.udp_sockets.get(&fd).ok_or_else(|| {
trace!("UDP read EBADF {}", fd);
syscall::Error::new(syscall::EBADF)
})?;
let mut socket_set = self.socket_set.borrow_mut();
let socket: &mut UdpSocket = socket_set.get_mut(handle.socket_handle).as_socket();
if socket.can_recv() {
let (length, _) = socket.recv_slice(buf).expect("Can't receive slice");
trace!("Upd read {}", fd);
Ok(length)
} else if handle.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
Ok(0)
} else {
Err(syscall::Error::new(syscall::EWOULDBLOCK))
}
}
fn fevent(&mut self, fd: usize, events: usize) -> syscall::Result<usize> {
trace!("udp fevent {}", fd);
let handle = self.udp_sockets
.get_mut(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
handle.events = events;
Ok(fd)
}
fn fsync(&mut self, fd: usize) -> syscall::Result<usize> {
trace!("udp fsync {}", fd);
{
let _handle = self.udp_sockets
.get_mut(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
}
Ok(0)
// TODO Implement fsyncing
// self.0.network_fsync()
}
}
fn parse_socket(socket: &str) -> (Ipv4Addr, u16) {
let mut socket_parts = socket.split(":");
let host = Ipv4Addr::from_str(socket_parts.next().unwrap_or(""));
let port = socket_parts
.next()
.unwrap_or("")
.parse::<u16>()
.unwrap_or(0);
(host, port)
}