diff --git a/Cargo.toml b/Cargo.toml index 2b69b83462..e6d2d024d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,22 +20,24 @@ netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox-daemon = "0.1.1" redox_syscall = "0.3" +redox-log = "0.1" byteorder = { version = "1.0", default-features = false } dns-parser = "0.7.1" [dependencies.log] -version = "0.3" +version = "0.4" default-features = false features = ["release_max_level_warn"] [dependencies.smoltcp] -path = "smoltcp" +version = "0.10.0" default-features = false features = [ "std", - "ethernet", + "medium-ethernet", "proto-ipv4", - "socket-raw", "socket-icmp", "socket-udp", "socket-tcp" + "socket-raw", "socket-icmp", "socket-udp", "socket-tcp", + "log" ] #For debugging: "log", "verbose" diff --git a/src/dnsd/main.rs b/src/dnsd/main.rs index 0fb01f491b..3ba52906f8 100644 --- a/src/dnsd/main.rs +++ b/src/dnsd/main.rs @@ -81,7 +81,7 @@ fn run(daemon: redox_daemon::Daemon) -> Result<()> { fn main() { redox_daemon::Daemon::new(move |daemon| { - logger::init_logger(); + logger::init_logger("dnsd"); if let Err(err) = run(daemon) { error!("dnsd: {}", err); process::exit(1); diff --git a/src/lib/logger.rs b/src/lib/logger.rs index 90ed1f8306..e2952e98db 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -1,22 +1,16 @@ -use log::{set_logger_raw, Log, LogLevelFilter, LogMetadata, LogRecord}; +use redox_log::{OutputBuilder, RedoxLogger}; -struct Logger; - -impl Log for Logger { - fn enabled(&self, _: &LogMetadata) -> bool { - true - } - - fn log(&self, record: &LogRecord) { - println!("{}: {}", record.target(), record.args()); - } -} - -pub fn init_logger() { - unsafe { - set_logger_raw(|max_log_level| { - max_log_level.set(LogLevelFilter::Trace); - &Logger - }).expect("Can't initialize logger"); +pub fn init_logger(process_name: &str) { + if let Err(_) = RedoxLogger::new() + .with_output( + OutputBuilder::stdout() + .with_ansi_escape_codes() + .flush_on_newline(true) + .with_filter(log::LevelFilter::Trace) + .build(), + ) + .with_process_name(process_name.into()) + .enable() { + eprintln!("{process_name}: Failed to init logger") } } diff --git a/src/smolnetd/device.rs b/src/smolnetd/device.rs index 63919c2be4..3c276fe558 100644 --- a/src/smolnetd/device.rs +++ b/src/smolnetd/device.rs @@ -45,9 +45,9 @@ pub struct RxToken { } impl smoltcp::phy::RxToken for RxToken { - fn consume(mut self, _timestamp: Instant, f: F) -> smoltcp::Result + fn consume(mut self, f: F) -> R where - F: FnOnce(&mut [u8]) -> smoltcp::Result, + F: FnOnce(&mut [u8]) -> R, { f(&mut self.buffer) } @@ -58,14 +58,14 @@ pub struct TxToken { } impl smoltcp::phy::TxToken for TxToken { - fn consume(self, _timestamp: Instant, len: usize, f: F) -> smoltcp::Result + fn consume(self, len: usize, f: F) -> R where - F: FnOnce(&mut [u8]) -> smoltcp::Result, + F: FnOnce(&mut [u8]) -> R, { let data = self.data.borrow_mut(); let mut buffer = data.buffer_pool.borrow_mut().get_buffer(); buffer.resize(len); - let res = f(&mut buffer)?; + let res = f(&mut buffer); let mut loopback = false; if let Ok(mut frame) = smoltcp::wire::EthernetFrame::new_checked(&mut buffer) { @@ -78,19 +78,19 @@ impl smoltcp::phy::TxToken for TxToken { if loopback { data.input_queue.borrow_mut().push_back(buffer.move_out()); } else { + // TODO: Handle error data.network_file .borrow_mut() - .write(&buffer) - .map_err(|_| smoltcp::Error::Dropped)?; + .write(&buffer); } - Ok(res) + res } } -impl<'a> smoltcp::phy::Device<'a> for NetworkDevice { - type RxToken = RxToken; - type TxToken = TxToken; +impl smoltcp::phy::Device for NetworkDevice { + type RxToken<'a> = RxToken; + type TxToken<'a> = TxToken; fn capabilities(&self) -> smoltcp::phy::DeviceCapabilities { let mut limits = smoltcp::phy::DeviceCapabilities::default(); @@ -99,7 +99,7 @@ impl<'a> smoltcp::phy::Device<'a> for NetworkDevice { limits } - fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> { + fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { let data = self.data.borrow_mut(); let buffer = data.input_queue.borrow_mut().pop_front(); @@ -115,7 +115,7 @@ impl<'a> smoltcp::phy::Device<'a> for NetworkDevice { } } - fn transmit(&'a mut self) -> Option { + fn transmit(&mut self, _timestamp: Instant) -> Option> { Some(TxToken { data: Rc::clone(&self.data), }) diff --git a/src/smolnetd/main.rs b/src/smolnetd/main.rs index b359245ec3..b1b6ebb8ce 100644 --- a/src/smolnetd/main.rs +++ b/src/smolnetd/main.rs @@ -151,7 +151,7 @@ fn run(daemon: redox_daemon::Daemon) -> Result<()> { fn main() { redox_daemon::Daemon::new(move |daemon| { - logger::init_logger(); + logger::init_logger("smolnetd"); if let Err(err) = run(daemon) { error!("smoltcpd: {}", err); diff --git a/src/smolnetd/scheme/icmp.rs b/src/smolnetd/scheme/icmp.rs index cd65926f81..5ecd94fc8c 100644 --- a/src/smolnetd/scheme/icmp.rs +++ b/src/smolnetd/scheme/icmp.rs @@ -1,5 +1,6 @@ -use smoltcp::socket::{IcmpEndpoint, IcmpPacketMetadata, IcmpSocket, IcmpSocketBuffer, SocketHandle}; -use smoltcp::wire::{Icmpv4Packet, Icmpv4Repr, IpAddress, IpEndpoint}; +use smoltcp::socket::icmp::{Endpoint as IcmpEndpoint, PacketMetadata as IcmpPacketMetadata, Socket as IcmpSocket, PacketBuffer as IcmpSocketBuffer}; +use smoltcp::iface::SocketHandle; +use smoltcp::wire::{Icmpv4Packet, Icmpv4Repr, IpAddress, IpListenEndpoint}; use std::mem; use std::str; use syscall::{Error as SyscallError, Result as SyscallResult}; @@ -9,9 +10,9 @@ use byteorder::{ByteOrder, NetworkEndian}; use crate::device::NetworkDevice; use crate::port_set::PortSet; use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme}; -use super::{Smolnetd, SocketSet}; +use super::{Smolnetd, SocketSet, Interface}; -pub type IcmpScheme = SocketScheme>; +pub type IcmpScheme = SocketScheme>; enum IcmpSocketType { Echo, @@ -24,7 +25,7 @@ pub struct IcmpData { ident: u16, } -impl<'a, 'b> SchemeSocket for IcmpSocket<'a, 'b> { +impl<'a> SchemeSocket for IcmpSocket<'a> { type SchemeDataT = PortSet; type DataT = IcmpData; type SettingT = (); @@ -74,6 +75,7 @@ impl<'a, 'b> SchemeSocket for IcmpSocket<'a, 'b> { path: &str, _uid: u32, ident_set: &mut Self::SchemeDataT, + iface: &Interface ) -> SyscallResult<(SocketHandle, Self::DataT)> { use std::str::FromStr; @@ -101,7 +103,7 @@ impl<'a, 'b> SchemeSocket for IcmpSocket<'a, 'b> { ) ); let handle = socket_set.add(socket); - let mut icmp_socket = socket_set.get::(handle); + let icmp_socket = socket_set.get_mut::(handle); let ident = ident_set .get_port() .ok_or_else(|| SyscallError::new(syscall::EINVAL))?; @@ -133,12 +135,12 @@ impl<'a, 'b> SchemeSocket for IcmpSocket<'a, 'b> { ) ); let handle = socket_set.add(socket); - let mut icmp_socket = socket_set.get::(handle); + let icmp_socket = socket_set.get_mut::(handle); let ident = ident_set .get_port() .ok_or_else(|| SyscallError::new(syscall::EINVAL))?; icmp_socket - .bind(IcmpEndpoint::Udp(IpEndpoint::from(ident))) + .bind(IcmpEndpoint::Udp(IpListenEndpoint::from(ident))) .map_err(|_| syscall::Error::new(syscall::EINVAL))?; let socket_data = IcmpData { socket_type: IcmpSocketType::Udp, diff --git a/src/smolnetd/scheme/ip.rs b/src/smolnetd/scheme/ip.rs index b13cbc2720..4f0d0d3254 100644 --- a/src/smolnetd/scheme/ip.rs +++ b/src/smolnetd/scheme/ip.rs @@ -1,16 +1,17 @@ -use smoltcp::socket::{RawPacketMetadata, RawSocket, RawSocketBuffer, SocketHandle}; +use smoltcp::socket::raw::{PacketMetadata as RawPacketMetadata, Socket as RawSocket, PacketBuffer as RawSocketBuffer}; +use smoltcp::iface::SocketHandle; use smoltcp::wire::{IpProtocol, IpVersion}; use std::str; use syscall::{Error as SyscallError, Result as SyscallResult}; use syscall; use crate::device::NetworkDevice; -use super::{Smolnetd, SocketSet}; +use super::{Smolnetd, SocketSet, Interface}; use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme}; -pub type IpScheme = SocketScheme>; +pub type IpScheme = SocketScheme>; -impl<'a, 'b> SchemeSocket for RawSocket<'a, 'b> { +impl<'a> SchemeSocket for RawSocket<'a> { type SchemeDataT = (); type DataT = (); type SettingT = (); @@ -58,6 +59,7 @@ impl<'a, 'b> SchemeSocket for RawSocket<'a, 'b> { path: &str, uid: u32, _: &mut Self::SchemeDataT, + iface: &Interface ) -> SyscallResult<(SocketHandle, Self::DataT)> { if uid != 0 { return Err(SyscallError::new(syscall::EACCES)); diff --git a/src/smolnetd/scheme/mod.rs b/src/smolnetd/scheme/mod.rs index eab5942b29..fdf60b012c 100644 --- a/src/smolnetd/scheme/mod.rs +++ b/src/smolnetd/scheme/mod.rs @@ -1,12 +1,12 @@ use netutils::getcfg; use smoltcp; -use smoltcp::iface::{EthernetInterface, EthernetInterfaceBuilder, NeighborCache, Routes}; -use smoltcp::phy::EthernetTracer; -use smoltcp::socket::SocketSet as SmoltcpSocketSet; +use smoltcp::iface::{Interface as SmoltcpInterface, Routes, Config}; +use smoltcp::phy::Tracer; +use crate::scheme::smoltcp::iface::SocketSet as SmoltcpSocketSet; use smoltcp::time::{Duration, Instant}; -use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, IpEndpoint, Ipv4Address}; +use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address, IpListenEndpoint, HardwareAddress}; use std::cell::RefCell; -use std::collections::{BTreeMap, VecDeque}; +use std::collections::VecDeque; use std::fs::File; use std::io::{self, Read, Write}; use std::mem::size_of; @@ -31,14 +31,15 @@ mod udp; mod icmp; mod netcfg; -type SocketSet = SmoltcpSocketSet<'static, 'static, 'static>; -type Interface = Rc>>>; +type SocketSet = SmoltcpSocketSet<'static>; +type Interface = Rc>; -const MAX_DURATION: Duration = Duration { millis: ::std::u64::MAX }; -const MIN_DURATION: Duration = Duration { millis: 0 }; +const MAX_DURATION: Duration = Duration::from_millis(u64::MAX); +const MIN_DURATION: Duration = Duration::from_millis(0); pub struct Smolnetd { network_file: Rc>, + network_device: Tracer, time_file: File, iface: Interface, @@ -58,8 +59,8 @@ pub struct Smolnetd { impl Smolnetd { const MAX_PACKET_SIZE: usize = 2048; const SOCKET_BUFFER_SIZE: usize = 128; //packets - const MIN_CHECK_TIMEOUT: Duration = Duration { millis: 10 }; - const MAX_CHECK_TIMEOUT: Duration = Duration { millis: 500 }; + const MIN_CHECK_TIMEOUT: Duration = Duration::from_millis(10); + const MAX_CHECK_TIMEOUT: Duration = Duration::from_millis(500); pub fn new( network_file: File, @@ -84,7 +85,7 @@ impl Smolnetd { let buffer_pool = Rc::new(RefCell::new(BufferPool::new(Self::MAX_PACKET_SIZE))); let input_queue = Rc::new(RefCell::new(VecDeque::new())); let network_file = Rc::new(RefCell::new(network_file)); - let network_device = EthernetTracer::new(NetworkDevice::new( + let mut network_device = Tracer::new(NetworkDevice::new( Rc::clone(&network_file), Rc::clone(&input_queue), hardware_addr, @@ -92,25 +93,23 @@ impl Smolnetd { ), |_timestamp, printer| { trace!("{}", printer) }); - let mut routes = Routes::new(BTreeMap::new()); - routes.add_default_ipv4_route(default_gw).expect("Failed to add default gateway"); - let iface = EthernetInterfaceBuilder::new(network_device) - .neighbor_cache(NeighborCache::new(BTreeMap::new())) - .ethernet_addr(hardware_addr) - .ip_addrs(protocol_addrs) - .routes(routes) - .finalize(); + let config = Config::new(HardwareAddress::Ethernet(hardware_addr)); + let mut iface = SmoltcpInterface::new(config, &mut network_device, Instant::now()); + iface.update_ip_addrs(|ip_addrs| ip_addrs.extend(protocol_addrs)); + iface.routes_mut().add_default_ipv4_route(default_gw).expect("Failed to add default gateway"); + let iface = Rc::new(RefCell::new(iface)); let socket_set = Rc::new(RefCell::new(SocketSet::new(vec![]))); Smolnetd { iface: Rc::clone(&iface), + network_device, socket_set: Rc::clone(&socket_set), timer: ::std::time::Instant::now(), time_file, - ip_scheme: IpScheme::new(Rc::clone(&socket_set), ip_file), - udp_scheme: UdpScheme::new(Rc::clone(&socket_set), udp_file), - tcp_scheme: TcpScheme::new(Rc::clone(&socket_set), tcp_file), - icmp_scheme: IcmpScheme::new(Rc::clone(&socket_set), icmp_file), + ip_scheme: IpScheme::new(Rc::clone(&iface), Rc::clone(&socket_set), ip_file), + udp_scheme: UdpScheme::new(Rc::clone(&iface), Rc::clone(&socket_set), udp_file), + tcp_scheme: TcpScheme::new(Rc::clone(&iface), Rc::clone(&socket_set), tcp_file), + icmp_scheme: IcmpScheme::new(Rc::clone(&iface), Rc::clone(&socket_set), icmp_file), netcfg_scheme: NetCfgScheme::new(Rc::clone(&iface), netcfg_file), input_queue, network_file, @@ -190,23 +189,22 @@ impl Smolnetd { break MIN_DURATION; } iter_limit -= 1; - match iface.poll(&mut socket_set, timestamp) { - Ok(_) | Err(smoltcp::Error::Unrecognized) => (), - Err(e) => { - error!("poll error: {}", e); - break MIN_DURATION; - } - } - match iface.poll_delay(&socket_set, timestamp) { - Some(Duration { millis: 0 }) => { } + + // TODO: Check what if the bool returned by poll can be useful + iface.poll(timestamp, &mut self.network_device, &mut socket_set); + + match iface.poll_delay(timestamp, &socket_set) { + Some(delay) if delay == Duration::ZERO => { } Some(delay) => { break ::std::cmp::min(MAX_DURATION, delay) } None => break MAX_DURATION - } + }; } }; + self.notify_sockets()?; + Ok(::std::cmp::min( ::std::cmp::max(Smolnetd::MIN_CHECK_TIMEOUT, timeout), Smolnetd::MAX_CHECK_TIMEOUT, @@ -257,17 +255,16 @@ fn post_fevent(scheme_file: &mut File, fd: usize, event: usize, data_len: usize) .map_err(|e| Error::from_io_error(e, "failed to post fevent")) } -fn parse_endpoint(socket: &str) -> IpEndpoint { +fn parse_endpoint(socket: &str) -> IpListenEndpoint { 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 host = + Ipv4Address::from_str(socket_parts.next().unwrap_or("")).ok().filter(|addr| !addr.is_unspecified()).map(IpAddress::Ipv4); + let port = socket_parts .next() .unwrap_or("") .parse::() .unwrap_or(0); - IpEndpoint::new(host, port) + IpListenEndpoint{ addr: host, port} } diff --git a/src/smolnetd/scheme/netcfg/mod.rs b/src/smolnetd/scheme/netcfg/mod.rs index c64b310092..d41dee0a44 100644 --- a/src/smolnetd/scheme/netcfg/mod.rs +++ b/src/smolnetd/scheme/netcfg/mod.rs @@ -82,7 +82,7 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe ro [iface] || { let mut gateway = None; iface.borrow_mut().routes_mut().update(|map| { - gateway = map.get(&gateway_cidr()).map(|route| route.via_router); + gateway = map.iter().find(|route| route.cidr == gateway_cidr()).map(|route| route.via_router) }); if let Some(ip) = gateway { format!("default via {}\n", ip) @@ -136,16 +136,17 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe let mut iface = iface.borrow_mut(); let mut gateway = None; iface.routes_mut().update(|map| { - gateway = map.get(&gateway_cidr()).map(|route| route.via_router); + gateway = map.iter().find(|route| route.cidr == gateway_cidr()).map(|route| route.via_router) }); - if gateway != Some(IpAddress::Ipv4(default_gw)) { - return Err(SyscallError::new(syscall::EINVAL)); + match gateway { + None => Err(SyscallError::new(syscall::EINVAL)), + Some(addr) if addr != IpAddress::Ipv4(default_gw) => Err(SyscallError::new(syscall::EINVAL)), + Some(_) => { + iface.routes_mut().remove_default_ipv4_route(); + notifier.borrow_mut().schedule_notify("route/list"); + Ok(()) + } } - iface.routes_mut().update(|map| { - map.remove(&gateway_cidr()); - }); - notifier.borrow_mut().schedule_notify("route/list"); - Ok(()) } else { Err(SyscallError::new(syscall::EINVAL)) } @@ -157,7 +158,7 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe "mac" => { rw [iface, notifier] (Option, None) || { - format!("{}\n", iface.borrow().ethernet_addr()) + format!("{}\n", iface.borrow().hardware_addr()) } |cur_value, line| { if cur_value.is_none() { @@ -174,7 +175,7 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe } |cur_value| { if let Some(mac) = *cur_value { - iface.borrow_mut().set_ethernet_addr(mac); + iface.borrow_mut().set_hardware_addr(smoltcp::wire::HardwareAddress::Ethernet(mac)); notifier.borrow_mut().schedule_notify("ifaces/eth0/mac"); } Ok(()) @@ -208,7 +209,7 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe let mut cidrs = vec![]; mem::swap(cur_value, &mut cidrs); iface.update_ip_addrs(|s| { - *s = From::from(cidrs); + *s = cidrs.into_iter().collect(); }); notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list"); } @@ -233,7 +234,7 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe cidrs.insert(0, *cidr); } iface.update_ip_addrs(|s| { - *s = From::from(cidrs); + *s = cidrs.into_iter().collect(); }); notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list"); Ok(()) @@ -261,7 +262,7 @@ fn mk_root_node(iface: Interface, notifier: NotifierRef, dns_config: DNSConfigRe } } iface.update_ip_addrs(|s| { - *s = From::from(cidrs); + *s = cidrs.into_iter().collect(); }); notifier.borrow_mut().schedule_notify("ifaces/eth0/addr/list"); Ok(()) diff --git a/src/smolnetd/scheme/socket.rs b/src/smolnetd/scheme/socket.rs index b61ee1ce23..df7cbfe8f3 100644 --- a/src/smolnetd/scheme/socket.rs +++ b/src/smolnetd/scheme/socket.rs @@ -1,10 +1,11 @@ use std::cell::RefCell; use std::collections::BTreeMap; +use std::collections::btree_map::Entry; use std::fs::File; use std::io::{ErrorKind, Read, Write}; use std::marker::PhantomData; use std::mem; -use std::ops::Deref; +use std::ops::{Deref, SubAssign}; use std::ops::DerefMut; use std::rc::Rc; use std::str; @@ -15,7 +16,9 @@ use syscall::data::TimeSpec; use syscall::flag::{EVENT_READ, EVENT_WRITE}; use redox_netstack::error::{Error, Result}; -use smoltcp::socket::{AnySocket, SocketHandle}; +use smoltcp::socket::AnySocket; +use crate::scheme::smoltcp::iface::SocketHandle; +use super::Interface; use super::{post_fevent, SocketSet}; @@ -98,7 +101,7 @@ where } } - pub fn events(&mut self, socket_set: &mut SocketSet) -> usize where SocketT: AnySocket<'static, 'static> { + pub fn events(&mut self, socket_set: &mut SocketSet) -> usize where SocketT: AnySocket<'static> { let mut revents = 0; if let &mut SchemeFile::Socket(SocketFile { socket_handle, @@ -170,6 +173,7 @@ where path: &str, uid: u32, data: &mut Self::SchemeDataT, + iface: &Interface ) -> SyscallResult<(SocketHandle, Self::DataT)>; fn close_file(&self, file: &SchemeFile, data: &mut Self::SchemeDataT) -> SyscallResult<()>; @@ -190,11 +194,13 @@ where pub struct SocketScheme where - SocketT: SchemeSocket + AnySocket<'static, 'static>, + SocketT: SchemeSocket + AnySocket<'static>, { next_fd: usize, nulls: BTreeMap, files: BTreeMap>, + ref_counts: BTreeMap, + iface: Interface, socket_set: Rc>, scheme_file: File, wait_queue: WaitQueue, @@ -204,13 +210,15 @@ where impl SocketScheme where - SocketT: SchemeSocket + AnySocket<'static, 'static>, + SocketT: SchemeSocket + AnySocket<'static>, { - pub fn new(socket_set: Rc>, scheme_file: File) -> SocketScheme { + pub fn new(iface: Interface, socket_set: Rc>, scheme_file: File) -> SocketScheme { SocketScheme { next_fd: 1, nulls: BTreeMap::new(), + iface, files: BTreeMap::new(), + ref_counts: BTreeMap::new(), socket_set, scheme_data: SocketT::new_scheme_data(), scheme_file, @@ -424,7 +432,7 @@ where } Setting::Ttl => if let Some(hop_limit) = buf.get(0) { let mut socket_set = self.socket_set.borrow_mut(); - let mut socket = socket_set.get::(file.socket_handle); + let socket = socket_set.get_mut::(file.socket_handle); socket.set_hop_limit(*hop_limit); Ok(1) } else { @@ -437,7 +445,7 @@ where impl syscall::SchemeBlockMut for SocketScheme where - SocketT: SchemeSocket + AnySocket<'static, 'static>, + SocketT: SchemeSocket + AnySocket<'static>, { fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> SyscallResult> { if path.is_empty() { @@ -459,6 +467,7 @@ where path, uid, &mut self.scheme_data, + &self.iface )?; let file = SchemeFile::Socket(SocketFile { @@ -475,6 +484,7 @@ where let id = self.next_fd; self.next_fd += 1; + self.ref_counts.insert(socket_handle, 1); self.files.insert(id, file); Ok(Some(id)) @@ -506,9 +516,29 @@ where }| a != fd, ); - socket_set.release(socket_handle); - //TODO: removing sockets in release should make prune unnecessary - socket_set.prune(); + let remove = match self.ref_counts.entry(socket_handle) { + Entry::Vacant(_) => { + warn!("Closing a socket_handle with no ref"); + true + }, + Entry::Occupied(mut e) => if *e.get() == 0 { + warn!("Closing a socket_handle with no ref"); + e.remove(); + true + } else { + *e.get_mut() -= 1; + if *e.get() == 0 { + e.remove(); + true + } else { + false + } + }, + }; + + if remove { + socket_set.remove(socket_handle); + } Ok(Some(0)) } @@ -524,8 +554,8 @@ where } SchemeFile::Socket(ref mut file) => { let mut socket_set = self.socket_set.borrow_mut(); - let mut socket = socket_set.get::(file.socket_handle); - return SocketT::write_buf(&mut socket, file, buf); + let socket = socket_set.get_mut::(file.socket_handle); + return SocketT::write_buf(socket, file, buf); } } }; @@ -543,8 +573,8 @@ where } SchemeFile::Socket(ref mut file) => { let mut socket_set = self.socket_set.borrow_mut(); - let mut socket = socket_set.get::(file.socket_handle); - return SocketT::read_buf(&mut socket, file, buf); + let socket = socket_set.get_mut::(file.socket_handle); + return SocketT::read_buf(socket, file, buf); } } }; @@ -609,10 +639,10 @@ where file.socket_handle = socket_handle; file.data = data; } else { - self.socket_set.borrow_mut().retain(file.socket_handle()); + *self.ref_counts.entry(file.socket_handle()).or_insert(0) += 1; } } else { - self.socket_set.borrow_mut().retain(file.socket_handle()); + *self.ref_counts.entry(file.socket_handle()).or_insert(0) += 1; } new_handle }; diff --git a/src/smolnetd/scheme/tcp.rs b/src/smolnetd/scheme/tcp.rs index 200ba42aa4..65bcfb190c 100644 --- a/src/smolnetd/scheme/tcp.rs +++ b/src/smolnetd/scheme/tcp.rs @@ -1,11 +1,13 @@ -use smoltcp::socket::{SocketHandle, TcpSocket, TcpSocketBuffer}; +use smoltcp::iface::SocketHandle; +use smoltcp::socket::tcp::{Socket as TcpSocket, SocketBuffer as TcpSocketBuffer}; +use smoltcp::wire::IpEndpoint; use std::str; -use syscall::{Error as SyscallError, Result as SyscallResult}; use syscall; +use syscall::{Error as SyscallError, Result as SyscallResult}; -use crate::port_set::PortSet; use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme}; -use super::{parse_endpoint, SocketSet}; +use super::{parse_endpoint, SocketSet, Interface}; +use crate::port_set::PortSet; pub type TcpScheme = SocketScheme>; @@ -59,6 +61,7 @@ impl<'a> SchemeSocket for TcpSocket<'a> { path: &str, uid: u32, port_set: &mut Self::SchemeDataT, + iface: &Interface ) -> SyscallResult<(SocketHandle, Self::DataT)> { trace!("TCP open {}", path); let mut parts = path.split('/'); @@ -85,12 +88,12 @@ impl<'a> SchemeSocket for TcpSocket<'a> { let socket_handle = socket_set.add(socket); - let mut tcp_socket = socket_set.get::(socket_handle); + let tcp_socket = socket_set.get_mut::(socket_handle); if remote_endpoint.is_specified() { trace!("Connecting tcp {} {}", local_endpoint, remote_endpoint); tcp_socket - .connect(remote_endpoint, local_endpoint) + .connect(iface.borrow_mut().context(), IpEndpoint::new(remote_endpoint.addr.unwrap(), remote_endpoint.port), local_endpoint) .expect("Can't connect tcp socket "); } else { trace!("Listening tcp {}", local_endpoint); @@ -108,7 +111,9 @@ impl<'a> SchemeSocket for TcpSocket<'a> { port_set: &mut Self::SchemeDataT, ) -> SyscallResult<()> { if let SchemeFile::Socket(_) = *file { - port_set.release_port(self.local_endpoint().port); + if let Some(endpoint) = self.local_endpoint() { + port_set.release_port(endpoint.port); + } } Ok(()) } @@ -163,34 +168,43 @@ impl<'a> SchemeSocket for TcpSocket<'a> { }; let file = match path { - "listen" => if let SchemeFile::Socket(ref tcp_handle) = *file { - if !is_active { - if tcp_handle.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { - return Err(SyscallError::new(syscall::EAGAIN)); - } else { - return Ok(None); + "listen" => { + if let SchemeFile::Socket(ref tcp_handle) = *file { + if !is_active { + if tcp_handle.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { + return Err(SyscallError::new(syscall::EAGAIN)); + } else { + return Ok(None); + } } - } - trace!("TCP creating new listening socket"); - let new_handle = SchemeFile::Socket(tcp_handle.clone_with_data(())); + trace!("TCP creating new listening socket"); + let new_handle = SchemeFile::Socket(tcp_handle.clone_with_data(())); - let rx_packets = vec![0; 0xffff]; - let tx_packets = vec![0; 0xffff]; - 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::(new_socket_handle); - tcp_socket - .listen(local_endpoint) - .expect("Can't listen on local endpoint"); + let rx_packets = vec![0; 0xffff]; + let tx_packets = vec![0; 0xffff]; + 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 tcp_socket = socket_set.get_mut::(new_socket_handle); + tcp_socket + .listen( + local_endpoint + .expect("Socket was active so local endpoint must be set"), + ) + .expect("Can't listen on local endpoint"); + } + port_set.acquire_port( + local_endpoint + .expect("Socket was active so local endpoint must be set") + .port, + ); + return Ok(Some((new_handle, Some((new_socket_handle, ()))))); + } else { + return Err(SyscallError::new(syscall::EBADF)); } - port_set.acquire_port(local_endpoint.port); - return Ok(Some((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 { @@ -202,14 +216,21 @@ impl<'a> SchemeSocket for TcpSocket<'a> { }; if let SchemeFile::Socket(_) = file { - port_set.acquire_port(local_endpoint.port); + if let Some(local_endpoint) = local_endpoint { + port_set.acquire_port(local_endpoint.port); + } } Ok(Some((file, None))) } fn fpath(&self, _: &SchemeFile, buf: &mut [u8]) -> SyscallResult { - let path = format!("tcp:{}/{}", self.remote_endpoint(), self.local_endpoint()); + let path = match (self.remote_endpoint(), self.local_endpoint()) { + (Some(remote_endpoint), Some(local_endpoint)) => format!("tcp:{}/{}", remote_endpoint, local_endpoint), + (Some(remote_endpoint), None) => format!("tcp:{}/none", remote_endpoint), + (None, Some(local_endpoint)) => format!("tcp:none/{}", local_endpoint), + (None, None) => "tcp:none/none".into(), + }; let path = path.as_bytes(); let mut i = 0; diff --git a/src/smolnetd/scheme/udp.rs b/src/smolnetd/scheme/udp.rs index 646821f625..4f0ce8ccd8 100644 --- a/src/smolnetd/scheme/udp.rs +++ b/src/smolnetd/scheme/udp.rs @@ -1,5 +1,6 @@ -use smoltcp::socket::{SocketHandle, UdpPacketMetadata, UdpSocket, UdpSocketBuffer}; -use smoltcp::wire::IpEndpoint; +use smoltcp::socket::udp::{PacketMetadata as UdpPacketMetadata, Socket as UdpSocket, PacketBuffer as UdpSocketBuffer}; +use smoltcp::iface::SocketHandle; +use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; use std::str; use syscall::{Error as SyscallError, Result as SyscallResult}; use syscall; @@ -7,13 +8,13 @@ use syscall; use crate::device::NetworkDevice; use crate::port_set::PortSet; use super::socket::{DupResult, SchemeFile, SchemeSocket, SocketFile, SocketScheme}; -use super::{parse_endpoint, Smolnetd, SocketSet}; +use super::{parse_endpoint, Smolnetd, SocketSet, Interface}; -pub type UdpScheme = SocketScheme>; +pub type UdpScheme = SocketScheme>; -impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> { +impl<'a> SchemeSocket for UdpSocket<'a> { type SchemeDataT = PortSet; - type DataT = IpEndpoint; + type DataT = IpListenEndpoint; type SettingT = (); fn new_scheme_data() -> Self::SchemeDataT { @@ -61,6 +62,7 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> { path: &str, uid: u32, port_set: &mut Self::SchemeDataT, + _iface: &Interface ) -> SyscallResult<(SocketHandle, Self::DataT)> { let mut parts = path.split('/'); let remote_endpoint = parse_endpoint(parts.next().unwrap_or("")); @@ -90,11 +92,12 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> { let socket_handle = socket_set.add(udp_socket); - let mut udp_socket = socket_set.get::(socket_handle); + let udp_socket = socket_set.get_mut::(socket_handle); udp_socket .bind(local_endpoint) .expect("Can't bind udp socket to local endpoint"); + Ok((socket_handle, remote_endpoint)) } @@ -118,7 +121,9 @@ impl<'a, 'b> SchemeSocket for UdpSocket<'a, 'b> { return Err(SyscallError::new(syscall::EADDRNOTAVAIL)); } if self.can_send() { - self.send_slice(buf, file.data).expect("Can't send slice"); + let endpoint = file.data; + let endpoint = IpEndpoint::new(endpoint.addr.expect("If we can send, this should be specified"), endpoint.port); + self.send_slice(buf, endpoint).expect("Can't send slice"); Ok(Some(buf.len())) } else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK { Err(SyscallError::new(syscall::EAGAIN))