#![allow(clippy::module_name_repetitions)]
use alloc::{borrow::ToOwned, vec::Vec};
use core::net::{IpAddr, Ipv4Addr, SocketAddr};
use embedded_io::{ErrorType, Read, Write};
use psp::sys::{self, sockaddr, socklen_t};
use core::ffi::c_void;
use crate::{
traits::{
io::{EasySocket, Open, OptionType},
SocketBuffer,
},
types::{SocketOptions, SocketRecvFlags, SocketSendFlags},
};
use super::{
super::netc,
error::SocketError,
sce::SocketFileDescriptor,
state::{Bound, Connected, SocketState, Unbound},
ToSockaddr, ToSocketAddr,
};
#[repr(C)]
#[derive(Clone)]
pub struct UdpSocket<S: SocketState = Unbound, B: SocketBuffer = Vec<u8>> {
fd: SocketFileDescriptor,
remote: Option<sockaddr>,
buffer: B,
send_flags: SocketSendFlags,
recv_flags: SocketRecvFlags,
_marker: core::marker::PhantomData<S>,
}
impl UdpSocket {
#[allow(dead_code)]
pub fn new() -> Result<UdpSocket<Unbound>, SocketError> {
let fd = unsafe { sys::sceNetInetSocket(i32::from(netc::AF_INET), netc::SOCK_DGRAM, 0) };
if fd < 0 {
Err(SocketError::Errno(unsafe { sys::sceNetInetGetErrno() }))
} else {
let fd = SocketFileDescriptor::new(fd);
Ok(UdpSocket {
fd,
remote: None,
buffer: Vec::with_capacity(0),
send_flags: SocketSendFlags::empty(),
recv_flags: SocketRecvFlags::empty(),
_marker: core::marker::PhantomData,
})
}
}
}
impl<S: SocketState> UdpSocket<S> {
fn socket_len() -> socklen_t {
core::mem::size_of::<netc::sockaddr>() as u32
}
#[must_use]
pub fn fd(&self) -> i32 {
*self.fd
}
#[must_use]
pub fn remote(&self) -> Option<SocketAddr> {
self.remote.map(|sockaddr| sockaddr.to_socket_addr())
}
#[must_use]
pub fn send_flags(&self) -> SocketSendFlags {
self.send_flags
}
pub fn set_send_flags(&mut self, send_flags: SocketSendFlags) {
self.send_flags = send_flags;
}
#[must_use]
pub fn recv_flags(&self) -> SocketRecvFlags {
self.recv_flags
}
pub fn set_recv_flags(&mut self, recv_flags: SocketRecvFlags) {
self.recv_flags = recv_flags;
}
}
impl UdpSocket<Unbound> {
fn transition(self, remote: Option<sockaddr>) -> UdpSocket<Bound> {
UdpSocket {
fd: self.fd,
remote,
buffer: Vec::with_capacity(0),
send_flags: self.send_flags,
recv_flags: self.recv_flags,
_marker: core::marker::PhantomData,
}
}
#[allow(unused)]
pub fn bind(mut self, addr: Option<SocketAddr>) -> Result<UdpSocket<Bound>, SocketError> {
let default_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
let addr = addr.unwrap_or(default_addr);
match addr {
SocketAddr::V4(v4) => {
let sockaddr = v4.to_sockaddr();
if unsafe {
sys::sceNetInetBind(
*self.fd,
&sockaddr,
core::mem::size_of::<netc::sockaddr>() as u32,
)
} != 0
{
let errno = unsafe { sys::sceNetInetGetErrno() };
Err(SocketError::Errno(errno))
} else {
Ok(self.transition(Some(sockaddr)))
}
}
SocketAddr::V6(_) => Err(SocketError::UnsupportedAddressFamily),
}
}
}
impl UdpSocket<Bound> {
fn transition(self, remote: sockaddr, buf: Option<Vec<u8>>) -> UdpSocket<Connected> {
UdpSocket {
fd: self.fd,
remote: Some(remote),
buffer: buf.unwrap_or_default(),
send_flags: self.send_flags,
recv_flags: self.recv_flags,
_marker: core::marker::PhantomData,
}
}
#[allow(unused)]
pub fn connect(mut self, addr: SocketAddr) -> Result<UdpSocket<Connected>, SocketError> {
match addr {
SocketAddr::V4(v4) => {
let sockaddr = v4.to_sockaddr();
if unsafe { sys::sceNetInetConnect(*self.fd, &sockaddr, Self::socket_len()) } != 0 {
let errno = unsafe { sys::sceNetInetGetErrno() };
Err(SocketError::Errno(errno))
} else {
Ok(self.transition(sockaddr, None))
}
}
SocketAddr::V6(_) => Err(SocketError::UnsupportedAddressFamily),
}
}
#[allow(unused)]
pub fn _read_from(
mut self,
buf: &mut [u8],
) -> Result<(usize, UdpSocket<Connected>), SocketError> {
let mut sockaddr = self
.remote
.ok_or(SocketError::Other("Remote not set".to_owned()))?;
let result = unsafe {
sys::sceNetInetRecvfrom(
*self.fd,
buf.as_mut_ptr().cast::<c_void>(),
buf.len(),
self.recv_flags.as_i32(),
&mut sockaddr,
&mut Self::socket_len(),
)
};
if result < 0 {
Err(SocketError::Errno(unsafe { sys::sceNetInetGetErrno() }))
} else {
Ok((result as usize, self.transition(sockaddr, None)))
}
}
#[allow(unused)]
pub fn _write_to(
self,
buf: &[u8],
len: usize,
to: SocketAddr,
) -> Result<(usize, UdpSocket<Connected>), SocketError> {
let sockaddr = match to {
SocketAddr::V4(v4) => Ok(super::socket_addr_v4_to_sockaddr(v4)),
SocketAddr::V6(_) => Err(SocketError::UnsupportedAddressFamily),
}?;
let socklen = core::mem::size_of::<netc::sockaddr>() as u32;
let mut buffer = Vec::with_capacity(buf.len());
buffer.append_buffer(buf);
let result = unsafe {
sys::sceNetInetSendto(
*self.fd,
buf.as_ptr().cast::<c_void>(),
len,
self.send_flags.as_i32(),
&sockaddr,
socklen,
)
};
if result < 0 {
Err(SocketError::Errno(unsafe { sys::sceNetInetGetErrno() }))
} else {
buffer.shift_left_buffer(result as usize);
Ok((result as usize, self.transition(sockaddr, Some(buffer))))
}
}
}
impl UdpSocket<Connected> {
#[allow(unused)]
pub fn internal_read(&mut self, buf: &mut [u8]) -> Result<usize, SocketError> {
let result = unsafe {
sys::sceNetInetRecv(
*self.fd,
buf.as_mut_ptr().cast::<c_void>(),
buf.len(),
self.recv_flags.as_i32(),
)
};
if result < 0 {
Err(SocketError::Errno(unsafe { sys::sceNetInetGetErrno() }))
} else {
Ok(result as usize)
}
}
#[allow(unused)]
pub fn internal_write(&mut self, buf: &[u8]) -> Result<usize, SocketError> {
self.buffer.append_buffer(buf);
self.send()
}
pub fn internal_flush(&mut self) -> Result<(), SocketError> {
while !self.buffer.is_empty() {
self.send()?;
}
Ok(())
}
fn send(&mut self) -> Result<usize, SocketError> {
let result = unsafe {
sys::sceNetInetSend(
*self.fd,
self.buffer.as_slice().as_ptr().cast::<c_void>(),
self.buffer.len(),
self.send_flags.as_i32(),
)
};
if result < 0 {
Err(SocketError::Errno(unsafe { sys::sceNetInetGetErrno() }))
} else {
self.buffer.shift_left_buffer(result as usize);
Ok(result as usize)
}
}
}
impl<S: SocketState> OptionType for UdpSocket<S> {
type Options<'a> = SocketOptions;
}
impl<S: SocketState> ErrorType for UdpSocket<S> {
type Error = SocketError;
}
impl Open<'_, '_> for UdpSocket<Unbound> {
type Return = UdpSocket<Connected>;
fn open(self, options: &'_ Self::Options<'_>) -> Result<Self::Return, Self::Error> {
let sock = self.bind(None)?;
let sock = sock.connect(options.remote())?;
Ok(sock)
}
}
impl Read for UdpSocket<Connected> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.internal_read(buf)
}
}
impl Write for UdpSocket<Connected> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.internal_write(buf)
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.internal_flush()
}
}
impl EasySocket for UdpSocket<Connected> {}