net: remove MessageChannel, replace with local sockets
This commit is contained in:
parent
0889e99049
commit
009f545cb3
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -34,6 +34,7 @@ name = "abi-serde"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
|
@ -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) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
@ -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()
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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(())
|
||||
}
|
||||
|
296
kernel/driver/net/core/src/socket/config.rs
Normal file
296
kernel/driver/net/core/src/socket/config.rs
Normal 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,
|
||||
})
|
||||
}
|
94
kernel/driver/net/core/src/socket/local/mod.rs
Normal file
94
kernel/driver/net/core/src/socket/local/mod.rs
Normal 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),
|
||||
}
|
||||
}
|
||||
}
|
329
kernel/driver/net/core/src/socket/local/packet.rs
Normal file
329
kernel/driver/net/core/src/socket/local/packet.rs
Normal 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()
|
||||
}
|
||||
}
|
@ -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()
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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};
|
||||
|
@ -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:?}");
|
||||
}
|
||||
|
@ -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>,
|
||||
|
@ -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)
|
||||
// })
|
||||
// }
|
||||
|
@ -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 _)
|
||||
});
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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",
|
||||
]
|
||||
|
||||
|
35
lib/abi-serde/src/impls/alloc.rs
Normal file
35
lib/abi-serde/src/impls/alloc.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
mod alloc;
|
||||
mod base;
|
||||
mod net;
|
||||
mod time;
|
||||
|
@ -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
46
lib/abi-serde/src/test.rs
Normal 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")
|
||||
}
|
||||
}
|
@ -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<()>;
|
||||
|
@ -96,3 +96,5 @@ impl From<u32> for RawFd {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
abi_serde::impl_newtype_serde!(RawFd);
|
||||
|
@ -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)]
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)]
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
]);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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) }
|
||||
}
|
||||
|
@ -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},
|
||||
|
@ -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
76
userspace/Cargo.lock
generated
@ -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"
|
||||
|
@ -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)'] }
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
|
55
userspace/lib/cross/src/mem.rs
Normal file
55
userspace/lib/cross/src/mem.rs
Normal 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()
|
||||
}
|
||||
}
|
104
userspace/lib/cross/src/net.rs
Normal file
104
userspace/lib/cross/src/net.rs
Normal 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())
|
||||
}
|
||||
}
|
@ -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>;
|
||||
}
|
||||
|
58
userspace/lib/cross/src/sys/unix/mem.rs
Normal file
58
userspace/lib/cross/src/sys/unix/mem.rs
Normal 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!()
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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!()
|
||||
}
|
||||
|
||||
|
185
userspace/lib/cross/src/sys/unix/socket.rs
Normal file
185
userspace/lib/cross/src/sys/unix/socket.rs
Normal 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())
|
||||
}
|
||||
}
|
65
userspace/lib/cross/src/sys/yggdrasil/mem.rs
Normal file
65
userspace/lib/cross/src/sys/yggdrasil/mem.rs
Normal 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()
|
||||
}
|
||||
}
|
@ -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};
|
||||
|
235
userspace/lib/cross/src/sys/yggdrasil/socket.rs
Normal file
235
userspace/lib/cross/src/sys/yggdrasil/socket.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
14
userspace/lib/runtime/Cargo.toml
Normal file
14
userspace/lib/runtime/Cargo.toml
Normal 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
|
12
userspace/lib/runtime/src/lib.rs
Normal file
12
userspace/lib/runtime/src/lib.rs
Normal 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;
|
@ -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)'] }
|
@ -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()
|
||||
}
|
||||
}
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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)))
|
||||
}
|
14
userspace/lib/uipc/Cargo.toml
Normal file
14
userspace/lib/uipc/Cargo.toml
Normal 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
|
149
userspace/lib/uipc/src/lib.rs
Normal file
149
userspace/lib/uipc/src/lib.rs
Normal 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()
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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)]
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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")]
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -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()),
|
||||
|
@ -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();
|
||||
// }
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
@ -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<()> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user