use std::net::SocketAddr;
use crate::{
api::{
self,
io::Io,
ops::{Bind, Connect, Listen, Recv, Send, Shutdown},
resource::{AsResource, FromResource, IntoResource, Resource},
},
net::ops::{SocketAccept, SocketNew},
};
pub struct Socket(Resource);
impl IntoResource for Socket {
fn into_resource(self) -> Resource {
self.0
}
}
impl AsResource for Socket {
fn as_resource(&self) -> &Resource {
&self.0
}
}
impl FromResource for Socket {
fn from_resource(resource: Resource) -> Self {
Self(resource)
}
}
impl Socket {
#[allow(clippy::new_ret_no_self)]
pub fn new(
domain: libc::c_int,
ty: libc::c_int,
proto: libc::c_int,
) -> Io<SocketNew> {
let socket_accept_op = SocketNew::new(domain, ty, proto);
Io::from_op(socket_accept_op)
}
pub fn bind(&self, addr: SocketAddr) -> Io<Bind> {
api::bind(&self.0, addr)
}
pub fn listen(&self) -> Io<Listen> {
api::listen(&self.0, 128)
}
pub fn accept(&self) -> Io<SocketAccept> {
let socket_accept_op = SocketAccept::new(self.0.clone());
Io::from_op(socket_accept_op)
}
pub fn connect(&self, addr: SocketAddr) -> Io<Connect> {
api::connect(&self.0, addr)
}
pub fn recv(&self, vec: Vec<u8>) -> Io<Recv<Vec<u8>>> {
api::recv(&self.0, vec, None)
}
pub fn send(&self, vec: Vec<u8>) -> Io<Send<Vec<u8>>> {
api::send(&self.0, vec, None)
}
pub fn shutdown(&self, how: i32) -> Io<Shutdown> {
api::shutdown(&self.0, how)
}
pub fn local_addr(&self) -> std::io::Result<SocketAddr> {
use std::os::fd::AsRawFd;
let fd = self.0.as_raw_fd();
let mut storage: libc::sockaddr_storage = unsafe { std::mem::zeroed() };
let mut len =
std::mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
let ret = unsafe {
libc::getsockname(
fd,
&mut storage as *mut _ as *mut libc::sockaddr,
&mut len,
)
};
if ret < 0 {
return Err(std::io::Error::last_os_error());
}
match storage.ss_family as libc::c_int {
libc::AF_INET => {
let addr: &libc::sockaddr_in =
unsafe { &*(&storage as *const _ as *const _) };
let ip = std::net::Ipv4Addr::from(u32::from_be(addr.sin_addr.s_addr));
let port = u16::from_be(addr.sin_port);
Ok(SocketAddr::from((ip, port)))
}
libc::AF_INET6 => {
let addr: &libc::sockaddr_in6 =
unsafe { &*(&storage as *const _ as *const _) };
let ip = std::net::Ipv6Addr::from(addr.sin6_addr.s6_addr);
let port = u16::from_be(addr.sin6_port);
Ok(SocketAddr::from((ip, port)))
}
_ => Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"unsupported address family",
)),
}
}
}