Merge remote-tracking branch 'batonius/smolnetd' into smolnetd

This commit is contained in:
Jeremy Soller
2017-10-09 20:49:37 -06:00
8 changed files with 547 additions and 546 deletions
Generated
+2 -2
View File
@@ -191,7 +191,7 @@ dependencies = [
[[package]]
name = "netutils"
version = "0.1.0"
source = "git+https://github.com/redox-os/netutils.git#ec1a835a9d4a95a8e41c4e994a540d298d897cd4"
source = "git+https://github.com/redox-os/netutils.git#29b8efd41d8c56b33c619db78e5b019934dbb7a3"
dependencies = [
"arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)",
"extra 0.1.0 (git+https://github.com/redox-os/libextra.git)",
@@ -328,7 +328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "smoltcp"
version = "0.4.0"
source = "git+https://github.com/m-labs/smoltcp.git#b0fc1d9542ef3b8e7add3b90dcf2d6f1fc4c633e"
source = "git+https://github.com/m-labs/smoltcp.git#096ce02ac4c935c4df485a79107fb26b5897065d"
dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+1 -3
View File
@@ -68,9 +68,7 @@ impl BufferPool {
pub fn get_buffer(&mut self) -> Buffer {
let buffer = match self.stack.borrow_mut().pop() {
None => {
vec![0u8; self.buffers_size]
}
None => vec![0u8; self.buffers_size],
Some(mut v) => {
// memsetting the buffer with `resize` would be a waste of time
let capacity = v.capacity();
+3 -1
View File
@@ -1,3 +1,5 @@
#![feature(drain_filter)]
extern crate event;
#[macro_use]
extern crate log;
@@ -19,8 +21,8 @@ mod buffer_pool;
mod device;
mod error;
mod logger;
mod scheme;
mod port_set;
mod scheme;
fn run() -> Result<()> {
use syscall::flag::*;
+44 -91
View File
@@ -1,30 +1,19 @@
use super::socket::*;
use smoltcp::socket::{RawPacketBuffer, RawSocket, RawSocketBuffer, Socket, SocketHandle};
use smoltcp::socket::{RawPacketBuffer, RawSocket, RawSocketBuffer, SocketHandle};
use smoltcp::wire::{IpProtocol, IpVersion};
use std::io::{Read, Write};
use std::str;
use std::mem;
use std::ops::Deref;
use std::ops::DerefMut;
use syscall::data::TimeSpec;
use syscall::{Error as SyscallError, Result as SyscallResult};
use syscall;
use device::NetworkDevice;
use super::Smolnetd;
use super::{Smolnetd, SocketSet};
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme};
pub type IpScheme = SocketScheme<RawSocket<'static, 'static>>;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Setting {
ReadTimeout,
WriteTimeout,
}
impl<'a, 'b> SchemeSocket for RawSocket<'a, 'b> {
type SchemeDataT = ();
type DataT = ();
type SettingT = Setting;
type SettingT = ();
fn new_scheme_data() -> Self::SchemeDataT {
()
@@ -39,69 +28,32 @@ impl<'a, 'b> SchemeSocket for RawSocket<'a, 'b> {
}
fn get_setting(
file: &SocketFile<Self::DataT>,
setting: Self::SettingT,
buf: &mut [u8],
) -> syscall::Result<usize> {
let timespec = match (setting, file.read_timeout, file.write_timeout) {
(Setting::ReadTimeout, Some(read_timeout), _) => read_timeout,
(Setting::WriteTimeout, _, Some(write_timeout)) => write_timeout,
_ => {
return Ok(0);
}
};
if buf.len() < mem::size_of::<TimeSpec>() {
Ok(0)
} else {
let count = timespec.deref().read(buf).map_err(|err| {
syscall::Error::new(err.raw_os_error().unwrap_or(syscall::EIO))
})?;
Ok(count)
}
_file: &SocketFile<Self::DataT>,
_setting: Self::SettingT,
_buf: &mut [u8],
) -> SyscallResult<usize> {
Ok(0)
}
fn set_setting(
file: &mut SocketFile<Self::DataT>,
setting: Self::SettingT,
buf: &[u8],
) -> syscall::Result<usize> {
match setting {
Setting::ReadTimeout | Setting::WriteTimeout => {
let (timeout, count) = {
if buf.len() < mem::size_of::<TimeSpec>() {
(None, 0)
} else {
let mut timespec = TimeSpec::default();
let count = timespec.deref_mut().write(buf).map_err(|err| {
syscall::Error::new(err.raw_os_error().unwrap_or(syscall::EIO))
})?;
(Some(timespec), count)
}
};
match setting {
Setting::ReadTimeout => {
file.read_timeout = timeout;
}
Setting::WriteTimeout => {
file.write_timeout = timeout;
}
};
return Ok(count);
}
}
_file: &mut SocketFile<Self::DataT>,
_setting: Self::SettingT,
_buf: &[u8],
) -> SyscallResult<usize> {
Ok(0)
}
fn new_socket(
socket_set: &mut SocketSet,
path: &str,
uid: u32,
_: &mut Self::SchemeDataT,
) -> syscall::Result<(Socket<'static, 'static>, Self::DataT)> {
) -> SyscallResult<(SocketHandle, Self::DataT)> {
if uid != 0 {
return Err(syscall::Error::new(syscall::EACCES));
return Err(SyscallError::new(syscall::EACCES));
}
let proto =
u8::from_str_radix(path, 16).or_else(|_| Err(syscall::Error::new(syscall::ENOENT)))?;
u8::from_str_radix(path, 16).or_else(|_| Err(SyscallError::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);
@@ -117,10 +69,12 @@ impl<'a, 'b> SchemeSocket for RawSocket<'a, 'b> {
rx_buffer,
tx_buffer,
);
Ok((ip_socket, ()))
let socket_handle = socket_set.add(ip_socket);
Ok((socket_handle, ()))
}
fn close_file(&self, _: &SchemeFile<Self>, _: &mut Self::SchemeDataT) -> syscall::Result<()> {
fn close_file(&self, _: &SchemeFile<Self>, _: &mut Self::SchemeDataT) -> SyscallResult<()> {
Ok(())
}
@@ -128,14 +82,14 @@ impl<'a, 'b> SchemeSocket for RawSocket<'a, 'b> {
&mut self,
file: &mut SocketFile<Self::DataT>,
buf: &[u8],
) -> syscall::Result<usize> {
) -> SyscallResult<usize> {
if self.can_send() {
self.send_slice(buf).expect("Can't send slice");
Ok(buf.len())
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
Ok(0)
} else {
Err(syscall::Error::new(syscall::EWOULDBLOCK))
Err(SyscallError::new(syscall::EWOULDBLOCK))
}
}
@@ -143,37 +97,36 @@ impl<'a, 'b> SchemeSocket for RawSocket<'a, 'b> {
&mut self,
file: &mut SocketFile<Self::DataT>,
buf: &mut [u8],
) -> syscall::Result<usize> {
) -> SyscallResult<usize> {
if self.can_recv() {
let length = self.recv_slice(buf).expect("Can't receive slice");
Ok(length)
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
Ok(0)
} else {
Err(syscall::Error::new(syscall::EWOULDBLOCK))
Err(SyscallError::new(syscall::EWOULDBLOCK))
}
}
fn dup(
&self,
_: &mut SchemeFile<Self>,
fd: usize,
socket_handle: SocketHandle,
path: &str,
_socket_set: &mut SocketSet,
_file: &mut SchemeFile<Self>,
_path: &str,
_: &mut Self::SchemeDataT,
) -> syscall::Result<SchemeFile<Self>> {
match path {
"write_timeout" => Ok(SchemeFile::Setting(SettingFile {
socket_handle,
fd,
setting: Setting::WriteTimeout,
})),
"read_timeout" => Ok(SchemeFile::Setting(SettingFile {
socket_handle,
fd,
setting: Setting::ReadTimeout,
})),
_ => Err(syscall::Error::new(syscall::EBADF)),
) -> SyscallResult<DupResult<Self>> {
Err(SyscallError::new(syscall::EBADF))
}
fn fpath(&self, _file: &SchemeFile<Self>, buf: &mut [u8]) -> SyscallResult<usize> {
let path = format!("ip:{}", self.ip_protocol());
let path = path.as_bytes();
let mut i = 0;
while i < buf.len() && i < path.len() {
buf[i] = path[i];
i += 1;
}
Ok(i)
}
}
+41 -25
View File
@@ -1,35 +1,38 @@
use netutils::getcfg;
use smoltcp;
use smoltcp::iface::{ArpCache, EthernetInterface, SliceArpCache};
use smoltcp::socket::SocketSet as SmoltcpSocketSet;
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, IpEndpoint, Ipv4Address};
use std::cell::RefCell;
use std::collections::VecDeque;
use std::fs::File;
use std::io::{Read, Write};
use std::mem;
use std::mem::size_of;
use std::rc::Rc;
use std::str::FromStr;
use std::time::Instant;
use syscall::data::TimeSpec;
use syscall;
use buffer_pool::{Buffer, BufferPool};
use device::NetworkDevice;
use error::{Error, Result};
use self::ip::IpScheme;
use self::udp::UdpScheme;
use self::tcp::TcpScheme;
use self::udp::UdpScheme;
mod ip;
mod socket;
mod udp;
mod tcp;
mod udp;
type SocketSet = Rc<RefCell<smoltcp::socket::SocketSet<'static, 'static, 'static>>>;
type SocketSet = SmoltcpSocketSet<'static, 'static, 'static>;
pub struct Smolnetd {
network_file: Rc<RefCell<File>>,
time_file: File,
iface: smoltcp::iface::EthernetInterface<'static, 'static, 'static, NetworkDevice>,
socket_set: SocketSet,
iface: EthernetInterface<'static, 'static, 'static, NetworkDevice>,
socket_set: Rc<RefCell<SocketSet>>,
startup_time: Instant,
@@ -54,26 +57,25 @@ impl Smolnetd {
tcp_file: File,
time_file: File,
) -> Smolnetd {
let arp_cache = smoltcp::iface::SliceArpCache::new(vec![Default::default(); 8]);
let hardware_addr = smoltcp::wire::EthernetAddress::from_str(getcfg("mac").unwrap().trim())
let arp_cache = SliceArpCache::new(vec![Default::default(); 8]);
let hardware_addr = EthernetAddress::from_str(getcfg("mac").unwrap().trim())
.expect("Can't parse the 'mac' cfg");
let local_ip = smoltcp::wire::IpAddress::from_str(getcfg("ip").unwrap().trim())
.expect("Can't parse the 'ip' cfg.");
let protocol_addrs = [smoltcp::wire::IpCidr::new(local_ip, 24)];
let default_gw = smoltcp::wire::Ipv4Address::from_str(getcfg("ip_router").unwrap().trim())
let local_ip =
IpAddress::from_str(getcfg("ip").unwrap().trim()).expect("Can't parse the 'ip' cfg.");
let protocol_addrs = [IpCidr::new(local_ip, 24)];
let default_gw = Ipv4Address::from_str(getcfg("ip_router").unwrap().trim())
.expect("Can't parse the 'ip_router' cfg.");
// 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(Rc::clone(&network_file), Rc::clone(&input_queue));
let iface = smoltcp::iface::EthernetInterface::new(
let iface = EthernetInterface::new(
Box::new(network_device),
Box::new(arp_cache) as Box<smoltcp::iface::ArpCache>,
Box::new(arp_cache) as Box<ArpCache>,
hardware_addr,
protocol_addrs,
Some(default_gw),
);
let socket_set = Rc::new(RefCell::new(smoltcp::socket::SocketSet::new(vec![])));
let socket_set = Rc::new(RefCell::new(SocketSet::new(vec![])));
Smolnetd {
iface,
socket_set: Rc::clone(&socket_set),
@@ -97,31 +99,31 @@ impl Smolnetd {
pub fn on_ip_scheme_event(&mut self) -> Result<Option<()>> {
self.ip_scheme.on_scheme_event()?;
self.poll()?;
let _ = self.poll()?;
Ok(None)
}
pub fn on_udp_scheme_event(&mut self) -> Result<Option<()>> {
self.udp_scheme.on_scheme_event()?;
self.poll()?;
let _ = self.poll()?;
Ok(None)
}
pub fn on_tcp_scheme_event(&mut self) -> Result<Option<()>> {
self.tcp_scheme.on_scheme_event()?;
self.poll()?;
let _ = self.poll()?;
Ok(None)
}
pub fn on_time_event(&mut self) -> Result<Option<()>> {
let timeout = self.poll()?;
self.schedule_timeout(timeout)?;
self.schedule_time_event(timeout)?;
Ok(None)
}
fn schedule_timeout(&mut self, timeout: i64) -> Result<()> {
let mut time = syscall::data::TimeSpec::default();
if self.time_file.read(&mut time)? < mem::size_of::<syscall::data::TimeSpec>() {
fn schedule_time_event(&mut self, timeout: i64) -> Result<()> {
let mut time = TimeSpec::default();
if self.time_file.read(&mut time)? < size_of::<TimeSpec>() {
return Err(Error::from_syscall_error(
syscall::Error::new(syscall::EBADF),
"Can't read current time",
@@ -181,7 +183,6 @@ impl Smolnetd {
if count == 0 {
break;
}
trace!("got frame {}", count);
buffer.resize(count);
self.input_queue.borrow_mut().push_back(buffer);
total_frames += 1;
@@ -216,3 +217,18 @@ fn post_fevent(scheme_file: &mut File, fd: usize, event: usize, data_len: usize)
.map(|_| ())
.map_err(|e| Error::from_io_error(e, "failed to post fevent"))
}
fn parse_endpoint(socket: &str) -> IpEndpoint {
let mut socket_parts = socket.split(':');
let host = IpAddress::Ipv4(
Ipv4Address::from_str(socket_parts.next().unwrap_or(""))
.unwrap_or_else(|_| Ipv4Address::new(0, 0, 0, 0)),
);
let port = socket_parts
.next()
.unwrap_or("")
.parse::<u16>()
.unwrap_or(0);
IpEndpoint::new(host, port)
}
+293 -167
View File
@@ -1,24 +1,29 @@
use smoltcp::socket::{AsSocket, Socket, SocketHandle};
use smoltcp::socket::{AnySocket, SocketHandle};
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::{Read, Write};
use std::str;
use std::marker::PhantomData;
use syscall::SchemeMut;
use std::mem;
use std::ops::Deref;
use std::ops::DerefMut;
use std::rc::Rc;
use std::str;
use syscall::data::TimeSpec;
use syscall::{Error as SyscallError, Packet as SyscallPacket, Result as SyscallResult, SchemeMut};
use syscall;
use error::{Error, Result};
use super::SocketSet;
use super::post_fevent;
use super::{SocketSet, post_fevent};
pub struct SocketFile<DataT> {
pub flags: usize,
pub data: DataT,
events: usize,
socket_handle: SocketHandle,
pub data: DataT,
pub read_timeout: Option<TimeSpec>,
pub write_timeout: Option<TimeSpec>,
read_timeout: Option<TimeSpec>,
write_timeout: Option<TimeSpec>,
}
impl<DataT> SocketFile<DataT> {
@@ -29,7 +34,7 @@ impl<DataT> SocketFile<DataT> {
read_timeout: self.read_timeout,
write_timeout: self.write_timeout,
socket_handle: self.socket_handle,
data
data,
}
}
@@ -40,15 +45,23 @@ impl<DataT> SocketFile<DataT> {
read_timeout: None,
write_timeout: None,
socket_handle,
data
data,
}
}
}
pub struct SettingFile<SettingT> {
pub fd: usize,
pub socket_handle: SocketHandle,
pub setting: SettingT,
#[derive(Copy, Clone)]
enum Setting<SettingT: Copy> {
Ttl,
ReadTimeout,
WriteTimeout,
#[allow(dead_code)] Other(SettingT),
}
pub struct SettingFile<SettingT: Copy> {
fd: usize,
socket_handle: SocketHandle,
setting: Setting<SettingT>,
}
pub enum SchemeFile<SocketT>
@@ -63,7 +76,7 @@ impl<SocketT> SchemeFile<SocketT>
where
SocketT: SchemeSocket,
{
fn socket_handle(&self) -> SocketHandle {
pub fn socket_handle(&self) -> SocketHandle {
match *self {
SchemeFile::Socket(SocketFile { socket_handle, .. }) |
SchemeFile::Setting(SettingFile { socket_handle, .. }) => socket_handle,
@@ -74,14 +87,17 @@ where
#[derive(Default, Clone)]
struct WaitHandle {
until: Option<TimeSpec>,
packet: syscall::Packet,
packet: SyscallPacket,
}
#[derive(Default)]
struct WaitQueues {
read_queue: Vec<WaitHandle>,
write_queue: Vec<WaitHandle>,
}
type WaitQueue = Vec<WaitHandle>;
type WaitQueueMap = BTreeMap<SocketHandle, WaitQueue>;
pub type DupResult<T> = (
SchemeFile<T>,
Option<(SocketHandle, <T as SchemeSocket>::DataT)>,
);
pub trait SchemeSocket
where
@@ -96,39 +112,39 @@ where
fn can_send(&self) -> bool;
fn can_recv(&self) -> bool;
fn get_setting(&SocketFile<Self::DataT>, Self::SettingT, &mut [u8]) -> syscall::Result<usize>;
fn set_setting(&mut SocketFile<Self::DataT>, Self::SettingT, &[u8]) -> syscall::Result<usize>;
fn get_setting(&SocketFile<Self::DataT>, Self::SettingT, &mut [u8]) -> SyscallResult<usize>;
fn set_setting(&mut SocketFile<Self::DataT>, Self::SettingT, &[u8]) -> SyscallResult<usize>;
fn new_socket(
&mut SocketSet,
&str,
u32,
&mut Self::SchemeDataT,
) -> syscall::Result<(Socket<'static, 'static>, Self::DataT)>;
fn close_file(&self, &SchemeFile<Self>, &mut Self::SchemeDataT) -> syscall::Result<()>;
) -> SyscallResult<(SocketHandle, Self::DataT)>;
fn write_buf(&mut self, &mut SocketFile<Self::DataT>, buf: &[u8]) -> syscall::Result<usize>;
fn read_buf(&mut self, &mut SocketFile<Self::DataT>, buf: &mut [u8]) -> syscall::Result<usize>;
fn close_file(&self, &SchemeFile<Self>, &mut Self::SchemeDataT) -> SyscallResult<()>;
fn write_buf(&mut self, &mut SocketFile<Self::DataT>, buf: &[u8]) -> SyscallResult<usize>;
fn read_buf(&mut self, &mut SocketFile<Self::DataT>, buf: &mut [u8]) -> SyscallResult<usize>;
fn fpath(&self, &SchemeFile<Self>, &mut [u8]) -> SyscallResult<usize>;
fn dup(
&self,
&mut SocketSet,
&mut SchemeFile<Self>,
usize,
SocketHandle,
&str,
&mut Self::SchemeDataT,
) -> syscall::Result<SchemeFile<Self>>;
) -> SyscallResult<DupResult<Self>>;
}
type WaitQueueMap = BTreeMap<SocketHandle, WaitQueues>;
pub struct SocketScheme<SocketT>
where
SocketT: SchemeSocket,
Socket<'static, 'static>: AsSocket<SocketT>,
SocketT: SchemeSocket + AnySocket<'static, 'static>,
{
next_fd: usize,
fds: BTreeMap<usize, SchemeFile<SocketT>>,
socket_set: SocketSet,
files: BTreeMap<usize, SchemeFile<SocketT>>,
socket_set: Rc<RefCell<SocketSet>>,
scheme_file: File,
wait_queue_map: WaitQueueMap,
scheme_data: SocketT::SchemeDataT,
@@ -137,13 +153,12 @@ where
impl<SocketT> SocketScheme<SocketT>
where
SocketT: SchemeSocket,
Socket<'static, 'static>: AsSocket<SocketT>,
SocketT: SchemeSocket + AnySocket<'static, 'static>,
{
pub fn new(socket_set: SocketSet, scheme_file: File) -> SocketScheme<SocketT> {
pub fn new(socket_set: Rc<RefCell<SocketSet>>, scheme_file: File) -> SocketScheme<SocketT> {
SocketScheme {
next_fd: 1,
fds: BTreeMap::new(),
files: BTreeMap::new(),
socket_set,
scheme_data: SocketT::new_scheme_data(),
scheme_file,
@@ -154,7 +169,7 @@ where
pub fn on_scheme_event(&mut self) -> Result<Option<()>> {
loop {
let mut packet = syscall::Packet::default();
let mut packet = SyscallPacket::default();
if self.scheme_file.read(&mut packet)? == 0 {
break;
}
@@ -172,15 +187,15 @@ where
pub fn notify_sockets(&mut self) -> Result<()> {
// Notify non-blocking sockets
for (&fd, handle) in &self.fds {
for (&fd, file) in &self.files {
if let SchemeFile::Socket(SocketFile {
socket_handle,
events,
..
}) = *handle
}) = *file
{
let mut socket_set = self.socket_set.borrow_mut();
let socket: &mut SocketT = socket_set.get_mut(socket_handle).as_socket();
let socket = socket_set.get::<SocketT>(socket_handle);
if events & syscall::EVENT_READ == syscall::EVENT_READ && socket.can_recv() {
post_fevent(&mut self.scheme_file, fd, syscall::EVENT_READ, 1)?;
@@ -206,35 +221,19 @@ where
let socket_handles: Vec<_> = self.wait_queue_map.keys().cloned().collect();
for socket_handle in socket_handles {
let (can_recv, can_send) = {
let mut socket_set = self.socket_set.borrow_mut();
let socket: &mut SocketT = socket_set.get_mut(socket_handle).as_socket();
(socket.can_recv(), socket.can_send())
};
if can_recv {
self.wake_up_wait_queue(socket_handle, cur_time, |wq| &mut wq.read_queue)?;
}
if can_send {
self.wake_up_wait_queue(socket_handle, cur_time, |wq| &mut wq.write_queue)?;
}
self.wake_up_wait_queue(socket_handle, cur_time)?;
}
Ok(())
}
fn wake_up_wait_queue<F>(
fn wake_up_wait_queue(
&mut self,
socket_handle: SocketHandle,
cur_time: syscall::TimeSpec,
f: F,
) -> Result<()>
where
F: Fn(&mut WaitQueues) -> &mut Vec<WaitHandle>,
{
let mut input_queue = if let Some(wait_queues) = self.wait_queue_map.get_mut(&socket_handle)
) -> Result<()> {
let mut input_queue = if let Some(wait_queue) = self.wait_queue_map.get_mut(&socket_handle)
{
::std::mem::replace(f(wait_queues), vec![])
::std::mem::replace(wait_queue, vec![])
} else {
vec![]
};
@@ -247,11 +246,10 @@ where
if packet.a == (-syscall::EWOULDBLOCK) as usize {
match wait_handle.until {
Some(until)
if (until.tv_sec >= cur_time.tv_sec
if (until.tv_sec < cur_time.tv_sec
|| (until.tv_sec == cur_time.tv_sec
&& until.tv_nsec >= cur_time.tv_nsec)) =>
&& until.tv_nsec < cur_time.tv_nsec)) =>
{
trace!("Timeouting fd {}", packet.b);
packet.a = (-syscall::ETIMEDOUT) as usize;
self.scheme_file.write_all(&packet)?;
}
@@ -260,20 +258,39 @@ where
}
}
} else {
trace!("Waking up fd {}", packet.b);
self.scheme_file.write_all(&packet)?;
}
}
if let Some(wait_queues) = self.wait_queue_map.get_mut(&socket_handle) {
f(wait_queues).extend(to_retain);
if let Some(wait_queue) = self.wait_queue_map.get_mut(&socket_handle) {
wait_queue.extend(to_retain);
}
Ok(())
}
fn handle_block(&mut self, mut packet: syscall::Packet) -> Result<()> {
trace!("Handling blocking call");
fn move_file_to_new_socket_handle(
wait_queue_map: &mut WaitQueueMap,
fd: usize,
from: SocketHandle,
to: SocketHandle,
) -> SyscallResult<()> {
let mut to_move = vec![];
if let Some(wait_queue) = wait_queue_map.get_mut(&from) {
to_move = wait_queue
.drain_filter(|wh| wh.packet.b == fd)
.collect::<Vec<_>>();
}
wait_queue_map
.entry(to)
.or_insert_with(|| vec![])
.extend(to_move);
Ok(())
}
fn handle_block(&mut self, mut packet: SyscallPacket) -> Result<()> {
let syscall_result = self.try_handle_block(&mut packet);
if let Err(syscall_error) = syscall_result {
packet.a = (-syscall_error.errno) as usize;
@@ -287,28 +304,28 @@ where
}
}
fn try_handle_block(&mut self, packet: &mut syscall::Packet) -> syscall::Result<()> {
fn try_handle_block(&mut self, packet: &mut SyscallPacket) -> SyscallResult<()> {
let fd = packet.b;
let (socket_handle, read_timeout, write_timeout) = {
let handle = self.fds
let file = self.files
.get(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
if let SchemeFile::Socket(ref scheme_file) = *handle {
if let SchemeFile::Socket(ref scheme_file) = *file {
Ok((
scheme_file.socket_handle,
scheme_file.read_timeout,
scheme_file.write_timeout,
))
} else {
Err(syscall::Error::new(syscall::EBADF))
Err(SyscallError::new(syscall::EBADF))
}
}?;
let mut timeout = match packet.a {
syscall::SYS_READ => Ok(read_timeout),
syscall::SYS_WRITE => Ok(write_timeout),
_ => Err(syscall::Error::new(syscall::EBADF)),
syscall::SYS_READ => Ok(read_timeout),
_ => Ok(None),
}?;
if let Some(ref mut timeout) = timeout {
@@ -317,18 +334,11 @@ where
*timeout = add_time(timeout, &cur_time)
}
trace!("Adding {} to wait queie", fd);
let wait_queues = self.wait_queue_map
let wait_queue = self.wait_queue_map
.entry(socket_handle)
.or_insert_with(WaitQueues::default);
.or_insert_with(|| vec![]);
let queue = match packet.a {
syscall::SYS_READ => Ok(&mut wait_queues.read_queue),
syscall::SYS_WRITE => Ok(&mut wait_queues.write_queue),
_ => Err(syscall::Error::new(syscall::EBADF)),
}?;
queue.push(WaitHandle {
wait_queue.push(WaitHandle {
until: timeout,
packet: *packet,
});
@@ -339,55 +349,103 @@ where
fn get_setting(
&mut self,
fd: usize,
setting: SocketT::SettingT,
setting: Setting<SocketT::SettingT>,
buf: &mut [u8],
) -> syscall::Result<usize> {
let handle = self.fds
) -> SyscallResult<usize> {
let file = self.files
.get_mut(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
let handle = match *handle {
SchemeFile::Socket(ref mut handle) => handle,
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *file {
SchemeFile::Socket(ref mut file) => file,
_ => {
return Err(syscall::Error::new(syscall::EBADF));
return Err(SyscallError::new(syscall::EBADF));
}
};
SocketT::get_setting(handle, setting, buf)
if let Setting::Other(setting) = setting {
SocketT::get_setting(file, setting, buf)
} else {
let timespec = match (setting, file.read_timeout, file.write_timeout) {
(Setting::ReadTimeout, Some(read_timeout), _) => read_timeout,
(Setting::WriteTimeout, _, Some(write_timeout)) => write_timeout,
_ => {
return Ok(0);
}
};
if buf.len() < mem::size_of::<TimeSpec>() {
Ok(0)
} else {
let count = timespec.deref().read(buf).map_err(|err| {
SyscallError::new(err.raw_os_error().unwrap_or(syscall::EIO))
})?;
Ok(count)
}
}
}
fn update_setting(
&mut self,
fd: usize,
setting: SocketT::SettingT,
setting: Setting<SocketT::SettingT>,
buf: &[u8],
) -> syscall::Result<usize> {
let handle = self.fds
) -> SyscallResult<usize> {
let file = self.files
.get_mut(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
let handle = match *handle {
SchemeFile::Socket(ref mut handle) => handle,
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let file = match *file {
SchemeFile::Socket(ref mut file) => file,
_ => {
return Err(syscall::Error::new(syscall::EBADF));
return Err(SyscallError::new(syscall::EBADF));
}
};
SocketT::set_setting(handle, setting, buf)
match setting {
Setting::ReadTimeout | Setting::WriteTimeout => {
let (timeout, count) = {
if buf.len() < mem::size_of::<TimeSpec>() {
(None, 0)
} else {
let mut timespec = TimeSpec::default();
let count = timespec.deref_mut().write(buf).map_err(|err| {
SyscallError::new(err.raw_os_error().unwrap_or(syscall::EIO))
})?;
(Some(timespec), count)
}
};
match setting {
Setting::ReadTimeout => {
file.read_timeout = timeout;
}
Setting::WriteTimeout => {
file.write_timeout = timeout;
}
_ => {}
};
Ok(count)
}
Setting::Ttl => Ok(0),
Setting::Other(setting) => SocketT::set_setting(file, setting, buf),
}
}
}
impl<SocketT> syscall::SchemeMut for SocketScheme<SocketT>
where
SocketT: SchemeSocket,
Socket<'static, 'static>: AsSocket<SocketT>,
SocketT: SchemeSocket + AnySocket<'static, 'static>,
{
fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> syscall::Result<usize> {
let path = str::from_utf8(url).or_else(|_| Err(syscall::Error::new(syscall::EINVAL)))?;
fn open(&mut self, url: &[u8], flags: usize, uid: u32, _gid: u32) -> SyscallResult<usize> {
let path = str::from_utf8(url).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
let (socket, data) = SocketT::new_socket(path, uid, &mut self.scheme_data)?;
let (socket_handle, data) = SocketT::new_socket(
&mut self.socket_set.borrow_mut(),
path,
uid,
&mut self.scheme_data,
)?;
let socket_handle = self.socket_set.borrow_mut().add(socket);
let id = self.next_fd;
self.fds.insert(
self.files.insert(
id,
SchemeFile::Socket(SocketFile {
flags,
@@ -402,34 +460,28 @@ where
Ok(id)
}
fn close(&mut self, fd: usize) -> syscall::Result<usize> {
fn close(&mut self, fd: usize) -> SyscallResult<usize> {
let socket_handle = {
let handle = self.fds
let file = self.files
.get(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
handle.socket_handle()
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
file.socket_handle()
};
let scheme_file = self.fds.remove(&fd);
let scheme_file = self.files.remove(&fd);
let mut socket_set = self.socket_set.borrow_mut();
if let Some(scheme_file) = scheme_file {
let socket: &mut SocketT = socket_set.get_mut(socket_handle).as_socket();
let socket = socket_set.get::<SocketT>(socket_handle);
socket.close_file(&scheme_file, &mut self.scheme_data)?;
}
let remove_wq =
if let Some(ref mut wait_queues) = self.wait_queue_map.get_mut(&socket_handle) {
wait_queues.read_queue.retain(
if let Some(ref mut wait_queue) = self.wait_queue_map.get_mut(&socket_handle) {
wait_queue.retain(
|&WaitHandle {
packet: syscall::Packet { a, .. },
packet: SyscallPacket { a, .. },
..
}| a != fd,
);
wait_queues.write_queue.retain(
|&WaitHandle {
packet: syscall::Packet { a, .. },
..
}| a != fd,
);
wait_queues.read_queue.is_empty() && wait_queues.write_queue.is_empty()
wait_queue.is_empty()
} else {
false
};
@@ -442,93 +494,167 @@ where
Ok(0)
}
fn write(&mut self, fd: usize, buf: &[u8]) -> syscall::Result<usize> {
fn write(&mut self, fd: usize, buf: &[u8]) -> SyscallResult<usize> {
let (fd, setting) = {
let handle = self.fds
let file = self.files
.get_mut(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
match *handle {
match *file {
SchemeFile::Setting(ref setting_handle) => {
(setting_handle.fd, setting_handle.setting)
}
SchemeFile::Socket(ref mut handle) => {
SchemeFile::Socket(ref mut file) => {
let mut socket_set = self.socket_set.borrow_mut();
let socket: &mut SocketT = socket_set.get_mut(handle.socket_handle).as_socket();
return <SocketT as SchemeSocket>::write_buf(socket, handle, buf);
let mut socket = socket_set.get::<SocketT>(file.socket_handle);
return SocketT::write_buf(&mut socket, file, buf);
}
}
};
self.update_setting(fd, setting, buf)
}
fn read(&mut self, fd: usize, buf: &mut [u8]) -> syscall::Result<usize> {
fn read(&mut self, fd: usize, buf: &mut [u8]) -> SyscallResult<usize> {
let (fd, setting) = {
let handle = self.fds
let file = self.files
.get_mut(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
match *handle {
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
match *file {
SchemeFile::Setting(ref setting_handle) => {
(setting_handle.fd, setting_handle.setting)
}
SchemeFile::Socket(ref mut handle) => {
SchemeFile::Socket(ref mut file) => {
let mut socket_set = self.socket_set.borrow_mut();
let socket: &mut SocketT = socket_set.get_mut(handle.socket_handle).as_socket();
return <SocketT as SchemeSocket>::read_buf(socket, handle, buf);
let mut socket = socket_set.get::<SocketT>(file.socket_handle);
return SocketT::read_buf(&mut socket, file, buf);
}
}
};
self.get_setting(fd, setting, buf)
}
fn dup(&mut self, fd: usize, buf: &[u8]) -> syscall::Result<usize> {
let path = str::from_utf8(buf).or_else(|_| Err(syscall::Error::new(syscall::EINVAL)))?;
fn dup(&mut self, fd: usize, buf: &[u8]) -> SyscallResult<usize> {
let path = str::from_utf8(buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
let handle = {
let handle = self.fds
let new_file = {
let file = self.files
.get_mut(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let socket_handle = handle.socket_handle();
let mut socket_set = self.socket_set.borrow_mut();
let socket: &mut SocketT = socket_set.get_mut(handle.socket_handle()).as_socket();
let socket_handle = file.socket_handle();
socket.dup(handle, fd, socket_handle, path, &mut self.scheme_data)
}?;
let (new_handle, update_with) = match path {
"ttl" => (
SchemeFile::Setting(SettingFile {
socket_handle,
fd,
setting: Setting::Ttl,
}),
None,
),
"read_timeout" => (
SchemeFile::Setting(SettingFile {
socket_handle,
fd,
setting: Setting::ReadTimeout,
}),
None,
),
"write_timeout" => (
SchemeFile::Setting(SettingFile {
socket_handle,
fd,
setting: Setting::WriteTimeout,
}),
None,
),
_ => SocketT::dup(
&mut self.socket_set.borrow_mut(),
file,
path,
&mut self.scheme_data,
)?,
};
self.socket_set.borrow_mut().retain(handle.socket_handle());
if let Some((socket_handle, data)) = update_with {
if let SchemeFile::Socket(ref mut file) = *file {
Self::move_file_to_new_socket_handle(
&mut self.wait_queue_map,
fd,
file.socket_handle,
socket_handle,
)?;
file.socket_handle = socket_handle;
file.data = data;
} else {
self.socket_set.borrow_mut().retain(file.socket_handle());
}
} else {
self.socket_set.borrow_mut().retain(file.socket_handle());
}
new_handle
};
let id = self.next_fd;
self.fds.insert(id, handle);
self.files.insert(id, new_file);
self.next_fd += 1;
Ok(id)
}
fn fevent(&mut self, fd: usize, events: usize) -> syscall::Result<usize> {
let handle = self.fds
fn fevent(&mut self, fd: usize, events: usize) -> SyscallResult<usize> {
let file = self.files
.get_mut(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
match *handle {
SchemeFile::Setting(_) => Err(syscall::Error::new(syscall::EBADF)),
SchemeFile::Socket(ref mut handle) => {
handle.events = events;
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
match *file {
SchemeFile::Setting(_) => Err(SyscallError::new(syscall::EBADF)),
SchemeFile::Socket(ref mut file) => {
file.events = events;
Ok(fd)
}
}
}
fn fsync(&mut self, fd: usize) -> syscall::Result<usize> {
fn fsync(&mut self, fd: usize) -> SyscallResult<usize> {
{
let _handle = self.fds
let _file = self.files
.get_mut(&fd)
.ok_or_else(|| syscall::Error::new(syscall::EBADF))?;
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
}
Ok(0)
// TODO Implement fsyncing
// self.0.network_fsync()
}
fn fpath(&mut self, fd: usize, buf: &mut [u8]) -> SyscallResult<usize> {
let file = self.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get::<SocketT>(file.socket_handle());
socket.fpath(file, buf)
}
fn fcntl(&mut self, fd: usize, cmd: usize, arg: usize) -> SyscallResult<usize> {
let file = self.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
if let SchemeFile::Socket(ref mut socket_file) = *file {
match cmd {
syscall::F_GETFL => Ok(socket_file.flags),
syscall::F_SETFL => {
socket_file.flags = arg & !syscall::O_ACCMODE;
Ok(0)
}
_ => Err(SyscallError::new(syscall::EINVAL)),
}
} else {
Err(SyscallError::new(syscall::EBADF))
}
}
}
fn add_time(a: &TimeSpec, b: &TimeSpec) -> TimeSpec {
+100 -132
View File
@@ -1,31 +1,18 @@
use super::socket::*;
use smoltcp::socket::{AsSocket, Socket, SocketHandle, TcpSocket, TcpSocketBuffer};
use smoltcp::wire::{IpAddress, IpEndpoint, Ipv4Address};
use std::io::{Read, Write};
use std::str::FromStr;
use smoltcp::socket::{SocketHandle, TcpSocket, TcpSocketBuffer};
use std::str;
use std::mem;
use std::ops::Deref;
use std::ops::DerefMut;
use syscall::data::TimeSpec;
use syscall::{Error as SyscallError, Result as SyscallResult};
use syscall;
use port_set::PortSet;
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme};
use super::{parse_endpoint, SocketSet};
pub type TcpScheme = SocketScheme<TcpSocket<'static>>;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Setting {
Ttl,
ReadTimeout,
WriteTimeout,
}
impl<'a> SchemeSocket for TcpSocket<'a> {
type SchemeDataT = PortSet;
type DataT = ();
type SettingT = Setting;
type SettingT = ();
fn new_scheme_data() -> Self::SchemeDataT {
PortSet::new(49_152u16, 65_535u16).expect("Wrong TCP port numbers")
@@ -40,108 +27,74 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
}
fn get_setting(
file: &SocketFile<Self::DataT>,
setting: Self::SettingT,
buf: &mut [u8],
) -> syscall::Result<usize> {
trace!("TCP get setting {:?}", setting);
let timespec = match (setting, file.read_timeout, file.write_timeout) {
(Setting::ReadTimeout, Some(read_timeout), _) => read_timeout,
(Setting::WriteTimeout, _, Some(write_timeout)) => write_timeout,
_ => {
return Ok(0);
}
};
if buf.len() < mem::size_of::<TimeSpec>() {
Ok(0)
} else {
let count = timespec.deref().read(buf).map_err(|err| {
syscall::Error::new(err.raw_os_error().unwrap_or(syscall::EIO))
})?;
Ok(count)
}
_file: &SocketFile<Self::DataT>,
_setting: Self::SettingT,
_buf: &mut [u8],
) -> SyscallResult<usize> {
Ok(0)
}
fn set_setting(
file: &mut SocketFile<Self::DataT>,
setting: Self::SettingT,
buf: &[u8],
) -> syscall::Result<usize> {
trace!("TCP set setting {:?}", setting);
match setting {
Setting::ReadTimeout | Setting::WriteTimeout => {
let (timeout, count) = {
if buf.len() < mem::size_of::<TimeSpec>() {
(None, 0)
} else {
let mut timespec = TimeSpec::default();
let count = timespec.deref_mut().write(buf).map_err(|err| {
syscall::Error::new(err.raw_os_error().unwrap_or(syscall::EIO))
})?;
(Some(timespec), count)
}
};
match setting {
Setting::ReadTimeout => {
file.read_timeout = timeout;
}
Setting::WriteTimeout => {
file.write_timeout = timeout;
}
_ => {}
};
return Ok(count);
}
Setting::Ttl => {}
}
_file: &mut SocketFile<Self::DataT>,
_setting: Self::SettingT,
_buf: &[u8],
) -> SyscallResult<usize> {
Ok(0)
}
fn new_socket(
socket_set: &mut SocketSet,
path: &str,
uid: u32,
port_set: &mut Self::SchemeDataT,
) -> syscall::Result<(Socket<'static, 'static>, Self::DataT)> {
) -> SyscallResult<(SocketHandle, Self::DataT)> {
trace!("TCP open {}", path);
let mut parts = path.split('/');
let remote_endpoint = parse_endpoint(parts.next().unwrap_or(""));
let mut local_endpoint = parse_endpoint(parts.next().unwrap_or(""));
if local_endpoint.port > 0 && local_endpoint.port <= 1024 && uid != 0 {
return Err(syscall::Error::new(syscall::EACCES));
return Err(SyscallError::new(syscall::EACCES));
}
let rx_packets = vec![0; 65_535];
let tx_packets = vec![0; 65_535];
let rx_buffer = TcpSocketBuffer::new(rx_packets);
let tx_buffer = TcpSocketBuffer::new(tx_packets);
let mut tcp_socket = TcpSocket::new(rx_buffer, tx_buffer);
let socket = TcpSocket::new(rx_buffer, tx_buffer);
if local_endpoint.port == 0 {
local_endpoint.port = port_set
.get_port()
.ok_or_else(|| syscall::Error::new(syscall::EINVAL))?;
.ok_or_else(|| SyscallError::new(syscall::EINVAL))?;
} else if !port_set.claim_port(local_endpoint.port) {
return Err(syscall::Error::new(syscall::EADDRINUSE));
return Err(SyscallError::new(syscall::EADDRINUSE));
}
{
let tcp_socket: &mut TcpSocket = tcp_socket.as_socket();
let socket_handle = socket_set.add(socket);
let mut tcp_socket = socket_set.get::<TcpSocket>(socket_handle);
if remote_endpoint.is_specified() {
trace!("Connecting tcp {} {}", local_endpoint, remote_endpoint);
tcp_socket
.connect(remote_endpoint, local_endpoint)
.expect("Can't connect tcp socket ");
} else {
trace!("Listening tcp {}", local_endpoint);
tcp_socket
.listen(local_endpoint)
.expect("Can't listen on local endpoint");
}
Ok((tcp_socket, ()))
Ok((socket_handle, ()))
}
fn close_file(
&self,
file: &SchemeFile<Self>,
port_set: &mut Self::SchemeDataT,
) -> syscall::Result<()> {
) -> SyscallResult<()> {
if let SchemeFile::Socket(_) = *file {
port_set.release_port(self.local_endpoint().port);
}
@@ -152,17 +105,16 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
&mut self,
file: &mut SocketFile<Self::DataT>,
buf: &[u8],
) -> syscall::Result<usize> {
if !self.is_open() {
return Err(syscall::Error::new(syscall::EADDRNOTAVAIL));
}
if self.can_send() {
) -> SyscallResult<usize> {
if !self.is_active() {
Err(SyscallError::new(syscall::ENOTCONN))
} else if self.can_send() {
self.send_slice(buf).expect("Can't send slice");
Ok(buf.len())
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
Ok(0)
} else {
Err(syscall::Error::new(syscall::EWOULDBLOCK))
Err(SyscallError::new(syscall::EWOULDBLOCK))
}
}
@@ -170,68 +122,84 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
&mut self,
file: &mut SocketFile<Self::DataT>,
buf: &mut [u8],
) -> syscall::Result<usize> {
if self.can_recv() {
) -> SyscallResult<usize> {
if !self.is_active() {
Err(SyscallError::new(syscall::ENOTCONN))
} else if self.can_recv() {
let length = self.recv_slice(buf).expect("Can't receive slice");
Ok(length)
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
Ok(0)
} else {
Err(syscall::Error::new(syscall::EWOULDBLOCK))
Err(SyscallError::new(syscall::EWOULDBLOCK))
}
}
fn dup(
&self,
socket_set: &mut SocketSet,
file: &mut SchemeFile<Self>,
fd: usize,
socket_handle: SocketHandle,
path: &str,
port_set: &mut Self::SchemeDataT,
) -> syscall::Result<SchemeFile<Self>> {
trace!("TCP dup {}", path);
let handle = match path {
"ttl" => SchemeFile::Setting(SettingFile {
socket_handle,
fd,
setting: Setting::Ttl,
}),
"read_timeout" => SchemeFile::Setting(SettingFile {
socket_handle,
fd,
setting: Setting::ReadTimeout,
}),
"write_timeout" => SchemeFile::Setting(SettingFile {
socket_handle,
fd,
setting: Setting::WriteTimeout,
}),
_ => if let SchemeFile::Socket(ref tcp_handle) = *file {
SchemeFile::Socket(tcp_handle.clone_with_data(()))
} else {
SchemeFile::Socket(SocketFile::new_with_data(socket_handle, ()))
},
) -> SyscallResult<DupResult<Self>> {
let socket_handle = file.socket_handle();
let (is_active, local_endpoint) = {
let socket = socket_set.get::<TcpSocket>(socket_handle);
(socket.is_active(), socket.local_endpoint())
};
if let SchemeFile::Socket(_) = handle {
port_set.acquire_port(self.local_endpoint().port);
let file = match path {
"listen" => if let SchemeFile::Socket(ref tcp_handle) = *file {
if !is_active {
return Err(SyscallError::new(syscall::EWOULDBLOCK));
}
trace!("TCP creating new listening socket");
let new_handle = SchemeFile::Socket(tcp_handle.clone_with_data(()));
let rx_packets = vec![0; 65_535];
let tx_packets = vec![0; 65_535];
let rx_buffer = TcpSocketBuffer::new(rx_packets);
let tx_buffer = TcpSocketBuffer::new(tx_packets);
let socket = TcpSocket::new(rx_buffer, tx_buffer);
let new_socket_handle = socket_set.add(socket);
{
let mut tcp_socket = socket_set.get::<TcpSocket>(new_socket_handle);
tcp_socket
.listen(local_endpoint)
.expect("Can't listen on local endpoint");
}
port_set.acquire_port(local_endpoint.port);
return Ok((new_handle, Some((new_socket_handle, ()))));
} else {
return Err(SyscallError::new(syscall::EBADF));
},
_ => {
trace!("TCP dup unknown {}", path);
if let SchemeFile::Socket(ref tcp_handle) = *file {
SchemeFile::Socket(tcp_handle.clone_with_data(()))
} else {
SchemeFile::Socket(SocketFile::new_with_data(socket_handle, ()))
}
}
};
if let SchemeFile::Socket(_) = file {
port_set.acquire_port(local_endpoint.port);
}
Ok(handle)
Ok((file, None))
}
fn fpath(&self, _: &SchemeFile<Self>, buf: &mut [u8]) -> SyscallResult<usize> {
let path = format!("tcp:{}/{}", self.remote_endpoint(), self.local_endpoint());
let path = path.as_bytes();
let mut i = 0;
while i < buf.len() && i < path.len() {
buf[i] = path[i];
i += 1;
}
Ok(i)
}
}
fn parse_endpoint(socket: &str) -> IpEndpoint {
let mut socket_parts = socket.split(':');
let host = IpAddress::Ipv4(
Ipv4Address::from_str(socket_parts.next().unwrap_or(""))
.unwrap_or_else(|_| Ipv4Address::new(0, 0, 0, 0)),
);
let port = socket_parts
.next()
.unwrap_or("")
.parse::<u16>()
.unwrap_or(0);
IpEndpoint::new(host, port)
}
+63 -125
View File
@@ -1,33 +1,20 @@
use super::socket::*;
use smoltcp::socket::{AsSocket, Socket, SocketHandle, UdpPacketBuffer, UdpSocket, UdpSocketBuffer};
use smoltcp::wire::{IpAddress, IpEndpoint, Ipv4Address};
use std::io::{Read, Write};
use std::str::FromStr;
use smoltcp::socket::{SocketHandle, UdpPacketBuffer, UdpSocket, UdpSocketBuffer};
use smoltcp::wire::IpEndpoint;
use std::str;
use std::mem;
use std::ops::Deref;
use std::ops::DerefMut;
use syscall::data::TimeSpec;
use syscall::{Error as SyscallError, Result as SyscallResult};
use syscall;
use device::NetworkDevice;
use super::Smolnetd;
use port_set::PortSet;
use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme};
use super::{parse_endpoint, Smolnetd, SocketSet};
pub type UdpScheme = SocketScheme<UdpSocket<'static, 'static>>;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Setting {
Ttl,
ReadTimeout,
WriteTimeout,
}
impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> {
type SchemeDataT = PortSet;
type DataT = IpEndpoint;
type SettingT = Setting;
type SettingT = ();
fn new_scheme_data() -> Self::SchemeDataT {
PortSet::new(49_152u16, 65_535u16).expect("Wrong UDP port numbers")
@@ -42,73 +29,33 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> {
}
fn get_setting(
file: &SocketFile<Self::DataT>,
setting: Self::SettingT,
buf: &mut [u8],
) -> syscall::Result<usize> {
let timespec = match (setting, file.read_timeout, file.write_timeout) {
(Setting::ReadTimeout, Some(read_timeout), _) => read_timeout,
(Setting::WriteTimeout, _, Some(write_timeout)) => write_timeout,
_ => {
return Ok(0);
}
};
if buf.len() < mem::size_of::<TimeSpec>() {
Ok(0)
} else {
let count = timespec.deref().read(buf).map_err(|err| {
syscall::Error::new(err.raw_os_error().unwrap_or(syscall::EIO))
})?;
Ok(count)
}
_file: &SocketFile<Self::DataT>,
_setting: Self::SettingT,
_buf: &mut [u8],
) -> SyscallResult<usize> {
Ok(0)
}
fn set_setting(
file: &mut SocketFile<Self::DataT>,
setting: Self::SettingT,
buf: &[u8],
) -> syscall::Result<usize> {
match setting {
Setting::ReadTimeout | Setting::WriteTimeout => {
let (timeout, count) = {
if buf.len() < mem::size_of::<TimeSpec>() {
(None, 0)
} else {
let mut timespec = TimeSpec::default();
let count = timespec.deref_mut().write(buf).map_err(|err| {
syscall::Error::new(err.raw_os_error().unwrap_or(syscall::EIO))
})?;
(Some(timespec), count)
}
};
match setting {
Setting::ReadTimeout => {
file.read_timeout = timeout;
}
Setting::WriteTimeout => {
file.write_timeout = timeout;
}
_ => {}
};
return Ok(count);
}
Setting::Ttl => {}
}
_file: &mut SocketFile<Self::DataT>,
_setting: Self::SettingT,
_buf: &[u8],
) -> SyscallResult<usize> {
Ok(0)
}
fn new_socket(
socket_set: &mut SocketSet,
path: &str,
uid: u32,
port_set: &mut Self::SchemeDataT,
) -> syscall::Result<(Socket<'static, 'static>, Self::DataT)> {
) -> SyscallResult<(SocketHandle, Self::DataT)> {
let mut parts = path.split('/');
let remote_endpoint = parse_endpoint(parts.next().unwrap_or(""));
let mut local_endpoint = parse_endpoint(parts.next().unwrap_or(""));
if local_endpoint.port > 0 && local_endpoint.port <= 1024 && uid != 0 {
return Err(syscall::Error::new(syscall::EACCES));
return Err(SyscallError::new(syscall::EACCES));
}
let mut rx_packets = Vec::with_capacity(Smolnetd::SOCKET_BUFFER_SIZE);
@@ -119,31 +66,31 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> {
}
let rx_buffer = UdpSocketBuffer::new(rx_packets);
let tx_buffer = UdpSocketBuffer::new(tx_packets);
let mut udp_socket = UdpSocket::new(rx_buffer, tx_buffer);
let udp_socket = UdpSocket::new(rx_buffer, tx_buffer);
if local_endpoint.port == 0 {
local_endpoint.port = port_set
.get_port()
.ok_or_else(|| syscall::Error::new(syscall::EINVAL))?;
.ok_or_else(|| SyscallError::new(syscall::EINVAL))?;
} else if !port_set.claim_port(local_endpoint.port) {
return Err(syscall::Error::new(syscall::EADDRINUSE));
return Err(SyscallError::new(syscall::EADDRINUSE));
}
{
let udp_socket: &mut UdpSocket = udp_socket.as_socket();
udp_socket
.bind(local_endpoint)
.expect("Can't bind udp socket to local endpoint");
}
let socket_handle = socket_set.add(udp_socket);
Ok((udp_socket, remote_endpoint))
let mut udp_socket = socket_set.get::<UdpSocket>(socket_handle);
udp_socket
.bind(local_endpoint)
.expect("Can't bind udp socket to local endpoint");
Ok((socket_handle, remote_endpoint))
}
fn close_file(
&self,
file: &SchemeFile<Self>,
port_set: &mut Self::SchemeDataT,
) -> syscall::Result<()> {
) -> SyscallResult<()> {
if let SchemeFile::Socket(_) = *file {
port_set.release_port(self.endpoint().port);
}
@@ -154,9 +101,9 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> {
&mut self,
file: &mut SocketFile<Self::DataT>,
buf: &[u8],
) -> syscall::Result<usize> {
) -> SyscallResult<usize> {
if !file.data.is_specified() {
return Err(syscall::Error::new(syscall::EADDRNOTAVAIL));
return Err(SyscallError::new(syscall::EADDRNOTAVAIL));
}
if self.can_send() {
self.send_slice(buf, file.data).expect("Can't send slice");
@@ -164,7 +111,7 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> {
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
Ok(0)
} else {
Err(syscall::Error::new(syscall::EWOULDBLOCK))
Err(SyscallError::new(syscall::EWOULDBLOCK))
}
}
@@ -172,41 +119,25 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> {
&mut self,
file: &mut SocketFile<Self::DataT>,
buf: &mut [u8],
) -> syscall::Result<usize> {
) -> SyscallResult<usize> {
if self.can_recv() {
let (length, _) = self.recv_slice(buf).expect("Can't receive slice");
Ok(length)
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
Ok(0)
} else {
Err(syscall::Error::new(syscall::EWOULDBLOCK))
Err(SyscallError::new(syscall::EWOULDBLOCK))
}
}
fn dup(
&self,
socket_set: &mut SocketSet,
file: &mut SchemeFile<Self>,
fd: usize,
socket_handle: SocketHandle,
path: &str,
port_set: &mut Self::SchemeDataT,
) -> syscall::Result<SchemeFile<Self>> {
let handle = match path {
"ttl" => SchemeFile::Setting(SettingFile {
socket_handle,
fd,
setting: Setting::Ttl,
}),
"read_timeout" => SchemeFile::Setting(SettingFile {
socket_handle,
fd,
setting: Setting::ReadTimeout,
}),
"write_timeout" => SchemeFile::Setting(SettingFile {
socket_handle,
fd,
setting: Setting::WriteTimeout,
}),
) -> SyscallResult<DupResult<Self>> {
let socket_handle = file.socket_handle();
let file = match path {
_ => {
let remote_endpoint = parse_endpoint(path);
if let SchemeFile::Socket(ref udp_handle) = *file {
@@ -223,25 +154,32 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> {
}
};
if let SchemeFile::Socket(_) = handle {
port_set.acquire_port(self.endpoint().port);
let endpoint = {
let socket = socket_set.get::<UdpSocket>(socket_handle);
socket.endpoint()
};
if let SchemeFile::Socket(_) = file {
port_set.acquire_port(endpoint.port);
}
Ok(handle)
Ok((file, None))
}
fn fpath(&self, file: &SchemeFile<Self>, buf: &mut [u8]) -> SyscallResult<usize> {
if let SchemeFile::Socket(ref socket_file) = *file {
let path = format!("udp:{}/{}", socket_file.data, self.endpoint());
let path = path.as_bytes();
let mut i = 0;
while i < buf.len() && i < path.len() {
buf[i] = path[i];
i += 1;
}
Ok(i)
} else {
Err(SyscallError::new(syscall::EBADF))
}
}
}
fn parse_endpoint(socket: &str) -> IpEndpoint {
let mut socket_parts = socket.split(':');
let host = IpAddress::Ipv4(
Ipv4Address::from_str(socket_parts.next().unwrap_or(""))
.unwrap_or_else(|_| Ipv4Address::new(0, 0, 0, 0)),
);
let port = socket_parts
.next()
.unwrap_or("")
.parse::<u16>()
.unwrap_or(0);
IpEndpoint::new(host, port)
}