forked from rcore-os/zCore
Compare commits
2 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
678a84b0ae | |
|
|
d399f96024 |
|
|
@ -481,3 +481,19 @@ pub fn fill_random(_buf: &mut [u8]) {
|
|||
pub fn current_page_table() -> usize {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Generate a random u64.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn rand_u64() -> u64 {
|
||||
let mut r = 0;
|
||||
unsafe {
|
||||
core::arch::x86_64::_rdrand64_step(&mut r);
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
/// Generate a random u64.
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub fn rand_u64() -> u64 {
|
||||
todo!()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ bitflags = "1.2"
|
|||
hashbrown = "0.9"
|
||||
numeric-enum-macro = "0.2"
|
||||
zircon-object = { path = "../zircon-object", features = ["elf"] }
|
||||
smoltcp = "0.7"
|
||||
kernel-hal = { path = "../kernel-hal" }
|
||||
downcast-rs = { version = "1.2", default-features = false }
|
||||
lazy_static = { version = "1.4", features = ["spin_no_std"] }
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
#![deny(warnings, unsafe_code, missing_docs)]
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
#[macro_use]
|
||||
|
|
@ -15,6 +17,7 @@ pub mod error;
|
|||
|
||||
// layer 1
|
||||
pub mod fs;
|
||||
pub mod net;
|
||||
|
||||
// layer 2
|
||||
pub mod ipc;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,411 @@
|
|||
#![allow(unsafe_code, dead_code, missing_docs)]
|
||||
|
||||
use crate::error::*;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::fmt::Debug;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use async_trait::async_trait;
|
||||
use bitflags::*;
|
||||
use core::future::Future;
|
||||
use core::mem::size_of;
|
||||
use core::pin::Pin;
|
||||
use core::task::{Context, Poll};
|
||||
use lazy_static::lazy_static;
|
||||
use numeric_enum_macro::numeric_enum;
|
||||
use smoltcp::iface::{EthernetInterface, EthernetInterfaceBuilder};
|
||||
use smoltcp::phy::Device;
|
||||
use smoltcp::socket::{AnySocket, SocketHandle, SocketRef, SocketSet};
|
||||
use smoltcp::time::Instant;
|
||||
pub use smoltcp::wire;
|
||||
use smoltcp::wire::*;
|
||||
use spin::Mutex;
|
||||
|
||||
//mod tcp;
|
||||
//mod udp;
|
||||
//mod raw;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LinkLevelEndpoint {
|
||||
pub interface_index: usize,
|
||||
}
|
||||
|
||||
impl LinkLevelEndpoint {
|
||||
pub fn new(ifindex: usize) -> Self {
|
||||
LinkLevelEndpoint {
|
||||
interface_index: ifindex,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NetlinkEndpoint {
|
||||
pub port_id: u32,
|
||||
pub multicast_groups_mask: u32,
|
||||
}
|
||||
|
||||
impl NetlinkEndpoint {
|
||||
pub fn new(port_id: u32, multicast_groups_mask: u32) -> Self {
|
||||
NetlinkEndpoint {
|
||||
port_id,
|
||||
multicast_groups_mask,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Endpoint {
|
||||
Ip(IpEndpoint),
|
||||
LinkLevel(LinkLevelEndpoint),
|
||||
Netlink(NetlinkEndpoint),
|
||||
}
|
||||
|
||||
/// Common methods that a socket must have
|
||||
#[async_trait]
|
||||
pub trait Socket: Send + Sync + Debug {
|
||||
async fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint);
|
||||
fn write(&self, data: &[u8], sendto_endpoint: Option<Endpoint>) -> SysResult;
|
||||
fn poll(&self) -> (bool, bool, bool); // (in, out, err)
|
||||
async fn connect(&self, endpoint: Endpoint) -> SysResult;
|
||||
fn bind(&self, _endpoint: Endpoint) -> SysResult {
|
||||
Err(LxError::EINVAL)
|
||||
}
|
||||
fn listen(&self) -> SysResult {
|
||||
Err(LxError::EINVAL)
|
||||
}
|
||||
fn shutdown(&self) -> SysResult {
|
||||
Err(LxError::EINVAL)
|
||||
}
|
||||
async fn accept(&self) -> LxResult<(Arc<dyn Socket>, Endpoint)> {
|
||||
Err(LxError::EINVAL)
|
||||
}
|
||||
fn endpoint(&self) -> Option<Endpoint> {
|
||||
None
|
||||
}
|
||||
fn remote_endpoint(&self) -> Option<Endpoint> {
|
||||
None
|
||||
}
|
||||
fn setsockopt(&self, _level: usize, _opt: usize, _data: &[u8]) -> SysResult {
|
||||
warn!("setsockopt is unimplemented");
|
||||
Ok(0)
|
||||
}
|
||||
fn ioctl(&self, _request: usize, _arg1: usize, _arg2: usize, _arg3: usize) -> SysResult {
|
||||
warn!("ioctl is unimplemented for this socket");
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Global SocketSet in smoltcp.
|
||||
///
|
||||
/// Because smoltcp is a single thread network stack,
|
||||
/// every socket operation needs to lock this.
|
||||
///
|
||||
/// TODO: remove from global
|
||||
pub static ref SOCKETS: Mutex<SocketSet<'static>> =
|
||||
Mutex::new(SocketSet::new(vec![]));
|
||||
}
|
||||
|
||||
/// A wrapper for `SocketHandle`.
|
||||
/// Auto increase and decrease reference count on Clone and Drop.
|
||||
#[derive(Debug)]
|
||||
struct GlobalSocketHandle(SocketHandle);
|
||||
|
||||
impl Drop for GlobalSocketHandle {
|
||||
fn drop(&mut self) {
|
||||
let mut sockets = SOCKETS.lock();
|
||||
sockets.release(self.0);
|
||||
sockets.prune();
|
||||
|
||||
// send FIN immediately when applicable
|
||||
drop(sockets);
|
||||
poll_ifaces();
|
||||
}
|
||||
}
|
||||
|
||||
struct SmoltcpBase<D: for<'d> Device<'d>> {
|
||||
iface: EthernetInterface<'static, D>,
|
||||
socket_set: SocketSet<'static>,
|
||||
current_time: fn() -> Instant,
|
||||
}
|
||||
|
||||
impl<D: for<'d> Device<'d>> SmoltcpBase<D> {
|
||||
fn new(dev: D, current_time: fn() -> Instant) -> Self {
|
||||
SmoltcpBase {
|
||||
iface: EthernetInterfaceBuilder::new(dev).finalize(),
|
||||
socket_set: SocketSet::new(vec![]),
|
||||
current_time,
|
||||
}
|
||||
}
|
||||
|
||||
fn poll(&mut self) {
|
||||
let timestamp = (self.current_time)();
|
||||
match self.iface.poll(&mut self.socket_set, timestamp) {
|
||||
Ok(_) => {}
|
||||
Err(e) => debug!("iface poll error: {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
fn get<T: AnySocket<'static>>(&mut self, handle: SocketHandle) -> SocketRef<T> {
|
||||
self.socket_set.get(handle)
|
||||
}
|
||||
}
|
||||
|
||||
struct IFaceFuture;
|
||||
|
||||
impl Future for IFaceFuture {
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct ArpReq {
|
||||
arp_pa: SockAddrPlaceholder,
|
||||
arp_ha: SockAddrPlaceholder,
|
||||
arp_flags: u32,
|
||||
arp_netmask: SockAddrPlaceholder,
|
||||
arp_dev: [u8; 16],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SockAddrIn {
|
||||
pub sin_family: u16,
|
||||
pub sin_port: u16,
|
||||
pub sin_addr: u32,
|
||||
pub sin_zero: [u8; 8],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SockAddrUn {
|
||||
pub sun_family: u16,
|
||||
pub sun_path: [u8; 108],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SockAddrLl {
|
||||
pub sll_family: u16,
|
||||
pub sll_protocol: u16,
|
||||
pub sll_ifindex: u32,
|
||||
pub sll_hatype: u16,
|
||||
pub sll_pkttype: u8,
|
||||
pub sll_halen: u8,
|
||||
pub sll_addr: [u8; 8],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SockAddrNl {
|
||||
nl_family: u16,
|
||||
nl_pad: u16,
|
||||
nl_pid: u32,
|
||||
nl_groups: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union SockAddr {
|
||||
pub family: u16,
|
||||
pub addr_in: SockAddrIn,
|
||||
pub addr_un: SockAddrUn,
|
||||
pub addr_ll: SockAddrLl,
|
||||
pub addr_nl: SockAddrNl,
|
||||
pub addr_ph: SockAddrPlaceholder,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SockAddrPlaceholder {
|
||||
pub family: u16,
|
||||
pub data: [u8; 14],
|
||||
}
|
||||
|
||||
/// Common structure:
|
||||
/// | nlmsghdr | ifinfomsg/ifaddrmsg | rtattr | rtattr | rtattr | ... | rtattr
|
||||
/// All aligned to 4 bytes boundary
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct NetlinkMessageHeader {
|
||||
nlmsg_len: u32, // length of message including header
|
||||
nlmsg_type: u16, // message content
|
||||
nlmsg_flags: NetlinkMessageFlags, // additional flags
|
||||
nlmsg_seq: u32, // sequence number
|
||||
nlmsg_pid: u32, // sending process port id
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct IfaceInfoMsg {
|
||||
ifi_family: u16,
|
||||
ifi_type: u16,
|
||||
ifi_index: u32,
|
||||
ifi_flags: u32,
|
||||
ifi_change: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct IfaceAddrMsg {
|
||||
ifa_family: u8,
|
||||
ifa_prefixlen: u8,
|
||||
ifa_flags: u8,
|
||||
ifa_scope: u8,
|
||||
ifa_index: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct RouteAttr {
|
||||
rta_len: u16,
|
||||
rta_type: u16,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
struct NetlinkMessageFlags : u16 {
|
||||
const REQUEST = 0x01;
|
||||
const MULTI = 0x02;
|
||||
const ACK = 0x04;
|
||||
const ECHO = 0x08;
|
||||
const DUMP_INTR = 0x10;
|
||||
const DUMP_FILTERED = 0x20;
|
||||
// GET request
|
||||
const ROOT = 0x100;
|
||||
const MATCH = 0x200;
|
||||
const ATOMIC = 0x400;
|
||||
const DUMP = 0x100 | 0x200;
|
||||
// NEW request
|
||||
const REPLACE = 0x100;
|
||||
const EXCL = 0x200;
|
||||
const CREATE = 0x400;
|
||||
const APPEND = 0x800;
|
||||
// DELETE request
|
||||
const NONREC = 0x100;
|
||||
// ACK message
|
||||
const CAPPED = 0x100;
|
||||
const ACK_TLVS = 0x200;
|
||||
}
|
||||
}
|
||||
|
||||
numeric_enum! {
|
||||
#[repr(u16)]
|
||||
/// Netlink message types
|
||||
pub enum NetlinkMessageType {
|
||||
/// Nothing
|
||||
Noop = 1,
|
||||
/// Error
|
||||
Error = 2,
|
||||
/// End of a dump
|
||||
Done = 3,
|
||||
/// Data lost
|
||||
Overrun = 4,
|
||||
/// New link
|
||||
NewLink = 16,
|
||||
/// Delete link
|
||||
DelLink = 17,
|
||||
/// Get link
|
||||
GetLink = 18,
|
||||
/// Set link
|
||||
SetLink = 19,
|
||||
/// New addr
|
||||
NewAddr = 20,
|
||||
/// Delete addr
|
||||
DelAddr = 21,
|
||||
/// Get addr
|
||||
GetAddr = 22,
|
||||
}
|
||||
}
|
||||
|
||||
numeric_enum! {
|
||||
#[repr(u16)]
|
||||
/// Route Attr Types
|
||||
pub enum RouteAttrTypes {
|
||||
/// Unspecified
|
||||
Unspecified = 0,
|
||||
/// MAC Address
|
||||
Address = 1,
|
||||
/// Broadcast
|
||||
Broadcast = 2,
|
||||
/// Interface name
|
||||
Ifname = 3,
|
||||
/// MTU
|
||||
MTU = 4,
|
||||
/// Link
|
||||
Link = 5,
|
||||
}
|
||||
}
|
||||
|
||||
trait VecExt {
|
||||
fn align4(&mut self);
|
||||
fn push_ext<T: Sized>(&mut self, data: T);
|
||||
fn set_ext<T: Sized>(&mut self, offset: usize, data: T);
|
||||
}
|
||||
|
||||
impl VecExt for Vec<u8> {
|
||||
fn align4(&mut self) {
|
||||
let len = (self.len() + 3) & !3;
|
||||
if len > self.len() {
|
||||
self.resize(len, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn push_ext<T: Sized>(&mut self, data: T) {
|
||||
let bytes =
|
||||
unsafe { core::slice::from_raw_parts(&data as *const T as *const u8, size_of::<T>()) };
|
||||
for byte in bytes {
|
||||
self.push(*byte);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_ext<T: Sized>(&mut self, offset: usize, data: T) {
|
||||
if self.len() < offset + size_of::<T>() {
|
||||
self.resize(offset + size_of::<T>(), 0);
|
||||
}
|
||||
let bytes =
|
||||
unsafe { core::slice::from_raw_parts(&data as *const T as *const u8, size_of::<T>()) };
|
||||
for i in 0..bytes.len() {
|
||||
self[offset + i] = bytes[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_ephemeral_port() -> u16 {
|
||||
// TODO selects non-conflict high port
|
||||
static mut EPHEMERAL_PORT: u16 = 0;
|
||||
unsafe {
|
||||
if EPHEMERAL_PORT == 0 {
|
||||
EPHEMERAL_PORT = (49152 + kernel_hal::rand_u64() % (65536 - 49152)) as u16;
|
||||
}
|
||||
if EPHEMERAL_PORT == 65535 {
|
||||
EPHEMERAL_PORT = 49152;
|
||||
} else {
|
||||
EPHEMERAL_PORT = EPHEMERAL_PORT + 1;
|
||||
}
|
||||
EPHEMERAL_PORT
|
||||
}
|
||||
}
|
||||
|
||||
/// Safety: call this without SOCKETS locked
|
||||
fn poll_ifaces() {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
numeric_enum! {
|
||||
#[repr(u16)]
|
||||
#[derive(Debug)]
|
||||
/// Address families
|
||||
pub enum AddressFamily {
|
||||
/// Unspecified
|
||||
Unspecified = 0,
|
||||
/// Unix domain sockets
|
||||
Unix = 1,
|
||||
/// Internet IP Protocol
|
||||
Internet = 2,
|
||||
/// Netlink
|
||||
Netlink = 16,
|
||||
/// Packet family
|
||||
Packet = 17,
|
||||
}
|
||||
}
|
||||
|
||||
const IPPROTO_IP: usize = 0;
|
||||
const IP_HDRINCL: usize = 3;
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
use super::*;
|
||||
use smoltcp::socket::{RawPacketMetadata, RawSocket, RawSocketBuffer};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RawSocketState {
|
||||
handle: GlobalSocketHandle,
|
||||
header_included: bool,
|
||||
}
|
||||
|
||||
impl RawSocketState {
|
||||
pub fn new(protocol: u8) -> Self {
|
||||
let rx_buffer = RawSocketBuffer::new(
|
||||
vec![RawPacketMetadata::EMPTY; RAW_METADATA_BUF],
|
||||
vec![0; RAW_RECVBUF],
|
||||
);
|
||||
let tx_buffer = RawSocketBuffer::new(
|
||||
vec![RawPacketMetadata::EMPTY; RAW_METADATA_BUF],
|
||||
vec![0; RAW_SENDBUF],
|
||||
);
|
||||
let socket = RawSocket::new(
|
||||
IpVersion::Ipv4,
|
||||
IpProtocol::from(protocol),
|
||||
rx_buffer,
|
||||
tx_buffer,
|
||||
);
|
||||
let handle = GlobalSocketHandle(SOCKETS.lock().add(socket));
|
||||
|
||||
RawSocketState {
|
||||
handle,
|
||||
header_included: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Socket for RawSocketState {
|
||||
async fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) {
|
||||
loop {
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let mut socket = sockets.get::<RawSocket>(self.handle.0);
|
||||
|
||||
if let Ok(size) = socket.recv_slice(data) {
|
||||
let packet = Ipv4Packet::new_unchecked(data);
|
||||
|
||||
return (
|
||||
Ok(size),
|
||||
Endpoint::Ip(IpEndpoint {
|
||||
addr: IpAddress::Ipv4(packet.src_addr()),
|
||||
port: 0,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
drop(socket);
|
||||
drop(sockets);
|
||||
IFaceFuture.await;
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, data: &[u8], sendto_endpoint: Option<Endpoint>) -> SysResult {
|
||||
if self.header_included {
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let mut socket = sockets.get::<RawSocket>(self.handle.0);
|
||||
|
||||
match socket.send_slice(&data) {
|
||||
Ok(()) => Ok(data.len()),
|
||||
Err(_) => Err(LxError::ENOBUFS),
|
||||
}
|
||||
} else {
|
||||
if let Some(Endpoint::Ip(_endpoint)) = sendto_endpoint {
|
||||
unimplemented!();
|
||||
// temporary solution
|
||||
// let iface = &*(NET_DRIVERS.read()[0]);
|
||||
// let v4_src = iface.ipv4_address().unwrap();
|
||||
// let mut sockets = SOCKETS.lock();
|
||||
// let mut socket = sockets.get::<RawSocket>(self.handle.0);
|
||||
//
|
||||
// if let IpAddress::Ipv4(v4_dst) = endpoint.addr {
|
||||
// let len = data.len();
|
||||
// // using 20-byte IPv4 header
|
||||
// let mut buffer = vec![0u8; len + 20];
|
||||
// let mut packet = Ipv4Packet::new_unchecked(&mut buffer);
|
||||
// packet.set_version(4);
|
||||
// packet.set_header_len(20);
|
||||
// packet.set_total_len((20 + len) as u16);
|
||||
// packet.set_protocol(socket.ip_protocol().into());
|
||||
// packet.set_src_addr(v4_src);
|
||||
// packet.set_dst_addr(v4_dst);
|
||||
// let payload = packet.payload_mut();
|
||||
// payload.copy_from_slice(data);
|
||||
// packet.fill_checksum();
|
||||
//
|
||||
// socket.send_slice(&buffer).unwrap();
|
||||
//
|
||||
// // avoid deadlock
|
||||
// drop(socket);
|
||||
// drop(sockets);
|
||||
// iface.poll();
|
||||
//
|
||||
// Ok(len)
|
||||
// } else {
|
||||
// unimplemented!("ip type")
|
||||
// }
|
||||
} else {
|
||||
Err(LxError::ENOTCONN)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn poll(&self) -> (bool, bool, bool) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
async fn connect(&self, _endpoint: Endpoint) -> SysResult {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn setsockopt(&self, level: usize, opt: usize, data: &[u8]) -> SysResult {
|
||||
match (level, opt) {
|
||||
(IPPROTO_IP, IP_HDRINCL) => {
|
||||
if let Some(arg) = data.first() {
|
||||
self.header_included = *arg > 0;
|
||||
debug!("hdrincl set to {}", self.header_included);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
const RAW_METADATA_BUF: usize = 1024;
|
||||
const RAW_SENDBUF: usize = 64 * 1024; // 64K
|
||||
const RAW_RECVBUF: usize = 64 * 1024; // 64K
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
use super::*;
|
||||
use smoltcp::socket::{TcpSocket, TcpSocketBuffer, TcpState};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TcpSocketState {
|
||||
inner: Mutex<TcpInner>,
|
||||
}
|
||||
|
||||
struct TcpInner {
|
||||
handle: GlobalSocketHandle,
|
||||
local_endpoint: Option<IpEndpoint>, // save local endpoint for bind()
|
||||
is_listening: bool,
|
||||
}
|
||||
|
||||
impl TcpSocketState {
|
||||
pub fn new() -> Self {
|
||||
let rx_buffer = TcpSocketBuffer::new(vec![0; TCP_RECVBUF]);
|
||||
let tx_buffer = TcpSocketBuffer::new(vec![0; TCP_SENDBUF]);
|
||||
let socket = TcpSocket::new(rx_buffer, tx_buffer);
|
||||
let handle = GlobalSocketHandle(SOCKETS.lock().add(socket));
|
||||
|
||||
TcpSocketState {
|
||||
inner: Mutex::new(TcpInner {
|
||||
handle,
|
||||
local_endpoint: None,
|
||||
is_listening: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Socket for TcpSocketState {
|
||||
async fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) {
|
||||
loop {
|
||||
poll_ifaces();
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
|
||||
|
||||
if socket.may_recv() {
|
||||
if let Ok(size) = socket.recv_slice(data) {
|
||||
if size > 0 {
|
||||
let endpoint = socket.remote_endpoint();
|
||||
// avoid deadlock
|
||||
drop(socket);
|
||||
drop(sockets);
|
||||
|
||||
poll_ifaces();
|
||||
return (Ok(size), Endpoint::Ip(endpoint));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
Err(LxError::ENOTCONN),
|
||||
Endpoint::Ip(IpEndpoint::UNSPECIFIED),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, data: &[u8], _sendto_endpoint: Option<Endpoint>) -> SysResult {
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
|
||||
|
||||
if socket.is_open() {
|
||||
if socket.can_send() {
|
||||
match socket.send_slice(&data) {
|
||||
Ok(size) => {
|
||||
// avoid deadlock
|
||||
drop(socket);
|
||||
drop(sockets);
|
||||
|
||||
poll_ifaces();
|
||||
Ok(size)
|
||||
}
|
||||
Err(_) => Err(LxError::ENOBUFS),
|
||||
}
|
||||
} else {
|
||||
Err(LxError::ENOBUFS)
|
||||
}
|
||||
} else {
|
||||
Err(LxError::ENOTCONN)
|
||||
}
|
||||
}
|
||||
|
||||
fn poll(&self) -> (bool, bool, bool) {
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let socket = sockets.get::<TcpSocket>(self.handle.0);
|
||||
|
||||
let (mut input, mut output, mut err) = (false, false, false);
|
||||
if self.is_listening && socket.is_active() {
|
||||
// a new connection
|
||||
input = true;
|
||||
} else if !socket.is_open() {
|
||||
err = true;
|
||||
} else {
|
||||
if socket.can_recv() {
|
||||
input = true;
|
||||
}
|
||||
if socket.can_send() {
|
||||
output = true;
|
||||
}
|
||||
}
|
||||
(input, output, err)
|
||||
}
|
||||
|
||||
async fn connect(&self, endpoint: Endpoint) -> SysResult {
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
|
||||
|
||||
if let Endpoint::Ip(ip) = endpoint {
|
||||
let temp_port = get_ephemeral_port();
|
||||
|
||||
socket
|
||||
.connect(ip, temp_port)
|
||||
.map_err(|_| LxError::ENOBUFS)?;
|
||||
// avoid deadlock
|
||||
drop(socket);
|
||||
drop(sockets);
|
||||
|
||||
// wait for connection result
|
||||
loop {
|
||||
poll_ifaces();
|
||||
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let socket = sockets.get::<TcpSocket>(self.handle.0);
|
||||
match socket.state() {
|
||||
TcpState::SynSent => {
|
||||
// still connecting
|
||||
drop(socket);
|
||||
debug!("poll for connection wait");
|
||||
drop(sockets);
|
||||
IFaceFuture.await;
|
||||
}
|
||||
TcpState::Established => {
|
||||
return Ok(0);
|
||||
}
|
||||
_ => {
|
||||
return Err(LxError::ECONNREFUSED);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(LxError::EINVAL)
|
||||
}
|
||||
}
|
||||
|
||||
fn bind(&self, endpoint: Endpoint) -> SysResult {
|
||||
if let Endpoint::Ip(mut ip) = endpoint {
|
||||
if ip.port == 0 {
|
||||
ip.port = get_ephemeral_port();
|
||||
}
|
||||
self.local_endpoint = Some(ip);
|
||||
self.is_listening = false;
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(LxError::EINVAL)
|
||||
}
|
||||
}
|
||||
|
||||
fn listen(&self) -> SysResult {
|
||||
if self.is_listening {
|
||||
// it is ok to listen twice
|
||||
return Ok(0);
|
||||
}
|
||||
let local_endpoint = self.local_endpoint.ok_or(LxError::EINVAL)?;
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
|
||||
|
||||
info!("socket listening on {:?}", local_endpoint);
|
||||
if socket.is_listening() {
|
||||
return Ok(0);
|
||||
}
|
||||
match socket.listen(local_endpoint) {
|
||||
Ok(()) => {
|
||||
self.is_listening = true;
|
||||
Ok(0)
|
||||
}
|
||||
Err(_) => Err(LxError::EINVAL),
|
||||
}
|
||||
}
|
||||
|
||||
fn shutdown(&self) -> SysResult {
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let mut socket = sockets.get::<TcpSocket>(self.handle.0);
|
||||
socket.close();
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
async fn accept(&self) -> LxResult<(Box<dyn Socket>, Endpoint)> {
|
||||
let endpoint = self.local_endpoint.ok_or(LxError::EINVAL)?;
|
||||
loop {
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let socket = sockets.get::<TcpSocket>(self.handle.0);
|
||||
|
||||
if socket.is_active() {
|
||||
let remote_endpoint = socket.remote_endpoint();
|
||||
drop(socket);
|
||||
|
||||
let new_socket = {
|
||||
let rx_buffer = TcpSocketBuffer::new(vec![0; TCP_RECVBUF]);
|
||||
let tx_buffer = TcpSocketBuffer::new(vec![0; TCP_SENDBUF]);
|
||||
let mut socket = TcpSocket::new(rx_buffer, tx_buffer);
|
||||
socket.listen(endpoint).unwrap();
|
||||
let new_handle = GlobalSocketHandle(sockets.add(socket));
|
||||
let old_handle = core::mem::replace(&self.handle, new_handle);
|
||||
|
||||
Box::new(TcpSocketState {
|
||||
handle: old_handle,
|
||||
local_endpoint: self.local_endpoint,
|
||||
is_listening: false,
|
||||
})
|
||||
};
|
||||
|
||||
drop(sockets);
|
||||
poll_ifaces();
|
||||
return Ok((new_socket, Endpoint::Ip(remote_endpoint)));
|
||||
}
|
||||
|
||||
drop(socket);
|
||||
drop(sockets);
|
||||
IFaceFuture.await;
|
||||
}
|
||||
}
|
||||
|
||||
fn endpoint(&self) -> Option<Endpoint> {
|
||||
self.local_endpoint
|
||||
.clone()
|
||||
.map(|e| Endpoint::Ip(e))
|
||||
.or_else(|| {
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let socket = sockets.get::<TcpSocket>(self.handle.0);
|
||||
let endpoint = socket.local_endpoint();
|
||||
if endpoint.port != 0 {
|
||||
Some(Endpoint::Ip(endpoint))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn remote_endpoint(&self) -> Option<Endpoint> {
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let socket = sockets.get::<TcpSocket>(self.handle.0);
|
||||
if socket.is_open() {
|
||||
Some(Endpoint::Ip(socket.remote_endpoint()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const TCP_SENDBUF: usize = 512 * 1024; // 512K
|
||||
pub const TCP_RECVBUF: usize = 512 * 1024; // 512K
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
use super::*;
|
||||
use smoltcp::socket::{UdpSocket, UdpSocketBuffer, UdpPacketMetadata};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UdpSocketState {
|
||||
handle: GlobalSocketHandle,
|
||||
remote_endpoint: Option<IpEndpoint>, // remember remote endpoint for connect()
|
||||
}
|
||||
|
||||
impl UdpSocketState {
|
||||
pub fn new() -> Self {
|
||||
let rx_buffer = UdpSocketBuffer::new(
|
||||
vec![UdpPacketMetadata::EMPTY; UDP_METADATA_BUF],
|
||||
vec![0; UDP_RECVBUF],
|
||||
);
|
||||
let tx_buffer = UdpSocketBuffer::new(
|
||||
vec![UdpPacketMetadata::EMPTY; UDP_METADATA_BUF],
|
||||
vec![0; UDP_SENDBUF],
|
||||
);
|
||||
let socket = UdpSocket::new(rx_buffer, tx_buffer);
|
||||
let handle = GlobalSocketHandle(SOCKETS.lock().add(socket));
|
||||
|
||||
UdpSocketState {
|
||||
handle,
|
||||
remote_endpoint: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for UdpSocketState {
|
||||
fn drop(&self) {
|
||||
let mut sockets = self.sockets.lock();
|
||||
sockets.release(self.handle);
|
||||
sockets.prune();
|
||||
|
||||
// send FIN immediately when applicable
|
||||
drop(sockets);
|
||||
poll_ifaces();
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Socket for UdpSocketState {
|
||||
async fn read(&self, data: &mut [u8]) -> (SysResult, Endpoint) {
|
||||
loop {
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let mut socket = sockets.get::<UdpSocket>(self.handle.0);
|
||||
|
||||
if socket.can_recv() {
|
||||
if let Ok((size, remote_endpoint)) = socket.recv_slice(data) {
|
||||
let endpoint = remote_endpoint;
|
||||
// avoid deadlock
|
||||
drop(socket);
|
||||
drop(sockets);
|
||||
|
||||
poll_ifaces();
|
||||
return (Ok(size), Endpoint::Ip(endpoint));
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
Err(LxError::ENOTCONN),
|
||||
Endpoint::Ip(IpEndpoint::UNSPECIFIED),
|
||||
);
|
||||
}
|
||||
|
||||
drop(socket);
|
||||
drop(sockets);
|
||||
IFaceFuture.await;
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, data: &[u8], sendto_endpoint: Option<Endpoint>) -> SysResult {
|
||||
let remote_endpoint = {
|
||||
if let Some(Endpoint::Ip(ref endpoint)) = sendto_endpoint {
|
||||
endpoint
|
||||
} else if let Some(ref endpoint) = self.remote_endpoint {
|
||||
endpoint
|
||||
} else {
|
||||
return Err(LxError::ENOTCONN);
|
||||
}
|
||||
};
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let mut socket = sockets.get::<UdpSocket>(self.handle.0);
|
||||
|
||||
if socket.endpoint().port == 0 {
|
||||
let temp_port = get_ephemeral_port();
|
||||
socket
|
||||
.bind(IpEndpoint::new(IpAddress::Unspecified, temp_port))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if socket.can_send() {
|
||||
match socket.send_slice(&data, *remote_endpoint) {
|
||||
Ok(()) => {
|
||||
// avoid deadlock
|
||||
drop(socket);
|
||||
drop(sockets);
|
||||
|
||||
poll_ifaces();
|
||||
Ok(data.len())
|
||||
}
|
||||
Err(_) => Err(LxError::ENOBUFS),
|
||||
}
|
||||
} else {
|
||||
Err(LxError::ENOBUFS)
|
||||
}
|
||||
}
|
||||
|
||||
fn poll(&self) -> (bool, bool, bool) {
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let socket = sockets.get::<UdpSocket>(self.handle.0);
|
||||
|
||||
let (mut input, mut output, err) = (false, false, false);
|
||||
if socket.can_recv() {
|
||||
input = true;
|
||||
}
|
||||
if socket.can_send() {
|
||||
output = true;
|
||||
}
|
||||
(input, output, err)
|
||||
}
|
||||
|
||||
async fn connect(&self, endpoint: Endpoint) -> SysResult {
|
||||
if let Endpoint::Ip(ip) = endpoint {
|
||||
self.remote_endpoint = Some(ip);
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(LxError::EINVAL)
|
||||
}
|
||||
}
|
||||
|
||||
fn bind(&self, endpoint: Endpoint) -> SysResult {
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let mut socket = sockets.get::<UdpSocket>(self.handle.0);
|
||||
if let Endpoint::Ip(ip) = endpoint {
|
||||
match socket.bind(ip) {
|
||||
Ok(()) => Ok(0),
|
||||
Err(_) => Err(LxError::EINVAL),
|
||||
}
|
||||
} else {
|
||||
Err(LxError::EINVAL)
|
||||
}
|
||||
}
|
||||
|
||||
fn ioctl(&self, request: usize, arg1: usize, _arg2: usize, _arg3: usize) -> SysResult {
|
||||
match request {
|
||||
// SIOCGARP
|
||||
0x8954 => {
|
||||
// FIXME: check addr
|
||||
let req = unsafe { &mut *(arg1 as *mut ArpReq) };
|
||||
if let AddressFamily::Internet = AddressFamily::from(req.arp_pa.family) {
|
||||
unimplemented!();
|
||||
|
||||
// let ifname = req.iface_name();
|
||||
// let addr = &req.arp_pa as *const SockAddrPlaceholder as *const SockAddr;
|
||||
// let addr = unsafe {
|
||||
// IpAddress::from(Ipv4Address::from_bytes(
|
||||
// &u32::from_be((*addr).addr_in.sin_addr).to_be_bytes()[..],
|
||||
// ))
|
||||
// };
|
||||
// for iface in NET_DRIVERS.read().iter() {
|
||||
// if iface.get_ifname() == ifname {
|
||||
// debug!("get arp matched ifname {}", ifname);
|
||||
// return match iface.get_arp(addr) {
|
||||
// Some(mac) => {
|
||||
// // TODO: update flags
|
||||
// req.arp_ha.data[0..6].copy_from_slice(mac.as_bytes());
|
||||
// Ok(0)
|
||||
// }
|
||||
// None => Err(LxError::ENOENT),
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// Err(LxError::ENOENT)
|
||||
} else {
|
||||
Err(LxError::EINVAL)
|
||||
}
|
||||
}
|
||||
_ => Ok(0),
|
||||
}
|
||||
}
|
||||
|
||||
fn endpoint(&self) -> Option<Endpoint> {
|
||||
let mut sockets = SOCKETS.lock();
|
||||
let socket = sockets.get::<UdpSocket>(self.handle.0);
|
||||
let endpoint = socket.endpoint();
|
||||
if endpoint.port != 0 {
|
||||
Some(Endpoint::Ip(endpoint))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn remote_endpoint(&self) -> Option<Endpoint> {
|
||||
self.remote_endpoint.clone().map(|e| Endpoint::Ip(e))
|
||||
}
|
||||
}
|
||||
|
||||
const UDP_METADATA_BUF: usize = 1024;
|
||||
const UDP_SENDBUF: usize = 64 * 1024; // 64K
|
||||
const UDP_RECVBUF: usize = 64 * 1024; // 64K
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
use crate::error::*;
|
||||
use crate::fs::*;
|
||||
use crate::ipc::*;
|
||||
use crate::net::Socket;
|
||||
use crate::signal::{Signal as LinuxSignal, SignalAction};
|
||||
use alloc::vec::Vec;
|
||||
use alloc::{
|
||||
|
|
@ -314,6 +315,21 @@ impl LinuxProcess {
|
|||
Ok(inner.files.clone())
|
||||
}
|
||||
|
||||
/// Add a socket to the file descriptor table.
|
||||
pub fn add_socket(&self, _socket: Arc<dyn Socket>) -> LxResult<FileDesc> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Get the `Socket` with given `fd`.
|
||||
pub fn get_socket(&self, _fd: FileDesc) -> LxResult<Arc<dyn Socket>> {
|
||||
unimplemented!()
|
||||
// let file = self
|
||||
// .get_file_like(fd)?
|
||||
// .downcast_arc::<Socket>()
|
||||
// .map_err(|_| LxError::EBADF)?;
|
||||
// Ok(file)
|
||||
}
|
||||
|
||||
/// Close file descriptor `fd`.
|
||||
pub fn close_file(&self, fd: FileDesc) -> LxResult {
|
||||
let mut inner = self.inner.lock();
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#![no_std]
|
||||
#![deny(warnings, unsafe_code, missing_docs)]
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
#![feature(untagged_unions)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
|
@ -47,6 +48,7 @@ mod consts {
|
|||
mod file;
|
||||
mod ipc;
|
||||
mod misc;
|
||||
mod net;
|
||||
mod signal;
|
||||
mod task;
|
||||
mod time;
|
||||
|
|
@ -166,21 +168,24 @@ impl Syscall<'_> {
|
|||
Sys::SCHED_GETAFFINITY => self.unimplemented("sched_getaffinity", Ok(0)),
|
||||
|
||||
// socket
|
||||
// Sys::SOCKET => self.sys_socket(a0, a1, a2),
|
||||
// Sys::CONNECT => self.sys_connect(a0, a1.into(), a2),
|
||||
// Sys::ACCEPT => self.sys_accept(a0, a1.into(), a2.into()),
|
||||
// Sys::ACCEPT4 => self.sys_accept(a0, a1.into(), a2.into()), // use accept for accept4
|
||||
// Sys::SENDTO => self.sys_sendto(a0, a1.into(), a2, a3, a4.into(), a5),
|
||||
// Sys::RECVFROM => self.sys_recvfrom(a0, a1.into(), a2, a3, a4.into(), a5.into()),
|
||||
Sys::SOCKET => self.sys_socket(a0, a1, a2),
|
||||
Sys::CONNECT => self.sys_connect(a0.into(), a1.into(), a2).await,
|
||||
Sys::ACCEPT => self.sys_accept(a0.into(), a1.into(), a2.into()).await,
|
||||
Sys::ACCEPT4 => self.sys_accept(a0.into(), a1.into(), a2.into()).await, // use accept for accept4
|
||||
Sys::SENDTO => self.sys_sendto(a0.into(), a1.into(), a2, a3, a4.into(), a5),
|
||||
Sys::RECVFROM => {
|
||||
self.sys_recvfrom(a0.into(), a1.into(), a2, a3, a4.into(), a5.into())
|
||||
.await
|
||||
}
|
||||
// Sys::SENDMSG => self.sys_sendmsg(),
|
||||
// Sys::RECVMSG => self.sys_recvmsg(a0, a1.into(), a2),
|
||||
// Sys::SHUTDOWN => self.sys_shutdown(a0, a1),
|
||||
// Sys::BIND => self.sys_bind(a0, a1.into(), a2),
|
||||
// Sys::LISTEN => self.sys_listen(a0, a1),
|
||||
// Sys::GETSOCKNAME => self.sys_getsockname(a0, a1.into(), a2.into()),
|
||||
// Sys::GETPEERNAME => self.sys_getpeername(a0, a1.into(), a2.into()),
|
||||
// Sys::SETSOCKOPT => self.sys_setsockopt(a0, a1, a2, a3.into(), a4),
|
||||
// Sys::GETSOCKOPT => self.sys_getsockopt(a0, a1, a2, a3.into(), a4.into()),
|
||||
Sys::SHUTDOWN => self.sys_shutdown(a0.into(), a1),
|
||||
Sys::BIND => self.sys_bind(a0.into(), a1.into(), a2),
|
||||
Sys::LISTEN => self.sys_listen(a0.into(), a1),
|
||||
Sys::GETSOCKNAME => self.sys_getsockname(a0.into(), a1.into(), a2.into()),
|
||||
Sys::GETPEERNAME => self.sys_getpeername(a0.into(), a1.into(), a2.into()),
|
||||
Sys::SETSOCKOPT => self.sys_setsockopt(a0.into(), a1, a2, a3.into(), a4),
|
||||
Sys::GETSOCKOPT => self.sys_getsockopt(a0.into(), a1, a2, a3.into(), a4.into()),
|
||||
|
||||
// process
|
||||
Sys::CLONE => self.sys_clone(a0, a1, a2.into(), a3.into(), a4),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,504 @@
|
|||
//! Syscalls for networking
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use super::*;
|
||||
use core::cmp::min;
|
||||
use core::mem::size_of;
|
||||
use linux_object::net::{wire::*, *};
|
||||
use numeric_enum_macro::numeric_enum;
|
||||
|
||||
impl Syscall<'_> {
|
||||
pub fn sys_socket(&mut self, domain: usize, socket_type: usize, protocol: usize) -> SysResult {
|
||||
let domain = AddressFamily::try_from(domain as u16).map_err(|_| LxError::EINVAL)?;
|
||||
let socket_type = SocketType::try_from(socket_type as u8 & SOCK_TYPE_MASK)
|
||||
.map_err(|_| LxError::EINVAL)?;
|
||||
info!(
|
||||
"socket: domain={:?}, socket_type={:?}, protocol={}",
|
||||
domain, socket_type, protocol
|
||||
);
|
||||
unimplemented!();
|
||||
// let proc = self.linux_process();
|
||||
// let socket: Arc<dyn Socket> = match domain {
|
||||
// AddressFamily::Internet | AddressFamily::Unix => match socket_type {
|
||||
// SocketType::Stream => Arc::new(TcpSocketState::new()),
|
||||
// SocketType::Datagram => Arc::new(UdpSocketState::new()),
|
||||
// SocketType::Raw => Arc::new(RawSocketState::new(protocol as u8)),
|
||||
// },
|
||||
// AddressFamily::Packet => match socket_type {
|
||||
// SocketType::Raw => Arc::new(PacketSocketState::new()),
|
||||
// _ => return Err(LxError::EINVAL),
|
||||
// },
|
||||
// AddressFamily::Netlink => match socket_type {
|
||||
// SocketType::Raw => Arc::new(NetlinkSocketState::new()),
|
||||
// _ => return Err(LxError::EINVAL),
|
||||
// },
|
||||
// _ => return Err(LxError::EAFNOSUPPORT),
|
||||
// };
|
||||
// let fd = proc.add_socket(socket)?;
|
||||
// Ok(fd.into())
|
||||
}
|
||||
|
||||
pub fn sys_setsockopt(
|
||||
&mut self,
|
||||
fd: FileDesc,
|
||||
level: usize,
|
||||
optname: usize,
|
||||
optval: UserInPtr<u8>,
|
||||
optlen: usize,
|
||||
) -> SysResult {
|
||||
info!(
|
||||
"setsockopt: fd={:?}, level={}, optname={}",
|
||||
fd, level, optname
|
||||
);
|
||||
let proc = self.linux_process();
|
||||
let data = optval.read_array(optlen)?;
|
||||
let socket = proc.get_socket(fd)?;
|
||||
socket.setsockopt(level, optname, &data)
|
||||
}
|
||||
|
||||
pub fn sys_getsockopt(
|
||||
&mut self,
|
||||
fd: FileDesc,
|
||||
level: usize,
|
||||
optname: usize,
|
||||
optval: UserOutPtr<u32>,
|
||||
mut optlen: UserOutPtr<u32>,
|
||||
) -> SysResult {
|
||||
info!(
|
||||
"getsockopt: fd={:?}, level={}, optname={} optval={:?} optlen={:?}",
|
||||
fd, level, optname, optval, optlen
|
||||
);
|
||||
match level {
|
||||
SOL_SOCKET => match optname {
|
||||
SO_SNDBUF => {
|
||||
// optval.write(TCP_SENDBUF as u32)?;
|
||||
optlen.write(4)?;
|
||||
Ok(0)
|
||||
}
|
||||
SO_RCVBUF => {
|
||||
// optval.write(TCP_RECVBUF as u32)?;
|
||||
optlen.write(4)?;
|
||||
Ok(0)
|
||||
}
|
||||
_ => Err(LxError::ENOPROTOOPT),
|
||||
},
|
||||
IPPROTO_TCP => match optname {
|
||||
TCP_CONGESTION => Ok(0),
|
||||
_ => Err(LxError::ENOPROTOOPT),
|
||||
},
|
||||
_ => Err(LxError::ENOPROTOOPT),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn sys_connect(
|
||||
&mut self,
|
||||
fd: FileDesc,
|
||||
addr: UserInPtr<SockAddr>,
|
||||
addr_len: usize,
|
||||
) -> SysResult {
|
||||
info!(
|
||||
"sys_connect: fd={:?}, addr={:?}, addr_len={}",
|
||||
fd, addr, addr_len
|
||||
);
|
||||
|
||||
let proc = self.linux_process();
|
||||
let endpoint = sockaddr_to_endpoint(addr, addr_len)?;
|
||||
let socket = proc.get_socket(fd)?;
|
||||
socket.connect(endpoint).await?;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
pub fn sys_sendto(
|
||||
&mut self,
|
||||
fd: FileDesc,
|
||||
base: UserInPtr<u8>,
|
||||
len: usize,
|
||||
_flags: usize,
|
||||
addr: UserInPtr<SockAddr>,
|
||||
addr_len: usize,
|
||||
) -> SysResult {
|
||||
info!(
|
||||
"sys_sendto: fd={:?} base={:?} len={} addr={:?} addr_len={}",
|
||||
fd, base, len, addr, addr_len
|
||||
);
|
||||
|
||||
let proc = self.linux_process();
|
||||
|
||||
let slice = base.read_array(len)?;
|
||||
let endpoint = if addr.is_null() {
|
||||
None
|
||||
} else {
|
||||
let endpoint = sockaddr_to_endpoint(addr, addr_len)?;
|
||||
info!("sys_sendto: sending to endpoint {:?}", endpoint);
|
||||
Some(endpoint)
|
||||
};
|
||||
let socket = proc.get_socket(fd)?;
|
||||
socket.write(&slice, endpoint)
|
||||
}
|
||||
|
||||
pub async fn sys_recvfrom(
|
||||
&mut self,
|
||||
fd: FileDesc,
|
||||
mut base: UserOutPtr<u8>,
|
||||
len: usize,
|
||||
flags: usize,
|
||||
addr: UserOutPtr<SockAddr>,
|
||||
addr_len: UserInOutPtr<u32>,
|
||||
) -> SysResult {
|
||||
info!(
|
||||
"sys_recvfrom: fd={:?} base={:?} len={} flags={} addr={:?} addr_len={:?}",
|
||||
fd, base, len, flags, addr, addr_len
|
||||
);
|
||||
|
||||
let proc = self.linux_process();
|
||||
|
||||
let socket = proc.get_socket(fd)?;
|
||||
let mut slice = vec![0u8; len];
|
||||
let (result, endpoint) = socket.read(&mut slice).await;
|
||||
base.write_array(&slice)?;
|
||||
|
||||
if result.is_ok() && !addr.is_null() {
|
||||
let sockaddr_in = SockAddr::from(endpoint);
|
||||
sockaddr_in.write_to(addr, addr_len)?;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
// pub fn sys_recvmsg(&mut self, fd: FileDesc, msg: *mut MsgHdr, flags: usize) -> SysResult {
|
||||
// info!("recvmsg: fd={:?}, msg={:?}, flags={}", fd, msg, flags);
|
||||
// let proc = self.linux_process();
|
||||
// let hdr = unsafe { self.vm().check_write_ptr(msg)? };
|
||||
// let mut iovs =
|
||||
// unsafe { IoVecs::check_and_new(hdr.msg_iov, hdr.msg_iovlen, &self.vm(), true)? };
|
||||
//
|
||||
// let mut buf = iovs.new_buf(true);
|
||||
// let socket = proc.get_socket(fd)?;
|
||||
// let (result, endpoint) = socket.read(&mut buf);
|
||||
//
|
||||
// if let Ok(len) = result {
|
||||
// // copy data to user
|
||||
// iovs.write_all_from_slice(&buf[..len]);
|
||||
// let sockaddr_in = SockAddr::from(endpoint);
|
||||
// sockaddr_in.write_to(hdr.msg_name, &mut hdr.msg_namelen as *mut u32)?;
|
||||
// }
|
||||
// result
|
||||
// }
|
||||
|
||||
pub fn sys_bind(
|
||||
&mut self,
|
||||
fd: FileDesc,
|
||||
addr: UserInPtr<SockAddr>,
|
||||
addr_len: usize,
|
||||
) -> SysResult {
|
||||
info!("sys_bind: fd={:?} addr={:?} len={}", fd, addr, addr_len);
|
||||
let proc = self.linux_process();
|
||||
|
||||
let endpoint = sockaddr_to_endpoint(addr, addr_len)?;
|
||||
info!("sys_bind: fd={:?} bind to {:?}", fd, endpoint);
|
||||
|
||||
let socket = proc.get_socket(fd)?;
|
||||
socket.bind(endpoint)
|
||||
}
|
||||
|
||||
pub fn sys_listen(&mut self, fd: FileDesc, backlog: usize) -> SysResult {
|
||||
info!("sys_listen: fd={:?} backlog={}", fd, backlog);
|
||||
// smoltcp tcp sockets do not support backlog
|
||||
// open multiple sockets for each connection
|
||||
let proc = self.linux_process();
|
||||
|
||||
let socket = proc.get_socket(fd)?;
|
||||
socket.listen()
|
||||
}
|
||||
|
||||
pub fn sys_shutdown(&mut self, fd: FileDesc, how: usize) -> SysResult {
|
||||
info!("sys_shutdown: fd={:?} how={}", fd, how);
|
||||
let proc = self.linux_process();
|
||||
|
||||
let socket = proc.get_socket(fd)?;
|
||||
socket.shutdown()
|
||||
}
|
||||
|
||||
pub async fn sys_accept(
|
||||
&mut self,
|
||||
fd: FileDesc,
|
||||
addr: UserOutPtr<SockAddr>,
|
||||
addr_len: UserInOutPtr<u32>,
|
||||
) -> SysResult {
|
||||
info!(
|
||||
"sys_accept: fd={:?} addr={:?} addr_len={:?}",
|
||||
fd, addr, addr_len
|
||||
);
|
||||
// smoltcp tcp sockets do not support backlog
|
||||
// open multiple sockets for each connection
|
||||
let proc = self.linux_process();
|
||||
|
||||
let socket = proc.get_socket(fd)?;
|
||||
let (new_socket, remote_endpoint) = socket.accept().await?;
|
||||
|
||||
let new_fd = proc.add_socket(new_socket)?;
|
||||
|
||||
if !addr.is_null() {
|
||||
let sockaddr_in = SockAddr::from(remote_endpoint);
|
||||
sockaddr_in.write_to(addr, addr_len)?;
|
||||
}
|
||||
Ok(new_fd.into())
|
||||
}
|
||||
|
||||
pub fn sys_getsockname(
|
||||
&mut self,
|
||||
fd: FileDesc,
|
||||
addr: UserOutPtr<SockAddr>,
|
||||
addr_len: UserInOutPtr<u32>,
|
||||
) -> SysResult {
|
||||
info!(
|
||||
"sys_getsockname: fd={:?} addr={:?} addr_len={:?}",
|
||||
fd, addr, addr_len
|
||||
);
|
||||
|
||||
let proc = self.linux_process();
|
||||
|
||||
if addr.is_null() {
|
||||
return Err(LxError::EINVAL);
|
||||
}
|
||||
|
||||
let socket = proc.get_socket(fd)?;
|
||||
let endpoint = socket.endpoint().ok_or(LxError::EINVAL)?;
|
||||
let sockaddr_in = SockAddr::from(endpoint);
|
||||
sockaddr_in.write_to(addr, addr_len)?;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
pub fn sys_getpeername(
|
||||
&mut self,
|
||||
fd: FileDesc,
|
||||
addr: UserOutPtr<SockAddr>,
|
||||
addr_len: UserInOutPtr<u32>,
|
||||
) -> SysResult {
|
||||
info!(
|
||||
"sys_getpeername: fd={:?} addr={:?} addr_len={:?}",
|
||||
fd, addr, addr_len
|
||||
);
|
||||
|
||||
// smoltcp tcp sockets do not support backlog
|
||||
// open multiple sockets for each connection
|
||||
let proc = self.linux_process();
|
||||
|
||||
if addr.is_null() {
|
||||
return Err(LxError::EINVAL);
|
||||
}
|
||||
|
||||
let socket = proc.get_socket(fd)?;
|
||||
let remote_endpoint = socket.remote_endpoint().ok_or(LxError::EINVAL)?;
|
||||
let sockaddr_in = SockAddr::from(remote_endpoint);
|
||||
sockaddr_in.write_to(addr, addr_len)?;
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SockAddrIn {
|
||||
pub sin_family: u16,
|
||||
pub sin_port: u16,
|
||||
pub sin_addr: u32,
|
||||
pub sin_zero: [u8; 8],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SockAddrUn {
|
||||
pub sun_family: u16,
|
||||
pub sun_path: [u8; 108],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SockAddrLl {
|
||||
pub sll_family: u16,
|
||||
pub sll_protocol: u16,
|
||||
pub sll_ifindex: u32,
|
||||
pub sll_hatype: u16,
|
||||
pub sll_pkttype: u8,
|
||||
pub sll_halen: u8,
|
||||
pub sll_addr: [u8; 8],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SockAddrNl {
|
||||
nl_family: u16,
|
||||
nl_pad: u16,
|
||||
nl_pid: u32,
|
||||
nl_groups: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union SockAddr {
|
||||
pub family: u16,
|
||||
pub addr_in: SockAddrIn,
|
||||
pub addr_un: SockAddrUn,
|
||||
pub addr_ll: SockAddrLl,
|
||||
pub addr_nl: SockAddrNl,
|
||||
pub addr_ph: SockAddrPlaceholder,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct SockAddrPlaceholder {
|
||||
pub family: u16,
|
||||
pub data: [u8; 14],
|
||||
}
|
||||
|
||||
impl From<Endpoint> for SockAddr {
|
||||
fn from(endpoint: Endpoint) -> Self {
|
||||
if let Endpoint::Ip(ip) = endpoint {
|
||||
match ip.addr {
|
||||
IpAddress::Ipv4(ipv4) => SockAddr {
|
||||
addr_in: SockAddrIn {
|
||||
sin_family: AddressFamily::Internet.into(),
|
||||
sin_port: u16::to_be(ip.port),
|
||||
sin_addr: u32::to_be(u32::from_be_bytes(ipv4.0)),
|
||||
sin_zero: [0; 8],
|
||||
},
|
||||
},
|
||||
IpAddress::Unspecified => SockAddr {
|
||||
addr_ph: SockAddrPlaceholder {
|
||||
family: AddressFamily::Unspecified.into(),
|
||||
data: [0; 14],
|
||||
},
|
||||
},
|
||||
_ => unimplemented!("only ipv4"),
|
||||
}
|
||||
} else if let Endpoint::LinkLevel(link_level) = endpoint {
|
||||
SockAddr {
|
||||
addr_ll: SockAddrLl {
|
||||
sll_family: AddressFamily::Packet.into(),
|
||||
sll_protocol: 0,
|
||||
sll_ifindex: link_level.interface_index as u32,
|
||||
sll_hatype: 0,
|
||||
sll_pkttype: 0,
|
||||
sll_halen: 0,
|
||||
sll_addr: [0; 8],
|
||||
},
|
||||
}
|
||||
} else if let Endpoint::Netlink(netlink) = endpoint {
|
||||
SockAddr {
|
||||
addr_nl: SockAddrNl {
|
||||
nl_family: AddressFamily::Netlink.into(),
|
||||
nl_pad: 0,
|
||||
nl_pid: netlink.port_id,
|
||||
nl_groups: netlink.multicast_groups_mask,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
unimplemented!("only ip");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert sockaddr to endpoint
|
||||
///
|
||||
/// Check len is long enough
|
||||
#[allow(unsafe_code)]
|
||||
fn sockaddr_to_endpoint(addr: UserInPtr<SockAddr>, len: usize) -> LxResult<Endpoint> {
|
||||
if len < size_of::<u16>() {
|
||||
return Err(LxError::EINVAL);
|
||||
}
|
||||
let addr = addr.read()?;
|
||||
if len < addr.len()? {
|
||||
return Err(LxError::EINVAL);
|
||||
}
|
||||
unsafe {
|
||||
match AddressFamily::try_from(addr.family) {
|
||||
Ok(AddressFamily::Internet) => {
|
||||
let port = u16::from_be(addr.addr_in.sin_port);
|
||||
let addr = IpAddress::from(Ipv4Address::from_bytes(
|
||||
&u32::from_be(addr.addr_in.sin_addr).to_be_bytes()[..],
|
||||
));
|
||||
Ok(Endpoint::Ip((addr, port).into()))
|
||||
}
|
||||
Ok(AddressFamily::Unix) => Err(LxError::EINVAL),
|
||||
Ok(AddressFamily::Packet) => Ok(Endpoint::LinkLevel(LinkLevelEndpoint::new(
|
||||
addr.addr_ll.sll_ifindex as usize,
|
||||
))),
|
||||
Ok(AddressFamily::Netlink) => Ok(Endpoint::Netlink(NetlinkEndpoint::new(
|
||||
addr.addr_nl.nl_pid,
|
||||
addr.addr_nl.nl_groups,
|
||||
))),
|
||||
_ => Err(LxError::EINVAL),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
impl SockAddr {
|
||||
fn len(&self) -> LxResult<usize> {
|
||||
match AddressFamily::try_from(unsafe { self.family }) {
|
||||
Ok(AddressFamily::Internet) => Ok(size_of::<SockAddrIn>()),
|
||||
Ok(AddressFamily::Packet) => Ok(size_of::<SockAddrLl>()),
|
||||
Ok(AddressFamily::Netlink) => Ok(size_of::<SockAddrNl>()),
|
||||
Ok(AddressFamily::Unix) => Err(LxError::EINVAL),
|
||||
_ => Err(LxError::EINVAL),
|
||||
}
|
||||
}
|
||||
|
||||
/// Write to user sockaddr
|
||||
/// Check mutability for user
|
||||
fn write_to(self, addr: UserOutPtr<SockAddr>, mut addr_len: UserInOutPtr<u32>) -> SysResult {
|
||||
// Ignore NULL
|
||||
if addr.is_null() {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let max_addr_len = addr_len.read()? as usize;
|
||||
let full_len = self.len()?;
|
||||
|
||||
let written_len = min(max_addr_len, full_len);
|
||||
if written_len > 0 {
|
||||
let source = unsafe {
|
||||
core::slice::from_raw_parts(&self as *const SockAddr as *const u8, written_len)
|
||||
};
|
||||
let mut addr: UserOutPtr<u8> = unsafe { core::mem::transmute(addr) };
|
||||
addr.write_array(source)?;
|
||||
}
|
||||
addr_len.write(full_len as u32)?;
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
|
||||
//#[repr(C)]
|
||||
//#[derive(Debug)]
|
||||
//pub struct MsgHdr {
|
||||
// msg_name: *mut SockAddr,
|
||||
// msg_namelen: u32,
|
||||
// msg_iov: *mut IoVec,
|
||||
// msg_iovlen: usize,
|
||||
// msg_control: usize,
|
||||
// msg_controllen: usize,
|
||||
// msg_flags: usize,
|
||||
//}
|
||||
|
||||
const SOCK_TYPE_MASK: u8 = 0xf;
|
||||
|
||||
numeric_enum! {
|
||||
#[repr(u8)]
|
||||
#[derive(Debug)]
|
||||
/// Socket types
|
||||
pub enum SocketType {
|
||||
/// Stream
|
||||
Stream = 1,
|
||||
/// Datagram
|
||||
Datagram = 2,
|
||||
/// Raw
|
||||
Raw = 3,
|
||||
}
|
||||
}
|
||||
|
||||
//const IPPROTO_IP: usize = 0;
|
||||
//const IPPROTO_ICMP: usize = 1;
|
||||
const IPPROTO_TCP: usize = 6;
|
||||
|
||||
const SOL_SOCKET: usize = 1;
|
||||
const SO_SNDBUF: usize = 7;
|
||||
const SO_RCVBUF: usize = 8;
|
||||
//const SO_LINGER: usize = 13;
|
||||
|
||||
const TCP_CONGESTION: usize = 13;
|
||||
|
||||
//const IP_HDRINCL: usize = 3;
|
||||
Loading…
Reference in New Issue