diff --git a/Cargo.lock b/Cargo.lock index 7c1b2430..bcb0de7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,6 +34,7 @@ name = "abi-serde" version = "0.1.0" dependencies = [ "compiler_builtins", + "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] diff --git a/kernel/driver/net/core/src/config.rs b/kernel/driver/net/core/src/config.rs index 13c6c836..4aa4f012 100644 --- a/kernel/driver/net/core/src/config.rs +++ b/kernel/driver/net/core/src/config.rs @@ -1,5 +1,5 @@ use alloc::{boxed::Box, sync::Arc, vec::Vec}; -use libk::vfs::{ChannelDescriptor, MessagePayload}; +use libk::vfs::ChannelDescriptor; use serde::Serialize; use yggdrasil_abi::{ error::Error, @@ -21,18 +21,19 @@ use crate::{ async fn receive_request( channel: &ChannelDescriptor, ) -> Result<(ChannelPublisherId, NetConfigRequest), Error> { - loop { - let raw = channel.receive_message_async().await?; - match &raw.payload { - MessagePayload::Data(message) => { - let msg = - serde_json::from_slice(message.as_ref()).map_err(|_| Error::InvalidArgument)?; + todo!() + // loop { + // let raw = channel.receive_message_async().await?; + // match &raw.payload { + // MessagePayload::Data(message) => { + // let msg = + // serde_json::from_slice(message.as_ref()).map_err(|_| Error::InvalidArgument)?; - return Ok((raw.source, msg)); - } - MessagePayload::File(_) => (), - } - } + // return Ok((raw.source, msg)); + // } + // MessagePayload::File(_) => (), + // } + // } } fn send_reply( @@ -40,11 +41,12 @@ fn send_reply( recepient: ChannelPublisherId, message: NetConfigResult, ) -> Result<(), Error> { - let data = serde_json::to_vec(&message).map_err(|_| Error::InvalidArgument)?; - channel.send_message( - MessagePayload::Data(data.into_boxed_slice()), - MessageDestination::Specific(recepient.into()), - ) + todo!() + // let data = serde_json::to_vec(&message).map_err(|_| Error::InvalidArgument)?; + // channel.send_message( + // MessagePayload::Data(data.into_boxed_slice()), + // MessageDestination::Specific(recepient.into()), + // ) } fn list_interfaces() -> Vec<(Box, u32)> { @@ -55,73 +57,6 @@ fn list_interfaces() -> Vec<(Box, u32)> { .collect() } -fn describe_interface(interface: &NetworkInterface) -> InterfaceInfo { - InterfaceInfo { - interface_id: interface.id, - interface_name: interface.name.clone(), - address: interface.address.read().map(Into::into), - mac: interface.mac, - } -} - -fn describe_route(route: &Route) -> RouteInfo { - // NOTE: must exist - let interface = NetworkInterface::get(route.interface).unwrap(); - - RouteInfo { - interface_name: interface.name.clone(), - interface_id: route.interface, - subnet: route.subnet, - gateway: route.gateway.map(Into::into), - } -} - -fn query_route(destination: IpAddr) -> Option { - let (interface_id, gateway, destination) = Route::lookup(destination)?; - let interface = NetworkInterface::get(interface_id).unwrap(); - let source = *interface.address.read(); - - Some(RoutingInfo { - interface_name: interface.name.clone(), - interface_id, - destination, - gateway, - source, - source_mac: interface.mac, - }) -} - -fn query_interface(query: InterfaceQuery) -> Option> { - match query { - InterfaceQuery::ById(id) => NetworkInterface::get(id).ok(), - InterfaceQuery::ByName(name) => { - let interfaces = NetworkInterface::list_ref(); - interfaces.iter().find_map(|(_, iface)| { - if iface.name == name { - Some(iface.clone()) - } else { - None - } - }) - } - } -} - -fn add_route( - query: InterfaceQuery, - gateway: Option, - subnet: SubnetAddr, -) -> Result<(), &'static str> { - let interface = query_interface(query).ok_or("No such interface")?; - let route = Route { - interface: interface.id, - gateway, - subnet, - }; - Route::insert(route).map_err(|_| "Could not insert route")?; - Ok(()) -} - pub async fn network_config_service() -> Result<(), Error> { let channel = ChannelDescriptor::open("@kernel-netconf", true); @@ -129,60 +64,9 @@ pub async fn network_config_service() -> Result<(), Error> { let (sender_id, request) = receive_request(&channel).await?; match request { - NetConfigRequest::ListRoutes => { - let routes = Route::list_ref(); - let route_info: Vec<_> = routes.iter().map(describe_route).collect(); - send_reply(&channel, sender_id, NetConfigResult::Ok(route_info))?; - } - NetConfigRequest::ListInterfaces => { - let interfaces = list_interfaces(); - send_reply(&channel, sender_id, NetConfigResult::Ok(interfaces))?; - } - NetConfigRequest::DescribeRoutes(_query) => todo!(), - NetConfigRequest::DescribeInterface(query) => { - let result = match query_interface(query) { - Some(interface) => NetConfigResult::Ok(describe_interface(&interface)), - None => NetConfigResult::err("No such interface"), - }; - send_reply(&channel, sender_id, result)?; - } - NetConfigRequest::AddRoute { - interface, - gateway, - subnet, - } => { - let result = match add_route(interface, gateway, subnet) { - Ok(()) => NetConfigResult::Ok(()), - Err(error) => NetConfigResult::err(error), - }; - send_reply(&channel, sender_id, result)?; - } - NetConfigRequest::SetNetworkAddress { interface, address } => { - let result = match query_interface(interface) { - Some(interface) => { - interface.set_address(address); - NetConfigResult::Ok(()) - } - None => NetConfigResult::err("No such interface"), - }; - - send_reply(&channel, sender_id, result)?; - } - NetConfigRequest::ClearNetworkAddress(_interface) => todo!(), - NetConfigRequest::QueryRoute(destination) => { - let result = match query_route(destination) { - Some(route) => NetConfigResult::Ok(route), - None => NetConfigResult::err("No route to host"), - }; - send_reply(&channel, sender_id, result)?; - } - NetConfigRequest::QueryArp(interface_id, destination, perform_query) => { - let result = match arp::lookup(interface_id, destination, perform_query).await { - Ok(mac) => NetConfigResult::Ok(mac), - Err(_) => NetConfigResult::err("No ARP entry"), - }; - send_reply(&channel, sender_id, result)?; - } + NetConfigRequest::SetNetworkAddress { interface, address } => {} + NetConfigRequest::QueryRoute(destination) => {} + NetConfigRequest::QueryArp(interface_id, destination, perform_query) => {} } } } diff --git a/kernel/driver/net/core/src/interface.rs b/kernel/driver/net/core/src/interface.rs index b85a2f3b..0d9ed3b6 100644 --- a/kernel/driver/net/core/src/interface.rs +++ b/kernel/driver/net/core/src/interface.rs @@ -1,5 +1,6 @@ use core::{ mem::size_of, + net::IpAddr, sync::atomic::{AtomicU32, AtomicUsize, Ordering}, }; @@ -12,7 +13,7 @@ use libk_util::{ }; use yggdrasil_abi::{ error::Error, - net::{protocols::EthernetFrame, IpAddr, MacAddress}, + net::{protocols::EthernetFrame, MacAddress}, }; use crate::l3::{arp::ArpTable, Route}; diff --git a/kernel/driver/net/core/src/l3/arp.rs b/kernel/driver/net/core/src/l3/arp.rs index d37ca575..e086f30f 100644 --- a/kernel/driver/net/core/src/l3/arp.rs +++ b/kernel/driver/net/core/src/l3/arp.rs @@ -1,6 +1,7 @@ use core::{ future::Future, mem::size_of, + net::{IpAddr, Ipv4Addr}, pin::Pin, task::{Context, Poll}, time::Duration, @@ -14,7 +15,7 @@ use yggdrasil_abi::{ net::{ protocols::{ArpFrame, EtherType}, types::NetValueImpl, - IpAddr, Ipv4Addr, MacAddress, + MacAddress, }, }; @@ -166,6 +167,21 @@ pub async fn lookup(interface: u32, ip: IpAddr, perform_query: bool) -> Result Result { + if let Some(mac) = ArpTable::lookup_cache(interface, ip) { + return Ok(mac); + } + if perform_query { + Err(Error::WouldBlock) + } else { + Err(Error::HostUnreachable) + } +} + async fn query( interface: u32, ip: IpAddr, diff --git a/kernel/driver/net/core/src/l3/ip.rs b/kernel/driver/net/core/src/l3/ip.rs index 9b9451e6..20ff3223 100644 --- a/kernel/driver/net/core/src/l3/ip.rs +++ b/kernel/driver/net/core/src/l3/ip.rs @@ -1,9 +1,15 @@ -use core::mem::size_of; +use core::{ + mem::size_of, + net::{IpAddr, Ipv4Addr, SocketAddr}, +}; -use yggdrasil_abi::net::{ - protocols::{IpProtocol, Ipv4Frame, TcpFrame, UdpFrame}, - types::NetValueImpl, - IpAddr, Ipv4Addr, +use libk::error::Error; +use yggdrasil_abi::{ + abi_serde::wire, + net::{ + protocols::{IpProtocol, Ipv4Frame, TcpFrame, UdpFrame}, + types::NetValueImpl, + }, }; use crate::{interface::NetworkInterface, L2Packet, L3Packet, ACCEPT_QUEUE}; @@ -26,6 +32,16 @@ impl IpFrame for Ipv4Frame { } } +pub fn load_address(bytes: &[u8]) -> Result { + Ok(wire::from_slice(bytes)?) +} +pub fn store_address(source: &mut Option<&mut [u8]>, address: &SocketAddr) -> Result<(), Error> { + if let Some(buffer) = source.as_mut() { + wire::to_slice(address, buffer)?; + } + Ok(()) +} + pub fn handle_v4_packet(packet: L2Packet) { let Ok(interface) = NetworkInterface::get(packet.interface_id) else { log::debug!("Invalid interface ID in L2 packet"); diff --git a/kernel/driver/net/core/src/l3/mod.rs b/kernel/driver/net/core/src/l3/mod.rs index ecc39b16..6229c4d9 100644 --- a/kernel/driver/net/core/src/l3/mod.rs +++ b/kernel/driver/net/core/src/l3/mod.rs @@ -1,4 +1,8 @@ -use core::{fmt, mem::size_of}; +use core::{ + fmt, + mem::size_of, + net::{IpAddr, Ipv4Addr}, +}; use alloc::{sync::Arc, vec::Vec}; use bytemuck::{Pod, Zeroable}; @@ -11,7 +15,7 @@ use yggdrasil_abi::{ net::{ protocols::{EtherType, EthernetFrame, InetChecksum, IpProtocol, Ipv4Frame}, types::NetValueImpl, - IpAddr, Ipv4Addr, MacAddress, SubnetAddr, + MacAddress, SubnetAddr, }, }; @@ -103,8 +107,8 @@ impl Route { // This is the address of loopback, return it return Some(( NetworkInterface::loopback().id, - Some(IpAddr::V4(Ipv4Addr::LOOPBACK)), - IpAddr::V4(Ipv4Addr::LOOPBACK), + Some(IpAddr::V4(Ipv4Addr::LOCALHOST)), + IpAddr::V4(Ipv4Addr::LOCALHOST), )); } } @@ -152,11 +156,18 @@ impl L4ResolvedPacket<'_, '_> { pub fn make_l3_frame(&self) -> Result { // TODO what if source_ip/gateway_ip/destination_ip are a mix of IPv4/IPv6? - let source_ip = self.source_ip.into_ipv4().ok_or(Error::NotImplemented)?; - let destination_ip = self - .destination_ip - .into_ipv4() - .ok_or(Error::NotImplemented)?; + let source_ip = match self.source_ip { + IpAddr::V4(v4) => v4, + IpAddr::V6(_) => { + return Err(Error::NotImplemented); + } + }; + let destination_ip = match self.destination_ip { + IpAddr::V4(v4) => v4, + IpAddr::V6(_) => { + return Err(Error::NotImplemented); + } + }; let total_length = (self.total_l4_len() + size_of::()) .try_into() diff --git a/kernel/driver/net/core/src/l4/icmp.rs b/kernel/driver/net/core/src/l4/icmp.rs index 641e2f20..25dc4494 100644 --- a/kernel/driver/net/core/src/l4/icmp.rs +++ b/kernel/driver/net/core/src/l4/icmp.rs @@ -1,11 +1,13 @@ -use core::mem::size_of; +use core::{ + mem::size_of, + net::{IpAddr, Ipv4Addr}, +}; use yggdrasil_abi::{ error::Error, net::{ protocols::{IcmpV4Frame, InetChecksum, IpProtocol}, types::NetValueImpl, - IpAddr, Ipv4Addr, }, }; diff --git a/kernel/driver/net/core/src/l4/tcp.rs b/kernel/driver/net/core/src/l4/tcp.rs index 9d70b63f..811238e2 100644 --- a/kernel/driver/net/core/src/l4/tcp.rs +++ b/kernel/driver/net/core/src/l4/tcp.rs @@ -1,5 +1,6 @@ use core::{ mem::size_of, + net::{IpAddr, SocketAddr}, task::{Context, Poll}, }; @@ -11,7 +12,6 @@ use yggdrasil_abi::{ net::{ protocols::{InetChecksum, IpProtocol, TcpFlags, TcpFrame, TcpV4PseudoHeader}, types::NetValueImpl, - IpAddr, SocketAddr, }, }; @@ -548,8 +548,14 @@ async fn send( ) -> Result<(), Error> { let (interface, source_ip, gateway_ip, destination_ip) = l3::resolve_l3_route(remote.ip())?; // TODO TCPv6 - let source_ip = source_ip.into_ipv4().unwrap(); - let destination_ip = destination_ip.into_ipv4().unwrap(); + let source_ip = match source_ip { + IpAddr::V4(v4) => v4, + IpAddr::V6(_) => todo!(), + }; + let destination_ip = match destination_ip { + IpAddr::V4(v4) => v4, + IpAddr::V6(_) => todo!(), + }; let tcp_length = size_of::() + data.len(); @@ -595,8 +601,14 @@ async fn send( fn validate(source: IpAddr, destination: IpAddr, tcp_frame: &TcpFrame, data: &[u8]) -> bool { // TODO TCPv6 - let source = source.into_ipv4().unwrap(); - let destination = destination.into_ipv4().unwrap(); + let source = match source { + IpAddr::V4(v4) => v4, + IpAddr::V6(_) => todo!(), + }; + let destination = match destination { + IpAddr::V4(v4) => v4, + IpAddr::V6(_) => todo!(), + }; let tcp_length = size_of::() + data.len(); let pseudo_header = TcpV4PseudoHeader { diff --git a/kernel/driver/net/core/src/l4/udp.rs b/kernel/driver/net/core/src/l4/udp.rs index e99fb4c8..d04b975b 100644 --- a/kernel/driver/net/core/src/l4/udp.rs +++ b/kernel/driver/net/core/src/l4/udp.rs @@ -1,11 +1,13 @@ -use core::mem::size_of; +use core::{ + mem::size_of, + net::{IpAddr, SocketAddr}, +}; use yggdrasil_abi::{ error::Error, net::{ protocols::{IpProtocol, UdpFrame}, types::NetValueImpl, - IpAddr, SocketAddr, }, }; diff --git a/kernel/driver/net/core/src/lib.rs b/kernel/driver/net/core/src/lib.rs index 7cd5413d..fcd56ccd 100644 --- a/kernel/driver/net/core/src/lib.rs +++ b/kernel/driver/net/core/src/lib.rs @@ -21,7 +21,6 @@ pub mod l4; pub mod socket; -pub mod config; pub mod interface; pub mod util; @@ -94,7 +93,6 @@ pub fn start_network_tasks() -> Result<(), Error> { for _ in 0..4 { runtime::spawn(l3_accept_worker())?; } - runtime::spawn(config::network_config_service())?; Ok(()) } diff --git a/kernel/driver/net/core/src/socket/config.rs b/kernel/driver/net/core/src/socket/config.rs new file mode 100644 index 00000000..ccc858ae --- /dev/null +++ b/kernel/driver/net/core/src/socket/config.rs @@ -0,0 +1,296 @@ +use core::{ + fmt, + net::IpAddr, + task::{Context, Poll}, + time::Duration, +}; + +use alloc::{boxed::Box, sync::Arc, vec::Vec}; +use async_trait::async_trait; +use libk::{ + error::Error, + vfs::{FileReadiness, Socket}, +}; +use libk_mm::PageBox; +use libk_util::queue::BoundedMpmcQueue; +use yggdrasil_abi::{ + abi_serde::{wire, Serialize}, + net::{ + netconfig::{ + InterfaceBinding, InterfaceInfo, NetConfigRequest, NetConfigResult, RouteInfo, + RoutingInfo, + }, + MacAddress, MessageHeader, MessageHeaderMut, SocketInterfaceQuery, SubnetAddr, + }, +}; + +use crate::{ + interface::NetworkInterface, + l3::{arp, Route}, +}; + +pub struct NetConfigSocket { + // Responses are written here + buffer: BoundedMpmcQueue<(usize, PageBox<[u8; 4096]>)>, +} + +impl NetConfigSocket { + pub fn new() -> Arc { + Arc::new(Self { + buffer: BoundedMpmcQueue::new(8), + }) + } + + fn write_response(&self, value: NetConfigResult) -> Result<(), Error> { + let mut response = PageBox::new([0; 4096])?; + let len = wire::to_slice(&value, &mut response[..]).unwrap(); + self.buffer + .try_push_back((len, response)) + .map_err(|_| Error::OutOfMemory) + } + + fn read_response(&self, buffer: &mut [u8]) -> Result { + // Don't allow truncated responses + let (len, data) = self.buffer.try_pop_front().ok_or(Error::WouldBlock)?; + if len > buffer.len() { + log::warn!( + "Buffer of {} is too small to write a response of {len}", + buffer.len() + ); + return Err(Error::InvalidArgument); + } + buffer[..len].copy_from_slice(&data[..len]); + Ok(len) + } + + async fn handle_request(&self, request: NetConfigRequest<'_>) -> Result<(), Error> { + match request { + NetConfigRequest::ArpQuery(query) if !query.cache_only => { + let iface = match query_interface(query.interface) { + Some(iface) => iface, + None => { + return self.write_response(NetConfigResult::::Err( + "No such interface", + )) + } + }; + let result = match arp::lookup(iface.id(), query.address, true).await { + Ok(mac) => NetConfigResult::Ok(mac), + Err(_) => NetConfigResult::Err("No ARP entry"), + }; + self.write_response(result) + } + _ => self.handle_request_nonblocking(request), + } + } + + fn handle_request_nonblocking(&self, request: NetConfigRequest) -> Result<(), Error> { + match request { + NetConfigRequest::ListRoutes(()) => { + let routes = Route::list_ref(); + let route_info: Vec<_> = routes.iter().map(describe_route).collect(); + self.write_response(NetConfigResult::Ok(route_info)) + } + NetConfigRequest::ListInterfaces(()) => { + let interfaces = NetworkInterface::list_ref(); + let interfaces: Vec<_> = interfaces + .iter() + .map(|(&id, iface)| InterfaceBinding { + name: iface.name.clone(), + id, + }) + .collect(); + self.write_response(NetConfigResult::Ok(interfaces)) + } + NetConfigRequest::DescribeRoutes(_query) => todo!(), + NetConfigRequest::DescribeInterface(query) => { + let result = match query_interface(query) { + Some(interface) => NetConfigResult::Ok(describe_interface(&interface)), + None => NetConfigResult::Err("No such interface"), + }; + self.write_response(result) + } + NetConfigRequest::AddRoute(op) => { + let result = match add_route(op.interface, op.gateway, op.subnet) { + Ok(()) => NetConfigResult::Ok(()), + Err(error) => NetConfigResult::Err(error), + }; + self.write_response(result) + } + NetConfigRequest::ArpQuery(query) => { + let iface = match query_interface(query.interface) { + Some(iface) => iface, + None => { + return self.write_response(NetConfigResult::::Err( + "No such interface", + )) + } + }; + let result = + match arp::lookup_nonblocking(iface.id(), query.address, !query.cache_only) { + Ok(mac) => NetConfigResult::Ok(mac), + Err(_) => NetConfigResult::Err("No ARP entry"), + }; + self.write_response(result) + } + NetConfigRequest::QueryRoute(query) => { + let result = match query_route(query) { + Some(route) => NetConfigResult::Ok(route), + None => NetConfigResult::Err("No route to host"), + }; + self.write_response(result) + } + NetConfigRequest::SetNetworkAddress(op) => { + let result = match query_interface(op.interface) { + Some(interface) => { + interface.set_address(op.address); + NetConfigResult::Ok(()) + } + None => NetConfigResult::Err("No such interface"), + }; + self.write_response(result) + } + NetConfigRequest::ClearNetworkAddress(_) => todo!(), + } + } +} + +#[async_trait] +impl Socket for NetConfigSocket { + fn bind(self: Arc, _local: &[u8]) -> Result<(), Error> { + Err(Error::InvalidOperation) + } + async fn connect( + self: Arc, + _remote: &[u8], + _timeout: Option, + ) -> Result<(), Error> { + Err(Error::InvalidOperation) + } + + fn close(self: Arc) -> Result<(), Error> { + Ok(()) + } + + fn set_option(&self, option: u32, buffer: &[u8]) -> Result<(), Error> { + let _ = option; + let _ = buffer; + Err(Error::InvalidOperation) + } + + fn get_option(&self, option: u32, buffer: &mut [u8]) -> Result { + let _ = option; + let _ = buffer; + Err(Error::InvalidOperation) + } + + fn send_nonblocking(self: Arc, message: &MessageHeader) -> Result { + let request: NetConfigRequest = wire::from_slice(message.payload) + .inspect_err(|_| log::warn!("Invalid netconfig request"))?; + self.handle_request_nonblocking(request)?; + Ok(message.payload.len()) + } + async fn send_message( + self: Arc, + message: &MessageHeader, + _timeout: Option, + ) -> Result { + let request: NetConfigRequest = wire::from_slice(message.payload) + .inspect_err(|_| log::warn!("Invalid netconfig request"))?; + self.handle_request(request).await?; + Ok(message.payload.len()) + } + + fn receive_nonblocking( + self: Arc, + message: &mut MessageHeaderMut, + ) -> Result { + self.read_response(message.payload) + } + async fn receive_message( + self: Arc, + message: &mut MessageHeaderMut, + _timeout: Option, + ) -> Result { + self.read_response(message.payload) + } +} + +impl FileReadiness for NetConfigSocket { + fn poll_read(&self, cx: &mut Context<'_>) -> Poll> { + self.buffer.poll_not_empty(cx).map(|_| Ok(())) + } +} + +impl fmt::Debug for NetConfigSocket { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("NetConfigSocket").finish_non_exhaustive() + } +} + +fn query_interface(query: SocketInterfaceQuery) -> Option> { + match query { + SocketInterfaceQuery::ById(id) => NetworkInterface::get(id).ok(), + SocketInterfaceQuery::ByName(name) => { + let interfaces = NetworkInterface::list_ref(); + interfaces.iter().find_map(|(_, iface)| { + if &*iface.name == name { + Some(iface.clone()) + } else { + None + } + }) + } + } +} + +fn describe_interface(interface: &NetworkInterface) -> InterfaceInfo { + InterfaceInfo { + interface_id: interface.id, + interface_name: interface.name.clone(), + address: interface.address.read().map(Into::into), + mac: interface.mac, + } +} + +fn describe_route(route: &Route) -> RouteInfo { + // NOTE: must exist + let interface = NetworkInterface::get(route.interface).unwrap(); + + RouteInfo { + interface_name: interface.name.clone(), + interface_id: route.interface, + subnet: route.subnet, + gateway: route.gateway.map(Into::into), + } +} + +fn add_route( + query: SocketInterfaceQuery, + gateway: Option, + subnet: SubnetAddr, +) -> Result<(), &'static str> { + let interface = query_interface(query).ok_or("No such interface")?; + let route = Route { + interface: interface.id, + gateway, + subnet, + }; + Route::insert(route).map_err(|_| "Could not insert route")?; + Ok(()) +} + +fn query_route(destination: IpAddr) -> Option { + let (interface_id, gateway, destination) = Route::lookup(destination)?; + let interface = NetworkInterface::get(interface_id).unwrap(); + let source = *interface.address.read(); + + Some(RoutingInfo { + interface_name: interface.name.clone(), + interface_id, + destination, + gateway, + source, + source_mac: interface.mac, + }) +} diff --git a/kernel/driver/net/core/src/socket/local/mod.rs b/kernel/driver/net/core/src/socket/local/mod.rs new file mode 100644 index 00000000..2a45d61d --- /dev/null +++ b/kernel/driver/net/core/src/socket/local/mod.rs @@ -0,0 +1,94 @@ +use alloc::sync::Arc; + +use libk::{error::Error, task::thread::Thread, vfs::File}; +use yggdrasil_abi::{ + abi_serde::wire, + net::{types::LocalSocketAddress, AncillaryMessage, MessageHeader, MessageHeaderMut}, +}; + +pub mod packet; +pub use packet::LocalPacketSocket; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +enum OwnedAddress { + Path(Arc), + Anonymous(u64), +} + +pub fn load_address(bytes: &[u8]) -> Result { + Ok(wire::from_slice(bytes)?) +} + +pub fn store_address( + message: &mut MessageHeaderMut, + address: &LocalSocketAddress, +) -> Result<(), Error> { + if let Some(source) = message.source.as_mut() { + wire::to_slice(address, source)?; + } + Ok(()) +} + +pub fn read_ancillary(message: &MessageHeader) -> Result>, Error> { + if message.ancillary.is_empty() { + return Ok(None); + } + let ancillary: AncillaryMessage = wire::from_slice(message.ancillary)?; + #[allow(irrefutable_let_patterns)] + let AncillaryMessage::File(fd) = ancillary + else { + log::warn!("local: invalid ancillary message: {ancillary:?}"); + return Err(Error::InvalidArgument); + }; + let process = Thread::current().process(); + let file = process.io.lock().files.file(fd).cloned()?; + Ok(Some(file)) +} +pub fn write_ancillary( + message: &mut MessageHeaderMut, + file: Option>, +) -> Result<(), Error> { + let have_file = file.is_some(); + if let (Some(ancillary), Some(file)) = (message.ancillary.as_mut(), file) { + let process = Thread::current().process(); + let mut io = process.io.lock(); + let fd = io.files.place_file(file, true)?; + let msg = AncillaryMessage::File(fd); + match wire::to_slice(&msg, ancillary).map_err(Error::from) { + Ok(len) => { + message.ancillary_len = len; + log::debug!("local: shared ancillary fd {fd:?}"); + Ok(()) + } + Err(error) => { + log::warn!("local: failed to store ancillary file: {error:?}"); + io.files.close_file(fd).ok(); + Err(error) + } + } + } else { + if have_file && message.ancillary.is_none() { + log::warn!("local: ancillary data discarded: receiver did not specify a buffer"); + } + message.ancillary_len = 0; + Ok(()) + } +} + +impl OwnedAddress { + fn to_borrowed(&self) -> LocalSocketAddress { + match self { + Self::Path(path) => LocalSocketAddress::Path(path.as_ref()), + Self::Anonymous(anon) => LocalSocketAddress::Anonymous(*anon), + } + } +} + +impl From> for OwnedAddress { + fn from(value: LocalSocketAddress) -> Self { + match value { + LocalSocketAddress::Path(path) => Self::Path(path.into()), + LocalSocketAddress::Anonymous(anon) => Self::Anonymous(anon), + } + } +} diff --git a/kernel/driver/net/core/src/socket/local/packet.rs b/kernel/driver/net/core/src/socket/local/packet.rs new file mode 100644 index 00000000..d54f9924 --- /dev/null +++ b/kernel/driver/net/core/src/socket/local/packet.rs @@ -0,0 +1,329 @@ +use core::{ + fmt, + sync::atomic::{AtomicU64, Ordering}, + task::{Context, Poll}, + time::Duration, +}; + +use alloc::{ + boxed::Box, + collections::btree_map::BTreeMap, + sync::{Arc, Weak}, +}; +use async_trait::async_trait; +use libk::{ + error::Error, + task::runtime::maybe_timeout, + vfs::{File, FileReadiness, Socket}, +}; +use libk_mm::PageBox; +use libk_util::{ + hash_table::DefaultHashTable, + queue::BoundedMpmcQueue, + sync::spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockReadGuard}, +}; +use yggdrasil_abi::net::{types::LocalSocketAddress, MessageHeader, MessageHeaderMut}; + +use super::OwnedAddress; + +struct Message { + source: OwnedAddress, + data: PageBox<[u8]>, + ancillary: Option>, +} + +struct Pairing { + address: OwnedAddress, + socket: Weak, +} + +pub struct LocalPacketSocket { + local: IrqSafeRwLock>>, + connected: IrqSafeRwLock>>, + remotes: IrqSafeRwLock>, + + receive_queue: BoundedMpmcQueue, + anonymous_socket_id: AtomicU64, +} + +impl LocalPacketSocket { + pub fn new() -> Arc { + Arc::new(Self { + local: IrqSafeRwLock::new(None), + connected: IrqSafeRwLock::new(None), + remotes: IrqSafeRwLock::new(DefaultHashTable::new()), + + receive_queue: BoundedMpmcQueue::new(128), + anonymous_socket_id: AtomicU64::new(0), + }) + } + + #[inline] + fn make_message(message: &MessageHeader, source: OwnedAddress) -> Result { + let mut data = PageBox::new_slice(0, message.payload.len())?; + let ancillary = super::read_ancillary(message)?; + data.copy_from_slice(message.payload); + Ok(Message { + data, + source, + ancillary, + }) + } + + fn push_nonblocking(&self, message: &MessageHeader, source: OwnedAddress) -> Result<(), Error> { + let message = Self::make_message(message, source)?; + self.receive_queue + .try_push_back(message) + .map_err(|_| Error::WouldBlock)?; + Ok(()) + } + + async fn push(&self, message: &MessageHeader<'_>, source: OwnedAddress) -> Result<(), Error> { + let message = Self::make_message(message, source)?; + self.receive_queue.push_back(message).await; + Ok(()) + } + + /// Makes the `socket` "known" to `self` by giving it an anonymous address. + /// + /// `self` must be a named socket (i.e., anonymous sockets cannot communicate to anonymous + /// sockets). + fn add_socket(&self, socket: &Arc) -> Result { + let path = self.local.read().clone().ok_or(Error::InvalidOperation)?; + let mut remotes = self.remotes.write(); + let index = self.anonymous_socket_id.fetch_add(1, Ordering::Acquire); + let address = OwnedAddress::Anonymous(index); + assert!(!remotes.contains_key(&address)); + // Messages will be sent to the `socket` using the named address + remotes.insert( + address.clone(), + Pairing { + address: OwnedAddress::Path(path), + socket: Arc::downgrade(socket), + }, + ); + Ok(address) + } + + /// Returns an address to use for sending data to the specified `remote` socket, and the + /// socket itself. + /// + /// 1. If this socket is bound to a name, the name will be used + /// 2. Otherwise: + /// 2.1. If `remote` is "known" by this socket, the address in the table will be used + /// 2.2. Otherwise, this socket is "paired" with the remote by generating a new anonymous + /// address unique to that socket + fn get_send_info( + self: &Arc, + remote: &OwnedAddress, + ) -> Result<(OwnedAddress, Arc), Error> { + // Find the socket first + let peer = match remote { + OwnedAddress::Path(path) => PATH_TABLE + .read() + .get(path) + .cloned() + .ok_or(Error::HostUnreachable)?, + &OwnedAddress::Anonymous(anon) => self + .remotes + .read() + .get(&OwnedAddress::Anonymous(anon)) + .and_then(|p| p.socket.upgrade()) + .ok_or(Error::HostUnreachable)?, + }; + + // (1) + if let Some(address) = self.local.read().clone() { + return Ok((OwnedAddress::Path(address), peer)); + } + + // (2.1) + let remotes = self.remotes.read(); + if let Some(pairing) = remotes.get(remote) { + return Ok((pairing.address.clone(), peer)); + } + + // (2.2) + let mut remotes = IrqSafeRwLockReadGuard::upgrade(remotes); + let address = peer.add_socket(self)?; + // Insert pairing to the table so the socket "knows" how to send the messages + // to the destination + log::info!("local: now known to {remote:?} as {address:?}"); + remotes.insert( + remote.clone(), + Pairing { + address: address.clone(), + socket: Arc::downgrade(&peer), + }, + ); + + Ok((address, peer)) + } + + fn write_message(message: &mut MessageHeaderMut, msg: Message) -> Result { + let address = msg.source.to_borrowed(); + if message.payload.len() < msg.data.len() { + log::warn!( + "local: buffer ({}) too small to store a message of {}", + message.payload.len(), + msg.data.len() + ); + return Err(Error::BufferTooSmall); + } + message.payload[..msg.data.len()].copy_from_slice(&msg.data); + super::store_address(message, &address)?; + super::write_ancillary(message, msg.ancillary)?; + log::trace!("local: received {} bytes", msg.data.len()); + Ok(msg.data.len()) + } + + fn read_destination(&self, message: &MessageHeader) -> Result { + if let Some(destination) = message.destination { + super::load_address(destination).map(Into::into) + } else if let Some(destination) = self.connected.read().clone() { + Ok(OwnedAddress::Path(destination)) + } else { + Err(Error::NotConnected) + } + } +} + +static PATH_TABLE: IrqSafeRwLock, Arc>> = + IrqSafeRwLock::new(BTreeMap::new()); + +#[async_trait] +impl Socket for LocalPacketSocket { + fn bind(self: Arc, local: &[u8]) -> Result<(), Error> { + let local = super::load_address(local)?; + + let LocalSocketAddress::Path(local) = local else { + // Cannot bind a local socket to an anonymous address + return Err(Error::InvalidArgument); + }; + + let mut bound = self.local.write(); + if bound.is_some() { + // Already bound + return Err(Error::InvalidOperation); + } + + let mut path_table = PATH_TABLE.write(); + if path_table.contains_key(local) { + return Err(Error::AddrInUse); + } + + log::info!("local: bound {local:?}"); + let local: Arc = Arc::from(local); + *bound = Some(local.clone()); + path_table.insert(local, self.clone()); + + Ok(()) + } + async fn connect( + self: Arc, + remote: &[u8], + _timeout: Option, + ) -> Result<(), Error> { + let remote = super::load_address(remote)?; + + let LocalSocketAddress::Path(remote) = remote else { + // Cannot connect a local socket to an anonymous address + return Err(Error::InvalidArgument); + }; + + let mut bound = self.connected.write(); + if bound.is_some() { + return Err(Error::InvalidOperation); + } + + let path: Arc = remote.into(); + let address = OwnedAddress::Path(path.clone()); + // Associate with the address, discard the actual result + let _ = self.get_send_info(&address)?; + log::info!("local: connected to {remote:?}"); + *bound = Some(path); + + Ok(()) + } + + fn close(self: Arc) -> Result<(), Error> { + let local = self.local.write().take(); + if let Some(path) = local { + log::info!("local: unbound {path:?}"); + PATH_TABLE.write().remove(path.as_ref()); + } + Ok(()) + } + + fn set_option(&self, option: u32, buffer: &[u8]) -> Result<(), Error> { + let _ = option; + let _ = buffer; + Err(Error::InvalidOperation) + } + + fn get_option(&self, option: u32, buffer: &mut [u8]) -> Result { + let _ = option; + let _ = buffer; + Err(Error::InvalidOperation) + } + + fn send_nonblocking(self: Arc, message: &MessageHeader) -> Result { + let destination = self.read_destination(message)?; + log::trace!( + "local: send {} bytes to {:?}", + message.payload.len(), + destination + ); + let (source, peer) = self.get_send_info(&destination)?; + peer.push_nonblocking(message, source)?; + Ok(message.payload.len()) + } + async fn send_message( + self: Arc, + message: &MessageHeader, + timeout: Option, + ) -> Result { + let _ = timeout; + let destination = self.read_destination(message)?; + log::trace!( + "local: send {} bytes to {:?}", + message.payload.len(), + destination + ); + let (source, peer) = self.get_send_info(&destination)?; + peer.push(message, source).await?; + Ok(message.payload.len()) + } + + fn receive_nonblocking( + self: Arc, + message: &mut MessageHeaderMut, + ) -> Result { + let msg = self + .receive_queue + .try_pop_front() + .ok_or(Error::WouldBlock)?; + Self::write_message(message, msg) + } + async fn receive_message( + self: Arc, + message: &mut MessageHeaderMut, + timeout: Option, + ) -> Result { + let future = self.receive_queue.pop_front(); + let msg = maybe_timeout(future, timeout).await?; + Self::write_message(message, msg) + } +} + +impl FileReadiness for LocalPacketSocket { + fn poll_read(&self, cx: &mut Context<'_>) -> Poll> { + self.receive_queue.poll_not_empty(cx).map(|_| Ok(())) + } +} + +impl fmt::Debug for LocalPacketSocket { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("LocalPacketSocket").finish_non_exhaustive() + } +} diff --git a/kernel/driver/net/core/src/socket/mod.rs b/kernel/driver/net/core/src/socket/mod.rs index 6d4f08c8..f8b9a456 100644 --- a/kernel/driver/net/core/src/socket/mod.rs +++ b/kernel/driver/net/core/src/socket/mod.rs @@ -1,11 +1,10 @@ +use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; + use alloc::{ collections::{btree_map::Entry, BTreeMap}, sync::Arc, }; -use yggdrasil_abi::{ - error::Error, - net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, -}; +use yggdrasil_abi::error::Error; pub mod udp; pub use udp::UdpSocket; @@ -13,6 +12,10 @@ pub mod tcp; pub use tcp::TcpSocket; pub mod raw; pub use raw::RawSocket; +pub mod config; +pub use config::NetConfigSocket; +pub mod local; +pub use local::LocalPacketSocket; pub struct SocketTable { inner: BTreeMap>, @@ -20,12 +23,14 @@ pub struct SocketTable { pub struct TwoWaySocketTable { inner: BTreeMap<(SocketAddr, SocketAddr), Arc>, + last_port: u16, } impl TwoWaySocketTable { pub const fn new() -> Self { Self { inner: BTreeMap::new(), + last_port: 32768, } } @@ -43,21 +48,54 @@ impl TwoWaySocketTable { Ok(socket) } + const fn next_port_wrapping(port: u16) -> u16 { + let port = port + 1; + if port >= u16::MAX - 1 { + 32768 + } else { + port + } + } + + fn try_insert_into_range Result, Error>, R: Iterator>( + &mut self, + local: IpAddr, + remote: SocketAddr, + range: R, + with: &mut F, + ) -> Result<(Arc, u16), Error> { + for port in range { + let local = SocketAddr::new(local, port); + + match self.try_insert_with(local, remote, || with(port)) { + Ok(socket) => return Ok((socket, port)), + Err(Error::AddrInUse) => continue, + Err(error) => return Err(error), + } + } + + Err(Error::AddrInUse) + } + pub fn try_insert_with_ephemeral_port Result, Error>>( &mut self, local: IpAddr, remote: SocketAddr, mut with: F, ) -> Result, Error> { - for port in 32768..u16::MAX - 1 { - let local = SocketAddr::new(local, port); - - match self.try_insert_with(local, remote, || with(port)) { - Ok(socket) => return Ok(socket), - Err(Error::AddrInUse) => continue, - Err(error) => return Err(error), - } + if let Ok((socket, port)) = + self.try_insert_into_range(local, remote, self.last_port..u16::MAX - 1, &mut with) + { + self.last_port = Self::next_port_wrapping(port); + return Ok(socket); } + if let Ok((socket, port)) = + self.try_insert_into_range(local, remote, 32768..self.last_port, &mut with) + { + self.last_port = Self::next_port_wrapping(port); + return Ok(socket); + } + Err(Error::AddrInUse) } @@ -151,7 +189,9 @@ impl SocketTable { let unspec = match local { SocketAddr::V4(_v4) => SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, local.port()).into(), - SocketAddr::V6(_v6) => SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, local.port()).into(), + SocketAddr::V6(_v6) => { + SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, local.port(), 0, 0).into() + } }; self.inner.get(&unspec).cloned() diff --git a/kernel/driver/net/core/src/socket/raw.rs b/kernel/driver/net/core/src/socket/raw.rs index a61452e7..965cdf4d 100644 --- a/kernel/driver/net/core/src/socket/raw.rs +++ b/kernel/driver/net/core/src/socket/raw.rs @@ -10,14 +10,14 @@ use async_trait::async_trait; use libk::{ error::Error, task::runtime::maybe_timeout, - vfs::{FileReadiness, PacketSocket, Socket}, + vfs::{FileReadiness, Socket}, }; use libk_mm::PageBox; use libk_util::{queue::BoundedMpmcQueue, sync::spin_rwlock::IrqSafeRwLock}; use yggdrasil_abi::{ net::{ options::{self, RawSocketOptionVariant}, - SocketAddr, SocketInterfaceQuery, + MessageHeader, MessageHeaderMut, SocketInterfaceQuery, }, option::OptionValue, }; @@ -66,14 +66,14 @@ impl RawSocket { } } - fn packet_to_user(packet: L2Packet, buffer: &mut [u8]) -> Result<(usize, SocketAddr), Error> { + fn packet_to_user(packet: L2Packet, buffer: &mut [u8]) -> Result { let full_len = packet.data.len(); let len = full_len - packet.l2_offset; if buffer.len() < len { return Err(Error::BufferTooSmall); } buffer[..len].copy_from_slice(&packet.data[packet.l2_offset..full_len]); - Ok((len, SocketAddr::NULL_V4)) + Ok(len) } } @@ -83,8 +83,16 @@ impl FileReadiness for RawSocket { } } +#[async_trait] impl Socket for RawSocket { - fn bind(self: Arc, _local: SocketAddr) -> Result<(), Error> { + fn bind(self: Arc, _local: &[u8]) -> Result<(), Error> { + Err(Error::InvalidOperation) + } + async fn connect( + self: Arc, + _remote: &[u8], + _timeout: Option, + ) -> Result<(), Error> { Err(Error::InvalidOperation) } @@ -156,68 +164,46 @@ impl Socket for RawSocket { Ok(()) } - fn local_address(&self) -> Option { - None - } - - fn remote_address(&self) -> Option { - None - } -} - -#[async_trait] -impl PacketSocket for RawSocket { - fn connect(self: Arc, _remote: SocketAddr) -> Result<(), Error> { - Err(Error::InvalidOperation) - } - - async fn send_to( - self: Arc, - destination: Option, - data: &[u8], - _timeout: Option, - ) -> Result { - self.send_nonblocking(destination, data) - } - - // TODO currently this is still blocking by NIC send code - fn send_nonblocking( - self: Arc, - _destination: Option, - buffer: &[u8], - ) -> Result { + fn send_nonblocking(self: Arc, message: &MessageHeader) -> Result { // TODO cap by MTU? let bound = self.bound.read().ok_or(Error::InvalidOperation)?; let interface = NetworkInterface::get(bound)?; let l2_offset = interface.device.packet_prefix_size(); - if buffer.len() > 4096 - l2_offset { + if message.payload.len() > 4096 - l2_offset { return Err(Error::InvalidArgument); } - let mut packet = PageBox::new_slice(0, l2_offset + buffer.len())?; - packet[l2_offset..l2_offset + buffer.len()].copy_from_slice(buffer); + let mut packet = PageBox::new_slice(0, l2_offset + message.payload.len())?; + packet[l2_offset..l2_offset + message.payload.len()].copy_from_slice(message.payload); interface.device.transmit(packet)?; - Ok(buffer.len()) + Ok(message.payload.len()) } - - async fn receive_from( + async fn send_message( self: Arc, - buffer: &mut [u8], + message: &MessageHeader, timeout: Option, - ) -> Result<(usize, SocketAddr), Error> { - let future = self.receive_queue.pop_front(); - let packet = maybe_timeout(future, timeout).await?; - Self::packet_to_user(packet, buffer) + ) -> Result { + let _ = timeout; + self.send_nonblocking(message) } fn receive_nonblocking( self: Arc, - buffer: &mut [u8], - ) -> Result<(usize, SocketAddr), Error> { + message: &mut MessageHeaderMut, + ) -> Result { let packet = self .receive_queue .try_pop_front() .ok_or(Error::WouldBlock)?; - Self::packet_to_user(packet, buffer) + Self::packet_to_user(packet, message.payload) + } + async fn receive_message( + self: Arc, + message: &mut MessageHeaderMut, + timeout: Option, + ) -> Result { + let future = self.receive_queue.pop_front(); + let packet = maybe_timeout(future, timeout).await?; + Self::packet_to_user(packet, message.payload) } } diff --git a/kernel/driver/net/core/src/socket/tcp/listener.rs b/kernel/driver/net/core/src/socket/tcp/listener.rs index 2840101e..ff807dca 100644 --- a/kernel/driver/net/core/src/socket/tcp/listener.rs +++ b/kernel/driver/net/core/src/socket/tcp/listener.rs @@ -1,6 +1,7 @@ use core::{ fmt, future::poll_fn, + net::SocketAddr, sync::atomic::{AtomicBool, Ordering}, task::{Context, Poll}, }; @@ -11,7 +12,6 @@ use libk_util::{ sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock, IrqSafeSpinlockGuard}, waker::QueueWaker, }; -use yggdrasil_abi::net::SocketAddr; use crate::socket::SocketTable; diff --git a/kernel/driver/net/core/src/socket/tcp/mod.rs b/kernel/driver/net/core/src/socket/tcp/mod.rs index 045d04f6..5b196d1b 100644 --- a/kernel/driver/net/core/src/socket/tcp/mod.rs +++ b/kernel/driver/net/core/src/socket/tcp/mod.rs @@ -11,13 +11,13 @@ use libk::{ block, error::Error, task::runtime::maybe_timeout, - vfs::{ConnectionSocket, FileReadiness, Socket}, + vfs::{FileReadiness, Socket}, }; use libk_util::sync::spin_rwlock::IrqSafeRwLock; use yggdrasil_abi::{ net::{ options::{self, TcpSocketOptionVariant}, - SocketAddr, + MessageHeader, MessageHeaderMut, }, option::OptionValue, }; @@ -28,6 +28,8 @@ mod stream; pub use listener::TcpListener; pub use stream::TcpStream; +use crate::l3::ip; + pub struct TcpSocket { options: IrqSafeRwLock, inner: IrqSafeRwLock, @@ -79,8 +81,10 @@ impl TcpSocket { } } +#[async_trait] impl Socket for TcpSocket { - fn bind(self: Arc, local: SocketAddr) -> Result<(), Error> { + fn bind(self: Arc, local: &[u8]) -> Result<(), Error> { + let local = ip::load_address(local)?; let mut inner = self.inner.write(); // Already connected or bound @@ -95,6 +99,69 @@ impl Socket for TcpSocket { Ok(()) } + fn listen(self: Arc) -> Result<(), Error> { + let listener = self.as_listener().ok_or(Error::InvalidOperation)?; + match listener + .listening + .compare_exchange(false, true, Ordering::Release, Ordering::Relaxed) + { + Ok(_) => Ok(()), + Err(_) => Err(Error::InvalidOperation), + } + } + + async fn accept( + self: Arc, + mut address: Option<&mut [u8]>, + timeout: Option, + ) -> Result, Error> { + let _ = timeout; + let listener = self.as_listener().ok_or(Error::InvalidOperation)?; + let stream = listener.accept().await?; + let remote = stream.remote; + let socket = Arc::new(TcpSocket { + options: IrqSafeRwLock::new(TcpSocketOptions::default()), + inner: IrqSafeRwLock::new(TcpSocketInner::Stream(stream)), + }); + // TODO if this store fails, socket leaks + ip::store_address(&mut address, &remote)?; + Ok(socket) + } + fn accept_nonblocking( + self: Arc, + mut address: Option<&mut [u8]>, + ) -> Result, Error> { + let listener = self.as_listener().ok_or(Error::InvalidOperation)?; + let stream = listener.accept_nonblocking()?; + let remote = stream.remote; + let socket = Arc::new(TcpSocket { + options: IrqSafeRwLock::new(TcpSocketOptions::default()), + inner: IrqSafeRwLock::new(TcpSocketInner::Stream(stream)), + }); + // TODO if this store fails, socket leaks + ip::store_address(&mut address, &remote)?; + Ok(socket) + } + + async fn connect( + self: Arc, + remote: &[u8], + timeout: Option, + ) -> Result<(), Error> { + let remote = ip::load_address(remote)?; + let mut inner = self.inner.write(); + + // Already connected or bound + if !matches!(&*inner, TcpSocketInner::Empty) { + return Err(Error::InvalidOperation); + } + + let stream = TcpStream::connect(remote, timeout).await?; + *inner = TcpSocketInner::Stream(stream); + + Ok(()) + } + fn close(self: Arc) -> Result<(), Error> { let inner = mem::replace(&mut *self.inner.write(), TcpSocketInner::Empty); @@ -105,20 +172,25 @@ impl Socket for TcpSocket { } } - fn local_address(&self) -> Option { - match &*self.inner.read() { - TcpSocketInner::Empty => None, - TcpSocketInner::Stream(socket) => Some(socket.local), - TcpSocketInner::Listener(socket) => Some(socket.local), - } + async fn shutdown(self: Arc, read: bool, write: bool) -> Result<(), Error> { + log::warn!("TODO: shutdown(read = {read}, write = {write})"); + Ok(()) } - fn remote_address(&self) -> Option { - match &*self.inner.read() { - TcpSocketInner::Empty | TcpSocketInner::Listener(_) => None, - TcpSocketInner::Stream(socket) => Some(socket.remote), - } - } + // fn local_address(&self) -> Option { + // match &*self.inner.read() { + // TcpSocketInner::Empty => None, + // TcpSocketInner::Stream(socket) => Some(socket.local), + // TcpSocketInner::Listener(socket) => Some(socket.local), + // } + // } + + // fn remote_address(&self) -> Option { + // match &*self.inner.read() { + // TcpSocketInner::Empty | TcpSocketInner::Listener(_) => None, + // TcpSocketInner::Stream(socket) => Some(socket.remote), + // } + // } fn set_option(&self, option: u32, buffer: &[u8]) -> Result<(), Error> { let option = TcpSocketOptionVariant::try_from(option)?; @@ -143,92 +215,40 @@ impl Socket for TcpSocket { TcpSocketOptionVariant::Ipv6Only => options::Ipv6Only::store(&options.v6_only, buffer), } } -} -#[async_trait] -impl ConnectionSocket for TcpSocket { - async fn connect( + fn send_nonblocking(self: Arc, message: &MessageHeader) -> Result { + let stream = self.as_stream().ok_or(Error::NotConnected)?; + let len = stream.send_nonblocking(message.payload)?; + Ok(len) + } + async fn send_message( self: Arc, - remote: SocketAddr, - _timeout: Option, - ) -> Result<(), Error> { - let mut inner = self.inner.write(); - - // Already connected or bound - if !matches!(&*inner, TcpSocketInner::Empty) { - return Err(Error::InvalidOperation); - } - - let stream = TcpStream::connect(remote).await?; - *inner = TcpSocketInner::Stream(stream); - - Ok(()) - } - - async fn receive( - &self, - buffer: &mut [u8], + message: &MessageHeader, timeout: Option, - ) -> Result<(usize, SocketAddr), Error> { + ) -> Result { let stream = self.as_stream().ok_or(Error::NotConnected)?; - let len = stream.receive(buffer, timeout).await?; - Ok((len, stream.remote)) - } - - fn receive_nonblocking(&self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), Error> { - let stream = self.as_stream().ok_or(Error::NotConnected)?; - let len = stream.receive_nonblocking(buffer)?; - Ok((len, stream.remote)) - } - - async fn send(&self, data: &[u8], timeout: Option) -> Result { - let stream = self.as_stream().ok_or(Error::NotConnected)?; - let future = stream.send(data); + let future = stream.send(message.payload); maybe_timeout(future, timeout).await? } - fn send_nonblocking(&self, buffer: &[u8]) -> Result { + fn receive_nonblocking( + self: Arc, + message: &mut MessageHeaderMut, + ) -> Result { let stream = self.as_stream().ok_or(Error::NotConnected)?; - let len = stream.send_nonblocking(buffer)?; + let len = stream.receive_nonblocking(message.payload)?; + ip::store_address(&mut message.source, &stream.remote)?; Ok(len) } - - fn listen(self: Arc) -> Result<(), Error> { - let listener = self.as_listener().ok_or(Error::InvalidOperation)?; - match listener - .listening - .compare_exchange(false, true, Ordering::Release, Ordering::Relaxed) - { - Ok(_) => Ok(()), - Err(_) => Err(Error::InvalidOperation), - } - } - - async fn accept(&self) -> Result<(SocketAddr, Arc), Error> { - let listener = self.as_listener().ok_or(Error::InvalidOperation)?; - let stream = listener.accept().await?; - let remote = stream.remote; - let socket = Arc::new(TcpSocket { - options: IrqSafeRwLock::new(TcpSocketOptions::default()), - inner: IrqSafeRwLock::new(TcpSocketInner::Stream(stream)), - }); - Ok((remote, socket)) - } - - fn accept_nonblocking(&self) -> Result<(SocketAddr, Arc), Error> { - let listener = self.as_listener().ok_or(Error::InvalidOperation)?; - let stream = listener.accept_nonblocking()?; - let remote = stream.remote; - let socket = Arc::new(TcpSocket { - options: IrqSafeRwLock::new(TcpSocketOptions::default()), - inner: IrqSafeRwLock::new(TcpSocketInner::Stream(stream)), - }); - Ok((remote, socket)) - } - - async fn shutdown(&self, read: bool, write: bool) -> Result<(), Error> { - log::warn!("TODO: shutdown(read = {read}, write = {write})"); - Ok(()) + async fn receive_message( + self: Arc, + message: &mut MessageHeaderMut, + timeout: Option, + ) -> Result { + let stream = self.as_stream().ok_or(Error::NotConnected)?; + let len = stream.receive(message.payload, timeout).await?; + ip::store_address(&mut message.source, &stream.remote)?; + Ok(len) } } diff --git a/kernel/driver/net/core/src/socket/tcp/stream.rs b/kernel/driver/net/core/src/socket/tcp/stream.rs index c06e633d..3a94e93d 100644 --- a/kernel/driver/net/core/src/socket/tcp/stream.rs +++ b/kernel/driver/net/core/src/socket/tcp/stream.rs @@ -1,6 +1,7 @@ use core::{ fmt, future::poll_fn, + net::SocketAddr, task::{Context, Poll}, time::Duration, }; @@ -12,7 +13,6 @@ use libk::{ time::monotonic_time, }; use libk_util::sync::spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockWriteGuard}; -use yggdrasil_abi::net::SocketAddr; use crate::{ interface::NetworkInterface, @@ -36,7 +36,11 @@ static TCP_STREAMS: IrqSafeRwLock> = IrqSafeRwLock::new(TwoWaySocketTable::new()); impl TcpStream { - pub async fn connect(remote: SocketAddr) -> Result, Error> { + pub async fn connect( + remote: SocketAddr, + timeout: Option, + ) -> Result, Error> { + log::info!("tcp: try connect to {remote} (timeout={timeout:?})"); // Lookup route to remote let (interface_id, _, remote_ip) = Route::lookup(remote.ip()).ok_or(Error::HostUnreachable)?; @@ -63,13 +67,23 @@ impl TcpStream { })? }; + let deadline = timeout.map(|t| monotonic_time() + t); + // TODO limit interval between attempts to timeout value if one is provided let mut t = 200; - for _ in 0..5 { + for i in 0..5 { let timeout = Duration::from_millis(t); log::debug!("Try SYN with timeout={:?}", timeout); match stream.try_connect(timeout).await { Ok(()) => return Ok(stream), - Err(Error::TimedOut) => (), + Err(Error::TimedOut) => { + log::warn!("tcp: connect attempt [{}/5] to {remote} timed out", i + 1); + + if let Some(deadline) = deadline + && monotonic_time() > deadline + { + break; + } + } Err(error) => return Err(error), } t *= 2; @@ -78,6 +92,8 @@ impl TcpStream { // Couldn't establish stream.close(false).await.ok(); + log::warn!("tcp: connection to {remote} timed out"); + Err(Error::TimedOut) } diff --git a/kernel/driver/net/core/src/socket/udp.rs b/kernel/driver/net/core/src/socket/udp.rs index 09a4a2f2..b39b1fbf 100644 --- a/kernel/driver/net/core/src/socket/udp.rs +++ b/kernel/driver/net/core/src/socket/udp.rs @@ -1,5 +1,6 @@ use core::{ fmt, + net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, task::{Context, Poll}, time::Duration, }; @@ -10,7 +11,7 @@ use libk::{ block, error::Error, task::runtime::maybe_timeout, - vfs::{FileReadiness, PacketSocket, Socket}, + vfs::{FileReadiness, Socket}, }; use libk_util::{ queue::BoundedMpmcQueue, @@ -19,12 +20,12 @@ use libk_util::{ use yggdrasil_abi::{ net::{ options::{self, UdpSocketOptionVariant}, - IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, + MessageHeader, MessageHeaderMut, }, option::OptionValue, }; -use crate::l4; +use crate::{l3::ip, l4}; use super::SocketTable; @@ -94,38 +95,14 @@ impl UdpSocket { Ok(port) } } -} -impl FileReadiness for UdpSocket { - fn poll_read(&self, cx: &mut Context<'_>) -> Poll> { - self.receive_queue.poll_not_empty(cx).map(Ok) - } -} - -#[async_trait] -impl PacketSocket for UdpSocket { - fn connect(self: Arc, remote: SocketAddr) -> Result<(), Error> { - let mut connected = self.remote.write(); - if connected.is_some() { - return Err(Error::InvalidOperation); - } - *connected = Some(remote); - Ok(()) - } - - async fn send_to( - self: Arc, - destination: Option, - data: &[u8], - _timeout: Option, + async fn send( + &self, + port: u16, + payload: &[u8], + destination: SocketAddr, ) -> Result { - let destination = destination - .or_else(|| self.remote_address()) - .ok_or(Error::NotConnected)?; - - // If socket wasn't bound yet, bind it to an ephemeral port - let port = self.ensure_address(destination.ip().is_ipv6())?; - + log::info!("udp: send {} bytes to {destination}", payload.len()); let options = self.options.read(); // TODO check that destnation family matches self family @@ -138,60 +115,42 @@ impl PacketSocket for UdpSocket { destination.ip(), destination.port(), options.ttl, - data, + payload, ) .await?; } } - Ok(data.len()) + Ok(payload.len()) } - fn send_nonblocking( - self: Arc, - destination: Option, - buffer: &[u8], + fn store_packet( + message: &mut MessageHeaderMut, + packet: &[u8], + source: &SocketAddr, ) -> Result { - log::warn!("TODO: UDP::send_nonblocking()"); - block!(self.send_to(destination, buffer, None).await)? - } - - async fn receive_from( - self: Arc, - buffer: &mut [u8], - timeout: Option, - ) -> Result<(usize, SocketAddr), Error> { - let future = self.receive_queue.pop_front(); - let (source, packet) = maybe_timeout(future, timeout).await?; - - if packet.len() > buffer.len() { + log::info!("udp: receive {} bytes from {source}", packet.len()); + if packet.len() > message.payload.len() { // TODO check how other OSs handle this return Err(Error::BufferTooSmall); } - buffer[..packet.len()].copy_from_slice(&packet); - Ok((packet.len(), source)) - } - - fn receive_nonblocking( - self: Arc, - buffer: &mut [u8], - ) -> Result<(usize, SocketAddr), Error> { - let (source, packet) = self - .receive_queue - .try_pop_front() - .ok_or(Error::WouldBlock)?; - - if packet.len() > buffer.len() { - // TODO check how other OSs handle this - return Err(Error::BufferTooSmall); - } - buffer[..packet.len()].copy_from_slice(&packet); - Ok((packet.len(), source)) + message.payload[..packet.len()].copy_from_slice(packet); + ip::store_address(&mut message.source, source)?; + Ok(packet.len()) } } +impl FileReadiness for UdpSocket { + fn poll_read(&self, cx: &mut Context<'_>) -> Poll> { + self.receive_queue.poll_not_empty(cx).map(Ok) + } +} + +#[async_trait] impl Socket for UdpSocket { - fn bind(self: Arc, local: SocketAddr) -> Result<(), Error> { + fn bind(self: Arc, local: &[u8]) -> Result<(), Error> { + let local = ip::load_address(local)?; + log::info!("udp: bind {local}"); let mut bound = self.local.write(); if bound.is_some() { return Err(Error::InvalidOperation); @@ -208,12 +167,18 @@ impl Socket for UdpSocket { Ok(()) } - fn local_address(&self) -> Option { - *self.local.read() - } - - fn remote_address(&self) -> Option { - *self.remote.read() + async fn connect( + self: Arc, + remote: &[u8], + _timeout: Option, + ) -> Result<(), Error> { + let remote = ip::load_address(remote)?; + let mut connected = self.remote.write(); + if connected.is_some() { + return Err(Error::InvalidOperation); + } + *connected = Some(remote); + Ok(()) } fn close(self: Arc) -> Result<(), Error> { @@ -268,6 +233,49 @@ impl Socket for UdpSocket { } } } + + fn send_nonblocking(self: Arc, message: &MessageHeader) -> Result { + log::warn!("TODO: UDP::send_nonblocking()"); + block!(self.send_message(message, None).await)? + } + async fn send_message( + self: Arc, + message: &MessageHeader, + timeout: Option, + ) -> Result { + let _ = timeout; + let destination = message + .destination + .map(ip::load_address) + .transpose()? + .or_else(|| *self.remote.read()) + .ok_or(Error::NotConnected)?; + + // If socket wasn't bound yet, bind it to an ephemeral port + let port = self.ensure_address(destination.ip().is_ipv6())?; + + self.send(port, message.payload, destination).await + } + + fn receive_nonblocking( + self: Arc, + message: &mut MessageHeaderMut, + ) -> Result { + let (source, packet) = self + .receive_queue + .try_pop_front() + .ok_or(Error::WouldBlock)?; + Self::store_packet(message, &packet, &source) + } + async fn receive_message( + self: Arc, + message: &mut MessageHeaderMut, + timeout: Option, + ) -> Result { + let future = self.receive_queue.pop_front(); + let (source, packet) = maybe_timeout(future, timeout).await?; + Self::store_packet(message, &packet, &source) + } } impl fmt::Debug for UdpSocket { diff --git a/kernel/driver/net/loopback/src/lib.rs b/kernel/driver/net/loopback/src/lib.rs index 8e4e2c11..b39b6843 100644 --- a/kernel/driver/net/loopback/src/lib.rs +++ b/kernel/driver/net/loopback/src/lib.rs @@ -2,6 +2,8 @@ extern crate alloc; +use core::net::{IpAddr, Ipv4Addr}; + use alloc::sync::Arc; use libk_mm::PageBox; use libk_util::OneTimeInit; @@ -9,10 +11,7 @@ use ygg_driver_net_core::{ interface::{NetworkDevice, NetworkInterfaceType}, Packet, }; -use yggdrasil_abi::{ - error::Error, - net::{IpAddr, Ipv4Addr, MacAddress}, -}; +use yggdrasil_abi::{error::Error, net::MacAddress}; struct LoopbackDevice; @@ -39,5 +38,5 @@ pub fn init() { LOOPBACK_ID.init(interface.id()); - interface.set_address(IpAddr::V4(Ipv4Addr::LOOPBACK)); + interface.set_address(IpAddr::V4(Ipv4Addr::LOCALHOST)); } diff --git a/kernel/libk/libk-util/src/hash_table.rs b/kernel/libk/libk-util/src/hash_table.rs index 5ca1a64d..5546637e 100644 --- a/kernel/libk/libk-util/src/hash_table.rs +++ b/kernel/libk/libk-util/src/hash_table.rs @@ -28,6 +28,14 @@ where } } +impl HashTable { + pub fn clear(&mut self) { + for bucket in self.buckets.iter_mut() { + bucket.clear(); + } + } +} + impl HashTable { pub fn insert(&mut self, key: K, value: V) -> Option { let h = self.hasher.hash_one(&key); @@ -61,4 +69,15 @@ impl HashTable { .iter() .find_map(|(k, v)| (k.borrow() == key).then_some((k, v))) } + + pub fn contains_key(&self, key: &Q) -> bool + where + Q: Hash + Eq + ?Sized, + K: Borrow, + { + let h = self.hasher.hash_one(key); + let bucket = &self.buckets[h as usize % self.buckets.len()]; + + bucket.iter().any(|(k, _)| (k.borrow() == key)) + } } diff --git a/kernel/libk/src/task/debug.rs b/kernel/libk/src/task/debug.rs index faa3bc5b..a63779aa 100644 --- a/kernel/libk/src/task/debug.rs +++ b/kernel/libk/src/task/debug.rs @@ -1,24 +1,25 @@ -use yggdrasil_abi::{debug::DebugFrame, error::Error, io::MessageDestination}; +use yggdrasil_abi::{debug::DebugFrame, error::Error}; -use crate::vfs::{ChannelDescriptor, MessagePayload}; - -pub struct ThreadDebugger { - channel: ChannelDescriptor, -} +pub struct ThreadDebugger {} impl ThreadDebugger { - pub fn new(channel: ChannelDescriptor) -> Self { - Self { channel } + pub fn new() -> Self { + todo!() } + // pub fn new(channel: ChannelDescriptor) -> Self { + // Self { channel } + // } pub fn send(&self, frame: &DebugFrame) -> Result<(), Error> { - let bytes = serde_json::to_vec(frame).unwrap(); - self.channel - .send_message( - MessagePayload::Data(bytes.into_boxed_slice()), - MessageDestination::AllExceptSelf, - ) - .unwrap(); - Ok(()) + let _ = frame; + todo!() + // let bytes = serde_json::to_vec(frame).unwrap(); + // self.channel + // .send_message( + // MessagePayload::Data(bytes.into_boxed_slice()), + // MessageDestination::AllExceptSelf, + // ) + // .unwrap(); + // Ok(()) } } diff --git a/kernel/libk/src/vfs/channel.rs b/kernel/libk/src/vfs/channel.rs index 61d5212a..13dacbad 100644 --- a/kernel/libk/src/vfs/channel.rs +++ b/kernel/libk/src/vfs/channel.rs @@ -28,25 +28,9 @@ pub struct Channel { subscriptions: Mutex>>, } -/// Describes message payload -pub enum MessagePayload { - /// Payload contains a file - File(FileRef), - /// Payload contains byte data - Data(Box<[u8]>), -} - -/// Describes a message sent over a channel -pub struct Message { - /// Channel descriptor ID from which the message came - pub source: ChannelPublisherId, - /// Data of the message - pub payload: MessagePayload, -} - /// Describes a single subscription so some [Channel] pub struct Subscription { - queue: Mutex>>, + // queue: Mutex>>, notify: AtomicWaker, } @@ -72,54 +56,55 @@ impl ChannelDescriptor { Self { tx, rx, id } } - /// Receives a message from the subscription - pub fn receive_message(&self) -> Result, Error> { - let Some(rx) = self.rx.as_ref() else { - return Err(Error::InvalidOperation); - }; + // /// Receives a message from the subscription + // pub fn receive_message(&self) -> Result, Error> { + // let Some(rx) = self.rx.as_ref() else { + // return Err(Error::InvalidOperation); + // }; - rx.receive_message_inner() - } + // rx.receive_message_inner() + // } - /// Asynchronously receives a message from the subscription - pub async fn receive_message_async(&self) -> Result, Error> { - let rx = self.rx.as_ref().ok_or(Error::InvalidOperation)?; - rx.receive_message_async().await - } + // /// Asynchronously receives a message from the subscription + // pub async fn receive_message_async(&self) -> Result, Error> { + // let rx = self.rx.as_ref().ok_or(Error::InvalidOperation)?; + // rx.receive_message_async().await + // } - /// Sends a message to the channel - pub fn send_message( - &self, - payload: MessagePayload, - dst: MessageDestination, - ) -> Result<(), Error> { - let message = Arc::new(Message { - source: unsafe { ChannelPublisherId::from_raw(self.id) }, - payload, - }); + // /// Sends a message to the channel + // pub fn send_message( + // &self, + // payload: MessagePayload, + // dst: MessageDestination, + // ) -> Result<(), Error> { + // todo!() + // // let message = Arc::new(Message { + // // source: unsafe { ChannelPublisherId::from_raw(self.id) }, + // // payload, + // // }); - let lock = self.tx.subscriptions.lock()?; + // // let lock = self.tx.subscriptions.lock()?; - match dst { - MessageDestination::Specific(id) => { - if let Some(sub) = lock.get(&id) { - sub.push_message(message)?; - } - } - MessageDestination::AllExceptSelf => { - for (&id, sub) in lock.iter() { - if id == self.id { - continue; - } + // // match dst { + // // MessageDestination::Specific(id) => { + // // if let Some(sub) = lock.get(&id) { + // // sub.push_message(message)?; + // // } + // // } + // // MessageDestination::AllExceptSelf => { + // // for (&id, sub) in lock.iter() { + // // if id == self.id { + // // continue; + // // } - sub.push_message(message.clone())?; - } - } - MessageDestination::All => todo!(), - } + // // sub.push_message(message.clone())?; + // // } + // // } + // // MessageDestination::All => todo!(), + // // } - Ok(()) - } + // // Ok(()) + // } } impl Clone for ChannelDescriptor { @@ -146,61 +131,63 @@ impl Channel { } fn subscribe(&self, id: u32) -> Arc { - let mut lock = self.subscriptions.lock().unwrap(); + todo!() + // let mut lock = self.subscriptions.lock().unwrap(); - let sub = Arc::new(Subscription { - queue: Mutex::new(VecDeque::new()), - notify: AtomicWaker::new(), - }); + // let sub = Arc::new(Subscription { + // queue: Mutex::new(VecDeque::new()), + // notify: AtomicWaker::new(), + // }); - lock.insert(id, sub.clone()); + // lock.insert(id, sub.clone()); - sub + // sub } } impl Subscription { - async fn receive_message_async(&self) -> Result, Error> { - poll_fn(|cx| { - let mut lock = self.queue.lock()?; - if let Some(msg) = lock.pop_front() { - Poll::Ready(Ok(msg)) - } else { - self.notify.register(cx.waker()); - Poll::Pending - } - }) - .await - } + // async fn receive_message_async(&self) -> Result, Error> { + // poll_fn(|cx| { + // let mut lock = self.queue.lock()?; + // if let Some(msg) = lock.pop_front() { + // Poll::Ready(Ok(msg)) + // } else { + // self.notify.register(cx.waker()); + // Poll::Pending + // } + // }) + // .await + // } - fn receive_message_inner(&self) -> Result, Error> { - block!(self.receive_message_async().await)? - } + // fn receive_message_inner(&self) -> Result, Error> { + // block!(self.receive_message_async().await)? + // } - fn push_message(&self, msg: Arc) -> Result<(), Error> { - self.queue.lock()?.push_back(msg); - self.notify.wake(); - Ok(()) - } + // fn push_message(&self, msg: Arc) -> Result<(), Error> { + // self.queue.lock()?.push_back(msg); + // self.notify.wake(); + // Ok(()) + // } } impl FileReadiness for ChannelDescriptor { fn poll_read(&self, cx: &mut Context<'_>) -> Poll> { - let Some(rx) = self.rx.as_ref() else { - return Poll::Ready(Err(Error::InvalidOperation)); - }; + todo!() + // let Some(rx) = self.rx.as_ref() else { + // return Poll::Ready(Err(Error::InvalidOperation)); + // }; - if !rx.queue.lock()?.is_empty() { - return Poll::Ready(Ok(())); - } + // if !rx.queue.lock()?.is_empty() { + // return Poll::Ready(Ok(())); + // } - rx.notify.register(cx.waker()); + // rx.notify.register(cx.waker()); - if !rx.queue.lock()?.is_empty() { - Poll::Ready(Ok(())) - } else { - Poll::Pending - } + // if !rx.queue.lock()?.is_empty() { + // Poll::Ready(Ok(())) + // } else { + // Poll::Pending + // } } } diff --git a/kernel/libk/src/vfs/file/mod.rs b/kernel/libk/src/vfs/file/mod.rs index 0b1f778c..5f5dd502 100644 --- a/kernel/libk/src/vfs/file/mod.rs +++ b/kernel/libk/src/vfs/file/mod.rs @@ -24,6 +24,7 @@ use yggdrasil_abi::{ DirectoryEntry, FileMode, OpenOptions, RawFd, SeekFrom, TerminalOptions, TerminalSize, TimerOptions, }, + net::{MessageHeader, MessageHeaderMut}, option::{OptionValue, RequestValue}, process::{ProcessGroupId, ProcessWait, WaitFlags}, }; @@ -32,7 +33,6 @@ use crate::{ device::{block::BlockDeviceFile, char::CharDeviceFile}, task::process::Process, vfs::{ - channel::ChannelDescriptor, node::NodeRef, traits::{Read, Seek, Write}, FdPoll, FileReadiness, Node, SharedMemory, TimerFile, @@ -86,7 +86,6 @@ enum FileInner { AnonymousPipe(PipeEnd), Poll(FdPoll), Timer(TimerFile), - Channel(ChannelDescriptor), SharedMemory(Arc), PtySlave(TerminalHalfWrapper), PtyMaster(TerminalHalfWrapper), @@ -136,12 +135,6 @@ impl File { Self::from_inner(FileInner::Poll(FdPoll::new())) } - /// Opens a new message channel, optionally subscribing to it as well - pub fn new_message_channel(name: &str, with_sub: bool) -> Arc { - let channel = ChannelDescriptor::open(name, with_sub); - Self::from_inner(FileInner::Channel(channel)) - } - /// Creates a buffer of shared memory and associates a [File] with it pub fn new_shared_memory(size: usize) -> Result, Error> { let shm = SharedMemory::new(size)?; @@ -333,7 +326,6 @@ impl File { pub fn poll_read(&self, cx: &mut Context<'_>) -> Poll> { match &self.inner { FileInner::Char(f) => f.device.poll_read(cx), - FileInner::Channel(ch) => ch.poll_read(cx), FileInner::Poll(ch) => ch.poll_read(cx), FileInner::PtyMaster(half) => half.half.poll_read(cx), FileInner::PtySlave(half) => half.half.poll_read(cx), @@ -374,15 +366,6 @@ impl File { } } - /// Interprets the file as a message channel - pub fn as_message_channel(&self) -> Result<&ChannelDescriptor, Error> { - if let FileInner::Channel(ch) = &self.inner { - Ok(ch) - } else { - Err(Error::InvalidOperation) - } - } - /// Interprets the file as a socket pub fn as_socket(&self) -> Result<&SocketWrapper, Error> { match &self.inner { @@ -455,13 +438,17 @@ impl Read for File { FileInner::Pid(pid) => pid.read(buf, non_blocking), // TODO allow reads from sockets FileInner::Socket(socket) => { - let (len, _) = socket.receive_from(buf, non_blocking)?; - Ok(len) + let mut header = MessageHeaderMut { + source: None, + ancillary: None, + ancillary_len: 0, + payload: buf, + }; + socket.receive_message(&mut header, non_blocking) + } + FileInner::Directory(_) | FileInner::Poll(_) | FileInner::SharedMemory(_) => { + Err(Error::InvalidOperation) } - FileInner::Directory(_) - | FileInner::Poll(_) - | FileInner::SharedMemory(_) - | FileInner::Channel(_) => Err(Error::InvalidOperation), } } } @@ -477,12 +464,18 @@ impl Write for File { FileInner::PtySlave(half) => half.write(buf), FileInner::PtyMaster(half) => half.write(buf), FileInner::Timer(timer) => timer.write(buf), - FileInner::Socket(socket) => socket.send_to(buf, None, non_blocking), + FileInner::Socket(socket) => { + let header = MessageHeader { + destination: None, + payload: buf, + ancillary: &[], + }; + socket.send_message(&header, non_blocking) + } FileInner::Pid(_) | FileInner::Poll(_) | FileInner::SharedMemory(_) - | FileInner::Directory(_) - | FileInner::Channel(_) => Err(Error::InvalidOperation), + | FileInner::Directory(_) => Err(Error::InvalidOperation), } } } @@ -554,7 +547,6 @@ impl fmt::Debug for File { FileInner::Directory(_) => f.debug_struct("DirectoryFile").finish_non_exhaustive(), FileInner::AnonymousPipe(_) => f.debug_struct("AnonymousPipe").finish_non_exhaustive(), FileInner::Poll(_) => f.debug_struct("Poll").finish_non_exhaustive(), - FileInner::Channel(_) => f.debug_struct("Channel").finish_non_exhaustive(), FileInner::SharedMemory(_) => f.debug_struct("SharedMemory").finish_non_exhaustive(), FileInner::PtySlave(_) => f.debug_struct("PtySlave").finish_non_exhaustive(), FileInner::PtyMaster(_) => f.debug_struct("PtyMaster").finish_non_exhaustive(), diff --git a/kernel/libk/src/vfs/mod.rs b/kernel/libk/src/vfs/mod.rs index 732d7f99..84cc47e7 100644 --- a/kernel/libk/src/vfs/mod.rs +++ b/kernel/libk/src/vfs/mod.rs @@ -5,7 +5,7 @@ extern crate alloc; pub mod pty; pub(crate) mod asyncio; -pub(crate) mod channel; +// pub(crate) mod channel; pub(crate) mod file; pub(crate) mod filesystem; pub(crate) mod ioctx; @@ -19,7 +19,7 @@ pub(crate) mod terminal; pub(crate) mod timer; pub(crate) mod traits; -pub use channel::{Channel, ChannelDescriptor, Message, MessagePayload, Subscription}; +// pub use channel::{Channel, ChannelDescriptor, Subscription}; // pub use device::CharDevice; pub use file::{DirectoryOpenPosition, File, FileRef, FileSet, InstanceData}; pub use filesystem::{ @@ -35,7 +35,7 @@ pub use path::{Filename, OwnedFilename}; pub use poll::FdPoll; pub use pty::{PseudoTerminalMaster, PseudoTerminalSlave}; pub use shared_memory::SharedMemory; -pub use socket::{ConnectionSocket, PacketSocket, Socket, SocketWrapper}; +pub use socket::{Socket, SocketWrapper}; pub use terminal::{Terminal, TerminalInput, TerminalOutput}; pub use timer::TimerFile; pub use traits::{FileReadiness, Read, Seek, Write}; diff --git a/kernel/libk/src/vfs/socket.rs b/kernel/libk/src/vfs/socket.rs index 54b997ae..b9be493e 100644 --- a/kernel/libk/src/vfs/socket.rs +++ b/kernel/libk/src/vfs/socket.rs @@ -11,20 +11,13 @@ use yggdrasil_abi::{ error::Error, net::{ options::{self, SocketOptionVariant}, - SocketAddr, SocketShutdown, + MessageHeader, MessageHeaderMut, SocketShutdown, }, option::OptionValue, }; use crate::vfs::FileReadiness; -use super::{File, FileRef}; - -enum SocketInner { - Connection(Arc), - Packet(Arc), -} - struct InnerOptions { connect_timeout: Option, recv_timeout: Option, @@ -32,239 +25,150 @@ struct InnerOptions { } pub struct SocketWrapper { - inner: SocketInner, + inner: Arc, options: IrqSafeRwLock, } /// Interface for interacting with network sockets -#[allow(unused)] +#[async_trait] pub trait Socket: FileReadiness + fmt::Debug + Send { - fn bind(self: Arc, local: SocketAddr) -> Result<(), Error>; + fn bind(self: Arc, local: &[u8]) -> Result<(), Error> { + let _ = local; + Err(Error::InvalidOperation) + } + async fn connect( + self: Arc, + remote: &[u8], + timeout: Option, + ) -> Result<(), Error>; - /// Socket listen/receive address - fn local_address(&self) -> Option; + fn listen(self: Arc) -> Result<(), Error> { + Err(Error::InvalidOperation) + } + async fn accept( + self: Arc, + address: Option<&mut [u8]>, + timeout: Option, + ) -> Result, Error> { + let _ = address; + let _ = timeout; + Err(Error::InvalidOperation) + } + fn accept_nonblocking( + self: Arc, + address: Option<&mut [u8]>, + ) -> Result, Error> { + let _ = address; + Err(Error::InvalidOperation) + } - /// Socket remote address - fn remote_address(&self) -> Option; + async fn shutdown(self: Arc, read: bool, write: bool) -> Result<(), Error> { + let _ = read; + let _ = write; + Err(Error::InvalidOperation) + } /// Closes a socket - fn close(self: Arc) -> Result<(), Error>; + fn close(self: Arc) -> Result<(), Error> { + Ok(()) + } /// Updates a socket option fn set_option(&self, option: u32, buffer: &[u8]) -> Result<(), Error> { + let _ = option; + let _ = buffer; Err(Error::InvalidOperation) } /// Gets a socket option fn get_option(&self, option: u32, buffer: &mut [u8]) -> Result { + let _ = option; + let _ = buffer; Err(Error::InvalidOperation) } -} -/// Stateless/packet-based socket interface -#[async_trait] -pub trait PacketSocket: Socket { - /// Receives a packet into provided buffer. Will return an error if packet cannot be placed - /// within the buffer. - async fn receive_from( + fn send_nonblocking(self: Arc, message: &MessageHeader) -> Result; + async fn send_message( self: Arc, - buffer: &mut [u8], - timeout: Option, - ) -> Result<(usize, SocketAddr), Error>; - - fn receive_nonblocking( - self: Arc, - buffer: &mut [u8], - ) -> Result<(usize, SocketAddr), Error>; - - /// Sends provided data to the recepient specified by `destination` - async fn send_to( - self: Arc, - destination: Option, - data: &[u8], + message: &MessageHeader, timeout: Option, ) -> Result; - fn send_nonblocking( + fn receive_nonblocking(self: Arc, message: &mut MessageHeaderMut) + -> Result; + async fn receive_message( self: Arc, - destination: Option, - buffer: &[u8], + message: &mut MessageHeaderMut, + timeout: Option, ) -> Result; - - fn connect(self: Arc, remote: SocketAddr) -> Result<(), Error>; -} - -/// Connection-based client socket interface -#[async_trait] -pub trait ConnectionSocket: Socket { - async fn connect( - self: Arc, - remote: SocketAddr, - timeout: Option, - ) -> Result<(), Error>; - - async fn receive( - &self, - buffer: &mut [u8], - timeout: Option, - ) -> Result<(usize, SocketAddr), Error>; - - fn receive_nonblocking(&self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), Error>; - - async fn send(&self, data: &[u8], timeout: Option) -> Result; - - fn send_nonblocking(&self, buffer: &[u8]) -> Result; - - fn listen(self: Arc) -> Result<(), Error>; - - async fn accept(&self) -> Result<(SocketAddr, Arc), Error>; - - fn accept_nonblocking(&self) -> Result<(SocketAddr, Arc), Error>; - - async fn shutdown(&self, read: bool, write: bool) -> Result<(), Error>; } impl SocketWrapper { - pub fn from_connection(socket: Arc) -> Self { - Self { - inner: SocketInner::Connection(socket), - options: IrqSafeRwLock::new(InnerOptions::default()), - } + pub fn from_inner(inner: Arc) -> Self { + Self::from(inner) } - pub fn from_packet(socket: Arc) -> Self { - Self { - inner: SocketInner::Packet(socket), - options: IrqSafeRwLock::new(InnerOptions::default()), - } - } - - pub fn as_inner(&self) -> &dyn Socket { - match &self.inner { - SocketInner::Packet(socket) => socket.as_ref(), - SocketInner::Connection(socket) => socket.as_ref(), - } - } - - async fn send_inner(&self, data: &[u8], remote: Option) -> Result { - let timeout = self.options.read().send_timeout; - - match &self.inner { - SocketInner::Packet(socket) => socket.clone().send_to(remote, data, timeout).await, - SocketInner::Connection(socket) => socket.send(data, timeout).await, - } - } - - async fn receive_inner(&self, data: &mut [u8]) -> Result<(usize, SocketAddr), Error> { - let timeout = self.options.read().recv_timeout; - - match &self.inner { - SocketInner::Packet(socket) => socket.clone().receive_from(data, timeout).await, - SocketInner::Connection(socket) => socket.clone().receive(data, timeout).await, - } - } - - async fn connect_inner(&self, remote: SocketAddr) -> Result<(), Error> { + pub fn connect(&self, remote: &[u8]) -> Result<(), Error> { let timeout = self.options.read().connect_timeout; - - match &self.inner { - SocketInner::Packet(socket) => socket.clone().connect(remote), - SocketInner::Connection(socket) => socket.clone().connect(remote, timeout).await, - } + block!(self.inner.clone().connect(remote, timeout).await)? } - pub fn connect(&self, remote: SocketAddr) -> Result<(), Error> { - block!(self.connect_inner(remote).await)? + pub fn accept(&self, remote: Option<&mut [u8]>, non_blocking: bool) -> Result { + let timeout = self.options.read().recv_timeout; + let socket = if non_blocking { + self.inner.clone().accept_nonblocking(remote)? + } else { + block!(self.inner.clone().accept(remote, timeout).await)?? + }; + Ok(Self::from_inner(socket)) } - pub fn send_to( + pub fn send_message( &self, - data: &[u8], - remote: Option, + message: &MessageHeader, non_blocking: bool, ) -> Result { if non_blocking { - match &self.inner { - SocketInner::Packet(socket) => socket.clone().send_nonblocking(remote, data), - SocketInner::Connection(socket) => socket.clone().send_nonblocking(data), - } + todo!() } else { - block!(self.send_inner(data, remote).await)? + let timeout = self.options.read().send_timeout; + block!(self.inner.clone().send_message(message, timeout).await)? } } - pub fn receive_from( + pub fn receive_message( &self, - data: &mut [u8], + message: &mut MessageHeaderMut, non_blocking: bool, - ) -> Result<(usize, SocketAddr), Error> { + ) -> Result { if non_blocking { - match &self.inner { - SocketInner::Packet(socket) => socket.clone().receive_nonblocking(data), - SocketInner::Connection(socket) => socket.receive_nonblocking(data), - } + self.inner.clone().receive_nonblocking(message) } else { - block!(self.receive_inner(data).await)? + let timeout = self.options.read().recv_timeout; + block!(self.inner.clone().receive_message(message, timeout).await)? } } - pub fn bind(&self, local: SocketAddr) -> Result<(), Error> { - match &self.inner { - SocketInner::Packet(socket) => socket.clone().bind(local), - SocketInner::Connection(socket) => socket.clone().bind(local), - } + pub fn bind(&self, local: &[u8]) -> Result<(), Error> { + self.inner.clone().bind(local) } pub fn listen(&self) -> Result<(), Error> { - match &self.inner { - SocketInner::Packet(_) => Err(Error::InvalidOperation), - SocketInner::Connection(socket) => socket.clone().listen(), - } - } - - pub fn accept(&self, non_blocking: bool) -> Result<(FileRef, SocketAddr), Error> { - let SocketInner::Connection(socket) = &self.inner else { - return Err(Error::InvalidOperation); - }; - - let (remote, stream) = if non_blocking { - socket.accept_nonblocking()? - } else { - block!(socket.accept().await)?? - }; - let file = File::from_socket(SocketWrapper::from_connection(stream)); - Ok((file, remote)) + self.inner.clone().listen() } pub fn shutdown(&self, how: SocketShutdown) -> Result<(), Error> { - let SocketInner::Connection(socket) = &self.inner else { - return Err(Error::InvalidOperation); - }; - block!( - socket + self.inner + .clone() .shutdown( how.contains(SocketShutdown::READ), - how.contains(SocketShutdown::WRITE), + how.contains(SocketShutdown::WRITE) ) .await )? } - pub fn local_address(&self) -> Option { - match &self.inner { - SocketInner::Packet(socket) => socket.local_address(), - SocketInner::Connection(socket) => socket.local_address(), - } - } - - pub fn remote_address(&self) -> Option { - match &self.inner { - SocketInner::Packet(socket) => socket.remote_address(), - SocketInner::Connection(socket) => socket.remote_address(), - } - } - pub fn set_option(&self, option: u32, buffer: &[u8]) -> Result<(), Error> { if let Ok(option) = SocketOptionVariant::try_from(option) { let mut options = self.options.write(); @@ -288,10 +192,7 @@ impl SocketWrapper { } // Not a socket-level option, pass to the specific protocol level - match &self.inner { - SocketInner::Connection(socket) => socket.set_option(option, buffer), - SocketInner::Packet(socket) => socket.set_option(option, buffer), - } + self.inner.set_option(option, buffer) } pub fn get_option(&self, option: u32, buffer: &mut [u8]) -> Result { @@ -299,12 +200,14 @@ impl SocketWrapper { let options = self.options.read(); return match option { SocketOptionVariant::LocalAddress => { - let address = self.local_address().map(Into::into); - options::LocalAddress::store(&address, buffer) + todo!() + // let address = self.local_address().map(Into::into); + // options::LocalAddress::store(&address, buffer) } SocketOptionVariant::PeerAddress => { - let address = self.local_address().map(Into::into); - options::PeerAddress::store(&address, buffer) + todo!() + // let address = self.local_address().map(Into::into); + // options::PeerAddress::store(&address, buffer) } SocketOptionVariant::RecvTimeout => { options::RecvTimeout::store(&options.recv_timeout, buffer) @@ -319,37 +222,34 @@ impl SocketWrapper { } // Not a socket-level option, pass to the specific protocol level - match &self.inner { - SocketInner::Connection(socket) => socket.get_option(option, buffer), - SocketInner::Packet(socket) => socket.get_option(option, buffer), + self.inner.get_option(option, buffer) + } +} + +impl From> for SocketWrapper { + fn from(value: Arc) -> Self { + Self { + inner: value, + options: IrqSafeRwLock::new(InnerOptions::default()), } } } impl FileReadiness for SocketWrapper { fn poll_read(&self, cx: &mut Context<'_>) -> Poll> { - match &self.inner { - SocketInner::Connection(socket) => socket.poll_read(cx), - SocketInner::Packet(socket) => socket.poll_read(cx), - } + self.inner.poll_read(cx) } } impl fmt::Debug for SocketWrapper { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.inner { - SocketInner::Packet(socket) => socket.fmt(f), - SocketInner::Connection(socket) => socket.fmt(f), - } + fmt::Debug::fmt(self.inner.as_ref(), f) } } -impl Drop for SocketInner { +impl Drop for SocketWrapper { fn drop(&mut self) { - let res = match self { - Self::Packet(socket) => socket.clone().close(), - Self::Connection(socket) => socket.clone().close(), - }; + let res = self.inner.clone().close(); if let Err(error) = res { log::warn!("Socket close error: {error:?}"); } diff --git a/kernel/src/syscall/imp/sys_io.rs b/kernel/src/syscall/imp/sys_io.rs index cc9ffb5b..2a35ff1d 100644 --- a/kernel/src/syscall/imp/sys_io.rs +++ b/kernel/src/syscall/imp/sys_io.rs @@ -3,17 +3,16 @@ use core::{mem::MaybeUninit, time::Duration}; use abi::{ error::Error, io::{ - AccessMode, ChannelPublisherId, DirectoryEntry, FileAttr, FileMetadataUpdate, FileMode, - FileSync, MessageDestination, OpenOptions, PollControl, RawFd, ReceivedMessageMetadata, - RemoveFlags, Rename, SeekFrom, SentMessage, TerminalOptions, TerminalSize, TimerOptions, + AccessMode, DirectoryEntry, FileAttr, FileMetadataUpdate, FileMode, FileSync, OpenOptions, + PollControl, RawFd, RemoveFlags, Rename, SeekFrom, TerminalOptions, TerminalSize, + TimerOptions, }, process::{ProcessWait, WaitFlags}, }; -use alloc::boxed::Box; use libk::{ block, task::thread::Thread, - vfs::{File, MessagePayload, Read, Seek, Write}, + vfs::{File, Read, Seek, Write}, }; use libk_util::io::{ReadAt, WriteAt}; @@ -314,16 +313,16 @@ pub(crate) fn device_request( } // Misc I/O -pub(crate) fn open_channel(name: &str, subscribe: bool) -> Result { - let thread = Thread::current(); - let process = thread.process(); - - run_with_io(&process, |mut io| { - let file = File::new_message_channel(name, subscribe); - let fd = io.files.place_file(file, true)?; - Ok(fd) - }) -} +// pub(crate) fn open_channel(name: &str, subscribe: bool) -> Result { +// let thread = Thread::current(); +// let process = thread.process(); +// +// run_with_io(&process, |mut io| { +// let file = File::new_message_channel(name, subscribe); +// let fd = io.files.place_file(file, true)?; +// Ok(fd) +// }) +// } pub(crate) fn create_timer(options: TimerOptions) -> Result { let thread = Thread::current(); @@ -455,73 +454,73 @@ pub(crate) fn poll_channel_control( }) } -pub(crate) fn send_message( - fd: RawFd, - message: &SentMessage<'_>, - destination: MessageDestination, -) -> Result<(), Error> { - let thread = Thread::current(); - let process = thread.process(); +// pub(crate) fn send_message( +// fd: RawFd, +// message: &SentMessage<'_>, +// destination: MessageDestination, +// ) -> Result<(), Error> { +// let thread = Thread::current(); +// let process = thread.process(); +// +// run_with_io(&process, |io| { +// let file = io.files.file(fd)?; +// let channel = file.as_message_channel()?; +// +// match message { +// &SentMessage::File(fd) => { +// let sent_file = io.files.file(fd)?; +// +// channel.send_message(MessagePayload::File(sent_file.clone()), destination)?; +// } +// &SentMessage::Data(data) => { +// channel.send_message(MessagePayload::Data(Box::from(data)), destination)?; +// } +// } +// +// Ok(()) +// }) +// } - run_with_io(&process, |io| { - let file = io.files.file(fd)?; - let channel = file.as_message_channel()?; - - match message { - &SentMessage::File(fd) => { - let sent_file = io.files.file(fd)?; - - channel.send_message(MessagePayload::File(sent_file.clone()), destination)?; - } - &SentMessage::Data(data) => { - channel.send_message(MessagePayload::Data(Box::from(data)), destination)?; - } - } - - Ok(()) - }) -} - -pub(crate) fn receive_message( - fd: RawFd, - metadata: &mut MaybeUninit, - buf: &mut [u8], - from: &mut MaybeUninit, -) -> Result<(), Error> { - let thread = Thread::current(); - let process = thread.process(); - - run_with_io(&process, |mut io| { - let file = io.files.file(fd)?; - let channel = file.as_message_channel()?; - - let message = channel.receive_message()?; - - from.write(message.source); - - match &message.payload { - MessagePayload::Data(data) => { - // TODO allow truncated messages? - let len = data.len(); - if buf.len() < len { - return Err(Error::MissingData); - } - - metadata.write(ReceivedMessageMetadata::Data(len)); - buf[..len].copy_from_slice(data); - - Ok(()) - } - MessagePayload::File(file) => { - let fd = io.files.place_file(file.clone(), true)?; - - metadata.write(ReceivedMessageMetadata::File(fd)); - - Ok(()) - } - } - }) -} +// pub(crate) fn receive_message( +// fd: RawFd, +// metadata: &mut MaybeUninit, +// buf: &mut [u8], +// from: &mut MaybeUninit, +// ) -> Result<(), Error> { +// let thread = Thread::current(); +// let process = thread.process(); +// +// run_with_io(&process, |mut io| { +// let file = io.files.file(fd)?; +// let channel = file.as_message_channel()?; +// +// let message = channel.receive_message()?; +// +// from.write(message.source); +// +// match &message.payload { +// MessagePayload::Data(data) => { +// // TODO allow truncated messages? +// let len = data.len(); +// if buf.len() < len { +// return Err(Error::MissingData); +// } +// +// metadata.write(ReceivedMessageMetadata::Data(len)); +// buf[..len].copy_from_slice(data); +// +// Ok(()) +// } +// MessagePayload::File(file) => { +// let fd = io.files.place_file(file.clone(), true)?; +// +// metadata.write(ReceivedMessageMetadata::File(fd)); +// +// Ok(()) +// } +// } +// }) +// } pub(crate) fn filesystem_control( fd: Option, diff --git a/kernel/src/syscall/imp/sys_net.rs b/kernel/src/syscall/imp/sys_net.rs index 01f3dd9b..40415fdd 100644 --- a/kernel/src/syscall/imp/sys_net.rs +++ b/kernel/src/syscall/imp/sys_net.rs @@ -1,15 +1,15 @@ -use core::{mem::MaybeUninit, net::SocketAddr}; - use abi::{ error::Error, io::RawFd, - net::{SocketShutdown, SocketType}, + net::{MessageHeader, MessageHeaderMut, SocketShutdown, SocketType}, }; use libk::{ task::thread::Thread, vfs::{File, FileRef, SocketWrapper}, }; -use ygg_driver_net_core::socket::{RawSocket, TcpSocket, UdpSocket}; +use ygg_driver_net_core::socket::{ + LocalPacketSocket, NetConfigSocket, RawSocket, TcpSocket, UdpSocket, +}; use crate::syscall::run_with_io; @@ -26,9 +26,11 @@ pub(crate) fn create_socket(ty: SocketType) -> Result { run_with_io(&process, |mut io| { let socket = match ty { - SocketType::RawPacket => SocketWrapper::from_packet(RawSocket::new()), - SocketType::UdpPacket => SocketWrapper::from_packet(UdpSocket::new()), - SocketType::TcpStream => SocketWrapper::from_connection(TcpSocket::new()), + SocketType::RawPacket => SocketWrapper::from_inner(RawSocket::new()), + SocketType::TcpStream => SocketWrapper::from_inner(TcpSocket::new()), + SocketType::UdpPacket => SocketWrapper::from_inner(UdpSocket::new()), + SocketType::LocalPacket => SocketWrapper::from_inner(LocalPacketSocket::new()), + SocketType::NetConfig => SocketWrapper::from_inner(NetConfigSocket::new()), }; let file = File::from_socket(socket); let fd = io.files.place_file(file, true)?; @@ -37,22 +39,22 @@ pub(crate) fn create_socket(ty: SocketType) -> Result { }) } -pub(crate) fn bind(sock_fd: RawFd, local: &SocketAddr) -> Result<(), Error> { - let file = get_socket(sock_fd)?; - file.as_socket()?.bind((*local).into()) -} - pub(crate) fn listen(sock_fd: RawFd) -> Result<(), Error> { let file = get_socket(sock_fd)?; file.as_socket()?.listen() } -pub(crate) fn connect(sock_fd: RawFd, remote: &SocketAddr) -> Result<(), Error> { +pub(crate) fn bind(sock_fd: RawFd, local: &[u8]) -> Result<(), Error> { let file = get_socket(sock_fd)?; - file.as_socket()?.connect((*remote).into()) + file.as_socket()?.bind(local) } -pub(crate) fn accept(sock_fd: RawFd, remote: &mut MaybeUninit) -> Result { +pub(crate) fn connect(sock_fd: RawFd, remote: &[u8]) -> Result<(), Error> { + let file = get_socket(sock_fd)?; + file.as_socket()?.connect(remote) +} + +pub(crate) fn accept(sock_fd: RawFd, remote: Option<&mut [u8]>) -> Result { let thread = Thread::current(); let process = thread.process(); @@ -61,10 +63,10 @@ pub(crate) fn accept(sock_fd: RawFd, remote: &mut MaybeUninit) -> Re let non_blocking = listener.is_non_blocking(); let listener = listener.as_socket()?; - let (stream_file, stream_remote) = listener.accept(non_blocking)?; - let stream_fd = io.files.place_file(stream_file, true)?; - - remote.write(stream_remote.into()); + let stream_socket = listener.accept(remote, non_blocking)?; + let stream_fd = io + .files + .place_file(File::from_socket(stream_socket), true)?; Ok(stream_fd) }) @@ -78,24 +80,43 @@ pub(crate) fn shutdown(sock_fd: RawFd, how: SocketShutdown) -> Result<(), Error> pub(crate) fn send_to( sock_fd: RawFd, data: &[u8], - remote: &Option, + remote: Option<&[u8]>, // remote: &Option, ) -> Result { - let file = get_socket(sock_fd)?; - let non_blocking = file.is_non_blocking(); - file.as_socket()? - .send_to(data, remote.map(Into::into), non_blocking) + let header = MessageHeader { + destination: remote, + payload: data, + ancillary: &[], + }; + send_message(sock_fd, &header) } pub(crate) fn receive_from( sock_fd: RawFd, data: &mut [u8], - remote: &mut MaybeUninit, + remote: Option<&mut [u8]>, +) -> Result { + let mut header = MessageHeaderMut { + source: remote, + payload: data, + ancillary: None, + ancillary_len: 0, + }; + receive_message(sock_fd, &mut header) +} + +pub(crate) fn send_message(sock_fd: RawFd, message: &MessageHeader) -> Result { + let file = get_socket(sock_fd)?; + let non_blocking = file.is_non_blocking(); + file.as_socket()?.send_message(message, non_blocking) +} + +pub(crate) fn receive_message( + sock_fd: RawFd, + message: &mut MessageHeaderMut, ) -> Result { let file = get_socket(sock_fd)?; let non_blocking = file.is_non_blocking(); - let (len, remote_) = file.as_socket()?.receive_from(data, non_blocking)?; - remote.write(remote_.into()); - Ok(len) + file.as_socket()?.receive_message(message, non_blocking) } pub(crate) fn get_socket_option( @@ -111,126 +132,3 @@ pub(crate) fn set_socket_option(sock_fd: RawFd, option: u32, value: &[u8]) -> Re let file = get_socket(sock_fd)?; file.as_socket()?.set_option(option, value) } - -// pub(crate) fn get_socket_option(sock_fd: RawFd, option: &mut SocketOption) -> Result<(), Error> { -// file.as_socket()?.get_option(option) -// } -// -// pub(crate) fn set_socket_option(sock_fd: RawFd, option: &SocketOption) -> Result<(), Error> { -// file.as_socket()?.set_option(option) -// } - -// // Network -// pub(crate) fn connect_socket( -// connect: &mut SocketConnect, -// local_result: &mut MaybeUninit, -// ) -> Result { -// let thread = Thread::current(); -// let process = thread.process(); -// -// run_with_io(&process, |mut io| { -// let (local, fd) = match connect { -// SocketConnect::Tcp(remote, timeout) => { -// let remote = (*remote).into(); -// let (local, socket) = libk::block!(TcpSocket::connect(remote, *timeout).await)??; -// let file = File::from_socket(SocketWrapper::from_connection(socket)); -// let fd = io.files.place_file(file, true)?; -// (local.into(), fd) -// } -// SocketConnect::Udp(_socket, _remote) => { -// todo!("UDP socket connect") -// } -// }; -// local_result.write(local); -// Ok(fd) -// }) -// } -// -// pub(crate) fn bind_socket(listen: &SocketAddr, ty: SocketType) -> Result { -// let thread = Thread::current(); -// let process = thread.process(); -// -// run_with_io(&process, |mut io| { -// let listen = (*listen).into(); -// let socket = match ty { -// SocketType::RawPacket => SocketWrapper::from_packet(RawSocket::bind()?), -// SocketType::UdpPacket => SocketWrapper::from_packet(UdpSocket::bind(listen)?), -// SocketType::TcpStream => SocketWrapper::from_listener(TcpListener::bind(listen)?), -// }; -// let file = File::from_socket(socket); -// let fd = io.files.place_file(file, true)?; -// Ok(fd) -// }) -// } -// -// pub(crate) fn accept( -// socket_fd: RawFd, -// remote_result: &mut MaybeUninit, -// ) -> Result { -// let thread = Thread::current(); -// let process = thread.process(); -// -// run_with_io(&process, |mut io| { -// let file = io.files.file(socket_fd)?; -// let listener = file.as_socket()?; -// let (socket, remote) = listener.accept()?; -// remote_result.write(remote.into()); -// let fd = io.files.place_file(File::from_socket(socket), true)?; -// Ok(fd) -// }) -// } -// -// pub(crate) fn send_to( -// socket_fd: RawFd, -// buffer: &[u8], -// recepient: &Option, -// ) -> Result { -// let thread = Thread::current(); -// let process = thread.process(); -// -// run_with_io(&process, |io| { -// let file = io.files.file(socket_fd)?; -// let socket = file.as_socket()?; -// let remote = recepient.map(Into::into); -// socket.send_to(buffer, remote) -// }) -// } -// -// pub(crate) fn receive_from( -// socket_fd: RawFd, -// buffer: &mut [u8], -// remote_result: &mut MaybeUninit, -// ) -> Result { -// let thread = Thread::current(); -// let process = thread.process(); -// -// run_with_io(&process, |io| { -// let file = io.files.file(socket_fd)?; -// let socket = file.as_socket()?; -// let (len, remote) = socket.receive_from(buffer)?; -// remote_result.write(remote.into()); -// Ok(len) -// }) -// } -// -// pub(crate) fn set_socket_option(socket_fd: RawFd, option: &SocketOption) -> Result<(), Error> { -// let thread = Thread::current(); -// let process = thread.process(); -// -// run_with_io(&process, |io| { -// let file = io.files.file(socket_fd)?; -// let socket = file.as_socket()?; -// socket.set_option(option) -// }) -// } -// -// pub(crate) fn get_socket_option(socket_fd: RawFd, option: &mut SocketOption) -> Result<(), Error> { -// let thread = Thread::current(); -// let process = thread.process(); -// -// run_with_io(&process, |io| { -// let file = io.files.file(socket_fd)?; -// let socket = file.as_socket()?; -// socket.get_option(option) -// }) -// } diff --git a/kernel/src/syscall/imp/sys_process.rs b/kernel/src/syscall/imp/sys_process.rs index 38408808..f440c23b 100644 --- a/kernel/src/syscall/imp/sys_process.rs +++ b/kernel/src/syscall/imp/sys_process.rs @@ -12,10 +12,7 @@ use abi::{ use alloc::sync::Arc; use libk::{ block, - task::{ - binary::LoadOptions, debug::ThreadDebugger, process::Process, runtime, thread::Thread, - ThreadId, - }, + task::{binary::LoadOptions, process::Process, runtime, thread::Thread, ThreadId}, time::monotonic_time, vfs::IoContext, }; @@ -24,7 +21,7 @@ use libk_mm::{ table::{EntryLevelExt, MapAttributes}, }; -use crate::{arch::L3, proc, syscall::run_with_io, util::IteratorExt}; +use crate::{arch::L3, proc, syscall::run_with_io}; // Memory management pub(crate) fn map_memory( @@ -94,19 +91,19 @@ pub(crate) fn spawn_process(options: &SpawnOptions<'_>) -> Result(|entry| { - if let &SpawnOption::AttachDebug(fd) = entry { - let channel = io.files.file(fd)?; - let channel = channel.as_message_channel()?.clone(); + // let attach_debugger = options + // .optional + // .iter() + // .try_find_map::<_, Error, _>(|entry| { + // if let &SpawnOption::AttachDebug(fd) = entry { + // let channel = io.files.file(fd)?; + // let channel = channel.as_message_channel()?.clone(); - Ok(Some(channel)) - } else { - Ok(None) - } - })?; + // Ok(Some(channel)) + // } else { + // Ok(None) + // } + // })?; // Setup a new process from the file let load_options = LoadOptions { @@ -115,7 +112,8 @@ pub(crate) fn spawn_process(options: &SpawnOptions<'_>) -> Result) -> Result(e: E) -> usize { (-(e.into_syscall_register() as isize)) as usize @@ -29,6 +29,58 @@ impl SyscallRegister for Result { } } +impl SyscallFatRegister for Option<&[T]> { + fn as_syscall_meta(&self) -> usize { + match self { + Some(value) => value.as_ptr().addr(), + None => 0, + } + } + + fn as_syscall_data(&self) -> usize { + match self { + Some(value) => value.len(), + None => 0, + } + } + + fn from_syscall_registers(meta: usize, data: usize) -> Self { + if meta != 0 { + Some(unsafe { + core::slice::from_raw_parts(core::ptr::with_exposed_provenance(meta), data) + }) + } else { + None + } + } +} + +impl SyscallFatRegister for Option<&mut [T]> { + fn as_syscall_meta(&self) -> usize { + match self { + Some(value) => value.as_ptr().addr(), + None => 0, + } + } + + fn as_syscall_data(&self) -> usize { + match self { + Some(value) => value.len(), + None => 0, + } + } + + fn from_syscall_registers(meta: usize, data: usize) -> Self { + if meta != 0 { + Some(unsafe { + core::slice::from_raw_parts_mut(core::ptr::with_exposed_provenance_mut(meta), data) + }) + } else { + None + } + } +} + impl SyscallRegister for Option { fn into_syscall_register(self) -> usize { match self { diff --git a/lib/abi-serde/Cargo.toml b/lib/abi-serde/Cargo.toml index 867a95a3..4ef6a9db 100644 --- a/lib/abi-serde/Cargo.toml +++ b/lib/abi-serde/Cargo.toml @@ -6,11 +6,13 @@ edition = "2021" [dependencies] compiler_builtins = { version = "0.1", optional = true } core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } +rustc_std_alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" } [features] default = [] rustc-dep-of-std = [ "core", + "rustc_std_alloc", "compiler_builtins/rustc-dep-of-std", ] diff --git a/lib/abi-serde/src/impls/alloc.rs b/lib/abi-serde/src/impls/alloc.rs new file mode 100644 index 00000000..67cf06b7 --- /dev/null +++ b/lib/abi-serde/src/impls/alloc.rs @@ -0,0 +1,35 @@ +use alloc::{boxed::Box, vec::Vec}; + +use crate::{des::Deserializer, ser::Serializer, Deserialize, Serialize}; + +impl Serialize for Vec { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { + serializer.write_usize(self.len())?; + for item in self.iter() { + item.serialize(serializer)?; + } + Ok(()) + } +} +impl<'de, T: Deserialize<'de>> Deserialize<'de> for Vec { + fn deserialize>(deserializer: &mut D) -> Result { + let len = deserializer.read_usize()?; + let mut result = Vec::new(); + for _ in 0..len { + let item = T::deserialize(deserializer)?; + result.push(item); + } + Ok(result) + } +} + +impl Serialize for Box { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { + serializer.write_str(self) + } +} +impl<'de> Deserialize<'de> for Box { + fn deserialize>(deserializer: &mut D) -> Result { + deserializer.read_str().map(Into::into) + } +} diff --git a/lib/abi-serde/src/impls/base.rs b/lib/abi-serde/src/impls/base.rs index 484601b9..b5bc4507 100644 --- a/lib/abi-serde/src/impls/base.rs +++ b/lib/abi-serde/src/impls/base.rs @@ -51,6 +51,18 @@ impl<'de> Deserialize<'de> for () { } } +impl Serialize for &[u8] { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { + serializer.write_bytes(self) + } +} + +impl<'de> Deserialize<'de> for &'de [u8] { + fn deserialize>(deserializer: &mut D) -> Result { + deserializer.read_bytes() + } +} + impl Serialize for &str { fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { serializer.write_str(self) @@ -87,9 +99,9 @@ where impl Serialize for Option { fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { match self { - None => serializer.write_enum_variant(0), + None => serializer.write_u8(0), Some(value) => { - serializer.write_enum_variant(1)?; + serializer.write_u8(1)?; value.serialize(serializer) } } @@ -98,10 +110,10 @@ impl Serialize for Option { impl<'de, T: Deserialize<'de>> Deserialize<'de> for Option { fn deserialize>(deserializer: &mut D) -> Result { - let variant = deserializer.read_enum_variant()?; + let variant = deserializer.read_u8()?; match variant { - 0 => T::deserialize(deserializer).map(Some), - 1 => Ok(None), + 0 => Ok(None), + 1 => T::deserialize(deserializer).map(Some), _ => Err(D::Error::INVALID_ENUM_VARIANT), } } @@ -111,11 +123,11 @@ impl Serialize for Result { fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { match self { Ok(value) => { - serializer.write_enum_variant(0)?; + serializer.write_u8(0)?; value.serialize(serializer) } Err(error) => { - serializer.write_enum_variant(1)?; + serializer.write_u8(1)?; error.serialize(serializer) } } @@ -124,7 +136,7 @@ impl Serialize for Result { impl<'de, T: Deserialize<'de>, E: Deserialize<'de>> Deserialize<'de> for Result { fn deserialize>(deserializer: &mut D) -> Result { - let variant = deserializer.read_enum_variant()?; + let variant = deserializer.read_u8()?; match variant { 0 => T::deserialize(deserializer).map(Ok), 1 => E::deserialize(deserializer).map(Err), @@ -132,3 +144,25 @@ impl<'de, T: Deserialize<'de>, E: Deserialize<'de>> Deserialize<'de> for Result< } } } + +#[cfg(test)] +mod test { + use crate::test::test_serialize_reversibility; + + #[test] + fn test_option_sanity() { + let mut buffer = [0; 256]; + test_serialize_reversibility(&mut buffer, &Some(1234u32)); + test_serialize_reversibility(&mut buffer, &Some("abcdef")); + test_serialize_reversibility(&mut buffer, &Option::::None); + test_serialize_reversibility(&mut buffer, &Option::::None); + test_serialize_reversibility(&mut buffer, &Option::<&str>::None); + } + + #[test] + fn test_result_sanity() { + let mut buffer = [0; 256]; + test_serialize_reversibility(&mut buffer, &Result::<_, u32>::Ok(1234u32)); + test_serialize_reversibility(&mut buffer, &Result::::Err("abcdef")); + } +} diff --git a/lib/abi-serde/src/impls/mod.rs b/lib/abi-serde/src/impls/mod.rs index d7003580..586a5d08 100644 --- a/lib/abi-serde/src/impls/mod.rs +++ b/lib/abi-serde/src/impls/mod.rs @@ -1,3 +1,4 @@ +mod alloc; mod base; mod net; mod time; diff --git a/lib/abi-serde/src/lib.rs b/lib/abi-serde/src/lib.rs index f5287551..9add94bd 100644 --- a/lib/abi-serde/src/lib.rs +++ b/lib/abi-serde/src/lib.rs @@ -1,11 +1,19 @@ #![feature(decl_macro, ip_from)] #![no_std] +#[cfg(not(feature = "rustc-dep-of-std"))] +extern crate alloc; +#[cfg(feature = "rustc-dep-of-std")] +extern crate rustc_std_alloc as alloc; + pub mod des; pub mod ser; mod impls; +#[cfg(test)] +pub mod test; + pub mod wire; pub use des::Deserialize; @@ -61,7 +69,7 @@ macro_rules! impl_struct_serde { } } - impl<'de> $crate::Deserialize<'de> for $name $(<$lifetime:lifetime>)? { + impl<'de> $crate::Deserialize<'de> for $name $(<$lifetime>)? { fn deserialize>(deserializer: &mut D) -> Result { $( let $field = $crate::Deserialize::deserialize(deserializer)?; diff --git a/lib/abi-serde/src/test.rs b/lib/abi-serde/src/test.rs new file mode 100644 index 00000000..d9deec65 --- /dev/null +++ b/lib/abi-serde/src/test.rs @@ -0,0 +1,46 @@ +use core::fmt::Debug; + +use crate::{wire, Deserialize, Serialize}; + +#[track_caller] +pub fn test_serialize_reversibility<'de, T: PartialEq + Serialize + Deserialize<'de> + Debug>( + buffer: &'de mut [u8], + value: &T, +) { + extern crate std; + + let len = wire::to_slice(value, buffer).expect("Serialize failed"); + let result: T = wire::from_slice(&buffer[..len]).expect("Deserialize failed"); + if result != *value { + std::eprintln!("Serialized value is not equal to deserialized one:"); + std::eprintln!("* Original: {value:?}"); + std::eprintln!("* Deserialized: {result:?}"); + + std::eprintln!("Message of {len} bytes:"); + for i in (0..len).step_by(16) { + std::eprint!("{i:02x}: "); + for j in 0..16 { + if j != 0 { + std::eprint!(" "); + } + + if i + j < len { + std::eprint!("{:02X}", buffer[i + j]); + } else { + std::eprint!(" "); + } + } + std::eprint!(" | "); + for j in 0..16 { + if i + j < len { + let c = buffer[i + j]; + let c = if c.is_ascii_graphic() { c as char } else { '.' }; + std::eprint!("{}", c); + } + } + std::eprintln!(); + } + + panic!("Equality test failed") + } +} diff --git a/lib/abi/def/yggdrasil.abi b/lib/abi/def/yggdrasil.abi index 82015701..ad2194c4 100644 --- a/lib/abi/def/yggdrasil.abi +++ b/lib/abi/def/yggdrasil.abi @@ -17,10 +17,6 @@ extern { type ExitCode = yggdrasil_abi::process::ExitCode; type ProcessWait = yggdrasil_abi::process::ProcessWait; - type SocketAddr = core::net::SocketAddr; - type SocketOption = yggdrasil_abi::net::SocketOption; - type SocketConnect = yggdrasil_abi::net::SocketConnect; - type SentMessage = yggdrasil_abi::io::SentMessage; type ReceivedMessageMetadata = yggdrasil_abi::io::ReceivedMessageMetadata; type DeviceRequest = yggdrasil_abi::io::DeviceRequest; @@ -28,6 +24,9 @@ extern { type FilesystemControl = yggdrasil_abi::io::FilesystemControl; type Rename = yggdrasil_abi::io::Rename; + type MessageHeader = yggdrasil_abi::net::MessageHeader; + type MessageHeaderMut = yggdrasil_abi::net::MessageHeaderMut; + type DebugOperation = yggdrasil_abi::debug::DebugOperation; type DebugFrame = yggdrasil_abi::debug::DebugFrame; @@ -46,6 +45,10 @@ enum SocketType(u32) { TcpStream = 1, /// UDP packet socket UdpPacket = 2, + /// Local packet socket + LocalPacket = 200, + /// Network configuration interface + NetConfig = 1000, } bitfield SocketShutdown(u32) { @@ -141,7 +144,6 @@ syscall get_metadata(at: Option, path: &str, metadata: &mut MaybeUninit Result; // Misc I/O -syscall open_channel(name: &str, subscribe: bool) -> Result; syscall create_timer(options: TimerOptions) -> Result; syscall create_pid(target: &ProcessWait, flags: WaitFlags) -> Result; syscall create_pty(opts: &TerminalOptions, size: &TerminalSize, fds: &mut [MaybeUninit; 2]) -> Result<()>; @@ -157,27 +159,22 @@ syscall poll_channel_wait( ) -> Result<()>; syscall poll_channel_control(poll_fd: RawFd, ctl: PollControl, fd: RawFd) -> Result<()>; -syscall send_message(fd: RawFd, msg: &SentMessage<'_>, dst: MessageDestination) -> Result<()>; -syscall receive_message( - fd: RawFd, - meta: &mut MaybeUninit, - data: &mut [u8], - from: &mut MaybeUninit -) -> Result<()>; - // Network syscall create_socket(ty: SocketType) -> Result; -syscall bind(sock_fd: RawFd, local: &SocketAddr) -> Result<()>; +syscall bind(sock_fd: RawFd, local: &[u8]) -> Result<()>; syscall listen(sock_fd: RawFd) -> Result<()>; -syscall connect(sock_fd: RawFd, remote: &SocketAddr) -> Result<()>; -syscall accept(sock_fd: RawFd, remote: &mut MaybeUninit) -> Result; +syscall connect(sock_fd: RawFd, remote: &[u8]) -> Result<()>; +syscall accept(sock_fd: RawFd, remote: Option<&mut [u8]>) -> Result; syscall shutdown(sock_fd: RawFd, how: SocketShutdown) -> Result<()>; -syscall send_to(sock_fd: RawFd, data: &[u8], remote: &Option) -> Result; -syscall receive_from(sock_fd: RawFd, data: &mut [u8], remote: &mut MaybeUninit) -> Result; +syscall send_to(sock_fd: RawFd, data: &[u8], address: Option<&[u8]>) -> Result; +syscall receive_from(sock_fd: RawFd, data: &mut [u8], address: Option<&mut [u8]>) -> Result; syscall get_socket_option(sock_fd: RawFd, option: u32, value: &mut [u8]) -> Result; syscall set_socket_option(sock_fd: RawFd, option: u32, value: &[u8]) -> Result<()>; +syscall send_message(sock_fd: RawFd, message: &MessageHeader<'_>) -> Result; +syscall receive_message(sock_fd: RawFd, message: &mut MessageHeaderMut<'_>) -> Result; + // C compat syscall fork() -> Result; syscall execve(options: &ExecveOptions<'_>) -> Result<()>; diff --git a/lib/abi/src/io/mod.rs b/lib/abi/src/io/mod.rs index e6d73a52..0f5537ad 100644 --- a/lib/abi/src/io/mod.rs +++ b/lib/abi/src/io/mod.rs @@ -96,3 +96,5 @@ impl From for RawFd { Self(value) } } + +abi_serde::impl_newtype_serde!(RawFd); diff --git a/lib/abi/src/lib.rs b/lib/abi/src/lib.rs index 3ef8850a..345defbd 100644 --- a/lib/abi/src/lib.rs +++ b/lib/abi/src/lib.rs @@ -20,6 +20,8 @@ extern crate rustc_std_alloc as alloc; pub(crate) mod macros; pub mod util; +pub use abi_serde; + mod generated { #![allow(missing_docs)] diff --git a/lib/abi/src/net/dns.rs b/lib/abi/src/net/dns.rs index c3f1be7e..f778b644 100644 --- a/lib/abi/src/net/dns.rs +++ b/lib/abi/src/net/dns.rs @@ -1,11 +1,15 @@ //! DNS-related protocol structures -use core::{fmt, mem::size_of}; +use core::{ + fmt, + mem::size_of, + net::{IpAddr, Ipv4Addr}, +}; -use crate::{net::Ipv4Addr, util}; +use crate::util; use alloc::{string::String, vec, vec::Vec}; -use super::IpAddr; +// use super::IpAddr; // TODO rewrite using NetValue diff --git a/lib/abi/src/net/mod.rs b/lib/abi/src/net/mod.rs index 0de948b3..6c5b0fa0 100644 --- a/lib/abi/src/net/mod.rs +++ b/lib/abi/src/net/mod.rs @@ -10,14 +10,54 @@ pub mod protocols; pub mod types; pub use crate::generated::{SocketShutdown, SocketType}; +use crate::io::RawFd; pub use types::{ - ip_addr::{IpAddr, Ipv4Addr, Ipv6Addr}, - socket_addr::{SocketAddr, SocketAddrV4, SocketAddrV6}, subnet_addr::{SubnetAddr, SubnetV4Addr}, MacAddress, }; +/// Message structure describing how data + metadata should be sent to the other side of some +/// socket +#[repr(C)] +pub struct MessageHeader<'a> { + /// Destination address, depends on the socket type + pub destination: Option<&'a [u8]>, + /// Raw payload data + pub payload: &'a [u8], + /// Ancillary data, depends on the socket type + pub ancillary: &'a [u8], +} + +/// Message structure describing how data + metadata should be received from a socket +#[repr(C)] +pub struct MessageHeaderMut<'a> { + /// Optional: storage for the source address, depends on the socket type + pub source: Option<&'a mut [u8]>, + /// Buffer to store the payload in + pub payload: &'a mut [u8], + /// Optional: storage for the ancillary data, depends on the socket type + pub ancillary: Option<&'a mut [u8]>, + /// Optional: if ancillary data is received, the length will be stored in this field + pub ancillary_len: usize, +} + +/// Ancillary message which can be sent over a socket +#[derive(Debug, Clone)] +pub enum AncillaryMessage { + /// Send a file descriptor to the recepient. (Local sockets only) + File(RawFd), +} + +abi_serde::impl_struct_serde!(MessageHeader<'de>: [ + destination, + payload, + ancillary +]); +abi_serde::impl_enum_serde!(AncillaryMessage: [ + File => 1 +]); + /// Describes a method to query an interface #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[derive(Clone, Debug, PartialEq)] diff --git a/lib/abi/src/net/netconfig.rs b/lib/abi/src/net/netconfig.rs index f8f66e2f..afe9a1e6 100644 --- a/lib/abi/src/net/netconfig.rs +++ b/lib/abi/src/net/netconfig.rs @@ -1,12 +1,32 @@ //! Network configuration service messages -use crate::alloc::boxed::Box; +use core::net::IpAddr; -use super::{IpAddr, MacAddress, SubnetAddr}; +use abi_serde::{ + des::{DeserializeError, Deserializer}, + ser::Serializer, + Deserialize, Serialize, +}; +use alloc::boxed::Box; + +use super::{MacAddress, SocketInterfaceQuery, SubnetAddr}; + +/// Describes the binding between interfaces and their IDs +#[derive(Clone, Debug, PartialEq)] +pub struct InterfaceBinding { + /// Name of the interface + pub name: Box, + /// Interface ID + pub id: u32, +} +abi_serde::impl_struct_serde!(InterfaceBinding: [ + name, + id +]); /// Describes a single route -#[derive(Clone, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, PartialEq)] +// #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct RouteInfo { /// Interface textual name (unique) pub interface_name: Box, @@ -17,10 +37,15 @@ pub struct RouteInfo { /// Gateway this route should be reached through pub gateway: Option, } +abi_serde::impl_struct_serde!(RouteInfo: [ + interface_name, + interface_id, + subnet, + gateway +]); /// Describes routing information about some address -#[derive(Clone, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, PartialEq)] pub struct RoutingInfo { /// Interface textual name (unique) pub interface_name: Box, @@ -35,10 +60,17 @@ pub struct RoutingInfo { /// Interface MAC address pub source_mac: MacAddress, } +abi_serde::impl_struct_serde!(RoutingInfo: [ + interface_name, + interface_id, + gateway, + destination, + source, + source_mac +]); /// Describes a single interface -#[derive(Clone, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, PartialEq)] pub struct InterfaceInfo { /// Interface textual name (unique) pub interface_name: Box, @@ -49,78 +81,121 @@ pub struct InterfaceInfo { /// Interface hardware address pub mac: MacAddress, } +abi_serde::impl_struct_serde!(InterfaceInfo: [ + interface_name, + interface_id, + address, + mac +]); -/// Describes a query to some interface either by its name or ID -#[derive(Clone, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum InterfaceQuery { - /// Query by ID number - ById(u32), - /// Query by name - ByName(Box), +/// Describes a request to add a route to an interface +#[derive(Clone, Debug, PartialEq)] +pub struct AddRouteRequest<'a> { + /// Interface to which the action applies + pub interface: SocketInterfaceQuery<'a>, + /// Optional gateway to reach the route through + pub gateway: Option, + /// Subnetwork of the route + pub subnet: SubnetAddr, } +abi_serde::impl_struct_serde!(AddRouteRequest<'de>: [ + interface, + gateway, + subnet +]); + +/// Describes a request to assign a network address to an interface +#[derive(Clone, Debug, PartialEq)] +pub struct SetNetworkAddressRequest<'a> { + /// Interface to which the action applies + pub interface: SocketInterfaceQuery<'a>, + /// Address to assign + pub address: IpAddr, +} +abi_serde::impl_struct_serde!(SetNetworkAddressRequest<'de>: [ + interface, + address +]); + +/// Describes a request to perform an ARP query +#[derive(Clone, Debug, PartialEq)] +pub struct ArpQueryRequest<'a> { + /// Interface to which the action applies + pub interface: SocketInterfaceQuery<'a>, + /// Address to query + pub address: IpAddr, + /// Whether to actually send any requests, or just lookup the cached result + pub cache_only: bool, +} +abi_serde::impl_struct_serde!(ArpQueryRequest<'de>: [ + interface, + address, + cache_only +]); /// kernel-netconf interface request -#[derive(Clone, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum NetConfigRequest { +#[derive(Clone, Debug, PartialEq)] +pub enum NetConfigRequest<'a> { /// List all routes - ListRoutes, + ListRoutes(()), /// List all interfaces - ListInterfaces, + ListInterfaces(()), /// Describe routes related to a single interface - DescribeRoutes(InterfaceQuery), + DescribeRoutes(SocketInterfaceQuery<'a>), /// Describe a single interface - DescribeInterface(InterfaceQuery), + DescribeInterface(SocketInterfaceQuery<'a>), /// Add a route - AddRoute { - /// Interface to which the action applies - interface: InterfaceQuery, - /// Optional gateway to reach the route through - gateway: Option, - /// Subnetwork of the route - subnet: SubnetAddr, - }, + AddRoute(AddRouteRequest<'a>), /// Set interface's IP address - SetNetworkAddress { - /// Interface to which the action applies - interface: InterfaceQuery, - /// Address to set - address: IpAddr, - }, + SetNetworkAddress(SetNetworkAddressRequest<'a>), /// Clear interface's IP address - ClearNetworkAddress(InterfaceQuery), + ClearNetworkAddress(SocketInterfaceQuery<'a>), /// Query a route and return routing information QueryRoute(IpAddr), /// Query the MAC address of the specified IP - QueryArp(u32, IpAddr, bool), + ArpQuery(ArpQueryRequest<'a>), } +abi_serde::impl_enum_serde!(NetConfigRequest<'de>: [ + ListRoutes => 1, + ListInterfaces => 2, + DescribeRoutes => 3, + DescribeInterface => 4, + AddRoute => 5, + SetNetworkAddress => 6, + ClearNetworkAddress => 7, + QueryRoute => 8, + ArpQuery => 9, +]); /// Wrapper to provide error status in replies -#[derive(Clone, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum NetConfigResult { +#[derive(Clone, Debug, PartialEq)] +pub enum NetConfigResult<'a, T> { /// Success Ok(T), /// Error - Err(Box), + Err(&'a str), } -impl NetConfigResult { - /// Constructs an error value - pub fn err>>(message: S) -> Self { - Self::Err(message.into()) +impl Serialize for NetConfigResult<'_, T> { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> { + match self { + Self::Ok(value) => { + serializer.write_enum_variant(0)?; + value.serialize(serializer) + } + Self::Err(error) => { + serializer.write_enum_variant(1)?; + error.serialize(serializer) + } + } } } - -impl From<&str> for InterfaceQuery { - fn from(value: &str) -> Self { - Self::ByName(Box::from(value)) - } -} - -impl From for InterfaceQuery { - fn from(value: u32) -> Self { - Self::ById(value) +impl<'de, T: Deserialize<'de>> Deserialize<'de> for NetConfigResult<'de, T> { + fn deserialize>(deserializer: &mut D) -> Result { + match deserializer.read_enum_variant()? { + 0 => T::deserialize(deserializer).map(Self::Ok), + 1 => <&str>::deserialize(deserializer).map(Self::Err), + _ => Err(D::Error::INVALID_ENUM_VARIANT), + } } } diff --git a/lib/abi/src/net/types/mod.rs b/lib/abi/src/net/types/mod.rs index 38d9a62f..6eb5c7f3 100644 --- a/lib/abi/src/net/types/mod.rs +++ b/lib/abi/src/net/types/mod.rs @@ -2,9 +2,9 @@ use core::fmt; -pub mod ip_addr; +// pub mod ip_addr; pub mod net_value; -pub mod socket_addr; +// pub mod socket_addr; pub mod subnet_addr; pub use net_value::{NetValue, NetValueImpl}; @@ -12,7 +12,7 @@ pub use net_value::{NetValue, NetValueImpl}; /// Describes a hardware MAC address #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] #[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +// #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[repr(transparent)] pub struct MacAddress([u8; 6]); @@ -21,6 +21,11 @@ impl MacAddress { pub const BROADCAST: Self = Self([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]); /// An unspecified MAC address pub const UNSPECIFIED: Self = Self([0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); + + /// Returns the bytes comprising this MAC address + pub const fn octets(self) -> [u8; 6] { + self.0 + } } impl From<[u8; 6]> for MacAddress { @@ -49,3 +54,16 @@ impl fmt::Display for MacAddress { } abi_serde::impl_newtype_serde!(MacAddress); + +/// Local socket address +#[derive(Clone, Debug, PartialEq)] +pub enum LocalSocketAddress<'a> { + /// Describes a named socket bound to a specific path + Path(&'a str), + /// Describes an anonymous socket + Anonymous(u64), +} +abi_serde::impl_enum_serde!(LocalSocketAddress<'de>: [ + Path => 1, + Anonymous => 2, +]); diff --git a/lib/abi/src/net/types/subnet_addr.rs b/lib/abi/src/net/types/subnet_addr.rs index 0c9bb95f..e3b06ee2 100644 --- a/lib/abi/src/net/types/subnet_addr.rs +++ b/lib/abi/src/net/types/subnet_addr.rs @@ -1,15 +1,14 @@ //! Subnetwork address types -use core::{fmt, str::FromStr}; - -use crate::{ - error::Error, +use core::{ + fmt, net::{IpAddr, Ipv4Addr}, + str::FromStr, }; +use crate::error::Error; + /// Describes an IPv4 subnetwork, e.g. 11.0.0.0/24 #[derive(Clone, Copy, PartialEq, Eq, Debug)] -#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[repr(C)] pub struct SubnetV4Addr { /// "Root" of the subnetwork, e.g. the "11.0.0.0" part in "11.0.0.0/24" @@ -18,14 +17,21 @@ pub struct SubnetV4Addr { pub mask_bits: u32, mask: u32, } +abi_serde::impl_struct_serde!(SubnetV4Addr: [ + root, + mask_bits, + mask +]); /// Describes an IPv4/IPv6 subnetwork #[derive(Clone, Copy, PartialEq, Eq, Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum SubnetAddr { /// IPv4 subnetwork V4(SubnetV4Addr), } +abi_serde::impl_enum_serde!(SubnetAddr: [ + V4 => 4 +]); // SubnetV4 diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 49e30199..3215dc86 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -21,7 +21,7 @@ extern crate compiler_builtins; #[allow(unused_extern_crates)] extern crate alloc; -extern crate yggdrasil_abi as abi; +pub extern crate yggdrasil_abi as abi; pub use abi::error::Error; pub use abi::path; diff --git a/lib/runtime/src/net/socket.rs b/lib/runtime/src/net/socket.rs index ee8b84c7..1d6fe184 100644 --- a/lib/runtime/src/net/socket.rs +++ b/lib/runtime/src/net/socket.rs @@ -4,9 +4,10 @@ use core::{net::SocketAddr, time::Duration}; use abi::{ error::Error, io::RawFd, - net::{options, SocketInterfaceQuery, SocketType}, + net::{options, MessageHeader, MessageHeaderMut, SocketInterfaceQuery, SocketType}, option::{OptionSizeHint, OptionValue}, }; +use abi_serde::wire; /// Short-hand macro for [get_socket_option]. /// @@ -61,24 +62,31 @@ pub fn peer_address(fd: RawFd) -> Result { get_socket_option::(fd, &mut buffer)?.ok_or(Error::NotConnected) } -fn bind_inner(fd: RawFd, local: &SocketAddr, listen: bool) -> Result<(), Error> { - unsafe { crate::sys::bind(fd, local) }?; +fn bind_ip(fd: RawFd, local: &SocketAddr, listen: bool) -> Result<(), Error> { + let mut address = [0; 32]; + let address_len = wire::to_slice(local, &mut address)?; + unsafe { crate::sys::bind(fd, &address[..address_len]) }?; if listen { unsafe { crate::sys::listen(fd) }?; } Ok(()) } -fn connect_inner(fd: RawFd, remote: &SocketAddr, timeout: Option) -> Result<(), Error> { +fn connect_ip(fd: RawFd, remote: &SocketAddr, timeout: Option) -> Result<(), Error> { + let mut address = [0; 32]; + let address_len = wire::to_slice(remote, &mut address)?; set_socket_option::(fd, &timeout)?; - unsafe { crate::sys::connect(fd, remote) }?; - Ok(()) + unsafe { crate::sys::connect(fd, &address[..address_len]) } } /// Creates a new socket and binds it to a local address -pub fn create_and_bind(ty: SocketType, local: &SocketAddr, listen: bool) -> Result { +pub fn create_and_bind_ip( + ty: SocketType, + local: &SocketAddr, + listen: bool, +) -> Result { let fd = unsafe { crate::sys::create_socket(ty) }?; - match bind_inner(fd, local, listen) { + match bind_ip(fd, local, listen) { Ok(()) => Ok(fd), Err(error) => { unsafe { crate::sys::close(fd) }.ok(); @@ -89,7 +97,7 @@ pub fn create_and_bind(ty: SocketType, local: &SocketAddr, listen: bool) -> Resu /// Binds a TCP listener socket to some local address pub fn bind_tcp(local: &SocketAddr) -> Result { - create_and_bind(SocketType::TcpStream, local, true) + create_and_bind_ip(SocketType::TcpStream, local, true) } /// Binds a raw socket to some network interface @@ -107,13 +115,13 @@ pub fn bind_raw(iface: SocketInterfaceQuery<'_>) -> Result { /// Binds an UDP socket to some local address pub fn bind_udp(local: &SocketAddr) -> Result { - create_and_bind(SocketType::UdpPacket, local, false) + create_and_bind_ip(SocketType::UdpPacket, local, false) } /// Connect to a TCP listener pub fn connect_tcp(remote: &SocketAddr, timeout: Option) -> Result { let fd = unsafe { crate::sys::create_socket(SocketType::TcpStream) }?; - match connect_inner(fd, remote, timeout) { + match connect_ip(fd, remote, timeout) { Ok(()) => Ok(fd), Err(error) => { unsafe { crate::sys::close(fd) }.ok(); @@ -124,5 +132,70 @@ pub fn connect_tcp(remote: &SocketAddr, timeout: Option) -> Result Result<(), Error> { - connect_inner(socket_fd, remote, None) + connect_ip(socket_fd, remote, None) +} + +/// Accept an IP connection +#[inline] +pub fn accept_ip(socket_fd: RawFd) -> Result<(RawFd, SocketAddr), Error> { + let mut source = [0; 32]; + let fd = unsafe { crate::sys::accept(socket_fd, Some(&mut source)) }?; + match wire::from_slice(&source) { + Ok(address) => Ok((fd, address)), + Err(error) => { + unsafe { crate::sys::close(fd) }.ok(); + Err(error.into()) + } + } +} + +/// Receive from an IP socket (TCP/UDP) +#[inline] +pub fn receive_from_ip(socket_fd: RawFd, buffer: &mut [u8]) -> Result<(usize, SocketAddr), Error> { + let mut source = [0; 32]; + let mut msg_header = MessageHeaderMut { + source: Some(&mut source), + ancillary: None, + ancillary_len: 0, + payload: buffer, + }; + let len = unsafe { crate::sys::receive_message(socket_fd, &mut msg_header) }?; + let source = wire::from_slice(&source)?; + Ok((len, source)) +} + +/// Receive data from a socket +#[inline] +pub fn receive(socket_fd: RawFd, buffer: &mut [u8]) -> Result { + let mut msg_header = MessageHeaderMut { + source: None, + ancillary: None, + ancillary_len: 0, + payload: buffer, + }; + unsafe { crate::sys::receive_message(socket_fd, &mut msg_header) } +} + +/// Send data to an IP address +#[inline] +pub fn send_to_ip(socket_fd: RawFd, data: &[u8], destination: &SocketAddr) -> Result { + let mut target = [0; 32]; + let address_len = wire::to_slice(destination, &mut target)?; + let msg_header = MessageHeader { + destination: Some(&target[..address_len]), + ancillary: &[], + payload: data, + }; + unsafe { crate::sys::send_message(socket_fd, &msg_header) } +} + +/// Send data over a socket +#[inline] +pub fn send(socket_fd: RawFd, data: &[u8]) -> Result { + let msg_header = MessageHeader { + destination: None, + ancillary: &[], + payload: data, + }; + unsafe { crate::sys::send_message(socket_fd, &msg_header) } } diff --git a/lib/runtime/src/sys/mod.rs b/lib/runtime/src/sys/mod.rs index c303280c..d5ff883a 100644 --- a/lib/runtime/src/sys/mod.rs +++ b/lib/runtime/src/sys/mod.rs @@ -16,9 +16,9 @@ mod generated { use abi::{ error::Error, io::{ - AccessMode, ChannelPublisherId, DirectoryEntry, FileAttr, FileMode, FileSync, - MountOptions, OpenOptions, PollControl, RawFd, RemoveFlags, TerminalOptions, - TerminalSize, TimerOptions, UnmountOptions, + AccessMode, DirectoryEntry, FileAttr, FileMode, FileSync, MountOptions, OpenOptions, + PollControl, RawFd, RemoveFlags, TerminalOptions, TerminalSize, TimerOptions, + UnmountOptions, }, mem::{MappingFlags, MappingSource}, net::{SocketShutdown, SocketType}, diff --git a/tool/abi-generator/src/abi/ty/complex.rs b/tool/abi-generator/src/abi/ty/complex.rs index 05a8d293..8e62cf5c 100644 --- a/tool/abi-generator/src/abi/ty/complex.rs +++ b/tool/abi-generator/src/abi/ty/complex.rs @@ -129,6 +129,9 @@ impl Type for ComplexType { { quote!(#value.into_syscall_register()) } + Self::Option(_) => { + quote!(#value.as_syscall_meta(), #value.as_syscall_data()) + } Self::Extern { kind: ExternKind::Thin, .. @@ -162,6 +165,13 @@ impl Type for ComplexType { 1, ) } + Self::Option(ty) => { + let ty = ty.as_rust_type(); + ( + quote!(>::from_syscall_registers(#args[#index], #args[#index + 1])), + 2, + ) + } Self::Result(_) => todo!("Result"), Self::Extern { kind: ExternKind::Thin, diff --git a/userspace/Cargo.lock b/userspace/Cargo.lock index 2fc7b839..7f83f912 100644 --- a/userspace/Cargo.lock +++ b/userspace/Cargo.lock @@ -260,11 +260,12 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" name = "colors" version = "0.1.0" dependencies = [ - "lazy_static", + "cross", "libcolors", + "runtime", "serde", - "serde-ipc", "thiserror", + "uipc", "yggdrasil-abi", ] @@ -294,6 +295,8 @@ name = "cross" version = "0.1.0" dependencies = [ "libc", + "runtime", + "tempfile", "yggdrasil-rt", ] @@ -478,12 +481,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -506,9 +509,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fiat-crypto" @@ -688,6 +691,7 @@ dependencies = [ name = "init" version = "0.1.0" dependencies = [ + "cross", "serde", "serde_json", "yggdrasil-rt", @@ -733,10 +737,11 @@ checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" name = "libcolors" version = "0.1.0" dependencies = [ + "cross", "raqote", "serde", - "serde-ipc", "thiserror", + "uipc", "yggdrasil-abi", ] @@ -757,9 +762,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "lock_api" @@ -828,6 +833,7 @@ dependencies = [ "http", "log", "rand 0.9.0-alpha.1", + "runtime", "serde", "serde_json", "thiserror", @@ -1225,6 +1231,15 @@ dependencies = [ "x25519-dalek", ] +[[package]] +name = "runtime" +version = "0.1.0" +dependencies = [ + "abi-serde", + "yggdrasil-abi", + "yggdrasil-rt", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -1242,15 +1257,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.38" +version = "0.38.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1280,16 +1295,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-ipc" -version = "0.1.0" -dependencies = [ - "postcard", - "serde", - "tempfile", - "thiserror", -] - [[package]] name = "serde_derive" version = "1.0.214" @@ -1476,6 +1481,7 @@ version = "0.1.0" dependencies = [ "chrono", "clap", + "cross", "humansize", "init", "libterm", @@ -1490,12 +1496,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.13.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", + "getrandom 0.2.15", "once_cell", "rustix", "windows-sys 0.59.0", @@ -1591,6 +1598,16 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "uipc" +version = "0.1.0" +dependencies = [ + "cross", + "postcard", + "serde", + "thiserror", +] + [[package]] name = "unicode-bidi" version = "0.3.17" @@ -1678,15 +1695,6 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.59.0" diff --git a/userspace/Cargo.toml b/userspace/Cargo.toml index c05f18db..0f40ed15 100644 --- a/userspace/Cargo.toml +++ b/userspace/Cargo.toml @@ -8,7 +8,6 @@ members = [ "colors", "term", "lib/libcolors", - "lib/serde-ipc", "lib/libterm", "netutils", "netutils", @@ -17,7 +16,9 @@ members = [ "lib/yasync", "rsh", "lib/cross", - "crypt"] + "crypt", + "lib/runtime" +, "lib/uipc"] exclude = ["dynload-program", "test-kernel-module", "lib/ygglibc"] [workspace.dependencies] @@ -41,12 +42,14 @@ x25519-dalek = { git = "https://git.alnyan.me/yggdrasil/curve25519-dalek.git", b ed25519-dalek = { git = "https://git.alnyan.me/yggdrasil/curve25519-dalek.git", branch = "alnyan/yggdrasil" } # Internal crates -serde-ipc.path = "lib/serde-ipc" libterm.path = "lib/libterm" +runtime.path = "lib/runtime" libcolors = { path = "lib/libcolors", default-features = false } cross.path = "lib/cross" +uipc.path = "lib/uipc" yggdrasil-rt.path = "../lib/runtime" yggdrasil-abi = { path = "../lib/abi", features = ["serde", "alloc", "bytemuck"] } +abi-serde = { path = "../lib/abi-serde" } [workspace.lints.rust] unexpected_cfgs = { level = "allow", check-cfg = ['cfg(rust_analyzer)'] } diff --git a/userspace/colors/Cargo.toml b/userspace/colors/Cargo.toml index b2ec65ba..eb8c293c 100644 --- a/userspace/colors/Cargo.toml +++ b/userspace/colors/Cargo.toml @@ -5,10 +5,15 @@ edition = "2021" authors = ["Mark Poliakov "] [dependencies] -yggdrasil-abi.workspace = true -serde-ipc.workspace = true +uipc.workspace = true +cross.workspace = true serde.workspace = true thiserror.workspace = true libcolors = { workspace = true, default-features = false } -lazy_static = "1.4.0" +[target.'cfg(target_os = "yggdrasil")'.dependencies] +yggdrasil-abi.workspace = true +runtime.workspace = true + +[lints] +workspace = true diff --git a/userspace/colors/src/error.rs b/userspace/colors/src/error.rs index c0065a80..0315cc8a 100644 --- a/userspace/colors/src/error.rs +++ b/userspace/colors/src/error.rs @@ -3,5 +3,5 @@ pub enum Error { #[error("I/O error: {0}")] IoError(#[from] std::io::Error), #[error("Communication error: {0}")] - IpcError(#[from] serde_ipc::Error), + IpcError(#[from] uipc::Error), } diff --git a/userspace/colors/src/main.rs b/userspace/colors/src/main.rs index 4d2aca29..31f1d4b4 100644 --- a/userspace/colors/src/main.rs +++ b/userspace/colors/src/main.rs @@ -1,27 +1,27 @@ -#![feature(yggdrasil_os, rustc_private)] - -// TODO rewrite and split this into meaningful components +#![cfg_attr(target_os = "yggdrasil", feature(yggdrasil_os, rustc_private))] use std::{ collections::{BTreeMap, HashMap}, env, os::{ fd::{AsRawFd, RawFd}, - yggdrasil::io::{mapping::FileMapping, poll::PollChannel, shared_memory::SharedMemory}, + yggdrasil::io::poll::PollChannel, }, path::Path, process::{Command, ExitCode}, }; +use cross::mem::{FileMapping, SharedMemory}; use display::Display; use error::Error; use input::{InputState, KeyboardInput}; use libcolors::{ - event::{Event, KeyModifiers, WindowEvent, WindowInfo}, + event::{EventData, KeyModifiers, KeyboardKey, KeyboardKeyEvent, WindowEvent, WindowInfo}, message::{ClientMessage, ServerMessage}, }; -use serde_ipc::{PeerAddr, Receiver, Sender}; -use yggdrasil_abi::io::{KeyboardKey, KeyboardKeyEvent}; +use uipc::{Channel, PeerAddress, Receiver, Sender}; + +// TODO rewrite and split this into meaningful components pub mod display; pub mod error; @@ -29,9 +29,9 @@ pub mod input; pub struct Window<'a> { window_id: u32, - client_id: PeerAddr, + client_id: PeerAddress, - surface_mapping: FileMapping<'a>, + surface_mapping: FileMapping, surface_data: &'a [u32], } @@ -62,7 +62,7 @@ pub struct Server<'a, 'd> { input_state: InputState, last_client_id: u32, - client_map: HashMap, + client_map: HashMap, // Window management windows: BTreeMap>, @@ -147,7 +147,8 @@ impl<'a> Server<'a, '_> { let mut display = Display::open(framebuffer)?; let input = KeyboardInput::open()?; - let (sender, receiver) = serde_ipc::listen(libcolors::CHANNEL_NAME)?; + let channel = Channel::bind(libcolors::CHANNEL_NAME)?; + let (sender, receiver) = channel.split(); let sender = ServerSender(sender); poll.add(input.as_poll_fd())?; @@ -180,7 +181,7 @@ impl<'a> Server<'a, '_> { }) } - fn create_window(&mut self, client_id: &PeerAddr) -> Result<(WindowInfo, RawFd), Error> { + fn create_window(&mut self, client_id: &PeerAddress) -> Result<(WindowInfo, RawFd), Error> { if self.rows.is_empty() { self.rows.push(Row::new( self.padding as _, @@ -201,7 +202,7 @@ impl<'a> Server<'a, '_> { let mapping_size = self.display.width() * self.display.height() * 4; let surface_shm = SharedMemory::new(mapping_size).unwrap(); let fd = surface_shm.as_raw_fd(); - let mut surface_mapping = surface_shm.into_mapping().unwrap(); + let mut surface_mapping = surface_shm.map().unwrap(); let surface_data = unsafe { std::slice::from_raw_parts_mut( @@ -343,7 +344,7 @@ impl<'a> Server<'a, '_> { // Deliver event to the window self.sender .send_event( - Event::WindowEvent(window.window_id, WindowEvent::KeyInput(input)), + EventData::WindowEvent(window.window_id, WindowEvent::KeyInput(input)), &window.client_id, ) .ok(); @@ -387,7 +388,7 @@ impl<'a> Server<'a, '_> { if let Some((_, old_window)) = self.get_focused_window() { self.sender .send_event( - Event::WindowEvent(old_window.window_id, WindowEvent::FocusChanged(false)), + EventData::WindowEvent(old_window.window_id, WindowEvent::FocusChanged(false)), &old_window.client_id, ) .ok(); @@ -408,7 +409,7 @@ impl<'a> Server<'a, '_> { self.sender .send_event( - Event::WindowEvent(window.window_id, WindowEvent::FocusChanged(true)), + EventData::WindowEvent(window.window_id, WindowEvent::FocusChanged(true)), &window.client_id, ) .ok(); @@ -457,7 +458,7 @@ impl<'a> Server<'a, '_> { self.sender .send_event( - Event::WindowEvent( + EventData::WindowEvent( window.window_id, WindowEvent::Resized { width: frame.w, @@ -473,7 +474,7 @@ impl<'a> Server<'a, '_> { fn handle_client_message( &mut self, - client_id: PeerAddr, + client_id: PeerAddress, message: ClientMessage, ) -> Result<(), Error> { match message { @@ -483,18 +484,21 @@ impl<'a> Server<'a, '_> { self.last_client_id += 1; let id = self.last_client_id; self.client_map.insert(id, client_id.clone()); - self.sender.send_event(Event::ServerHello(id), &client_id) + + self.sender.send_event(EventData::ServerHello(id), &client_id) } ClientMessage::CreateWindow => { debug_trace!("{:?}: CreateWindow", client_id); let (info, shm_fd) = self.create_window(&client_id)?; let window_id = info.window_id; - self.sender - .send_event(Event::NewWindowInfo(info), &client_id)?; - self.sender.send_fd(&shm_fd, &client_id)?; + self.sender.send_event_with_file( + EventData::NewWindowInfo(info), + &shm_fd, + &client_id, + )?; self.sender.send_event( - Event::WindowEvent(window_id, WindowEvent::RedrawRequested), + EventData::WindowEvent(window_id, WindowEvent::RedrawRequested), &client_id, )?; @@ -545,8 +549,8 @@ impl<'a> Server<'a, '_> { self.handle_keyboard_event(event)?; } Some((fd, Ok(_))) if fd == self.receiver.as_raw_fd() => { - let (client_id, message) = self.receiver.receive_message()?; - self.handle_client_message(client_id, message)?; + let (data, client_id) = self.receiver.receive_from()?; + self.handle_client_message(client_id, data)?; } Some((_, Ok(_))) => { todo!() @@ -571,14 +575,20 @@ impl<'a> Server<'a, '_> { } impl ServerSender { - pub fn send_event(&self, event: Event, client_id: &PeerAddr) -> Result<(), Error> { - self.0 - .send_to(&ServerMessage::Event(event), client_id) - .map_err(Error::from) + pub fn send_event(&self, event: EventData, client_id: &PeerAddress) -> Result<(), Error> { + self.0.send_to(&ServerMessage::Event(event), client_id)?; + Ok(()) } - pub fn send_fd(&self, file: &F, client_id: &PeerAddr) -> Result<(), Error> { - self.0.send_file_to(file, client_id).map_err(Error::from) + pub fn send_event_with_file( + &self, + event: EventData, + file: &F, + client_id: &PeerAddress, + ) -> Result<(), Error> { + self.0 + .send_with_file_to(&ServerMessage::Event(event), file, client_id)?; + Ok(()) } } diff --git a/userspace/init/Cargo.toml b/userspace/init/Cargo.toml index 0e95231c..1f49cec2 100644 --- a/userspace/init/Cargo.toml +++ b/userspace/init/Cargo.toml @@ -15,6 +15,7 @@ name = "rc" path = "src/rc.rs" [dependencies] +cross.workspace = true serde.workspace = true serde_json.workspace = true yggdrasil-rt.workspace = true diff --git a/userspace/init/src/main.rs b/userspace/init/src/main.rs index 285fdf41..826b17f3 100644 --- a/userspace/init/src/main.rs +++ b/userspace/init/src/main.rs @@ -4,12 +4,12 @@ use std::{ fmt, fs::File, io::{self, BufRead, BufReader}, - os::yggdrasil::io::message_channel::{MessageChannel, MessageReceiver}, path::Path, process::{Command, ExitCode, Stdio}, str::FromStr, }; +use cross::net::LocalPacketSocket; use init::InitMsg; use yggdrasil_rt::debug_trace; @@ -155,14 +155,14 @@ fn handle_message(msg: InitMsg) -> io::Result<()> { } } -fn main_loop(channel: MessageChannel) -> io::Result { +fn main_loop(socket: LocalPacketSocket) -> io::Result { let mut buf = [0; 1024]; loop { - let (_, len) = channel.receive_message(&mut buf)?; + let len = socket.receive(&mut buf)?; if let Ok(msg) = serde_json::from_slice::(&buf[..len]) { if let Err(err) = handle_message(msg) { - debug_trace!("init::handle_message: {}", err); + debug_trace!("init::handle_message: {err}"); } } } @@ -179,7 +179,8 @@ fn main() -> ExitCode { } }; - let channel = MessageChannel::open("service-control", true).unwrap(); + //let channel = MessageChannel::open("service-control", true).unwrap(); + let control_socket = LocalPacketSocket::bind("/init.sock").unwrap(); debug_trace!("Rules loaded"); @@ -190,7 +191,7 @@ fn main() -> ExitCode { } } - let Err(error) = main_loop(channel); + let Err(error) = main_loop(control_socket); debug_trace!("init: main_loop returned {error}"); ExitCode::FAILURE } diff --git a/userspace/lib/cross/Cargo.toml b/userspace/lib/cross/Cargo.toml index e5b88b75..9aa488b0 100644 --- a/userspace/lib/cross/Cargo.toml +++ b/userspace/lib/cross/Cargo.toml @@ -7,11 +7,14 @@ edition = "2021" [target.'cfg(target_os = "yggdrasil")'.dependencies] yggdrasil-rt.workspace = true +runtime.workspace = true [target.'cfg(unix)'.dependencies] +tempfile = "3.15.0" libc = "*" [dev-dependencies] +tempfile = "3.15.0" libc = "*" [lints.rust] diff --git a/userspace/lib/cross/src/lib.rs b/userspace/lib/cross/src/lib.rs index cfa03a2c..64a26729 100644 --- a/userspace/lib/cross/src/lib.rs +++ b/userspace/lib/cross/src/lib.rs @@ -1,5 +1,8 @@ #![cfg_attr(target_os = "yggdrasil", feature(yggdrasil_os, rustc_private))] +#![cfg_attr(any(rust_analyzer, unix), feature(unix_socket_ancillary_data))] pub(crate) mod sys; pub mod io; +pub mod net; +pub mod mem; diff --git a/userspace/lib/cross/src/mem.rs b/userspace/lib/cross/src/mem.rs new file mode 100644 index 00000000..a88e999c --- /dev/null +++ b/userspace/lib/cross/src/mem.rs @@ -0,0 +1,55 @@ +use std::{ + io, + ops::{Deref, DerefMut}, + os::fd::{AsRawFd, OwnedFd, RawFd}, +}; + +use crate::sys::{ + FileMapping as SysFileMapping, FileMappingImpl, SharedMemory as SysSharedMemory, + SharedMemoryImpl, +}; + +pub struct SharedMemory(SharedMemoryImpl); +pub struct FileMapping(FileMappingImpl); + +impl SharedMemory { + pub fn new(size: usize) -> io::Result { + SharedMemoryImpl::new(size).map(Self) + } + + pub fn map(self) -> io::Result { + self.0.map().map(FileMapping) + } +} + +impl AsRawFd for SharedMemory { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl FileMapping { + pub fn map>(file: F, size: usize) -> io::Result { + FileMappingImpl::map(file, size).map(Self) + } +} + +impl Deref for FileMapping { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.0.deref() + } +} + +impl DerefMut for FileMapping { + fn deref_mut(&mut self) -> &mut Self::Target { + self.0.deref_mut() + } +} + +impl AsRawFd for FileMapping { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} diff --git a/userspace/lib/cross/src/net.rs b/userspace/lib/cross/src/net.rs new file mode 100644 index 00000000..91596d96 --- /dev/null +++ b/userspace/lib/cross/src/net.rs @@ -0,0 +1,104 @@ +use std::{ + io, + os::fd::{AsRawFd, OwnedFd, RawFd}, + path::Path, +}; + +use crate::sys; + +use self::sys::{LocalPacketSocket as SysLocalPacketSocket, OwnedAddress as SysOwnedAddress}; + +#[repr(transparent)] +pub struct LocalPacketSocket(sys::LocalPacketSocketImpl); + +#[derive(Debug)] +#[repr(transparent)] +pub struct BorrowedLocalAddress<'a>(sys::BorrowedAddressImpl<'a>); + +#[derive(Debug, Clone)] +#[repr(transparent)] +pub struct OwnedLocalAddress(sys::OwnedAddressImpl); + +impl LocalPacketSocket { + pub fn new() -> io::Result { + sys::LocalPacketSocketImpl::new().map(Self) + } + + pub fn connect>(path: P) -> io::Result { + sys::LocalPacketSocketImpl::connect(path).map(Self) + } + + pub fn bind>(path: P) -> io::Result { + sys::LocalPacketSocketImpl::bind(path).map(Self) + } + + pub fn receive(&self, buffer: &mut [u8]) -> io::Result { + self.0.receive(buffer) + } + + pub fn receive_from(&self, buffer: &mut [u8]) -> io::Result<(usize, OwnedLocalAddress)> { + let (len, address) = self.0.receive_from(buffer)?; + Ok((len, OwnedLocalAddress(address))) + } + + pub fn receive_with_ancillary( + &self, + buffer: &mut [u8], + ) -> io::Result<(usize, Option)> { + self.0.receive_with_ancillary(buffer) + } + + pub fn receive_with_ancillary_from( + &self, + buffer: &mut [u8], + ) -> io::Result<(usize, Option, OwnedLocalAddress)> { + let (len, fd, address) = self.0.receive_with_ancillary_from(buffer)?; + Ok((len, fd, OwnedLocalAddress(address))) + } + + pub fn send(&self, data: &[u8]) -> io::Result { + self.0.send(data) + } + + pub fn send_to<'a, A: Into>>( + &self, + data: &[u8], + remote: A, + ) -> io::Result { + let remote = remote.into(); + self.0.send_to(data, &remote.0) + } + + pub fn send_with_ancillary(&self, data: &[u8], ancillary: RawFd) -> io::Result { + self.0.send_with_ancillary(data, ancillary) + } + + pub fn send_with_ancillary_to<'a, A: Into>>( + &self, + data: &[u8], + ancillary: RawFd, + remote: A, + ) -> io::Result { + let remote = remote.into(); + self.0.send_with_ancillary_to(data, ancillary, &remote.0) + } +} + +impl AsRawFd for LocalPacketSocket { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +#[cfg(any(rust_analyzer, target_os = "yggdrasil"))] +impl<'a> From<&'a Path> for BorrowedLocalAddress<'a> { + fn from(value: &'a Path) -> Self { + Self(sys::BorrowedAddressImpl::from(value)) + } +} + +impl<'a> From<&'a OwnedLocalAddress> for BorrowedLocalAddress<'a> { + fn from(value: &'a OwnedLocalAddress) -> Self { + Self(value.0.as_borrowed()) + } +} diff --git a/userspace/lib/cross/src/sys/mod.rs b/userspace/lib/cross/src/sys/mod.rs index 2c64d827..f27bda83 100644 --- a/userspace/lib/cross/src/sys/mod.rs +++ b/userspace/lib/cross/src/sys/mod.rs @@ -9,13 +9,17 @@ mod unix; pub(crate) use unix::*; use std::{ + fmt, io::{self, Read, Stdin, Write}, ops::DerefMut, - os::fd::{AsRawFd, RawFd}, + os::fd::{AsRawFd, OwnedFd, RawFd}, + path::Path, process::Stdio, time::Duration, }; +// I/O + pub(crate) trait Poll: Sized + AsRawFd { fn new() -> io::Result; fn add(&mut self, interest: &F) -> io::Result<()>; @@ -42,3 +46,58 @@ pub(crate) trait Pipe: Read + Write + AsRawFd + Sized { pub(crate) trait RawStdin<'a>: Sized + DerefMut + 'a { fn new(stdin: &'a mut Stdin) -> io::Result; } + +// Networking + +#[allow(unused)] +pub(crate) trait BorrowedAddress<'a>: fmt::Debug + From<&'a Path> { + type Owned: OwnedAddress; +} + +#[allow(unused)] +pub(crate) trait OwnedAddress: fmt::Debug + Clone { + type Borrowed<'a>: BorrowedAddress<'a>; + + fn from_borrowed(borrowed: &Self::Borrowed<'_>) -> Self; + fn as_borrowed(&self) -> Self::Borrowed<'_>; +} + +pub(crate) trait LocalPacketSocket: AsRawFd + Sized { + type Address<'a>: BorrowedAddress<'a>; + type OwnedAddress: OwnedAddress; + + fn new() -> io::Result; + fn bind>(path: P) -> io::Result; + fn connect>(path: P) -> io::Result; + + fn receive(&self, data: &mut [u8]) -> io::Result; + fn receive_from(&self, data: &mut [u8]) -> io::Result<(usize, Self::OwnedAddress)>; + fn receive_with_ancillary(&self, data: &mut [u8]) -> io::Result<(usize, Option)>; + fn receive_with_ancillary_from( + &self, + data: &mut [u8], + ) -> io::Result<(usize, Option, Self::OwnedAddress)>; + + fn send(&self, data: &[u8]) -> io::Result; + fn send_to(&self, data: &[u8], address: &Self::Address<'_>) -> io::Result; + fn send_with_ancillary(&self, data: &[u8], ancillary: RawFd) -> io::Result; + fn send_with_ancillary_to( + &self, + data: &[u8], + ancillary: RawFd, + address: &Self::Address<'_>, + ) -> io::Result; +} + +// Memory + +pub(crate) trait FileMapping: AsRawFd + DerefMut + Sized { + fn map>(file: F, size: usize) -> io::Result; +} + +pub(crate) trait SharedMemory: AsRawFd + Sized { + type Mapping: FileMapping; + + fn new(size: usize) -> io::Result; + fn map(self) -> io::Result; +} diff --git a/userspace/lib/cross/src/sys/unix/mem.rs b/userspace/lib/cross/src/sys/unix/mem.rs new file mode 100644 index 00000000..4f021d03 --- /dev/null +++ b/userspace/lib/cross/src/sys/unix/mem.rs @@ -0,0 +1,58 @@ +use std::{ + io, + ops::{Deref, DerefMut}, + os::fd::{AsRawFd, OwnedFd, RawFd}, +}; + +use crate::sys; + +pub struct SharedMemoryImpl {} + +pub struct FileMappingImpl {} + +impl sys::SharedMemory for SharedMemoryImpl { + type Mapping = FileMappingImpl; + + fn map(self) -> io::Result { + todo!() + } + + fn new(size: usize) -> io::Result { + let _ = size; + todo!() + } +} + +impl AsRawFd for SharedMemoryImpl { + fn as_raw_fd(&self) -> RawFd { + todo!() + } +} + +impl sys::FileMapping for FileMappingImpl { + fn map>(file: F, size: usize) -> io::Result { + let _ = file; + let _ = size; + todo!() + } +} + +impl Deref for FileMappingImpl { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + todo!() + } +} + +impl DerefMut for FileMappingImpl { + fn deref_mut(&mut self) -> &mut Self::Target { + todo!() + } +} + +impl AsRawFd for FileMappingImpl { + fn as_raw_fd(&self) -> RawFd { + todo!() + } +} diff --git a/userspace/lib/cross/src/sys/unix/mod.rs b/userspace/lib/cross/src/sys/unix/mod.rs index 2a641dda..10df7962 100644 --- a/userspace/lib/cross/src/sys/unix/mod.rs +++ b/userspace/lib/cross/src/sys/unix/mod.rs @@ -1,11 +1,15 @@ -pub mod poll; -pub mod timer; +pub mod mem; pub mod pid; pub mod pipe; +pub mod poll; +pub mod socket; pub mod term; +pub mod timer; -pub use poll::PollImpl; -pub use timer::TimerFdImpl; +pub use mem::{FileMappingImpl, SharedMemoryImpl}; pub use pid::PidFdImpl; pub use pipe::PipeImpl; +pub use poll::PollImpl; +pub use socket::{BorrowedAddressImpl, LocalPacketSocketImpl, OwnedAddressImpl}; pub use term::RawStdinImpl; +pub use timer::TimerFdImpl; diff --git a/userspace/lib/cross/src/sys/unix/pipe.rs b/userspace/lib/cross/src/sys/unix/pipe.rs index 1f25fc8a..c87cd6a1 100644 --- a/userspace/lib/cross/src/sys/unix/pipe.rs +++ b/userspace/lib/cross/src/sys/unix/pipe.rs @@ -8,6 +8,9 @@ pub struct PipeImpl { impl Pipe for PipeImpl { fn new(read_nonblocking: bool, write_nonblocking: bool) -> io::Result<(Self, Self)> { + if read_nonblocking || write_nonblocking { + todo!() + } let mut fds = [0; 2]; let res = unsafe { libc::pipe(fds.as_mut_ptr()) }; if res < 0 { @@ -26,12 +29,14 @@ impl Pipe for PipeImpl { impl Read for PipeImpl { fn read(&mut self, buf: &mut [u8]) -> io::Result { + let _ = buf; todo!() } } impl Write for PipeImpl { fn write(&mut self, buf: &[u8]) -> io::Result { + let _ = buf; todo!() } diff --git a/userspace/lib/cross/src/sys/unix/socket.rs b/userspace/lib/cross/src/sys/unix/socket.rs new file mode 100644 index 00000000..3be0df8a --- /dev/null +++ b/userspace/lib/cross/src/sys/unix/socket.rs @@ -0,0 +1,185 @@ +use std::{ + io::{self, IoSlice, IoSliceMut}, + os::{ + fd::{AsRawFd, FromRawFd, OwnedFd, RawFd}, + unix::net::{AncillaryData, SocketAddr, SocketAncillary, UnixDatagram}, + }, + path::{Path, PathBuf}, +}; + +use tempfile::TempDir; + +use crate::sys::{self, LocalPacketSocket}; + +pub struct LocalPacketSocketImpl { + inner: UnixDatagram, + #[allow(unused)] + ephemeral: Option, +} + +#[derive(Debug)] +pub struct BorrowedAddressImpl<'a>(&'a Path); +#[derive(Debug, Clone)] +pub struct OwnedAddressImpl(PathBuf); + +impl<'a> sys::BorrowedAddress<'a> for BorrowedAddressImpl<'a> { + type Owned = OwnedAddressImpl; +} + +impl sys::OwnedAddress for OwnedAddressImpl { + type Borrowed<'a> = BorrowedAddressImpl<'a>; + + fn as_borrowed(&self) -> Self::Borrowed<'_> { + BorrowedAddressImpl(self.0.as_path()) + } + + fn from_borrowed(borrowed: &Self::Borrowed<'_>) -> Self { + Self(borrowed.0.into()) + } +} + +fn read_ancillary(ancillary: &SocketAncillary) -> Option { + for message in ancillary.messages() { + let Ok(message) = message else { + continue; + }; + let fd = match message { + AncillaryData::ScmRights(mut rights) => rights.next(), + _ => None, + }; + + if let Some(fd) = fd { + return Some(unsafe { OwnedFd::from_raw_fd(fd) }); + } + } + + None +} + +impl LocalPacketSocketImpl { + pub fn bind_ephemeral() -> io::Result { + let temp = TempDir::new()?; + let path = temp.path().join("temp.sock"); + let inner = UnixDatagram::bind(path)?; + Ok(Self { + inner, + ephemeral: Some(temp), + }) + } +} + +impl LocalPacketSocket for LocalPacketSocketImpl { + type Address<'a> = BorrowedAddressImpl<'a>; + type OwnedAddress = OwnedAddressImpl; + + fn new() -> io::Result { + let inner = UnixDatagram::unbound()?; + Ok(Self { + inner, + ephemeral: None, + }) + } + + fn bind>(path: P) -> io::Result { + let inner = UnixDatagram::bind(path)?; + Ok(Self { + inner, + ephemeral: None, + }) + } + + fn connect>(path: P) -> io::Result { + let this = Self::bind_ephemeral()?; + this.inner.connect(path)?; + Ok(this) + } + + fn send(&self, data: &[u8]) -> io::Result { + self.inner.send(data) + } + + fn send_to<'a>(&self, data: &[u8], address: &Self::Address<'a>) -> io::Result { + self.inner.send_to(data, address.0) + } + + fn send_with_ancillary(&self, data: &[u8], fd: RawFd) -> io::Result { + let mut ancillary_buffer = [0; 256]; + let mut ancillary = SocketAncillary::new(&mut ancillary_buffer); + ancillary.add_fds(&[fd]); + let buffers = [IoSlice::new(data)]; + let len = self + .inner + .send_vectored_with_ancillary(&buffers, &mut ancillary)?; + Ok(len) + } + + fn send_with_ancillary_to<'a>( + &self, + data: &[u8], + fd: RawFd, + address: &Self::Address<'a>, + ) -> io::Result { + let mut ancillary_buffer = [0; 256]; + let mut ancillary = SocketAncillary::new(&mut ancillary_buffer); + ancillary.add_fds(&[fd]); + let buffers = [IoSlice::new(data)]; + let len = + self.inner + .send_vectored_with_ancillary_to(&buffers, &mut ancillary, address.0)?; + Ok(len) + } + + fn receive(&self, data: &mut [u8]) -> io::Result { + self.inner.recv(data) + } + + fn receive_from(&self, data: &mut [u8]) -> io::Result<(usize, Self::OwnedAddress)> { + let (len, source) = self.inner.recv_from(data)?; + Ok((len, source.into())) + } + + fn receive_with_ancillary(&self, data: &mut [u8]) -> io::Result<(usize, Option)> { + let (len, fd, _) = self.receive_with_ancillary_from(data)?; + Ok((len, fd)) + } + + fn receive_with_ancillary_from( + &self, + data: &mut [u8], + ) -> io::Result<(usize, Option, Self::OwnedAddress)> { + let mut ancillary_buffer = [0; 256]; + let mut ancillary = SocketAncillary::new(&mut ancillary_buffer); + let mut buffers = [IoSliceMut::new(data)]; + let (len, truncated, source) = self + .inner + .recv_vectored_with_ancillary_from(&mut buffers, &mut ancillary)?; + assert!(!truncated); + let fd = read_ancillary(&ancillary); + Ok((len, fd, source.into())) + } +} + +impl AsRawFd for LocalPacketSocketImpl { + fn as_raw_fd(&self) -> RawFd { + self.inner.as_raw_fd() + } +} + +impl<'a> From<&'a Path> for BorrowedAddressImpl<'a> { + fn from(value: &'a Path) -> Self { + Self(value) + } +} + +impl<'a> From<&'a BorrowedAddressImpl<'a>> for OwnedAddressImpl { + fn from(value: &'a BorrowedAddressImpl) -> Self { + Self(value.0.into()) + } +} + +impl From for OwnedAddressImpl { + fn from(value: SocketAddr) -> Self { + let path = value.as_pathname().unwrap(); + Self(path.into()) + } +} diff --git a/userspace/lib/cross/src/sys/yggdrasil/mem.rs b/userspace/lib/cross/src/sys/yggdrasil/mem.rs new file mode 100644 index 00000000..494bbafa --- /dev/null +++ b/userspace/lib/cross/src/sys/yggdrasil/mem.rs @@ -0,0 +1,65 @@ +use std::{ + io, + ops::{Deref, DerefMut}, + os::{ + fd::{AsRawFd, OwnedFd, RawFd}, + yggdrasil::io::{mapping as map, shared_memory as shm}, + }, +}; + +use crate::sys::{FileMapping, SharedMemory}; + +pub struct SharedMemoryImpl { + inner: shm::SharedMemory, +} + +pub struct FileMappingImpl { + inner: map::FileMapping<'static>, +} + +impl SharedMemory for SharedMemoryImpl { + type Mapping = FileMappingImpl; + + fn new(size: usize) -> io::Result { + let inner = shm::SharedMemory::new(size)?; + Ok(Self { inner }) + } + + fn map(self) -> io::Result { + let inner = self.inner.into_mapping()?; + Ok(FileMappingImpl { inner }) + } +} + +impl AsRawFd for SharedMemoryImpl { + fn as_raw_fd(&self) -> RawFd { + self.inner.as_raw_fd() + } +} + +impl FileMapping for FileMappingImpl { + fn map>(file: F, size: usize) -> io::Result { + let inner = map::FileMapping::new(file, 0, size)?; + Ok(Self { inner }) + } +} + +impl AsRawFd for FileMappingImpl { + fn as_raw_fd(&self) -> RawFd { + self.inner.as_raw_fd() + } +} + +impl Deref for FileMappingImpl { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.inner.deref() + } +} + +impl DerefMut for FileMappingImpl { + fn deref_mut(&mut self) -> &mut Self::Target { + self.inner.deref_mut() + } +} diff --git a/userspace/lib/cross/src/sys/yggdrasil/mod.rs b/userspace/lib/cross/src/sys/yggdrasil/mod.rs index 2a641dda..59974690 100644 --- a/userspace/lib/cross/src/sys/yggdrasil/mod.rs +++ b/userspace/lib/cross/src/sys/yggdrasil/mod.rs @@ -3,9 +3,13 @@ pub mod timer; pub mod pid; pub mod pipe; pub mod term; +pub mod socket; +pub mod mem; pub use poll::PollImpl; pub use timer::TimerFdImpl; pub use pid::PidFdImpl; pub use pipe::PipeImpl; pub use term::RawStdinImpl; +pub use socket::{LocalPacketSocketImpl, OwnedAddressImpl, BorrowedAddressImpl}; +pub use mem::{SharedMemoryImpl, FileMappingImpl}; diff --git a/userspace/lib/cross/src/sys/yggdrasil/socket.rs b/userspace/lib/cross/src/sys/yggdrasil/socket.rs new file mode 100644 index 00000000..152d88c9 --- /dev/null +++ b/userspace/lib/cross/src/sys/yggdrasil/socket.rs @@ -0,0 +1,235 @@ +use std::{ + io, + os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd}, + path::{Path, PathBuf}, +}; + +use runtime::{ + abi::net::{types::LocalSocketAddress, AncillaryMessage, MessageHeader, MessageHeaderMut}, + abi_serde::wire, + rt as yggdrasil_rt, +}; +use yggdrasil_rt::net::SocketType; + +use crate::sys::{self, LocalPacketSocket}; + +pub struct LocalPacketSocketImpl { + fd: OwnedFd, +} + +#[derive(Debug)] +pub enum BorrowedAddressImpl<'a> { + Named(&'a Path), + #[allow(unused)] + Anonymous(u64), +} + +#[derive(Debug, Clone)] +pub enum OwnedAddressImpl { + Named(PathBuf), + Anonymous(u64), +} + + +impl<'a> BorrowedAddressImpl<'a> { + pub fn to_sys(&self) -> LocalSocketAddress<'a> { + match *self { + Self::Named(path) => LocalSocketAddress::Path(path.to_str().unwrap()), + Self::Anonymous(id) => LocalSocketAddress::Anonymous(id), + } + } +} + +impl OwnedAddressImpl { + pub fn from_sys(address: &LocalSocketAddress) -> Self { + match *address { + LocalSocketAddress::Path(path) => Self::Named(path.into()), + LocalSocketAddress::Anonymous(id) => Self::Anonymous(id), + } + } +} + +impl<'a> sys::BorrowedAddress<'a> for BorrowedAddressImpl<'a> { + type Owned = OwnedAddressImpl; +} + +impl sys::OwnedAddress for OwnedAddressImpl { + type Borrowed<'a> = BorrowedAddressImpl<'a>; + + fn as_borrowed(&self) -> Self::Borrowed<'_> { + match self { + Self::Named(path) => BorrowedAddressImpl::Named(path.as_path()), + &Self::Anonymous(id) => BorrowedAddressImpl::Anonymous(id) + } + } + + fn from_borrowed(borrowed: &Self::Borrowed<'_>) -> Self { + match *borrowed { + BorrowedAddressImpl::Named(path) => Self::Named(path.into()), + BorrowedAddressImpl::Anonymous(id) => Self::Anonymous(id) + } + } +} + +fn read_ancillary(buffer: &[u8]) -> io::Result> { + if buffer.is_empty() { + return Ok(None); + } + let message: AncillaryMessage = wire::from_slice(buffer).map_err(yggdrasil_rt::Error::from)?; + match message { + AncillaryMessage::File(fd) => Ok(Some(unsafe { OwnedFd::from_raw_fd(fd) })), + } +} + +impl LocalPacketSocket for LocalPacketSocketImpl { + type Address<'a> = BorrowedAddressImpl<'a>; + type OwnedAddress = OwnedAddressImpl; + + fn new() -> io::Result { + let raw = unsafe { yggdrasil_rt::sys::create_socket(SocketType::LocalPacket) }?; + let fd = unsafe { OwnedFd::from_raw_fd(raw) }; + Ok(Self { fd }) + } + + fn connect>(path: P) -> io::Result { + let path = path.as_ref().to_str().unwrap(); + let path = LocalSocketAddress::Path(path); + let mut address = [0; 512]; + let len = wire::to_slice(&path, &mut address).map_err(yggdrasil_rt::Error::from)?; + let this = Self::new()?; + unsafe { yggdrasil_rt::sys::connect(this.as_raw_fd(), &address[..len]) }?; + Ok(this) + } + + fn bind>(path: P) -> io::Result { + let path = path.as_ref().to_str().unwrap(); + let path = LocalSocketAddress::Path(path); + let mut address = [0; 512]; + let len = wire::to_slice(&path, &mut address).map_err(yggdrasil_rt::Error::from)?; + let this = Self::new()?; + unsafe { yggdrasil_rt::sys::bind(this.as_raw_fd(), &address[..len]) }?; + Ok(this) + } + + fn receive(&self, data: &mut [u8]) -> io::Result { + let len = yggdrasil_rt::net::socket::receive(self.as_raw_fd(), data)?; + Ok(len) + } + + fn receive_from(&self, data: &mut [u8]) -> io::Result<(usize, Self::OwnedAddress)> { + let mut address = [0; 512]; + let mut message = MessageHeaderMut { + source: Some(&mut address), + payload: data, + ancillary: None, + ancillary_len: 0 + }; + let len = unsafe { yggdrasil_rt::sys::receive_message(self.as_raw_fd(), &mut message) }?; + let address: LocalSocketAddress = + wire::from_slice(&address).map_err(yggdrasil_rt::Error::from)?; + Ok((len, OwnedAddressImpl::from_sys(&address))) + } + + fn receive_with_ancillary( + &self, + data: &mut [u8], + ) -> io::Result<(usize, Option)> { + let mut ancillary = [0; 32]; + let mut message = MessageHeaderMut { + source: None, + payload: data, + ancillary: Some(&mut ancillary), + ancillary_len: 0 + }; + let len = unsafe { yggdrasil_rt::sys::receive_message(self.as_raw_fd(), &mut message) }?; + let anc_len = message.ancillary_len; + let fd = read_ancillary(&ancillary[..anc_len])?; + Ok((len, fd)) + } + + fn receive_with_ancillary_from( + &self, + data: &mut [u8], + ) -> io::Result<(usize, Option, Self::OwnedAddress)> { + let mut ancillary = [0; 32]; + let mut address = [0; 512]; + let mut message = MessageHeaderMut { + source: Some(&mut address), + payload: data, + ancillary: Some(&mut ancillary), + ancillary_len: 0 + }; + let len = unsafe { yggdrasil_rt::sys::receive_message(self.as_raw_fd(), &mut message) }?; + let anc_len = message.ancillary_len; + let address: LocalSocketAddress = wire::from_slice(&address).map_err(yggdrasil_rt::Error::from)?; + let address = OwnedAddressImpl::from_sys(&address); + let fd = read_ancillary(&ancillary[..anc_len])?; + Ok((len, fd, address)) + } + + fn send(&self, data: &[u8]) -> io::Result { + let len = yggdrasil_rt::net::socket::send(self.as_raw_fd(), data)?; + Ok(len) + } + + fn send_to(&self, data: &[u8], address: &Self::Address<'_>) -> io::Result { + let address = address.to_sys(); + let mut destination = [0; 512]; + let address_len = + wire::to_slice(&address, &mut destination).map_err(yggdrasil_rt::Error::from)?; + let message = MessageHeader { + payload: data, + destination: Some(&destination[..address_len]), + ancillary: &[], + }; + let len = unsafe { yggdrasil_rt::sys::send_message(self.as_raw_fd(), &message) }?; + Ok(len) + } + + fn send_with_ancillary(&self, data: &[u8], ancillary: RawFd) -> io::Result { + let mut anc_buffer = [0; 32]; + let anc_len = wire::to_slice(&AncillaryMessage::File(ancillary), &mut anc_buffer) + .map_err(yggdrasil_rt::Error::from)?; + let message = MessageHeader { + destination: None, + payload: data, + ancillary: &anc_buffer[..anc_len], + }; + let len = unsafe { yggdrasil_rt::sys::send_message(self.as_raw_fd(), &message) }?; + Ok(len) + } + + fn send_with_ancillary_to( + &self, + data: &[u8], + ancillary: RawFd, + address: &Self::Address<'_>, + ) -> io::Result { + let address = address.to_sys(); + let mut destination = [0; 512]; + let mut anc_buffer = [0; 32]; + let anc_len = wire::to_slice(&AncillaryMessage::File(ancillary), &mut anc_buffer) + .map_err(yggdrasil_rt::Error::from)?; + let address_len = + wire::to_slice(&address, &mut destination).map_err(yggdrasil_rt::Error::from)?; + let message = MessageHeader { + destination: Some(&destination[..address_len]), + payload: data, + ancillary: &anc_buffer[..anc_len], + }; + let len = unsafe { yggdrasil_rt::sys::send_message(self.as_raw_fd(), &message) }?; + Ok(len) + } +} + +impl AsRawFd for LocalPacketSocketImpl { + fn as_raw_fd(&self) -> RawFd { + self.fd.as_raw_fd() + } +} + +impl<'a> From<&'a Path> for BorrowedAddressImpl<'a> { + fn from(value: &'a Path) -> Self { + Self::Named(value) + } +} diff --git a/userspace/lib/libcolors/Cargo.toml b/userspace/lib/libcolors/Cargo.toml index bd0e8622..0fc924e2 100644 --- a/userspace/lib/libcolors/Cargo.toml +++ b/userspace/lib/libcolors/Cargo.toml @@ -5,8 +5,10 @@ edition = "2021" authors = ["Mark Poliakov "] [dependencies] -serde-ipc.workspace = true +cross.workspace = true +uipc.workspace = true yggdrasil-abi.workspace = true + serde.workspace = true thiserror.workspace = true @@ -17,3 +19,6 @@ raqote = { version = "0.8.3", default-features = false, optional = true } default = [] client_raqote = ["client", "raqote"] client = [] + +[lints] +workspace = true diff --git a/userspace/lib/libcolors/src/application/connection.rs b/userspace/lib/libcolors/src/application/connection.rs index 68b26a27..018fd542 100644 --- a/userspace/lib/libcolors/src/application/connection.rs +++ b/userspace/lib/libcolors/src/application/connection.rs @@ -1,17 +1,17 @@ use std::{ collections::VecDeque, os::{ - fd::{AsRawFd, OwnedFd, RawFd}, - yggdrasil::io::{poll::PollChannel}, + fd::{AsRawFd, RawFd}, + yggdrasil::io::poll::PollChannel, }, time::Duration, }; -use serde_ipc::{Either, Receiver, Sender}; +use uipc::{Channel, Receiver, Sender}; use crate::{ error::Error, - event::Event, + event::{Event, EventData}, message::{ClientMessage, ServerMessage}, }; @@ -25,7 +25,8 @@ pub struct Connection { impl Connection { pub fn new() -> Result { - let (sender, receiver) = serde_ipc::connect(crate::CHANNEL_NAME)?; + let channel = Channel::connect(crate::CHANNEL_NAME)?; + let (sender, receiver) = channel.split(); let timeout = Duration::from_secs(1); let mut poll = PollChannel::new()?; let event_queue = VecDeque::new(); @@ -45,27 +46,7 @@ impl Connection { self.poll.as_raw_fd() } - pub fn receive_file(&mut self) -> Result { - loop { - let Some((_, Ok(_))) = self.poll.wait(Some(self.timeout), true)? else { - return Err(Error::CommunicationTimeout); - }; - - let (_, msg) = self.receiver.receive()?; - - // TODO ignore non-server messages - match msg { - Either::Left(ServerMessage::Event(event)) => { - self.event_queue.push_back(event); - } - Either::Right(fd) => { - break Ok(fd); - } - } - } - } - - pub fn receive_map Result>( + pub fn filter_events Result>( &mut self, predicate: F, ) -> Result { @@ -74,11 +55,9 @@ impl Connection { return Err(Error::CommunicationTimeout); }; - // Unless we're doing a request, the server should not send any FDs, so just drop - // anything that's not a message - let (_, Either::Left(ServerMessage::Event(event))) = self.receiver.receive()? else { - continue; - }; + let (data, file, _) = self.receiver.receive_with_file_from()?; + let ServerMessage::Event(data) = data; + let event = Event { data, file }; match predicate(event) { Ok(val) => break Ok(val), @@ -98,33 +77,37 @@ impl Connection { match self.poll.wait(Some(self.timeout), true)? { Some((_, Ok(_))) => (), Some((_, Err(e))) => { - todo!("Connection error: {:?}", e) + todo!("Poll error: {e:?}") } None => continue, - }; + } - let (_, Either::Left(ServerMessage::Event(event))) = self.receiver.receive()? else { - continue; - }; + let (data, file, _) = self.receiver.receive_with_file_from()?; + let ServerMessage::Event(data) = data; - break Ok(event); + break Ok(Event { data, file }); } } - pub fn send(&mut self, msg: ClientMessage) -> Result<(), Error> { - self.sender.send_to_host(&msg).map_err(Error::from) + pub fn send(&mut self, message: &ClientMessage) -> Result<(), Error> { + self.sender.send(message)?; + Ok(()) + } + + pub fn send_with_file( + &mut self, + message: &ClientMessage, + file: &F, + ) -> Result<(), Error> { + self.sender.send_with_file(message, file)?; + Ok(()) } pub fn connect(&mut self) -> Result { - self.sender - .send_to_host(&ClientMessage::ClientHello)?; - - self.receive_map(|ev| { - if let Event::ServerHello(id) = ev { - Ok(id) - } else { - Err(ev) - } + self.sender.send(&ClientMessage::ClientHello)?; + self.filter_events(|ev| match ev.data { + EventData::ServerHello(id) => Ok(id), + _ => Err(ev), }) } } diff --git a/userspace/lib/libcolors/src/application/mod.rs b/userspace/lib/libcolors/src/application/mod.rs index dabad61a..834d62d5 100644 --- a/userspace/lib/libcolors/src/application/mod.rs +++ b/userspace/lib/libcolors/src/application/mod.rs @@ -6,7 +6,7 @@ use std::{ use crate::{ error::Error, - event::{Event, WindowEvent}, + event::{Event, EventData, WindowEvent}, message::ClientMessage, }; @@ -43,7 +43,7 @@ impl<'a> Application<'a> { } pub fn handle_event(&mut self, event: Event) -> Result<(), Error> { - if let Event::WindowEvent(window_id, ev) = event { + if let EventData::WindowEvent(window_id, ev) = event.data { if let Some(window) = self.windows.get_mut(&window_id) { window.handle_event(ev)?; } else { @@ -90,7 +90,7 @@ impl Drop for Application<'_> { fn drop(&mut self) { let mut conn = self.connection.lock().unwrap(); for (window_id, _) in self.windows.iter() { - conn.send(ClientMessage::DestroyWindow(*window_id)).ok(); + conn.send(&ClientMessage::DestroyWindow(*window_id)).ok(); } } } diff --git a/userspace/lib/libcolors/src/application/window.rs b/userspace/lib/libcolors/src/application/window.rs index 3dbe239d..3f984e58 100644 --- a/userspace/lib/libcolors/src/application/window.rs +++ b/userspace/lib/libcolors/src/application/window.rs @@ -1,11 +1,10 @@ -use std::{ - os::yggdrasil::io::mapping::FileMapping, - sync::{Arc, Mutex}, -}; +use std::sync::{Arc, Mutex}; + +use cross::mem::FileMapping; use crate::{ error::Error, - event::{Event, KeyInput, WindowEvent}, + event::{EventData, KeyInput, WindowEvent}, message::ClientMessage, }; @@ -32,7 +31,7 @@ pub enum EventOutcome { pub struct Window<'a> { connection: Arc>, window_id: u32, - surface_mapping: FileMapping<'a>, + surface_mapping: FileMapping, #[cfg(feature = "client_raqote")] surface_draw_target: raqote::DrawTarget<&'a mut [u32]>, #[cfg(not(feature = "client_raqote"))] @@ -52,16 +51,19 @@ impl Window<'_> { pub fn new(application: &Application) -> Result { let mut connection = application.connection.lock().unwrap(); - connection.send(ClientMessage::CreateWindow)?; + connection.send(&ClientMessage::CreateWindow)?; - let create_info = connection.receive_map(|r| match r { - Event::NewWindowInfo(info) => Ok(info), + let (create_info, surface_shm_fd) = connection.filter_events(|r| match r.data { + EventData::NewWindowInfo(info) => { + let file = r.file.expect("Server sent window info without shm fd"); + Ok((info, file)) + } _ => Err(r), })?; assert_eq!(create_info.surface_stride % 4, 0); - let surface_shm_fd = connection.receive_file()?; + let mut surface_mapping = - FileMapping::new(surface_shm_fd, 0, create_info.surface_mapping_size)?; + FileMapping::map(surface_shm_fd, create_info.surface_mapping_size)?; let surface_data = unsafe { std::slice::from_raw_parts_mut( surface_mapping.as_mut_ptr() as *mut u32, @@ -212,7 +214,7 @@ impl Window<'_> { } let mut connection = self.connection.lock().unwrap(); - connection.send(ClientMessage::BlitWindow { + connection.send(&ClientMessage::BlitWindow { window_id: self.window_id, x, y, diff --git a/userspace/lib/libcolors/src/error.rs b/userspace/lib/libcolors/src/error.rs index bed52c8f..82dfdb46 100644 --- a/userspace/lib/libcolors/src/error.rs +++ b/userspace/lib/libcolors/src/error.rs @@ -7,5 +7,5 @@ pub enum Error { #[error("I/O error: {0}")] IoError(#[from] io::Error), #[error("Communication error: {0:?}")] - CommunicationError(#[from] serde_ipc::Error), + CommunicationError(#[from] uipc::Error), } diff --git a/userspace/lib/libcolors/src/event.rs b/userspace/lib/libcolors/src/event.rs index 0fe465a8..f034bc51 100644 --- a/userspace/lib/libcolors/src/event.rs +++ b/userspace/lib/libcolors/src/event.rs @@ -1,3 +1,5 @@ +use std::os::fd::OwnedFd; + pub use yggdrasil_abi::io::{KeyboardKey, KeyboardKeyEvent}; use serde::{Deserialize, Serialize}; @@ -44,7 +46,7 @@ pub enum WindowEvent { } #[derive(Debug, Serialize, Deserialize)] -pub enum Event { +pub enum EventData { // Server events KeyboardKey(KeyboardKeyEvent), RedrawRequested, @@ -57,6 +59,12 @@ pub enum Event { NewWindowInfo(WindowInfo), } +#[derive(Debug)] +pub struct Event { + pub data: EventData, + pub file: Option +} + impl KeyModifiers { pub const SHIFT: Self = Self { shift: true, diff --git a/userspace/lib/libcolors/src/lib.rs b/userspace/lib/libcolors/src/lib.rs index 7616fc49..4788be90 100644 --- a/userspace/lib/libcolors/src/lib.rs +++ b/userspace/lib/libcolors/src/lib.rs @@ -1,7 +1,10 @@ -#![feature(yggdrasil_os, rustc_private)] +#![cfg_attr(target_os = "yggdrasil", feature(yggdrasil_os, rustc_private))] #![cfg_attr(feature = "client", feature(trait_alias))] -pub const CHANNEL_NAME: &str = "colors"; +#[cfg(any(rust_analyzer, target_os = "yggdrasil"))] +pub const CHANNEL_NAME: &str = "/colors.sock"; +#[cfg(any(rust_analyzer, unix))] +pub const CHANNEL_NAME: &str = "/tmp/colors.sock"; #[cfg(feature = "client")] pub mod application; diff --git a/userspace/lib/libcolors/src/message.rs b/userspace/lib/libcolors/src/message.rs index dd977abb..bdeadab6 100644 --- a/userspace/lib/libcolors/src/message.rs +++ b/userspace/lib/libcolors/src/message.rs @@ -1,10 +1,10 @@ -use crate::event::Event; +use crate::event::EventData; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug)] pub enum ServerMessage { - Event(Event), + Event(EventData), } #[derive(Serialize, Deserialize, Debug)] @@ -21,7 +21,7 @@ pub enum ClientMessage { DestroyWindow(u32), } -impl From<(u32, ServerMessage)> for Event { +impl From<(u32, ServerMessage)> for EventData { fn from((_, msg): (u32, ServerMessage)) -> Self { let ServerMessage::Event(ev) = msg; diff --git a/userspace/lib/runtime/Cargo.toml b/userspace/lib/runtime/Cargo.toml new file mode 100644 index 00000000..59665a7a --- /dev/null +++ b/userspace/lib/runtime/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "runtime" +version = "0.1.0" +edition = "2021" + +[dependencies] + +[dev-dependencies] +yggdrasil-abi = { workspace = true, features = ["alloc", "bytemuck"] } +yggdrasil-rt.workspace = true +abi-serde.workspace = true + +[lints] +workspace = true diff --git a/userspace/lib/runtime/src/lib.rs b/userspace/lib/runtime/src/lib.rs new file mode 100644 index 00000000..67f212b4 --- /dev/null +++ b/userspace/lib/runtime/src/lib.rs @@ -0,0 +1,12 @@ +#![feature(yggdrasil_os, rustc_private)] + +#[cfg(rust_analyzer)] +pub use yggdrasil_rt as rt; +#[cfg(rust_analyzer)] +pub use yggdrasil_abi as abi; +#[cfg(rust_analyzer)] +pub use abi_serde; + +pub use std::os::yggdrasil::rt; +pub use std::os::yggdrasil::rt::abi; +pub use std::os::yggdrasil::rt::abi::abi_serde; diff --git a/userspace/lib/serde-ipc/Cargo.toml b/userspace/lib/serde-ipc/Cargo.toml deleted file mode 100644 index 416970ae..00000000 --- a/userspace/lib/serde-ipc/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "serde-ipc" -version = "0.1.0" -edition = "2021" -authors = ["Mark Poliakov "] - -[dependencies] -postcard.workspace = true -serde.workspace = true -thiserror.workspace = true - -tempfile = "3.12.0" - -[lints.rust] -unexpected_cfgs = { level = "allow", check-cfg = ['cfg(rust_analyzer)'] } diff --git a/userspace/lib/serde-ipc/src/lib.rs b/userspace/lib/serde-ipc/src/lib.rs deleted file mode 100644 index 71164522..00000000 --- a/userspace/lib/serde-ipc/src/lib.rs +++ /dev/null @@ -1,147 +0,0 @@ -#![cfg_attr(target_os = "yggdrasil", feature(yggdrasil_os, rustc_private))] -#![cfg_attr(unix, feature(unix_socket_ancillary_data))] - -use std::{ - io, - marker::PhantomData, - os::fd::{AsRawFd, OwnedFd, RawFd}, -}; - -use serde::{de::DeserializeOwned, Serialize}; -use sys::{IpcReceiver, RawReceiver, RawSender}; - -mod sys; - -pub use sys::{Either, PeerAddr}; - -use crate::sys::IpcSender; - -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error("Ser/des error: {0}")] - Serialize(postcard::Error), - #[error("I/O error: {0}")] - Io(#[from] io::Error), -} - -pub struct Sender { - inner: RawSender, - // inner: MessageChannelSender, - _pd: PhantomData, -} - -pub struct Receiver { - inner: RawReceiver, - // inner: MessageChannelReceiver, - buffer: [u8; 1024], - _pd: PhantomData, -} - -fn wrap( - sender: RawSender, - receiver: RawReceiver, -) -> (Sender, Receiver) { - ( - Sender { - inner: sender, - _pd: PhantomData, - }, - Receiver { - inner: receiver, - buffer: [0; 1024], - _pd: PhantomData, - }, - ) -} - -#[cfg(target_os = "yggdrasil")] -pub fn listen( - name: &str, -) -> Result<(Sender, Receiver), Error> { - let (sender, receiver) = sys::create_channel(name)?; - Ok(wrap(sender, receiver)) -} - -#[cfg(target_os = "yggdrasil")] -pub fn connect( - name: &str, -) -> Result<(Sender, Receiver), Error> { - let (sender, receiver) = sys::create_channel(name)?; - Ok(wrap(sender, receiver)) -} - -#[cfg(any(unix, rust_analyzer))] -pub fn listen>( - path: P, -) -> Result<(Sender, Receiver), Error> { - let (sender, receiver) = sys::listen(path)?; - Ok(wrap(sender, receiver)) -} - -#[cfg(any(unix, rust_analyzer))] -pub fn connect>( - path: P, -) -> Result<(Sender, Receiver), Error> { - let (sender, receiver) = sys::connect(path)?; - Ok(wrap(sender, receiver)) -} - -impl Sender { - pub fn send_to(&self, message: &T, peer: &PeerAddr) -> Result<(), Error> { - let message = postcard::to_allocvec(message).map_err(Error::Serialize)?; - self.inner - .send_message_to(&message, peer) - .map_err(Error::Io) - } - - #[inline] - pub fn send_to_host(&self, message: &T) -> Result<(), Error> { - self.send_to(message, self.inner.host_addr()) - } - - pub fn send_file_to(&self, file: &F, peer: &PeerAddr) -> Result<(), Error> { - self.inner.send_file_to(file, peer).map_err(Error::Io) - } -} - -impl AsRawFd for Sender { - fn as_raw_fd(&self) -> RawFd { - self.inner.as_raw_fd() - } -} - -impl Receiver { - pub fn receive(&mut self) -> Result<(PeerAddr, Either), Error> { - let (peer, message) = self.inner.receive(&mut self.buffer)?; - let message = message - .try_map_left(|len| postcard::from_bytes(&self.buffer[..len])) - .map_err(Error::Serialize)?; - Ok((peer, message)) - } - - pub fn receive_message(&mut self) -> Result<(PeerAddr, U), Error> { - loop { - let (peer, message) = self.receive()?; - - if let Either::Left(message) = message { - break Ok((peer, message)); - } - } - } - - pub fn receive_file(&mut self) -> Result<(PeerAddr, OwnedFd), Error> { - loop { - let (peer, message) = self.receive()?; - - if let Either::Right(fd) = message { - break Ok((peer, fd)); - } - } - } -} - -impl AsRawFd for Receiver { - fn as_raw_fd(&self) -> RawFd { - self.inner.as_raw_fd() - } -} diff --git a/userspace/lib/serde-ipc/src/sys/mod.rs b/userspace/lib/serde-ipc/src/sys/mod.rs deleted file mode 100644 index 1928130d..00000000 --- a/userspace/lib/serde-ipc/src/sys/mod.rs +++ /dev/null @@ -1,36 +0,0 @@ -use std::{io, os::fd::{AsRawFd, OwnedFd}}; - -#[cfg(target_os = "yggdrasil")] -pub mod yggdrasil; -#[cfg(target_os = "yggdrasil")] -pub use yggdrasil::*; - -#[cfg(any(unix, rust_analyzer))] -pub mod unix; -#[cfg(unix)] -pub use unix::*; - -pub enum Either { - Left(T), - Right(U) -} - -pub trait IpcSender: AsRawFd { - fn send_message_to(&self, message: &[u8], peer: &PeerAddr) -> Result<(), io::Error>; - fn send_file_to(&self, file: &F, peer: &PeerAddr) -> Result<(), io::Error>; - - fn host_addr(&self) -> &PeerAddr; -} - -pub trait IpcReceiver: AsRawFd { - fn receive(&self, buffer: &mut [u8]) -> Result<(PeerAddr, Either), io::Error>; -} - -impl Either { - pub fn try_map_left Result>(self, map: F) -> Result, E> { - match self { - Self::Left(val) => map(val).map(Either::Left), - Self::Right(val) => Ok(Either::Right(val)) - } - } -} diff --git a/userspace/lib/serde-ipc/src/sys/unix.rs b/userspace/lib/serde-ipc/src/sys/unix.rs deleted file mode 100644 index 0276fd37..00000000 --- a/userspace/lib/serde-ipc/src/sys/unix.rs +++ /dev/null @@ -1,210 +0,0 @@ -use std::{ - io::{self, IoSlice, IoSliceMut}, - os::{ - fd::{AsRawFd, FromRawFd, OwnedFd, RawFd}, - unix::net::{AncillaryData, SocketAddr, SocketAncillary, UnixDatagram}, - }, - path::Path, - sync::Arc, -}; - -use tempfile::{tempdir, NamedTempFile, TempDir, TempPath}; - -use crate::Either; - -use super::{IpcReceiver, IpcSender}; - -#[derive(Debug, Clone)] -pub struct PeerAddr(SocketAddr); - -struct Inner { - socket: UnixDatagram, - listener_addr: PeerAddr, - client_addr: Option, -} - -pub struct RawSender { - inner: Arc, -} - -pub struct RawReceiver { - inner: Arc, -} - -impl AsRawFd for Inner { - fn as_raw_fd(&self) -> RawFd { - self.socket.as_raw_fd() - } -} - -impl IpcSender for RawSender { - fn send_message_to(&self, message: &[u8], peer: &PeerAddr) -> Result<(), io::Error> { - self.inner.socket.send_to_addr(message, &peer.0).map(|_| ()) - } - - fn send_file_to(&self, file: &F, peer: &PeerAddr) -> Result<(), io::Error> { - let peer = peer.0.as_pathname().expect("Peer address is not a path"); - let mut ancillary_buffer = [0; 128]; - let mut ancillary = SocketAncillary::new(&mut ancillary_buffer); - - ancillary.add_fds(&[file.as_raw_fd()]); - - self.inner.socket.send_vectored_with_ancillary_to(&[], &mut ancillary, peer).map(|_| ()) - } - - fn host_addr(&self) -> &PeerAddr { - &self.inner.listener_addr - } -} - -impl AsRawFd for RawReceiver { - fn as_raw_fd(&self) -> RawFd { - self.inner.as_raw_fd() - } -} - -impl IpcReceiver for RawReceiver { - fn receive(&self, buffer: &mut [u8]) -> Result<(PeerAddr, Either), io::Error> { - let mut ancillary_buffer = [0; 128]; - let mut ancillary = SocketAncillary::new(&mut ancillary_buffer); - - let (len, truncated, addr) = self - .inner - .socket - .recv_vectored_with_ancillary_from(&mut [IoSliceMut::new(buffer)], &mut ancillary)?; - let peer = PeerAddr(addr); - - for message in ancillary.messages() { - if let Ok(AncillaryData::ScmRights(mut rights)) = message { - if let Some(fd) = rights.next() { - return Ok((peer, Either::Right(unsafe { OwnedFd::from_raw_fd(fd) }))); - } - } - } - - assert_ne!(len, 0); - Ok((peer, Either::Left(len))) - } -} - -impl AsRawFd for RawSender { - fn as_raw_fd(&self) -> RawFd { - self.inner.as_raw_fd() - } -} - -pub fn listen>(path: P) -> Result<(RawSender, RawReceiver), io::Error> { - let socket = UnixDatagram::bind(&path)?; - let listener_addr = PeerAddr(socket.local_addr()?); - let inner = Arc::new(Inner { - client_addr: None, - socket, - listener_addr, - }); - - let sender = RawSender { - inner: inner.clone(), - }; - let receiver = RawReceiver { inner }; - Ok((sender, receiver)) -} - -pub fn connect>(path: P) -> Result<(RawSender, RawReceiver), io::Error> { - let temp_dir = tempdir()?; - let client_addr = temp_dir.path().join("socket"); - let socket = UnixDatagram::bind(&client_addr)?; - socket.connect(&path)?; - let listener_addr = PeerAddr(socket.peer_addr()?); - - let inner = Arc::new(Inner { - client_addr: Some(temp_dir), - socket, - listener_addr, - }); - let sender = RawSender { - inner: inner.clone(), - }; - let receiver = RawReceiver { inner }; - Ok((sender, receiver)) -} - -#[cfg(test)] -mod tests { - use std::{fs::File, io::{Read, Write}, os::{fd::{AsRawFd, FromRawFd}, unix::net::SocketAddr}}; - - use tempfile::{tempdir, NamedTempFile}; - - use crate::{sys::{IpcReceiver, IpcSender}, Either}; - - use super::{connect, listen, PeerAddr}; - - #[test] - fn peer_addr() { - let temp_dir = tempdir().unwrap(); - let listen_path = temp_dir.path().join("listener"); - let (lsender, _) = listen(&listen_path).unwrap(); - let (csender, _) = connect(listen_path).unwrap(); - - let PeerAddr(l) = lsender.host_addr(); - let PeerAddr(c) = csender.host_addr(); - - let lp = l.as_pathname().unwrap(); - let cp = c.as_pathname().unwrap(); - - assert_eq!(lp, cp); - } - - #[test] - fn receive_message() { - let temp_dir = tempdir().unwrap(); - let listen_path = temp_dir.path().join("listener"); - let (_, lreceiver) = listen(&listen_path).unwrap(); - let (csender, _) = connect(listen_path).unwrap(); - - let msg = b"Hello"; - csender.send_message_to(msg, csender.host_addr()).unwrap(); - let mut buffer = [0; 512]; - let (_, message) = lreceiver.receive(&mut buffer).unwrap(); - let Either::Left(len) = message else { - panic!(); - }; - - assert_eq!(len, msg.len()); - assert_eq!(&buffer[..len], msg); - } - - #[test] - fn receive_file() { - let text = b"Hello"; - - let temp_dir = tempdir().unwrap(); - let temp_file = temp_dir.path().join("testfile"); - - { - let mut file = File::create(&temp_file).unwrap(); - file.write_all(text).unwrap(); - } - - let listen_path = temp_dir.path().join("listener"); - let (_, lreceiver) = listen(&listen_path).unwrap(); - let (csender, _) = connect(listen_path).unwrap(); - - { - let file = File::open(&temp_file).unwrap(); - csender.send_file_to(&file, csender.host_addr()).unwrap(); - } - - { - let mut buffer = [0; 512]; - let (_, message) = lreceiver.receive(&mut buffer).unwrap(); - let Either::Right(fd) = message else { - panic!(); - }; - - let mut file = unsafe { File::from_raw_fd(fd.as_raw_fd()) }; - let len = file.read(&mut buffer).unwrap(); - assert_eq!(len, text.len()); - assert_eq!(&buffer[..len], text); - } - } -} diff --git a/userspace/lib/serde-ipc/src/sys/yggdrasil.rs b/userspace/lib/serde-ipc/src/sys/yggdrasil.rs deleted file mode 100644 index dd1057a0..00000000 --- a/userspace/lib/serde-ipc/src/sys/yggdrasil.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::{ - io, - os::{ - fd::{AsRawFd, FromRawFd, OwnedFd, RawFd}, - yggdrasil::io::message_channel::{ - ChannelPublisherId, MessageChannel, MessageChannelReceiver, MessageChannelSender, - MessageDestination, MessageReceiver, MessageSender, ReceivedMessageMetadata, - }, - }, -}; - -use super::{Either, IpcReceiver, IpcSender}; - -#[derive(Debug, Clone)] -pub struct PeerAddr(ChannelPublisherId); - -pub struct RawSender(MessageChannelSender); -pub struct RawReceiver(MessageChannelReceiver); - -const HOST_ADDR: PeerAddr = PeerAddr(ChannelPublisherId::ZERO); - -impl IpcSender for RawSender { - fn send_file_to(&self, file: &F, peer: &PeerAddr) -> Result<(), io::Error> { - self.0.send_raw_fd( - file.as_raw_fd(), - MessageDestination::Specific(peer.0.into()), - ) - } - - fn send_message_to(&self, message: &[u8], peer: &PeerAddr) -> Result<(), io::Error> { - self.0 - .send_message(message, MessageDestination::Specific(peer.0.into())) - } - - fn host_addr(&self) -> &PeerAddr { - // TODO - &HOST_ADDR - } -} - -impl AsRawFd for RawSender { - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} - -impl IpcReceiver for RawReceiver { - fn receive(&self, buffer: &mut [u8]) -> Result<(PeerAddr, Either), io::Error> { - let (addr, metadata) = self.0.receive_raw(buffer)?; - let peer = PeerAddr(addr); - - match metadata { - ReceivedMessageMetadata::File(fd) => { - Ok((peer, Either::Right(unsafe { OwnedFd::from_raw_fd(fd) }))) - } - ReceivedMessageMetadata::Data(len) => Ok((peer, Either::Left(len))), - } - } -} - -impl AsRawFd for RawReceiver { - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} - -pub fn create_channel(name: &str) -> Result<(RawSender, RawReceiver), io::Error> { - let channel = MessageChannel::open(name, true)?; - let (sender, receiver) = channel.split(); - Ok((RawSender(sender), RawReceiver(receiver))) -} diff --git a/userspace/lib/uipc/Cargo.toml b/userspace/lib/uipc/Cargo.toml new file mode 100644 index 00000000..f1825bcd --- /dev/null +++ b/userspace/lib/uipc/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "uipc" +version = "0.1.0" +edition = "2021" + +[dependencies] +cross.workspace = true + +postcard.workspace = true +serde.workspace = true +thiserror.workspace = true + +[lints] +workspace = true diff --git a/userspace/lib/uipc/src/lib.rs b/userspace/lib/uipc/src/lib.rs new file mode 100644 index 00000000..b86a8233 --- /dev/null +++ b/userspace/lib/uipc/src/lib.rs @@ -0,0 +1,149 @@ +#![cfg_attr(target_os = "yggdrasil", feature(yggdrasil_os))] + +use std::{ + io, + marker::PhantomData, + ops::Deref, + os::fd::{AsRawFd, OwnedFd, RawFd}, + path::Path, + sync::Arc, +}; + +use cross::net::{LocalPacketSocket, OwnedLocalAddress}; +use serde::{de::DeserializeOwned, Serialize}; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("{0}")] + Io(#[from] io::Error), + #[error("{0}")] + Serde(#[from] postcard::Error), +} + +pub struct Channel(LocalPacketSocket); + +pub struct Sender { + channel: Arc, + _pd: PhantomData, +} + +pub struct Receiver { + channel: Arc, + buffer: [u8; 4096], + _pd: PhantomData, +} + +#[repr(transparent)] +#[derive(Debug, Clone)] +pub struct PeerAddress(OwnedLocalAddress); + +impl Channel { + pub fn connect>(path: P) -> Result { + let socket = LocalPacketSocket::connect(path)?; + Ok(Self(socket)) + } + + pub fn bind>(path: P) -> Result { + let socket = LocalPacketSocket::bind(path)?; + Ok(Self(socket)) + } + + pub fn split(self) -> (Sender, Receiver) { + let this = Arc::new(self); + let sender = Sender { + channel: this.clone(), + _pd: PhantomData, + }; + let receiver = Receiver { + channel: this, + buffer: [0; 4096], + _pd: PhantomData, + }; + (sender, receiver) + } +} + +impl Deref for Channel { + type Target = LocalPacketSocket; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Sender { + pub fn send(&self, message: &T) -> Result { + let mut buffer = [0; 512]; + let payload = postcard::to_slice(message, &mut buffer)?; + let len = self.channel.send(payload)?; + Ok(len) + } + + pub fn send_with_file(&self, message: &T, file: &F) -> Result { + let mut buffer = [0; 512]; + let ancillary = file.as_raw_fd(); + let payload = postcard::to_slice(message, &mut buffer)?; + let len = self.channel.send_with_ancillary(payload, ancillary)?; + Ok(len) + } + + pub fn send_to(&self, message: &T, destination: &PeerAddress) -> Result { + let mut buffer = [0; 512]; + let payload = postcard::to_slice(message, &mut buffer)?; + let len = self.channel.send_to(payload, &destination.0)?; + Ok(len) + } + + pub fn send_with_file_to( + &self, + message: &T, + file: &F, + destination: &PeerAddress, + ) -> Result { + let mut buffer = [0; 512]; + let ancillary = file.as_raw_fd(); + let payload = postcard::to_slice(message, &mut buffer)?; + let len = self + .channel + .send_with_ancillary_to(payload, ancillary, &destination.0)?; + Ok(len) + } +} + +impl AsRawFd for Sender { + fn as_raw_fd(&self) -> RawFd { + self.channel.as_raw_fd() + } +} + +impl Receiver { + pub fn receive(&mut self) -> Result { + let len = self.channel.receive(&mut self.buffer)?; + let message = postcard::from_bytes(&self.buffer[..len])?; + Ok(message) + } + + pub fn receive_with_file(&mut self) -> Result<(T, Option), Error> { + let (len, fd) = self.channel.receive_with_ancillary(&mut self.buffer)?; + let message = postcard::from_bytes(&self.buffer[..len])?; + Ok((message, fd)) + } + + pub fn receive_from(&mut self) -> Result<(T, PeerAddress), Error> { + let (len, address) = self.channel.receive_from(&mut self.buffer)?; + let message = postcard::from_bytes(&self.buffer[..len])?; + Ok((message, PeerAddress(address))) + } + + pub fn receive_with_file_from(&mut self) -> Result<(T, Option, PeerAddress), Error> { + let (len, fd, address) = self.channel.receive_with_ancillary_from(&mut self.buffer)?; + let message = postcard::from_bytes(&self.buffer[..len])?; + Ok((message, fd, PeerAddress(address))) + } +} + +impl AsRawFd for Receiver { + fn as_raw_fd(&self) -> RawFd { + self.channel.as_raw_fd() + } +} diff --git a/userspace/netutils/Cargo.toml b/userspace/netutils/Cargo.toml index aa208b2e..8377f401 100644 --- a/userspace/netutils/Cargo.toml +++ b/userspace/netutils/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] log.workspace = true yggdrasil-abi.workspace = true +runtime.workspace = true bytemuck.workspace = true serde_json.workspace = true serde.workspace = true diff --git a/userspace/netutils/src/dhcp_client.rs b/userspace/netutils/src/dhcp_client.rs index 71d0c268..50086abd 100644 --- a/userspace/netutils/src/dhcp_client.rs +++ b/userspace/netutils/src/dhcp_client.rs @@ -1,18 +1,23 @@ -#![feature(yggdrasil_os)] +#![feature(yggdrasil_os, rustc_private)] -use std::os::{ - fd::AsRawFd, - yggdrasil::io::{poll::PollChannel, net::raw_socket::RawSocket, timer::TimerFd}, -}; +use std::net::IpAddr; use std::{io, mem::size_of, process::ExitCode, time::Duration}; +use std::{ + net::Ipv4Addr, + os::{ + fd::AsRawFd, + yggdrasil::io::{net::raw_socket::RawSocket, poll::PollChannel, timer::TimerFd}, + }, +}; use bytemuck::{Pod, Zeroable}; use netutils::{netconfig::NetConfig, proto::parse_udp_protocol, Error}; -use yggdrasil_abi::net::protocols::{ - EtherType, EthernetFrame, InetChecksum, IpProtocol, Ipv4Frame, UdpFrame, -}; +use runtime::abi::net::{SubnetAddr, SubnetV4Addr}; use yggdrasil_abi::net::types::NetValueImpl; -use yggdrasil_abi::net::{IpAddr, Ipv4Addr, MacAddress, SubnetAddr, SubnetV4Addr}; +use yggdrasil_abi::net::{ + protocols::{EtherType, EthernetFrame, InetChecksum, IpProtocol, Ipv4Frame, UdpFrame}, + MacAddress, +}; #[derive(Clone, Copy, Debug, Pod, Zeroable)] #[repr(C, packed)] diff --git a/userspace/netutils/src/dnsq.rs b/userspace/netutils/src/dnsq.rs index db4b69d9..7eb2de81 100644 --- a/userspace/netutils/src/dnsq.rs +++ b/userspace/netutils/src/dnsq.rs @@ -79,7 +79,7 @@ fn handle_query( match (answer.ty, answer.class, answer.rdata) { (DnsType::A, DnsClass::IN, DnsRecordData::A(ip)) => { debug_trace!("Resolved: {} -> {}", name, ip); - a_cache.insert(name, ip.into()); + a_cache.insert(name, ip); } _ => (), } @@ -114,7 +114,7 @@ fn run_server(addr: SocketAddr, nameservers: &[SocketAddr]) -> Result<(), Error> .filter_map(|q| q.name.0.as_deref().map(|name| (name, q.ty, q.class))) { match handle_query(nameservers, &mut a_cache, ty, class, name) { - Ok(ip) => answers.push((name.to_owned(), ip.into())), + Ok(ip) => answers.push((name.to_owned(), ip)), Err(_) => { continue; } diff --git a/userspace/netutils/src/lib.rs b/userspace/netutils/src/lib.rs index 60e063e9..98e359a4 100644 --- a/userspace/netutils/src/lib.rs +++ b/userspace/netutils/src/lib.rs @@ -13,6 +13,8 @@ pub enum Error { IoError(#[from] io::Error), #[error("NetConfig returned error: {0}")] NetConfError(Box), + #[error("{0:?}")] + RtError(std::os::yggdrasil::rt::Error), #[error("Serialize/deserialize error: {0}")] SerializeError(#[from] serde_json::Error), #[error("Timed out")] diff --git a/userspace/netutils/src/netconf.rs b/userspace/netutils/src/netconf.rs index 67fa66f7..c90a3256 100644 --- a/userspace/netutils/src/netconf.rs +++ b/userspace/netutils/src/netconf.rs @@ -1,8 +1,12 @@ +#![feature(rustc_private)] use std::{net::IpAddr, process::ExitCode, str::FromStr}; use clap::{Args, Parser, Subcommand}; use netutils::{netconfig::NetConfig, Error}; -use yggdrasil_abi::net::netconfig::{InterfaceInfo, InterfaceQuery, NetConfigRequest, RouteInfo}; +use runtime::abi::net::{ + self, + netconfig::{InterfaceInfo, RouteInfo}, +}; #[derive(Debug, Parser)] #[clap(author, version, about, long_about = None)] @@ -101,14 +105,13 @@ pub enum LinkCommands { } #[derive(Clone, Debug)] -pub struct SubnetAddr(yggdrasil_abi::net::SubnetAddr); +pub struct SubnetAddr(net::SubnetAddr); impl FromStr for SubnetAddr { type Err = &'static str; fn from_str(s: &str) -> Result { - let inner = - yggdrasil_abi::net::SubnetAddr::from_str(s).map_err(|_| "Invalid subnet format")?; + let inner = net::SubnetAddr::from_str(s).map_err(|_| "Invalid subnet format")?; Ok(Self(inner)) } } @@ -116,8 +119,7 @@ impl FromStr for SubnetAddr { pub fn run_route_action(nc: &mut NetConfig, action: RouteCommands) -> Result<(), Error> { match action { RouteCommands::List { interface: None } => { - let list = nc.request::>(&NetConfigRequest::ListRoutes)?; - + let list = nc.list_routes()?; for route in list { print_route_info(&route); } @@ -127,9 +129,7 @@ pub fn run_route_action(nc: &mut NetConfig, action: RouteCommands) -> Result<(), RouteCommands::List { interface: Some(interface), } => { - let list = nc.request::>(&NetConfigRequest::DescribeRoutes( - InterfaceQuery::ByName(interface.into_boxed_str()), - ))?; + let list = nc.describe_routes(&*interface)?; for route in list { print_route_info(&route); @@ -141,41 +141,31 @@ pub fn run_route_action(nc: &mut NetConfig, action: RouteCommands) -> Result<(), interface, subnet, gateway, - } => nc.request::<()>(&NetConfigRequest::AddRoute { - interface: InterfaceQuery::ByName(interface.into_boxed_str()), - gateway: gateway.map(Into::into), - subnet: subnet.0, - }), + } => nc.add_route(&*interface, subnet.0, gateway.map(Into::into)), } } pub fn run_addr_action(nc: &mut NetConfig, action: AddrCommands) -> Result<(), Error> { match action { AddrCommands::List => { - let list = nc.request::, u32)>>(&NetConfigRequest::ListInterfaces)?; - - for (name, id) in list { - let info = match nc.request::(&NetConfigRequest::DescribeInterface( - InterfaceQuery::ById(id), - )) { + for binding in nc.list_interfaces()? { + let info = match nc.describe_interface(binding.id) { Ok(info) => info, Err(error) => { - eprintln!("{}: {}", name, error); + eprintln!("{}: {error}", binding.name); continue; } }; if let Some(address) = info.address { - println!("{}: {}", name, address); + println!("{}: {address}", binding.name); } } Ok(()) } AddrCommands::Get { interface } => { - let info = nc.request::(&NetConfigRequest::DescribeInterface( - InterfaceQuery::ByName(interface.into_boxed_str()), - ))?; + let info = nc.describe_interface(&*interface)?; if let Some(address) = info.address { println!("{}", address); @@ -185,27 +175,20 @@ pub fn run_addr_action(nc: &mut NetConfig, action: AddrCommands) -> Result<(), E Ok(()) } - AddrCommands::Set { interface, address } => { - nc.request::<()>(&NetConfigRequest::SetNetworkAddress { - interface: InterfaceQuery::ByName(interface.into_boxed_str()), - address: address.into(), - }) - } + AddrCommands::Set { interface, address } => nc.set_interface_address(&*interface, address), } } pub fn run_link_action(nc: &mut NetConfig, action: LinkCommands) -> Result<(), Error> { match action { LinkCommands::List => { - let list = nc.request::, u32)>>(&NetConfigRequest::ListInterfaces)?; + let list = nc.list_interfaces()?; - for (name, id) in list { - let info = match nc.request::(&NetConfigRequest::DescribeInterface( - InterfaceQuery::ById(id), - )) { + for binding in list { + let info = match nc.describe_interface(binding.id) { Ok(info) => info, Err(error) => { - eprintln!("{}: {}", name, error); + eprintln!("{}: {error}", binding.name); continue; } }; @@ -216,18 +199,14 @@ pub fn run_link_action(nc: &mut NetConfig, action: LinkCommands) -> Result<(), E Ok(()) } LinkCommands::Show { interface } => { - let info = nc.request::(&NetConfigRequest::DescribeInterface( - InterfaceQuery::ByName(interface.into_boxed_str()), - ))?; + let info = nc.describe_interface(&*interface)?; print_interface_info(&info); Ok(()) } LinkCommands::GetMac { interface } => { - let info = nc.request::(&NetConfigRequest::DescribeInterface( - InterfaceQuery::ByName(interface.into_boxed_str()), - ))?; + let info = nc.describe_interface(&*interface)?; println!("{}", info.mac); diff --git a/userspace/netutils/src/netconfig.rs b/userspace/netutils/src/netconfig.rs index 4caefd63..9eb54126 100644 --- a/userspace/netutils/src/netconfig.rs +++ b/userspace/netutils/src/netconfig.rs @@ -1,91 +1,129 @@ -use std::os::yggdrasil::io::message_channel::{ - MessageChannel, MessageChannelReceiver, MessageChannelSender, MessageDestination, - MessageReceiver, MessageSender, -}; - -use serde::Deserialize; -use yggdrasil_abi::net::{ - netconfig::{InterfaceQuery, NetConfigRequest, NetConfigResult, RoutingInfo}, - IpAddr, MacAddress, SubnetAddr, -}; - use crate::Error; +use std::{ + net::IpAddr, + os::fd::{AsRawFd, FromRawFd, OwnedFd}, +}; + +use runtime::{ + abi::net::{self, netconfig}, + abi_serde::{wire, Deserialize}, + rt, +}; + pub struct NetConfig { - sender: MessageChannelSender, - receiver: MessageChannelReceiver, + socket: OwnedFd, buffer: [u8; 4096], } impl NetConfig { pub fn open() -> Result { - let channel = MessageChannel::open("@kernel-netconf", true)?; - let (sender, receiver) = channel.split(); + let raw = unsafe { rt::sys::create_socket(rt::abi::net::SocketType::NetConfig) } + .map_err(Error::RtError)?; + let fd = unsafe { OwnedFd::from_raw_fd(raw) }; Ok(Self { - sender, - receiver, + socket: fd, buffer: [0; 4096], }) } - pub fn send(&mut self, request: &NetConfigRequest) -> Result<(), Error> { - let bytes = serde_json::to_vec(&request)?; - self.sender - .send_message(&bytes, MessageDestination::Specific(0))?; + fn send_inner(&mut self, request: &netconfig::NetConfigRequest) -> Result<(), rt::Error> { + let len = wire::to_slice(request, &mut self.buffer)?; + rt::net::socket::send(self.socket.as_raw_fd(), &self.buffer[..len])?; Ok(()) } + fn receive_inner<'de, T: Deserialize<'de>>( + &'de mut self, + ) -> Result, rt::Error> { + let len = rt::net::socket::receive(self.socket.as_raw_fd(), &mut self.buffer)?; + let value = wire::from_slice(&self.buffer[..len]).unwrap(); + Ok(value) + } + + pub fn send(&mut self, request: &netconfig::NetConfigRequest) -> Result<(), Error> { + self.send_inner(request).map_err(Error::RtError) + } + pub fn request<'de, T: Deserialize<'de>>( &'de mut self, - request: &NetConfigRequest, + request: &netconfig::NetConfigRequest, ) -> Result { self.send(request)?; - let (_sender, len) = self.receiver.receive_message(&mut self.buffer)?; - let msg: NetConfigResult = serde_json::from_slice(&self.buffer[..len])?; - match msg { - NetConfigResult::Ok(value) => Ok(value), - NetConfigResult::Err(error) => Err(Error::NetConfError(error)), + match self.receive_inner().map_err(Error::RtError)? { + netconfig::NetConfigResult::Ok(value) => Ok(value), + netconfig::NetConfigResult::Err(error) => Err(Error::NetConfError(error.into())), } } - pub fn query_route(&mut self, address: IpAddr) -> Result { - self.request(&NetConfigRequest::QueryRoute(address)) + pub fn query_route(&mut self, address: IpAddr) -> Result { + self.request(&netconfig::NetConfigRequest::QueryRoute(address)) } - pub fn query_arp( + pub fn query_arp<'a, Q: Into>>( &mut self, - interface_id: u32, + query: Q, address: IpAddr, - perform_query: bool, - ) -> Result { - self.request(&NetConfigRequest::QueryArp( - interface_id, - address, - perform_query, + cache_only: bool, + ) -> Result { + self.request(&netconfig::NetConfigRequest::ArpQuery( + netconfig::ArpQueryRequest { + interface: query.into(), + address, + cache_only, + }, )) } - pub fn set_interface_address>( - &mut self, - interface: Q, - address: IpAddr, - ) -> Result<(), Error> { - self.request(&NetConfigRequest::SetNetworkAddress { - interface: interface.into(), - address, - }) + pub fn list_interfaces(&mut self) -> Result, Error> { + self.request(&netconfig::NetConfigRequest::ListInterfaces(())) } - pub fn add_route>( + pub fn describe_interface<'a, Q: Into>>( &mut self, - interface: Q, - subnet: SubnetAddr, + query: Q, + ) -> Result { + self.request(&netconfig::NetConfigRequest::DescribeInterface( + query.into(), + )) + } + + pub fn list_routes(&mut self) -> Result, Error> { + self.request(&netconfig::NetConfigRequest::ListRoutes(())) + } + + pub fn describe_routes<'a, Q: Into>>( + &mut self, + query: Q, + ) -> Result, Error> { + self.request(&netconfig::NetConfigRequest::DescribeRoutes(query.into())) + } + + pub fn set_interface_address<'a, Q: Into>>( + &mut self, + query: Q, + address: IpAddr, + ) -> Result<(), Error> { + self.request(&netconfig::NetConfigRequest::SetNetworkAddress( + netconfig::SetNetworkAddressRequest { + interface: query.into(), + address, + }, + )) + } + + pub fn add_route<'a, Q: Into>>( + &mut self, + query: Q, + subnet: net::SubnetAddr, gateway: Option, ) -> Result<(), Error> { - self.request(&NetConfigRequest::AddRoute { - interface: interface.into(), - gateway, - subnet, - }) + self.request(&netconfig::NetConfigRequest::AddRoute( + netconfig::AddRouteRequest { + interface: query.into(), + gateway, + subnet, + }, + )) } } diff --git a/userspace/netutils/src/ping.rs b/userspace/netutils/src/ping.rs index 531e423e..9e027b17 100644 --- a/userspace/netutils/src/ping.rs +++ b/userspace/netutils/src/ping.rs @@ -1,23 +1,19 @@ #![feature(yggdrasil_os, rustc_private)] use std::{ - mem::size_of, - os::{ + mem::size_of, net::{IpAddr, Ipv4Addr}, os::{ fd::AsRawFd, - yggdrasil::io::{poll::PollChannel, net::raw_socket::RawSocket, timer::TimerFd}, - }, - process::ExitCode, - sync::atomic::{AtomicBool, Ordering}, - time::Duration, + yggdrasil::io::{net::raw_socket::RawSocket, poll::PollChannel, timer::TimerFd}, + }, process::ExitCode, sync::atomic::{AtomicBool, Ordering}, time::Duration }; use bytemuck::Zeroable; use clap::Parser; use netutils::{netconfig::NetConfig, Error}; +use runtime::abi::net::MacAddress; use yggdrasil_abi::net::{ protocols::{EtherType, EthernetFrame, IcmpV4Frame, InetChecksum, IpProtocol, Ipv4Frame}, types::NetValueImpl, - IpAddr, Ipv4Addr, MacAddress, }; #[derive(Parser)] @@ -193,8 +189,14 @@ fn ping_once( ) -> Result { let mut buffer = [0; 4096]; - let source_ip = info.source_ip.into_ipv4().unwrap(); - let destination_ip = info.destination_ip.into_ipv4().unwrap(); + let source_ip = match info.source_ip { + IpAddr::V4(v4) => v4, + IpAddr::V6(_) => todo!(), + }; + let destination_ip = match info.destination_ip { + IpAddr::V4(v4) => v4, + IpAddr::V6(_) => todo!(), + }; let mut l4_data = Vec::with_capacity(data_len); for _ in 0..data_len { @@ -206,8 +208,8 @@ fn ping_once( .unwrap(); let l2_frame = EthernetFrame { - source_mac: info.source_mac, - destination_mac: info.gateway_mac, + source_mac: (info.source_mac.octets()).into(), + destination_mac: (info.gateway_mac.octets()).into(), ethertype: EtherType::IPV4.to_network_order(), }; let mut l3_frame = Ipv4Frame { @@ -324,7 +326,7 @@ fn main() -> ExitCode { let args = Args::parse(); let stats = match ping( - args.address.into(), + args.address, args.count, args.data_size, Duration::from_millis(args.inteval.into()), diff --git a/userspace/rdb/src/main.rs b/userspace/rdb/src/main.rs index 2cb390e7..6e14af7d 100644 --- a/userspace/rdb/src/main.rs +++ b/userspace/rdb/src/main.rs @@ -1,66 +1,68 @@ #![feature(yggdrasil_os, if_let_guard)] -use std::{fmt::{LowerHex, Display}, io, path::PathBuf, process::Command}; -use clap::Parser; -use debugger::{Debugger, SymbolResolver}; -use imp::TargetImpl; -use yggdrasil_abi::arch::SavedFrame; - -#[cfg(any(target_arch = "x86_64", target_arch = "x86", rust_analyzer))] -#[path = "x86.rs"] -pub mod imp; -#[cfg(any(target_arch = "aarch64", rust_analyzer))] -#[path = "aarch64.rs"] -pub mod imp; - -pub mod comm; -pub mod state; - -pub mod debugger; - -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error("I/O error: {0}")] - IoError(#[from] io::Error), - #[error("Terminal error: {0}")] - TermError(#[from] libterm::Error), - #[error("Debug control error: {0:?}")] - DebugError(yggdrasil_rt::Error), - #[error("Invalid address: {0:?}")] - InvalidAddress(String) -} - -pub trait Target { - type Instruction; - type InstructionFormatter: InstructionFormatter; - type Register: LowerHex; - - fn disassemble( - window: &[u8], - ip: usize, - limit: usize, - ) -> Result, Error>; - fn new_instruction_formatter(resolver: SymbolResolver) -> Self::InstructionFormatter; - - fn register_list(frame: &SavedFrame, out: &mut Vec<(String, Self::Register)>); - fn flags_register_as_display(frame: &SavedFrame) -> impl Display; - fn real_ip(frame: &SavedFrame) -> usize; -} - -pub trait InstructionFormatter { - fn format_instruction(&mut self, insn: &I, out: &mut String); -} - -#[derive(Parser)] -struct Args { - program: PathBuf, -} - -fn main() { - let args = Args::parse(); - - let command = Command::new(&args.program); - let debug: Debugger = Debugger::from_command(&args.program, command).unwrap(); - - debug.run().unwrap(); -} +fn main() {} +// use std::{fmt::{LowerHex, Display}, io, path::PathBuf, process::Command}; +// +// use clap::Parser; +// use debugger::{Debugger, SymbolResolver}; +// use imp::TargetImpl; +// use yggdrasil_abi::arch::SavedFrame; +// +// #[cfg(any(target_arch = "x86_64", target_arch = "x86", rust_analyzer))] +// #[path = "x86.rs"] +// pub mod imp; +// #[cfg(any(target_arch = "aarch64", rust_analyzer))] +// #[path = "aarch64.rs"] +// pub mod imp; +// +// pub mod comm; +// pub mod state; +// +// pub mod debugger; +// +// #[derive(thiserror::Error, Debug)] +// pub enum Error { +// #[error("I/O error: {0}")] +// IoError(#[from] io::Error), +// #[error("Terminal error: {0}")] +// TermError(#[from] libterm::Error), +// #[error("Debug control error: {0:?}")] +// DebugError(yggdrasil_rt::Error), +// #[error("Invalid address: {0:?}")] +// InvalidAddress(String) +// } +// +// pub trait Target { +// type Instruction; +// type InstructionFormatter: InstructionFormatter; +// type Register: LowerHex; +// +// fn disassemble( +// window: &[u8], +// ip: usize, +// limit: usize, +// ) -> Result, Error>; +// fn new_instruction_formatter(resolver: SymbolResolver) -> Self::InstructionFormatter; +// +// fn register_list(frame: &SavedFrame, out: &mut Vec<(String, Self::Register)>); +// fn flags_register_as_display(frame: &SavedFrame) -> impl Display; +// fn real_ip(frame: &SavedFrame) -> usize; +// } +// +// pub trait InstructionFormatter { +// fn format_instruction(&mut self, insn: &I, out: &mut String); +// } +// +// #[derive(Parser)] +// struct Args { +// program: PathBuf, +// } +// +// fn main() { +// let args = Args::parse(); +// +// let command = Command::new(&args.program); +// let debug: Debugger = Debugger::from_command(&args.program, command).unwrap(); +// +// debug.run().unwrap(); +// } diff --git a/userspace/sysutils/Cargo.toml b/userspace/sysutils/Cargo.toml index 66ce9f07..232b9bc9 100644 --- a/userspace/sysutils/Cargo.toml +++ b/userspace/sysutils/Cargo.toml @@ -13,6 +13,7 @@ yggdrasil-abi.workspace = true yggdrasil-rt.workspace = true thiserror.workspace = true clap.workspace = true +cross.workspace = true serde.workspace = true serde_json.workspace = true sha2.workspace = true diff --git a/userspace/sysutils/src/lib.rs b/userspace/sysutils/src/lib.rs index 41693cc1..f0e60b8d 100644 --- a/userspace/sysutils/src/lib.rs +++ b/userspace/sysutils/src/lib.rs @@ -48,33 +48,33 @@ pub mod unix { } } -pub struct Syslog { - #[cfg(target_os = "yggdrasil")] - channel: std::os::yggdrasil::io::message_channel::MessageChannel, -} +// pub struct Syslog { +// #[cfg(target_os = "yggdrasil")] +// channel: std::os::yggdrasil::io::message_channel::MessageChannel, +// } // TODO replace this pub trait ToExitCode { fn to_exit_code(&self) -> i32; } -#[cfg(target_os = "yggdrasil")] -impl Syslog { - pub fn open() -> io::Result { - use std::os::yggdrasil::io::message_channel::MessageChannel; - - let channel = MessageChannel::open("log", false)?; - - Ok(Self { channel }) - } - - pub fn send_str(&mut self, msg: &str) -> io::Result<()> { - use std::os::yggdrasil::io::message_channel::{MessageDestination, MessageSender}; - - self.channel - .send_message(msg.as_bytes(), MessageDestination::Specific(0)) - } -} +// #[cfg(target_os = "yggdrasil")] +// impl Syslog { +// pub fn open() -> io::Result { +// use std::os::yggdrasil::io::message_channel::MessageChannel; +// +// let channel = MessageChannel::open("log", false)?; +// +// Ok(Self { channel }) +// } +// +// pub fn send_str(&mut self, msg: &str) -> io::Result<()> { +// use std::os::yggdrasil::io::message_channel::{MessageDestination, MessageSender}; +// +// self.channel +// .send_message(msg.as_bytes(), MessageDestination::Specific(0)) +// } +// } impl ToExitCode for io::Result { fn to_exit_code(&self) -> i32 { diff --git a/userspace/sysutils/src/logd.rs b/userspace/sysutils/src/logd.rs index f3351e19..922694e0 100644 --- a/userspace/sysutils/src/logd.rs +++ b/userspace/sysutils/src/logd.rs @@ -1,18 +1,18 @@ #![feature(yggdrasil_os)] -use std::os::yggdrasil::io::message_channel::{MessageChannel, MessageReceiver}; +//use std::os::yggdrasil::io::message_channel::{MessageChannel, MessageReceiver}; fn main() { - let channel = MessageChannel::open("log", true).unwrap(); - let mut buf = [0; 1024]; + // let channel = MessageChannel::open("log", true).unwrap(); + // let mut buf = [0; 1024]; - loop { - let Ok((_, len)) = channel.receive_message(&mut buf) else { - continue; - }; + // loop { + // let Ok((_, len)) = channel.receive_message(&mut buf) else { + // continue; + // }; - if let Ok(msg) = std::str::from_utf8(&buf[..len]) { - debug_trace!("log::message: {:?}", msg); - } - } + // if let Ok(msg) = std::str::from_utf8(&buf[..len]) { + // debug_trace!("log::message: {:?}", msg); + // } + // } } diff --git a/userspace/sysutils/src/service.rs b/userspace/sysutils/src/service.rs index 570db355..25675e33 100644 --- a/userspace/sysutils/src/service.rs +++ b/userspace/sysutils/src/service.rs @@ -1,12 +1,9 @@ #![feature(yggdrasil_os, rustc_private)] -use std::{ - io, - os::yggdrasil::io::message_channel::{MessageChannel, MessageDestination, MessageSender}, - process::ExitCode, -}; +use std::{io, path::Path, process::ExitCode}; use clap::{Parser, Subcommand}; +use cross::net::LocalPacketSocket; #[derive(Debug, Parser)] struct Args { @@ -21,10 +18,11 @@ enum Command { } fn send_message(msg: init::InitMsg) -> io::Result<()> { - let channel = MessageChannel::open("service-control", false)?; - let msg = serde_json::to_string(&msg).unwrap(); - - channel.send_message(msg.as_bytes(), MessageDestination::Specific(0)) + let path = Path::new("/init.sock"); + let socket = LocalPacketSocket::new()?; + let msg = serde_json::to_vec(&msg).unwrap(); + socket.send_to(&msg, path)?; + Ok(()) } fn run(command: Command) -> io::Result<()> {