net: remove MessageChannel, replace with local sockets

This commit is contained in:
Mark Poliakov 2025-01-16 18:06:00 +02:00
parent 0889e99049
commit 009f545cb3
97 changed files with 3459 additions and 1982 deletions

1
Cargo.lock generated
View File

@ -34,6 +34,7 @@ name = "abi-serde"
version = "0.1.0"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]

View File

@ -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<T: Serialize>(
@ -40,11 +41,12 @@ fn send_reply<T: Serialize>(
recepient: ChannelPublisherId,
message: NetConfigResult<T>,
) -> 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<str>, u32)> {
@ -55,73 +57,6 @@ fn list_interfaces() -> Vec<(Box<str>, 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<RoutingInfo> {
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<Arc<NetworkInterface>> {
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<IpAddr>,
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) => {}
}
}
}

View File

@ -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};

View File

@ -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<M
query(interface, ip, 5, Duration::from_millis(200)).await
}
pub fn lookup_nonblocking(
interface: u32,
ip: IpAddr,
perform_query: bool,
) -> Result<MacAddress, Error> {
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,

View File

@ -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<SocketAddr, Error> {
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");

View File

@ -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<Ipv4Frame, Error> {
// 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::<Ipv4Frame>())
.try_into()

View File

@ -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,
},
};

View File

@ -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::<TcpFrame>() + 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::<TcpFrame>() + data.len();
let pseudo_header = TcpV4PseudoHeader {

View File

@ -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,
},
};

View File

@ -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(())
}

View File

@ -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<Self> {
Arc::new(Self {
buffer: BoundedMpmcQueue::new(8),
})
}
fn write_response<T: Serialize>(&self, value: NetConfigResult<T>) -> 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<usize, Error> {
// 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::<MacAddress>::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::<MacAddress>::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<Self>, _local: &[u8]) -> Result<(), Error> {
Err(Error::InvalidOperation)
}
async fn connect(
self: Arc<Self>,
_remote: &[u8],
_timeout: Option<Duration>,
) -> Result<(), Error> {
Err(Error::InvalidOperation)
}
fn close(self: Arc<Self>) -> 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<usize, Error> {
let _ = option;
let _ = buffer;
Err(Error::InvalidOperation)
}
fn send_nonblocking(self: Arc<Self>, message: &MessageHeader) -> Result<usize, Error> {
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<Self>,
message: &MessageHeader,
_timeout: Option<Duration>,
) -> Result<usize, Error> {
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<Self>,
message: &mut MessageHeaderMut,
) -> Result<usize, Error> {
self.read_response(message.payload)
}
async fn receive_message(
self: Arc<Self>,
message: &mut MessageHeaderMut,
_timeout: Option<Duration>,
) -> Result<usize, Error> {
self.read_response(message.payload)
}
}
impl FileReadiness for NetConfigSocket {
fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
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<Arc<NetworkInterface>> {
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<IpAddr>,
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<RoutingInfo> {
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,
})
}

View File

@ -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<str>),
Anonymous(u64),
}
pub fn load_address(bytes: &[u8]) -> Result<LocalSocketAddress, Error> {
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<Option<Arc<File>>, 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<Arc<File>>,
) -> 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<LocalSocketAddress<'_>> for OwnedAddress {
fn from(value: LocalSocketAddress) -> Self {
match value {
LocalSocketAddress::Path(path) => Self::Path(path.into()),
LocalSocketAddress::Anonymous(anon) => Self::Anonymous(anon),
}
}
}

View File

@ -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<Arc<File>>,
}
struct Pairing {
address: OwnedAddress,
socket: Weak<LocalPacketSocket>,
}
pub struct LocalPacketSocket {
local: IrqSafeRwLock<Option<Arc<str>>>,
connected: IrqSafeRwLock<Option<Arc<str>>>,
remotes: IrqSafeRwLock<DefaultHashTable<OwnedAddress, Pairing>>,
receive_queue: BoundedMpmcQueue<Message>,
anonymous_socket_id: AtomicU64,
}
impl LocalPacketSocket {
pub fn new() -> Arc<Self> {
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<Message, Error> {
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<LocalPacketSocket>) -> Result<OwnedAddress, Error> {
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<Self>,
remote: &OwnedAddress,
) -> Result<(OwnedAddress, Arc<LocalPacketSocket>), 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<usize, Error> {
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<OwnedAddress, Error> {
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<BTreeMap<Arc<str>, Arc<LocalPacketSocket>>> =
IrqSafeRwLock::new(BTreeMap::new());
#[async_trait]
impl Socket for LocalPacketSocket {
fn bind(self: Arc<Self>, 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<str> = Arc::from(local);
*bound = Some(local.clone());
path_table.insert(local, self.clone());
Ok(())
}
async fn connect(
self: Arc<Self>,
remote: &[u8],
_timeout: Option<Duration>,
) -> 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<str> = 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<Self>) -> 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<usize, Error> {
let _ = option;
let _ = buffer;
Err(Error::InvalidOperation)
}
fn send_nonblocking(self: Arc<Self>, message: &MessageHeader) -> Result<usize, Error> {
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<Self>,
message: &MessageHeader,
timeout: Option<Duration>,
) -> Result<usize, Error> {
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<Self>,
message: &mut MessageHeaderMut,
) -> Result<usize, Error> {
let msg = self
.receive_queue
.try_pop_front()
.ok_or(Error::WouldBlock)?;
Self::write_message(message, msg)
}
async fn receive_message(
self: Arc<Self>,
message: &mut MessageHeaderMut,
timeout: Option<Duration>,
) -> Result<usize, Error> {
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<Result<(), Error>> {
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()
}
}

View File

@ -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<T> {
inner: BTreeMap<SocketAddr, Arc<T>>,
@ -20,12 +23,14 @@ pub struct SocketTable<T> {
pub struct TwoWaySocketTable<T> {
inner: BTreeMap<(SocketAddr, SocketAddr), Arc<T>>,
last_port: u16,
}
impl<T> TwoWaySocketTable<T> {
pub const fn new() -> Self {
Self {
inner: BTreeMap::new(),
last_port: 32768,
}
}
@ -43,21 +48,54 @@ impl<T> TwoWaySocketTable<T> {
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<F: FnMut(u16) -> Result<Arc<T>, Error>, R: Iterator<Item = u16>>(
&mut self,
local: IpAddr,
remote: SocketAddr,
range: R,
with: &mut F,
) -> Result<(Arc<T>, 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<F: FnMut(u16) -> Result<Arc<T>, Error>>(
&mut self,
local: IpAddr,
remote: SocketAddr,
mut with: F,
) -> Result<Arc<T>, 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<T> SocketTable<T> {
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()

View File

@ -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<usize, Error> {
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<Self>, _local: SocketAddr) -> Result<(), Error> {
fn bind(self: Arc<Self>, _local: &[u8]) -> Result<(), Error> {
Err(Error::InvalidOperation)
}
async fn connect(
self: Arc<Self>,
_remote: &[u8],
_timeout: Option<Duration>,
) -> Result<(), Error> {
Err(Error::InvalidOperation)
}
@ -156,68 +164,46 @@ impl Socket for RawSocket {
Ok(())
}
fn local_address(&self) -> Option<SocketAddr> {
None
}
fn remote_address(&self) -> Option<SocketAddr> {
None
}
}
#[async_trait]
impl PacketSocket for RawSocket {
fn connect(self: Arc<Self>, _remote: SocketAddr) -> Result<(), Error> {
Err(Error::InvalidOperation)
}
async fn send_to(
self: Arc<Self>,
destination: Option<SocketAddr>,
data: &[u8],
_timeout: Option<Duration>,
) -> Result<usize, Error> {
self.send_nonblocking(destination, data)
}
// TODO currently this is still blocking by NIC send code
fn send_nonblocking(
self: Arc<Self>,
_destination: Option<SocketAddr>,
buffer: &[u8],
) -> Result<usize, Error> {
fn send_nonblocking(self: Arc<Self>, message: &MessageHeader) -> Result<usize, Error> {
// 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<Self>,
buffer: &mut [u8],
message: &MessageHeader,
timeout: Option<Duration>,
) -> 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<usize, Error> {
let _ = timeout;
self.send_nonblocking(message)
}
fn receive_nonblocking(
self: Arc<Self>,
buffer: &mut [u8],
) -> Result<(usize, SocketAddr), Error> {
message: &mut MessageHeaderMut,
) -> Result<usize, Error> {
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<Self>,
message: &mut MessageHeaderMut,
timeout: Option<Duration>,
) -> Result<usize, Error> {
let future = self.receive_queue.pop_front();
let packet = maybe_timeout(future, timeout).await?;
Self::packet_to_user(packet, message.payload)
}
}

View File

@ -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;

View File

@ -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<TcpSocketOptions>,
inner: IrqSafeRwLock<TcpSocketInner>,
@ -79,8 +81,10 @@ impl TcpSocket {
}
}
#[async_trait]
impl Socket for TcpSocket {
fn bind(self: Arc<Self>, local: SocketAddr) -> Result<(), Error> {
fn bind(self: Arc<Self>, 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<Self>) -> 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<Self>,
mut address: Option<&mut [u8]>,
timeout: Option<Duration>,
) -> Result<Arc<dyn Socket>, 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<Self>,
mut address: Option<&mut [u8]>,
) -> Result<Arc<dyn Socket>, 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<Self>,
remote: &[u8],
timeout: Option<Duration>,
) -> 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<Self>) -> 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<SocketAddr> {
match &*self.inner.read() {
TcpSocketInner::Empty => None,
TcpSocketInner::Stream(socket) => Some(socket.local),
TcpSocketInner::Listener(socket) => Some(socket.local),
}
async fn shutdown(self: Arc<Self>, read: bool, write: bool) -> Result<(), Error> {
log::warn!("TODO: shutdown(read = {read}, write = {write})");
Ok(())
}
fn remote_address(&self) -> Option<SocketAddr> {
match &*self.inner.read() {
TcpSocketInner::Empty | TcpSocketInner::Listener(_) => None,
TcpSocketInner::Stream(socket) => Some(socket.remote),
}
}
// fn local_address(&self) -> Option<SocketAddr> {
// match &*self.inner.read() {
// TcpSocketInner::Empty => None,
// TcpSocketInner::Stream(socket) => Some(socket.local),
// TcpSocketInner::Listener(socket) => Some(socket.local),
// }
// }
// fn remote_address(&self) -> Option<SocketAddr> {
// 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<Self>, message: &MessageHeader) -> Result<usize, Error> {
let stream = self.as_stream().ok_or(Error::NotConnected)?;
let len = stream.send_nonblocking(message.payload)?;
Ok(len)
}
async fn send_message(
self: Arc<Self>,
remote: SocketAddr,
_timeout: Option<Duration>,
) -> 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<Duration>,
) -> Result<(usize, SocketAddr), Error> {
) -> Result<usize, Error> {
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<Duration>) -> Result<usize, Error> {
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<usize, Error> {
fn receive_nonblocking(
self: Arc<Self>,
message: &mut MessageHeaderMut,
) -> Result<usize, Error> {
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<Self>) -> 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<dyn ConnectionSocket>), 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<dyn ConnectionSocket>), 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<Self>,
message: &mut MessageHeaderMut,
timeout: Option<Duration>,
) -> Result<usize, Error> {
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)
}
}

View File

@ -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<TwoWaySocketTable<TcpStream>> =
IrqSafeRwLock::new(TwoWaySocketTable::new());
impl TcpStream {
pub async fn connect(remote: SocketAddr) -> Result<Arc<Self>, Error> {
pub async fn connect(
remote: SocketAddr,
timeout: Option<Duration>,
) -> Result<Arc<Self>, 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)
}

View File

@ -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<Result<(), Error>> {
self.receive_queue.poll_not_empty(cx).map(Ok)
}
}
#[async_trait]
impl PacketSocket for UdpSocket {
fn connect(self: Arc<Self>, 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<Self>,
destination: Option<SocketAddr>,
data: &[u8],
_timeout: Option<Duration>,
async fn send(
&self,
port: u16,
payload: &[u8],
destination: SocketAddr,
) -> Result<usize, Error> {
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<Self>,
destination: Option<SocketAddr>,
buffer: &[u8],
fn store_packet(
message: &mut MessageHeaderMut,
packet: &[u8],
source: &SocketAddr,
) -> Result<usize, Error> {
log::warn!("TODO: UDP::send_nonblocking()");
block!(self.send_to(destination, buffer, None).await)?
}
async fn receive_from(
self: Arc<Self>,
buffer: &mut [u8],
timeout: Option<Duration>,
) -> 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<Self>,
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<Result<(), Error>> {
self.receive_queue.poll_not_empty(cx).map(Ok)
}
}
#[async_trait]
impl Socket for UdpSocket {
fn bind(self: Arc<Self>, local: SocketAddr) -> Result<(), Error> {
fn bind(self: Arc<Self>, 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<SocketAddr> {
*self.local.read()
}
fn remote_address(&self) -> Option<SocketAddr> {
*self.remote.read()
async fn connect(
self: Arc<Self>,
remote: &[u8],
_timeout: Option<Duration>,
) -> 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<Self>) -> Result<(), Error> {
@ -268,6 +233,49 @@ impl Socket for UdpSocket {
}
}
}
fn send_nonblocking(self: Arc<Self>, message: &MessageHeader) -> Result<usize, Error> {
log::warn!("TODO: UDP::send_nonblocking()");
block!(self.send_message(message, None).await)?
}
async fn send_message(
self: Arc<Self>,
message: &MessageHeader,
timeout: Option<Duration>,
) -> Result<usize, Error> {
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<Self>,
message: &mut MessageHeaderMut,
) -> Result<usize, Error> {
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<Self>,
message: &mut MessageHeaderMut,
timeout: Option<Duration>,
) -> Result<usize, Error> {
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 {

View File

@ -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));
}

View File

@ -28,6 +28,14 @@ where
}
}
impl<K, V, H, const N: usize> HashTable<K, V, H, N> {
pub fn clear(&mut self) {
for bucket in self.buckets.iter_mut() {
bucket.clear();
}
}
}
impl<K: Hash + Eq, V, const N: usize> HashTable<K, V, DefaultHashBuilder, N> {
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
let h = self.hasher.hash_one(&key);
@ -61,4 +69,15 @@ impl<K: Hash + Eq, V, const N: usize> HashTable<K, V, DefaultHashBuilder, N> {
.iter()
.find_map(|(k, v)| (k.borrow() == key).then_some((k, v)))
}
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
Q: Hash + Eq + ?Sized,
K: Borrow<Q>,
{
let h = self.hasher.hash_one(key);
let bucket = &self.buckets[h as usize % self.buckets.len()];
bucket.iter().any(|(k, _)| (k.borrow() == key))
}
}

View File

@ -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(())
}
}

View File

@ -28,25 +28,9 @@ pub struct Channel {
subscriptions: Mutex<BTreeMap<u32, Arc<Subscription>>>,
}
/// 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<VecDeque<Arc<Message>>>,
// queue: Mutex<VecDeque<Arc<Message>>>,
notify: AtomicWaker,
}
@ -72,54 +56,55 @@ impl ChannelDescriptor {
Self { tx, rx, id }
}
/// Receives a message from the subscription
pub fn receive_message(&self) -> Result<Arc<Message>, 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<Arc<Message>, 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<Arc<Message>, 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<Arc<Message>, 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<Subscription> {
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<Arc<Message>, 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<Arc<Message>, 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<Arc<Message>, Error> {
block!(self.receive_message_async().await)?
}
// fn receive_message_inner(&self) -> Result<Arc<Message>, Error> {
// block!(self.receive_message_async().await)?
// }
fn push_message(&self, msg: Arc<Message>) -> Result<(), Error> {
self.queue.lock()?.push_back(msg);
self.notify.wake();
Ok(())
}
// fn push_message(&self, msg: Arc<Message>) -> Result<(), Error> {
// self.queue.lock()?.push_back(msg);
// self.notify.wake();
// Ok(())
// }
}
impl FileReadiness for ChannelDescriptor {
fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
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
// }
}
}

View File

@ -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<SharedMemory>),
PtySlave(TerminalHalfWrapper<PseudoTerminalSlave>),
PtyMaster(TerminalHalfWrapper<PseudoTerminalMaster>),
@ -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<Self> {
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<Arc<Self>, Error> {
let shm = SharedMemory::new(size)?;
@ -333,7 +326,6 @@ impl File {
pub fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
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(),

View File

@ -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};

View File

@ -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<dyn ConnectionSocket + 'static>),
Packet(Arc<dyn PacketSocket + 'static>),
}
struct InnerOptions {
connect_timeout: Option<Duration>,
recv_timeout: Option<Duration>,
@ -32,239 +25,150 @@ struct InnerOptions {
}
pub struct SocketWrapper {
inner: SocketInner,
inner: Arc<dyn Socket>,
options: IrqSafeRwLock<InnerOptions>,
}
/// Interface for interacting with network sockets
#[allow(unused)]
#[async_trait]
pub trait Socket: FileReadiness + fmt::Debug + Send {
fn bind(self: Arc<Self>, local: SocketAddr) -> Result<(), Error>;
fn bind(self: Arc<Self>, local: &[u8]) -> Result<(), Error> {
let _ = local;
Err(Error::InvalidOperation)
}
async fn connect(
self: Arc<Self>,
remote: &[u8],
timeout: Option<Duration>,
) -> Result<(), Error>;
/// Socket listen/receive address
fn local_address(&self) -> Option<SocketAddr>;
fn listen(self: Arc<Self>) -> Result<(), Error> {
Err(Error::InvalidOperation)
}
async fn accept(
self: Arc<Self>,
address: Option<&mut [u8]>,
timeout: Option<Duration>,
) -> Result<Arc<dyn Socket>, Error> {
let _ = address;
let _ = timeout;
Err(Error::InvalidOperation)
}
fn accept_nonblocking(
self: Arc<Self>,
address: Option<&mut [u8]>,
) -> Result<Arc<dyn Socket>, Error> {
let _ = address;
Err(Error::InvalidOperation)
}
/// Socket remote address
fn remote_address(&self) -> Option<SocketAddr>;
async fn shutdown(self: Arc<Self>, read: bool, write: bool) -> Result<(), Error> {
let _ = read;
let _ = write;
Err(Error::InvalidOperation)
}
/// Closes a socket
fn close(self: Arc<Self>) -> Result<(), Error>;
fn close(self: Arc<Self>) -> 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<usize, Error> {
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<Self>, message: &MessageHeader) -> Result<usize, Error>;
async fn send_message(
self: Arc<Self>,
buffer: &mut [u8],
timeout: Option<Duration>,
) -> Result<(usize, SocketAddr), Error>;
fn receive_nonblocking(
self: Arc<Self>,
buffer: &mut [u8],
) -> Result<(usize, SocketAddr), Error>;
/// Sends provided data to the recepient specified by `destination`
async fn send_to(
self: Arc<Self>,
destination: Option<SocketAddr>,
data: &[u8],
message: &MessageHeader,
timeout: Option<Duration>,
) -> Result<usize, Error>;
fn send_nonblocking(
fn receive_nonblocking(self: Arc<Self>, message: &mut MessageHeaderMut)
-> Result<usize, Error>;
async fn receive_message(
self: Arc<Self>,
destination: Option<SocketAddr>,
buffer: &[u8],
message: &mut MessageHeaderMut,
timeout: Option<Duration>,
) -> Result<usize, Error>;
fn connect(self: Arc<Self>, remote: SocketAddr) -> Result<(), Error>;
}
/// Connection-based client socket interface
#[async_trait]
pub trait ConnectionSocket: Socket {
async fn connect(
self: Arc<Self>,
remote: SocketAddr,
timeout: Option<Duration>,
) -> Result<(), Error>;
async fn receive(
&self,
buffer: &mut [u8],
timeout: Option<Duration>,
) -> Result<(usize, SocketAddr), Error>;
fn receive_nonblocking(&self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), Error>;
async fn send(&self, data: &[u8], timeout: Option<Duration>) -> Result<usize, Error>;
fn send_nonblocking(&self, buffer: &[u8]) -> Result<usize, Error>;
fn listen(self: Arc<Self>) -> Result<(), Error>;
async fn accept(&self) -> Result<(SocketAddr, Arc<dyn ConnectionSocket>), Error>;
fn accept_nonblocking(&self) -> Result<(SocketAddr, Arc<dyn ConnectionSocket>), Error>;
async fn shutdown(&self, read: bool, write: bool) -> Result<(), Error>;
}
impl SocketWrapper {
pub fn from_connection(socket: Arc<dyn ConnectionSocket + 'static>) -> Self {
Self {
inner: SocketInner::Connection(socket),
options: IrqSafeRwLock::new(InnerOptions::default()),
}
pub fn from_inner(inner: Arc<dyn Socket>) -> Self {
Self::from(inner)
}
pub fn from_packet(socket: Arc<dyn PacketSocket + 'static>) -> 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<SocketAddr>) -> Result<usize, Error> {
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<Self, Error> {
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<SocketAddr>,
message: &MessageHeader,
non_blocking: bool,
) -> Result<usize, Error> {
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<usize, Error> {
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<SocketAddr> {
match &self.inner {
SocketInner::Packet(socket) => socket.local_address(),
SocketInner::Connection(socket) => socket.local_address(),
}
}
pub fn remote_address(&self) -> Option<SocketAddr> {
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<usize, Error> {
@ -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<Arc<dyn Socket>> for SocketWrapper {
fn from(value: Arc<dyn Socket>) -> Self {
Self {
inner: value,
options: IrqSafeRwLock::new(InnerOptions::default()),
}
}
}
impl FileReadiness for SocketWrapper {
fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
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:?}");
}

View File

@ -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<RawFd, Error> {
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<RawFd, Error> {
// 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<RawFd, Error> {
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<ReceivedMessageMetadata>,
buf: &mut [u8],
from: &mut MaybeUninit<ChannelPublisherId>,
) -> 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<ReceivedMessageMetadata>,
// buf: &mut [u8],
// from: &mut MaybeUninit<ChannelPublisherId>,
// ) -> 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<RawFd>,

View File

@ -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<RawFd, Error> {
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<RawFd, Error> {
})
}
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<SocketAddr>) -> Result<RawFd, Error> {
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<RawFd, Error> {
let thread = Thread::current();
let process = thread.process();
@ -61,10 +63,10 @@ pub(crate) fn accept(sock_fd: RawFd, remote: &mut MaybeUninit<SocketAddr>) -> 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<SocketAddr>,
remote: Option<&[u8]>, // remote: &Option<SocketAddr>,
) -> Result<usize, Error> {
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<SocketAddr>,
remote: Option<&mut [u8]>,
) -> Result<usize, Error> {
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<usize, Error> {
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<usize, Error> {
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<SocketAddr>,
// ) -> Result<RawFd, Error> {
// 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<RawFd, Error> {
// 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<SocketAddr>,
// ) -> Result<RawFd, Error> {
// 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<SocketAddr>,
// ) -> Result<usize, 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()?;
// 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<SocketAddr>,
// ) -> Result<usize, 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()?;
// 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)
// })
// }

View File

@ -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<ProcessId, Err
let process = thread.process();
let result = run_with_io(&process, |mut io| {
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();
// 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<ProcessId, Err
path: options.program,
args: options.arguments,
envs: options.arguments,
single_step: attach_debugger.is_some(),
single_step: false,
// single_step: attach_debugger.is_some(),
disable_aslr: options.flags.contains(SpawnFlags::DISABLE_ASLR),
};
let (child_process, child_main) = proc::load_binary(io.ioctx_mut(), &load_options)?;
@ -172,11 +170,12 @@ pub(crate) fn spawn_process(options: &SpawnOptions<'_>) -> Result<ProcessId, Err
drop(child_io);
if let Some(debugger) = attach_debugger {
child_main.attach_debugger(ThreadDebugger::new(debugger));
} else {
child_main.enqueue();
}
child_main.enqueue();
// if let Some(debugger) = attach_debugger {
// child_main.attach_debugger(ThreadDebugger::new(debugger));
// } else {
// child_main.enqueue();
// }
Ok(pid as _)
});

View File

@ -64,11 +64,10 @@ mod generated {
#![allow(unreachable_code)]
use abi::{
io::ChannelPublisherId,
process::{ExecveOptions, ProcessId, ThreadSpawnOptions},
SyscallFunction,
};
use abi_lib::SyscallRegister;
use abi_lib::{SyscallFatRegister, SyscallRegister};
use super::{
arg,

View File

@ -1,6 +1,6 @@
use core::num::NonZeroUsize;
use crate::{SyscallRegister, ThinWrapped};
use crate::{SyscallFatRegister, SyscallRegister, ThinWrapped};
pub fn make_error<E: SyscallRegister>(e: E) -> usize {
(-(e.into_syscall_register() as isize)) as usize
@ -29,6 +29,58 @@ impl<E: SyscallRegister> SyscallRegister for Result<usize, E> {
}
}
impl<T: Sized> 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<T: Sized> 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<T: ThinWrapped> SyscallRegister for Option<T> {
fn into_syscall_register(self) -> usize {
match self {

View File

@ -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",
]

View File

@ -0,0 +1,35 @@
use alloc::{boxed::Box, vec::Vec};
use crate::{des::Deserializer, ser::Serializer, Deserialize, Serialize};
impl<T: Serialize> Serialize for Vec<T> {
fn serialize<S: Serializer>(&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<T> {
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
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<str> {
fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
serializer.write_str(self)
}
}
impl<'de> Deserialize<'de> for Box<str> {
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
deserializer.read_str().map(Into::into)
}
}

View File

@ -51,6 +51,18 @@ impl<'de> Deserialize<'de> for () {
}
}
impl Serialize for &[u8] {
fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
serializer.write_bytes(self)
}
}
impl<'de> Deserialize<'de> for &'de [u8] {
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
deserializer.read_bytes()
}
}
impl Serialize for &str {
fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
serializer.write_str(self)
@ -87,9 +99,9 @@ where
impl<T: Serialize> Serialize for Option<T> {
fn serialize<S: Serializer>(&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<T: Serialize> Serialize for Option<T> {
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Option<T> {
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
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<T: Serialize, E: Serialize> Serialize for Result<T, E> {
fn serialize<S: Serializer>(&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<T: Serialize, E: Serialize> Serialize for Result<T, E> {
impl<'de, T: Deserialize<'de>, E: Deserialize<'de>> Deserialize<'de> for Result<T, E> {
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
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::<u32>::None);
test_serialize_reversibility(&mut buffer, &Option::<u8>::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::<u32, _>::Err("abcdef"));
}
}

View File

@ -1,3 +1,4 @@
mod alloc;
mod base;
mod net;
mod time;

View File

@ -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<D: $crate::des::Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
$(
let $field = $crate::Deserialize::deserialize(deserializer)?;

46
lib/abi-serde/src/test.rs Normal file
View File

@ -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")
}
}

View File

@ -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<RawFd>, path: &str, metadata: &mut MaybeUninit<F
syscall device_request(fd: RawFd, option: u32, value: &mut [u8], len: usize) -> Result<usize>;
// Misc I/O
syscall open_channel(name: &str, subscribe: bool) -> Result<RawFd>;
syscall create_timer(options: TimerOptions) -> Result<RawFd>;
syscall create_pid(target: &ProcessWait, flags: WaitFlags) -> Result<RawFd>;
syscall create_pty(opts: &TerminalOptions, size: &TerminalSize, fds: &mut [MaybeUninit<RawFd>; 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<ReceivedMessageMetadata>,
data: &mut [u8],
from: &mut MaybeUninit<ChannelPublisherId>
) -> Result<()>;
// Network
syscall create_socket(ty: SocketType) -> Result<RawFd>;
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<SocketAddr>) -> Result<RawFd>;
syscall connect(sock_fd: RawFd, remote: &[u8]) -> Result<()>;
syscall accept(sock_fd: RawFd, remote: Option<&mut [u8]>) -> Result<RawFd>;
syscall shutdown(sock_fd: RawFd, how: SocketShutdown) -> Result<()>;
syscall send_to(sock_fd: RawFd, data: &[u8], remote: &Option<SocketAddr>) -> Result<usize>;
syscall receive_from(sock_fd: RawFd, data: &mut [u8], remote: &mut MaybeUninit<SocketAddr>) -> Result<usize>;
syscall send_to(sock_fd: RawFd, data: &[u8], address: Option<&[u8]>) -> Result<usize>;
syscall receive_from(sock_fd: RawFd, data: &mut [u8], address: Option<&mut [u8]>) -> Result<usize>;
syscall get_socket_option(sock_fd: RawFd, option: u32, value: &mut [u8]) -> Result<usize>;
syscall set_socket_option(sock_fd: RawFd, option: u32, value: &[u8]) -> Result<()>;
syscall send_message(sock_fd: RawFd, message: &MessageHeader<'_>) -> Result<usize>;
syscall receive_message(sock_fd: RawFd, message: &mut MessageHeaderMut<'_>) -> Result<usize>;
// C compat
syscall fork() -> Result<ProcessId>;
syscall execve(options: &ExecveOptions<'_>) -> Result<()>;

View File

@ -96,3 +96,5 @@ impl From<u32> for RawFd {
Self(value)
}
}
abi_serde::impl_newtype_serde!(RawFd);

View File

@ -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)]

View File

@ -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

View File

@ -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)]

View File

@ -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<str>,
/// 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<str>,
@ -17,10 +37,15 @@ pub struct RouteInfo {
/// Gateway this route should be reached through
pub gateway: Option<IpAddr>,
}
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<str>,
@ -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<str>,
@ -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<str>),
/// 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<IpAddr>,
/// 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<IpAddr>,
/// 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<T> {
#[derive(Clone, Debug, PartialEq)]
pub enum NetConfigResult<'a, T> {
/// Success
Ok(T),
/// Error
Err(Box<str>),
Err(&'a str),
}
impl<T> NetConfigResult<T> {
/// Constructs an error value
pub fn err<S: Into<Box<str>>>(message: S) -> Self {
Self::Err(message.into())
impl<T: Serialize> Serialize for NetConfigResult<'_, T> {
fn serialize<S: Serializer>(&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<u32> for InterfaceQuery {
fn from(value: u32) -> Self {
Self::ById(value)
impl<'de, T: Deserialize<'de>> Deserialize<'de> for NetConfigResult<'de, T> {
fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
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),
}
}
}

View File

@ -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,
]);

View File

@ -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

View File

@ -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;

View File

@ -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<SocketAddr, Error> {
get_socket_option::<options::PeerAddress>(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<Duration>) -> Result<(), Error> {
fn connect_ip(fd: RawFd, remote: &SocketAddr, timeout: Option<Duration>) -> Result<(), Error> {
let mut address = [0; 32];
let address_len = wire::to_slice(remote, &mut address)?;
set_socket_option::<options::ConnectTimeout>(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<RawFd, Error> {
pub fn create_and_bind_ip(
ty: SocketType,
local: &SocketAddr,
listen: bool,
) -> Result<RawFd, Error> {
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<RawFd, Error> {
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<RawFd, Error> {
/// Binds an UDP socket to some local address
pub fn bind_udp(local: &SocketAddr) -> Result<RawFd, Error> {
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<Duration>) -> Result<RawFd, Error> {
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<Duration>) -> Result<Raw
/// "Connect" an UDP socket
pub fn connect_udp(socket_fd: RawFd, remote: &SocketAddr) -> 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<usize, Error> {
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<usize, Error> {
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<usize, Error> {
let msg_header = MessageHeader {
destination: None,
ancillary: &[],
payload: data,
};
unsafe { crate::sys::send_message(socket_fd, &msg_header) }
}

View File

@ -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},

View File

@ -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!(<Option<#ty>>::from_syscall_registers(#args[#index], #args[#index + 1])),
2,
)
}
Self::Result(_) => todo!("Result"),
Self::Extern {
kind: ExternKind::Thin,

76
userspace/Cargo.lock generated
View File

@ -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"

View File

@ -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)'] }

View File

@ -5,10 +5,15 @@ edition = "2021"
authors = ["Mark Poliakov <mark@alnyan.me>"]
[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

View File

@ -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),
}

View File

@ -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<u32, PeerAddr>,
client_map: HashMap<u32, PeerAddress>,
// Window management
windows: BTreeMap<u32, Window<'a>>,
@ -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<F: AsRawFd>(&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<F: AsRawFd>(
&self,
event: EventData,
file: &F,
client_id: &PeerAddress,
) -> Result<(), Error> {
self.0
.send_with_file_to(&ServerMessage::Event(event), file, client_id)?;
Ok(())
}
}

View File

@ -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

View File

@ -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::<InitMsg>(&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
}

View File

@ -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]

View File

@ -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;

View File

@ -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<Self> {
SharedMemoryImpl::new(size).map(Self)
}
pub fn map(self) -> io::Result<FileMapping> {
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<F: Into<OwnedFd>>(file: F, size: usize) -> io::Result<Self> {
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()
}
}

View File

@ -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<Self> {
sys::LocalPacketSocketImpl::new().map(Self)
}
pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<Self> {
sys::LocalPacketSocketImpl::connect(path).map(Self)
}
pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<Self> {
sys::LocalPacketSocketImpl::bind(path).map(Self)
}
pub fn receive(&self, buffer: &mut [u8]) -> io::Result<usize> {
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<OwnedFd>)> {
self.0.receive_with_ancillary(buffer)
}
pub fn receive_with_ancillary_from(
&self,
buffer: &mut [u8],
) -> io::Result<(usize, Option<OwnedFd>, 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<usize> {
self.0.send(data)
}
pub fn send_to<'a, A: Into<BorrowedLocalAddress<'a>>>(
&self,
data: &[u8],
remote: A,
) -> io::Result<usize> {
let remote = remote.into();
self.0.send_to(data, &remote.0)
}
pub fn send_with_ancillary(&self, data: &[u8], ancillary: RawFd) -> io::Result<usize> {
self.0.send_with_ancillary(data, ancillary)
}
pub fn send_with_ancillary_to<'a, A: Into<BorrowedLocalAddress<'a>>>(
&self,
data: &[u8],
ancillary: RawFd,
remote: A,
) -> io::Result<usize> {
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())
}
}

View File

@ -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<Self>;
fn add<F: AsRawFd>(&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<Target = Stdin> + 'a {
fn new(stdin: &'a mut Stdin) -> io::Result<Self>;
}
// 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<Self>;
fn bind<P: AsRef<Path>>(path: P) -> io::Result<Self>;
fn connect<P: AsRef<Path>>(path: P) -> io::Result<Self>;
fn receive(&self, data: &mut [u8]) -> io::Result<usize>;
fn receive_from(&self, data: &mut [u8]) -> io::Result<(usize, Self::OwnedAddress)>;
fn receive_with_ancillary(&self, data: &mut [u8]) -> io::Result<(usize, Option<OwnedFd>)>;
fn receive_with_ancillary_from(
&self,
data: &mut [u8],
) -> io::Result<(usize, Option<OwnedFd>, Self::OwnedAddress)>;
fn send(&self, data: &[u8]) -> io::Result<usize>;
fn send_to(&self, data: &[u8], address: &Self::Address<'_>) -> io::Result<usize>;
fn send_with_ancillary(&self, data: &[u8], ancillary: RawFd) -> io::Result<usize>;
fn send_with_ancillary_to(
&self,
data: &[u8],
ancillary: RawFd,
address: &Self::Address<'_>,
) -> io::Result<usize>;
}
// Memory
pub(crate) trait FileMapping: AsRawFd + DerefMut<Target = [u8]> + Sized {
fn map<F: Into<OwnedFd>>(file: F, size: usize) -> io::Result<Self>;
}
pub(crate) trait SharedMemory: AsRawFd + Sized {
type Mapping: FileMapping;
fn new(size: usize) -> io::Result<Self>;
fn map(self) -> io::Result<Self::Mapping>;
}

View File

@ -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<Self::Mapping> {
todo!()
}
fn new(size: usize) -> io::Result<Self> {
let _ = size;
todo!()
}
}
impl AsRawFd for SharedMemoryImpl {
fn as_raw_fd(&self) -> RawFd {
todo!()
}
}
impl sys::FileMapping for FileMappingImpl {
fn map<F: Into<OwnedFd>>(file: F, size: usize) -> io::Result<Self> {
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!()
}
}

View File

@ -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;

View File

@ -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<usize> {
let _ = buf;
todo!()
}
}
impl Write for PipeImpl {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let _ = buf;
todo!()
}

View File

@ -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<TempDir>,
}
#[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<OwnedFd> {
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<Self> {
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<Self> {
let inner = UnixDatagram::unbound()?;
Ok(Self {
inner,
ephemeral: None,
})
}
fn bind<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let inner = UnixDatagram::bind(path)?;
Ok(Self {
inner,
ephemeral: None,
})
}
fn connect<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let this = Self::bind_ephemeral()?;
this.inner.connect(path)?;
Ok(this)
}
fn send(&self, data: &[u8]) -> io::Result<usize> {
self.inner.send(data)
}
fn send_to<'a>(&self, data: &[u8], address: &Self::Address<'a>) -> io::Result<usize> {
self.inner.send_to(data, address.0)
}
fn send_with_ancillary(&self, data: &[u8], fd: RawFd) -> io::Result<usize> {
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<usize> {
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<usize> {
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<OwnedFd>)> {
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<OwnedFd>, 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<SocketAddr> for OwnedAddressImpl {
fn from(value: SocketAddr) -> Self {
let path = value.as_pathname().unwrap();
Self(path.into())
}
}

View File

@ -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<Self> {
let inner = shm::SharedMemory::new(size)?;
Ok(Self { inner })
}
fn map(self) -> io::Result<Self::Mapping> {
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<F: Into<OwnedFd>>(file: F, size: usize) -> io::Result<Self> {
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()
}
}

View File

@ -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};

View File

@ -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<Option<OwnedFd>> {
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<Self> {
let raw = unsafe { yggdrasil_rt::sys::create_socket(SocketType::LocalPacket) }?;
let fd = unsafe { OwnedFd::from_raw_fd(raw) };
Ok(Self { fd })
}
fn connect<P: AsRef<Path>>(path: P) -> io::Result<Self> {
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<P: AsRef<Path>>(path: P) -> io::Result<Self> {
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<usize> {
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<OwnedFd>)> {
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<OwnedFd>, 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<usize> {
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<usize> {
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<usize> {
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<usize> {
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)
}
}

View File

@ -5,8 +5,10 @@ edition = "2021"
authors = ["Mark Poliakov <mark@alnyan.me>"]
[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

View File

@ -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<Self, Error> {
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<OwnedFd, Error> {
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<T, F: Fn(Event) -> Result<T, Event>>(
pub fn filter_events<T, F: Fn(Event) -> Result<T, Event>>(
&mut self,
predicate: F,
) -> Result<T, Error> {
@ -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<F: AsRawFd>(
&mut self,
message: &ClientMessage,
file: &F,
) -> Result<(), Error> {
self.sender.send_with_file(message, file)?;
Ok(())
}
pub fn connect(&mut self) -> Result<u32, Error> {
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),
})
}
}

View File

@ -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();
}
}
}

View File

@ -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<Mutex<Connection>>,
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<Self, Error> {
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,

View File

@ -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),
}

View File

@ -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<OwnedFd>
}
impl KeyModifiers {
pub const SHIFT: Self = Self {
shift: true,

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -1,15 +0,0 @@
[package]
name = "serde-ipc"
version = "0.1.0"
edition = "2021"
authors = ["Mark Poliakov <mark@alnyan.me>"]
[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)'] }

View File

@ -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<M: Serialize> {
inner: RawSender,
// inner: MessageChannelSender,
_pd: PhantomData<M>,
}
pub struct Receiver<M: DeserializeOwned> {
inner: RawReceiver,
// inner: MessageChannelReceiver,
buffer: [u8; 1024],
_pd: PhantomData<M>,
}
fn wrap<T: Serialize, U: DeserializeOwned>(
sender: RawSender,
receiver: RawReceiver,
) -> (Sender<T>, Receiver<U>) {
(
Sender {
inner: sender,
_pd: PhantomData,
},
Receiver {
inner: receiver,
buffer: [0; 1024],
_pd: PhantomData,
},
)
}
#[cfg(target_os = "yggdrasil")]
pub fn listen<T: Serialize, U: DeserializeOwned>(
name: &str,
) -> Result<(Sender<T>, Receiver<U>), Error> {
let (sender, receiver) = sys::create_channel(name)?;
Ok(wrap(sender, receiver))
}
#[cfg(target_os = "yggdrasil")]
pub fn connect<T: Serialize, U: DeserializeOwned>(
name: &str,
) -> Result<(Sender<T>, Receiver<U>), Error> {
let (sender, receiver) = sys::create_channel(name)?;
Ok(wrap(sender, receiver))
}
#[cfg(any(unix, rust_analyzer))]
pub fn listen<T: Serialize, U: DeserializeOwned, P: AsRef<std::path::Path>>(
path: P,
) -> Result<(Sender<T>, Receiver<U>), Error> {
let (sender, receiver) = sys::listen(path)?;
Ok(wrap(sender, receiver))
}
#[cfg(any(unix, rust_analyzer))]
pub fn connect<T: Serialize, U: DeserializeOwned, P: AsRef<std::path::Path>>(
path: P,
) -> Result<(Sender<T>, Receiver<U>), Error> {
let (sender, receiver) = sys::connect(path)?;
Ok(wrap(sender, receiver))
}
impl<T: Serialize> Sender<T> {
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<F: AsRawFd>(&self, file: &F, peer: &PeerAddr) -> Result<(), Error> {
self.inner.send_file_to(file, peer).map_err(Error::Io)
}
}
impl<T: Serialize> AsRawFd for Sender<T> {
fn as_raw_fd(&self) -> RawFd {
self.inner.as_raw_fd()
}
}
impl<U: DeserializeOwned> Receiver<U> {
pub fn receive(&mut self) -> Result<(PeerAddr, Either<U, OwnedFd>), 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<T: DeserializeOwned> AsRawFd for Receiver<T> {
fn as_raw_fd(&self) -> RawFd {
self.inner.as_raw_fd()
}
}

View File

@ -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<T, U> {
Left(T),
Right(U)
}
pub trait IpcSender: AsRawFd {
fn send_message_to(&self, message: &[u8], peer: &PeerAddr) -> Result<(), io::Error>;
fn send_file_to<F: AsRawFd>(&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<usize, OwnedFd>), io::Error>;
}
impl<T, U> Either<T, U> {
pub fn try_map_left<E, R, F: FnOnce(T) -> Result<R, E>>(self, map: F) -> Result<Either<R, U>, E> {
match self {
Self::Left(val) => map(val).map(Either::Left),
Self::Right(val) => Ok(Either::Right(val))
}
}
}

View File

@ -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<TempDir>,
}
pub struct RawSender {
inner: Arc<Inner>,
}
pub struct RawReceiver {
inner: Arc<Inner>,
}
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<F: AsRawFd>(&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<usize, OwnedFd>), 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<P: AsRef<Path>>(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<P: AsRef<Path>>(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);
}
}
}

View File

@ -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<F: AsRawFd>(&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<usize, OwnedFd>), 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)))
}

View File

@ -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

View File

@ -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<T> {
channel: Arc<Channel>,
_pd: PhantomData<T>,
}
pub struct Receiver<T> {
channel: Arc<Channel>,
buffer: [u8; 4096],
_pd: PhantomData<T>,
}
#[repr(transparent)]
#[derive(Debug, Clone)]
pub struct PeerAddress(OwnedLocalAddress);
impl Channel {
pub fn connect<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
let socket = LocalPacketSocket::connect(path)?;
Ok(Self(socket))
}
pub fn bind<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
let socket = LocalPacketSocket::bind(path)?;
Ok(Self(socket))
}
pub fn split<T: Serialize, U: DeserializeOwned>(self) -> (Sender<T>, Receiver<U>) {
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<T: Serialize> Sender<T> {
pub fn send(&self, message: &T) -> Result<usize, Error> {
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<F: AsRawFd>(&self, message: &T, file: &F) -> Result<usize, Error> {
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<usize, Error> {
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<F: AsRawFd>(
&self,
message: &T,
file: &F,
destination: &PeerAddress,
) -> Result<usize, Error> {
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<T> AsRawFd for Sender<T> {
fn as_raw_fd(&self) -> RawFd {
self.channel.as_raw_fd()
}
}
impl<T: DeserializeOwned> Receiver<T> {
pub fn receive(&mut self) -> Result<T, Error> {
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<OwnedFd>), 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<OwnedFd>, 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<T> AsRawFd for Receiver<T> {
fn as_raw_fd(&self) -> RawFd {
self.channel.as_raw_fd()
}
}

View File

@ -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

View File

@ -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)]

View File

@ -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;
}

View File

@ -13,6 +13,8 @@ pub enum Error {
IoError(#[from] io::Error),
#[error("NetConfig returned error: {0}")]
NetConfError(Box<str>),
#[error("{0:?}")]
RtError(std::os::yggdrasil::rt::Error),
#[error("Serialize/deserialize error: {0}")]
SerializeError(#[from] serde_json::Error),
#[error("Timed out")]

View File

@ -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<Self, Self::Err> {
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::<Vec<RouteInfo>>(&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::<Vec<RouteInfo>>(&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::<Vec<(Box<str>, u32)>>(&NetConfigRequest::ListInterfaces)?;
for (name, id) in list {
let info = match nc.request::<InterfaceInfo>(&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::<InterfaceInfo>(&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::<Vec<(Box<str>, u32)>>(&NetConfigRequest::ListInterfaces)?;
let list = nc.list_interfaces()?;
for (name, id) in list {
let info = match nc.request::<InterfaceInfo>(&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::<InterfaceInfo>(&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::<InterfaceInfo>(&NetConfigRequest::DescribeInterface(
InterfaceQuery::ByName(interface.into_boxed_str()),
))?;
let info = nc.describe_interface(&*interface)?;
println!("{}", info.mac);

View File

@ -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<Self, Error> {
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<netconfig::NetConfigResult<'de, T>, 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<T, Error> {
self.send(request)?;
let (_sender, len) = self.receiver.receive_message(&mut self.buffer)?;
let msg: NetConfigResult<T> = 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<RoutingInfo, Error> {
self.request(&NetConfigRequest::QueryRoute(address))
pub fn query_route(&mut self, address: IpAddr) -> Result<netconfig::RoutingInfo, Error> {
self.request(&netconfig::NetConfigRequest::QueryRoute(address))
}
pub fn query_arp(
pub fn query_arp<'a, Q: Into<net::SocketInterfaceQuery<'a>>>(
&mut self,
interface_id: u32,
query: Q,
address: IpAddr,
perform_query: bool,
) -> Result<MacAddress, Error> {
self.request(&NetConfigRequest::QueryArp(
interface_id,
address,
perform_query,
cache_only: bool,
) -> Result<net::MacAddress, Error> {
self.request(&netconfig::NetConfigRequest::ArpQuery(
netconfig::ArpQueryRequest {
interface: query.into(),
address,
cache_only,
},
))
}
pub fn set_interface_address<Q: Into<InterfaceQuery>>(
&mut self,
interface: Q,
address: IpAddr,
) -> Result<(), Error> {
self.request(&NetConfigRequest::SetNetworkAddress {
interface: interface.into(),
address,
})
pub fn list_interfaces(&mut self) -> Result<Vec<netconfig::InterfaceBinding>, Error> {
self.request(&netconfig::NetConfigRequest::ListInterfaces(()))
}
pub fn add_route<Q: Into<InterfaceQuery>>(
pub fn describe_interface<'a, Q: Into<net::SocketInterfaceQuery<'a>>>(
&mut self,
interface: Q,
subnet: SubnetAddr,
query: Q,
) -> Result<netconfig::InterfaceInfo, Error> {
self.request(&netconfig::NetConfigRequest::DescribeInterface(
query.into(),
))
}
pub fn list_routes(&mut self) -> Result<Vec<netconfig::RouteInfo>, Error> {
self.request(&netconfig::NetConfigRequest::ListRoutes(()))
}
pub fn describe_routes<'a, Q: Into<net::SocketInterfaceQuery<'a>>>(
&mut self,
query: Q,
) -> Result<Vec<netconfig::RouteInfo>, Error> {
self.request(&netconfig::NetConfigRequest::DescribeRoutes(query.into()))
}
pub fn set_interface_address<'a, Q: Into<net::SocketInterfaceQuery<'a>>>(
&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<net::SocketInterfaceQuery<'a>>>(
&mut self,
query: Q,
subnet: net::SubnetAddr,
gateway: Option<IpAddr>,
) -> Result<(), Error> {
self.request(&NetConfigRequest::AddRoute {
interface: interface.into(),
gateway,
subnet,
})
self.request(&netconfig::NetConfigRequest::AddRoute(
netconfig::AddRouteRequest {
interface: query.into(),
gateway,
subnet,
},
))
}
}

View File

@ -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<bool, Error> {
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()),

View File

@ -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<Self::Instruction>;
type Register: LowerHex;
fn disassemble(
window: &[u8],
ip: usize,
limit: usize,
) -> Result<Vec<(usize, Self::Instruction)>, 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<I> {
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<TargetImpl> = 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<Self::Instruction>;
// type Register: LowerHex;
//
// fn disassemble(
// window: &[u8],
// ip: usize,
// limit: usize,
// ) -> Result<Vec<(usize, Self::Instruction)>, 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<I> {
// 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<TargetImpl> = Debugger::from_command(&args.program, command).unwrap();
//
// debug.run().unwrap();
// }

View File

@ -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

View File

@ -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<Self> {
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<Self> {
// 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<T> ToExitCode for io::Result<T> {
fn to_exit_code(&self) -> i32 {

View File

@ -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);
// }
// }
}

View File

@ -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<()> {