starry_api/file/
net.rs

1use core::net::SocketAddr;
2
3use alloc::sync::Arc;
4use axerrno::{LinuxError, LinuxResult};
5use axio::PollState;
6use axnet::{TcpSocket, UdpSocket};
7use axsync::Mutex;
8use linux_raw_sys::general::S_IFSOCK;
9
10use super::{FileLike, Kstat};
11
12pub enum Socket {
13    Udp(Mutex<UdpSocket>),
14    Tcp(Mutex<TcpSocket>),
15}
16
17macro_rules! impl_socket {
18    ($pub:vis fn $name:ident(&self $(,$arg:ident: $arg_ty:ty)*) -> $ret:ty) => {
19        $pub fn $name(&self, $($arg: $arg_ty),*) -> $ret {
20            match self {
21                Socket::Udp(udpsocket) => Ok(udpsocket.lock().$name($($arg),*)?),
22                Socket::Tcp(tcpsocket) => Ok(tcpsocket.lock().$name($($arg),*)?),
23            }
24        }
25    };
26}
27
28impl Socket {
29    pub fn recv(&self, buf: &mut [u8]) -> LinuxResult<usize> {
30        match self {
31            Socket::Udp(udpsocket) => Ok(udpsocket.lock().recv_from(buf).map(|e| e.0)?),
32            Socket::Tcp(tcpsocket) => Ok(tcpsocket.lock().recv(buf)?),
33        }
34    }
35
36    pub fn sendto(&self, buf: &[u8], addr: SocketAddr) -> LinuxResult<usize> {
37        match self {
38            // diff: must bind before sendto
39            Socket::Udp(udpsocket) => Ok(udpsocket.lock().send_to(buf, addr)?),
40            Socket::Tcp(_) => Err(LinuxError::EISCONN),
41        }
42    }
43
44    pub fn recvfrom(&self, buf: &mut [u8]) -> LinuxResult<(usize, Option<SocketAddr>)> {
45        match self {
46            // diff: must bind before recvfrom
47            Socket::Udp(udpsocket) => Ok(udpsocket
48                .lock()
49                .recv_from(buf)
50                .map(|res| (res.0, Some(res.1)))?),
51            Socket::Tcp(tcpsocket) => Ok(tcpsocket.lock().recv(buf).map(|res| (res, None))?),
52        }
53    }
54
55    pub fn listen(&self) -> LinuxResult {
56        match self {
57            Socket::Udp(_) => Err(LinuxError::EOPNOTSUPP),
58            Socket::Tcp(tcpsocket) => Ok(tcpsocket.lock().listen()?),
59        }
60    }
61
62    pub fn accept(&self) -> LinuxResult<TcpSocket> {
63        match self {
64            Socket::Udp(_) => Err(LinuxError::EOPNOTSUPP),
65            Socket::Tcp(tcpsocket) => Ok(tcpsocket.lock().accept()?),
66        }
67    }
68
69    impl_socket!(pub fn send(&self, buf: &[u8]) -> LinuxResult<usize>);
70    impl_socket!(pub fn poll(&self) -> LinuxResult<PollState>);
71    impl_socket!(pub fn local_addr(&self) -> LinuxResult<SocketAddr>);
72    impl_socket!(pub fn peer_addr(&self) -> LinuxResult<SocketAddr>);
73    impl_socket!(pub fn bind(&self, addr: SocketAddr) -> LinuxResult);
74    impl_socket!(pub fn connect(&self, addr: SocketAddr) -> LinuxResult);
75    impl_socket!(pub fn shutdown(&self) -> LinuxResult);
76}
77
78impl FileLike for Socket {
79    fn read(&self, buf: &mut [u8]) -> LinuxResult<usize> {
80        self.recv(buf)
81    }
82
83    fn write(&self, buf: &[u8]) -> LinuxResult<usize> {
84        self.send(buf)
85    }
86
87    fn stat(&self) -> LinuxResult<Kstat> {
88        // not really implemented
89        Ok(Kstat {
90            mode: S_IFSOCK | 0o777u32, // rwxrwxrwx
91            blksize: 4096,
92            ..Default::default()
93        })
94    }
95
96    fn into_any(self: Arc<Self>) -> Arc<dyn core::any::Any + Send + Sync> {
97        self
98    }
99
100    fn poll(&self) -> LinuxResult<PollState> {
101        self.poll()
102    }
103
104    fn set_nonblocking(&self, nonblock: bool) -> LinuxResult {
105        match self {
106            Socket::Udp(udpsocket) => udpsocket.lock().set_nonblocking(nonblock),
107            Socket::Tcp(tcpsocket) => tcpsocket.lock().set_nonblocking(nonblock),
108        }
109        Ok(())
110    }
111}