mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 21:06:48 +00:00
Rewrite the whole net/addr.rs
file
This commit is contained in:
parent
d814603504
commit
4deba9baca
@ -4,14 +4,15 @@ use crate::{fs::path::Dentry, net::socket::util::socket_addr::SocketAddr, prelud
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum UnixSocketAddr {
|
||||
Unnamed,
|
||||
Path(String),
|
||||
Abstract(String),
|
||||
Abstract(Vec<u8>),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(super) enum UnixSocketAddrBound {
|
||||
Path(Arc<Dentry>),
|
||||
Abstract(String),
|
||||
Abstract(Vec<u8>),
|
||||
}
|
||||
|
||||
impl PartialEq for UnixSocketAddrBound {
|
||||
|
@ -33,6 +33,7 @@ impl Init {
|
||||
}
|
||||
|
||||
let bound_addr = match addr_to_bind {
|
||||
UnixSocketAddr::Unnamed => todo!(),
|
||||
UnixSocketAddr::Abstract(_) => todo!(),
|
||||
UnixSocketAddr::Path(path) => {
|
||||
let dentry = create_socket_file(path)?;
|
||||
|
@ -211,6 +211,7 @@ impl Socket for UnixStreamSocket {
|
||||
let remote_addr = {
|
||||
let unix_socket_addr = UnixSocketAddr::try_from(socket_addr)?;
|
||||
match unix_socket_addr {
|
||||
UnixSocketAddr::Unnamed => todo!(),
|
||||
UnixSocketAddr::Abstract(abstract_name) => {
|
||||
UnixSocketAddrBound::Abstract(abstract_name)
|
||||
}
|
||||
|
@ -13,6 +13,5 @@ use crate::{
|
||||
pub enum SocketAddr {
|
||||
Unix(UnixSocketAddr),
|
||||
IPv4(Ipv4Address, PortNum),
|
||||
IPv6,
|
||||
Vsock(VsockSocketAddr),
|
||||
}
|
||||
|
@ -1,372 +0,0 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use crate::{
|
||||
net::socket::{ip::Ipv4Address, unix::UnixSocketAddr, vsock::VsockSocketAddr, SocketAddr},
|
||||
prelude::*,
|
||||
util::{read_bytes_from_user, read_val_from_user, write_val_to_user},
|
||||
};
|
||||
|
||||
pub fn read_socket_addr_from_user(addr: Vaddr, addr_len: usize) -> Result<SocketAddr> {
|
||||
debug_assert!(addr_len >= core::mem::size_of::<CSocketAddr>());
|
||||
let sockaddr: CSocketAddr = read_val_from_user(addr)?;
|
||||
let socket_addr = match sockaddr.sa_family()? {
|
||||
CSocketAddrFamily::AF_UNSPEC => {
|
||||
return_errno_with_message!(Errno::EINVAL, "the socket addr family is unspecified")
|
||||
}
|
||||
CSocketAddrFamily::AF_UNIX => {
|
||||
debug_assert!(addr_len >= core::mem::size_of::<CSocketAddr>());
|
||||
let sa_family: u16 = read_val_from_user(addr)?;
|
||||
debug_assert!(sa_family == CSocketAddrFamily::AF_UNIX as u16);
|
||||
|
||||
let bytes = {
|
||||
let bytes_len = addr_len - core::mem::size_of::<u16>();
|
||||
let mut bytes = vec![0u8; bytes_len];
|
||||
read_bytes_from_user(
|
||||
addr + core::mem::size_of::<u16>(),
|
||||
&mut VmWriter::from(bytes.as_mut_slice()),
|
||||
)?;
|
||||
bytes
|
||||
};
|
||||
|
||||
let unix_socket_addr = if bytes.starts_with(&[0]) {
|
||||
// Abstract unix socket addr
|
||||
let cstr = CStr::from_bytes_until_nul(&bytes[1..])?;
|
||||
let abstract_path = cstr.to_string_lossy().to_string();
|
||||
UnixSocketAddr::Abstract(abstract_path)
|
||||
} else {
|
||||
// Normal unix sockket addr
|
||||
let cstr = CStr::from_bytes_until_nul(&bytes)?;
|
||||
let path = cstr.to_string_lossy().to_string();
|
||||
UnixSocketAddr::Path(path)
|
||||
};
|
||||
|
||||
SocketAddr::Unix(unix_socket_addr)
|
||||
}
|
||||
CSocketAddrFamily::AF_INET => {
|
||||
debug_assert!(addr_len >= core::mem::size_of::<CSocketAddrInet>());
|
||||
let sock_addr_in: CSocketAddrInet = read_val_from_user(addr)?;
|
||||
SocketAddr::from(sock_addr_in)
|
||||
}
|
||||
CSocketAddrFamily::AF_INET6 => {
|
||||
debug_assert!(addr_len >= core::mem::size_of::<CSocketAddrInet6>());
|
||||
let sock_addr_in6: CSocketAddrInet6 = read_val_from_user(addr)?;
|
||||
todo!()
|
||||
}
|
||||
CSocketAddrFamily::AF_VSOCK => {
|
||||
debug_assert!(addr_len >= core::mem::size_of::<CSocketAddrVm>());
|
||||
let sock_addr_vm: CSocketAddrVm = read_val_from_user(addr)?;
|
||||
SocketAddr::Vsock(VsockSocketAddr::new(
|
||||
sock_addr_vm.svm_cid,
|
||||
sock_addr_vm.svm_port,
|
||||
))
|
||||
}
|
||||
_ => {
|
||||
return_errno_with_message!(Errno::EAFNOSUPPORT, "cannot support address for the family")
|
||||
}
|
||||
};
|
||||
Ok(socket_addr)
|
||||
}
|
||||
|
||||
pub fn write_socket_addr_to_user(
|
||||
socket_addr: &SocketAddr,
|
||||
dest: Vaddr,
|
||||
addrlen_ptr: Vaddr,
|
||||
) -> Result<()> {
|
||||
debug_assert!(addrlen_ptr != 0);
|
||||
if addrlen_ptr == 0 {
|
||||
return_errno_with_message!(Errno::EINVAL, "must provide the addrlen ptr");
|
||||
}
|
||||
|
||||
let write_size = {
|
||||
let max_len = read_val_from_user::<i32>(addrlen_ptr)?;
|
||||
write_socket_addr_with_max_len(socket_addr, dest, max_len)?
|
||||
};
|
||||
|
||||
if addrlen_ptr != 0 {
|
||||
write_val_to_user(addrlen_ptr, &write_size)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_socket_addr_with_max_len(
|
||||
socket_addr: &SocketAddr,
|
||||
dest: Vaddr,
|
||||
max_len: i32,
|
||||
) -> Result<i32> {
|
||||
let max_len = max_len as usize;
|
||||
|
||||
let write_size = match socket_addr {
|
||||
SocketAddr::Unix(path) => {
|
||||
let sock_addr_unix = CSocketAddrUnix::try_from(path)?;
|
||||
let write_size = core::mem::size_of::<CSocketAddrUnix>();
|
||||
debug_assert!(max_len >= write_size);
|
||||
write_val_to_user(dest, &sock_addr_unix)?;
|
||||
write_size as i32
|
||||
}
|
||||
SocketAddr::IPv4(addr, port) => {
|
||||
let in_addr = CInetAddr::from(*addr);
|
||||
let sock_addr_in = CSocketAddrInet::new(*port, in_addr);
|
||||
let write_size = core::mem::size_of::<CSocketAddrInet>();
|
||||
debug_assert!(max_len >= write_size);
|
||||
write_val_to_user(dest, &sock_addr_in)?;
|
||||
write_size as i32
|
||||
}
|
||||
SocketAddr::IPv6 => todo!(),
|
||||
SocketAddr::Vsock(addr) => {
|
||||
let vm_addr = CSocketAddrVm::new(addr.cid, addr.port);
|
||||
let write_size = core::mem::size_of::<CSocketAddrVm>();
|
||||
write_val_to_user(dest, &vm_addr)?;
|
||||
write_size as i32
|
||||
}
|
||||
};
|
||||
|
||||
Ok(write_size)
|
||||
}
|
||||
|
||||
/// PlaceHolder
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct CSocketAddr {
|
||||
sa_family: u16, // SaFamily
|
||||
sa_data: [u8; 14],
|
||||
}
|
||||
|
||||
impl CSocketAddr {
|
||||
pub fn sa_family(&self) -> Result<CSocketAddrFamily> {
|
||||
Ok(CSocketAddrFamily::try_from(self.sa_family as i32)?)
|
||||
}
|
||||
}
|
||||
|
||||
const SOCKET_ADDR_UNIX_LEN: usize = 108;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
pub struct CSocketAddrUnix {
|
||||
sun_family: u16, // Always SaFamily::AF_UNIX
|
||||
sun_path: [u8; SOCKET_ADDR_UNIX_LEN],
|
||||
}
|
||||
|
||||
/// IPv4 4-byte address
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
pub struct CInetAddr {
|
||||
s_addr: [u8; 4],
|
||||
}
|
||||
|
||||
impl CInetAddr {
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
&self.s_addr
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Self {
|
||||
debug_assert!(bytes.len() == 4);
|
||||
let mut s_addr = [0u8; 4];
|
||||
s_addr.copy_from_slice(bytes);
|
||||
Self { s_addr }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct CPortNum {
|
||||
port: [u8; 2],
|
||||
}
|
||||
|
||||
impl CPortNum {
|
||||
pub fn as_u16(&self) -> u16 {
|
||||
u16::from_be_bytes(self.port)
|
||||
}
|
||||
|
||||
pub fn from_u16(value: u16) -> Self {
|
||||
let bytes = value.to_be_bytes();
|
||||
Self { port: bytes }
|
||||
}
|
||||
}
|
||||
|
||||
/// IPv4 socket address
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
pub struct CSocketAddrInet {
|
||||
/// always SaFamily::AF_INET
|
||||
sin_family: u16,
|
||||
/// Port number
|
||||
sin_port_t: CPortNum,
|
||||
/// IPv4 address
|
||||
sin_addr: CInetAddr,
|
||||
/// Pad to size of 'SockAddr' structure (16 bytes)
|
||||
_pad: [u8; 8],
|
||||
}
|
||||
|
||||
impl CSocketAddrInet {
|
||||
pub fn new(port: u16, addr: CInetAddr) -> Self {
|
||||
let port = CPortNum::from_u16(port);
|
||||
Self {
|
||||
sin_family: CSocketAddrFamily::AF_INET as _,
|
||||
sin_port_t: port,
|
||||
sin_addr: addr,
|
||||
_pad: [0u8; 8],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
pub struct CInet6Addr {
|
||||
s6_addr: [u8; 16],
|
||||
}
|
||||
|
||||
impl CInet6Addr {
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
&self.s6_addr
|
||||
}
|
||||
}
|
||||
|
||||
/// IPv6 socket address
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
pub struct CSocketAddrInet6 {
|
||||
/// always SaFamily::AF_INET6
|
||||
sin6_family: u16,
|
||||
/// Port number
|
||||
sin6_port: CPortNum,
|
||||
/// IPv6 flow information
|
||||
sin6_flowinfo: u32,
|
||||
/// IPv6 address
|
||||
sin6_addr: CInet6Addr,
|
||||
// Scope ID
|
||||
sin6_scope_id: u32,
|
||||
}
|
||||
|
||||
/// vm socket address
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
pub struct CSocketAddrVm {
|
||||
/// always [SaFamily::AF_VSOCK]
|
||||
svm_family: u16,
|
||||
/// always 0
|
||||
svm_reserved1: u16,
|
||||
/// Port number in host byte order.
|
||||
svm_port: u32,
|
||||
/// Address in host byte order.
|
||||
svm_cid: u32,
|
||||
/// Pad to size of [SockAddr] structure (16 bytes), must be zero-filled
|
||||
svm_zero: [u8; 4],
|
||||
}
|
||||
|
||||
impl CSocketAddrVm {
|
||||
pub fn new(cid: u32, port: u32) -> Self {
|
||||
Self {
|
||||
svm_family: CSocketAddrFamily::AF_VSOCK as _,
|
||||
svm_reserved1: 0,
|
||||
svm_port: port,
|
||||
svm_cid: cid,
|
||||
svm_zero: [0u8; 4],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Address family. The definition is from https://elixir.bootlin.com/linux/v6.0.9/source/include/linux/socket.h.
|
||||
#[repr(i32)]
|
||||
#[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum CSocketAddrFamily {
|
||||
AF_UNSPEC = 0,
|
||||
AF_UNIX = 1, /* Unix domain sockets */
|
||||
//AF_LOCAL 1 /* POSIX name for AF_UNIX */
|
||||
AF_INET = 2, /* Internet IP Protocol */
|
||||
AF_AX25 = 3, /* Amateur Radio AX.25 */
|
||||
AF_IPX = 4, /* Novell IPX */
|
||||
AF_APPLETALK = 5, /* AppleTalk DDP */
|
||||
AF_NETROM = 6, /* Amateur Radio NET/ROM */
|
||||
AF_BRIDGE = 7, /* Multiprotocol bridge */
|
||||
AF_ATMPVC = 8, /* ATM PVCs */
|
||||
AF_X25 = 9, /* Reserved for X.25 project */
|
||||
AF_INET6 = 10, /* IP version 6 */
|
||||
AF_ROSE = 11, /* Amateur Radio X.25 PLP */
|
||||
AF_DECnet = 12, /* Reserved for DECnet project */
|
||||
AF_NETBEUI = 13, /* Reserved for 802.2LLC project*/
|
||||
AF_SECURITY = 14, /* Security callback pseudo AF */
|
||||
AF_KEY = 15, /* PF_KEY key management API */
|
||||
AF_NETLINK = 16,
|
||||
//AF_ROUTE = AF_NETLINK /* Alias to emulate 4.4BSD */
|
||||
AF_PACKET = 17, /* Packet family */
|
||||
AF_ASH = 18, /* Ash */
|
||||
AF_ECONET = 19, /* Acorn Econet */
|
||||
AF_ATMSVC = 20, /* ATM SVCs */
|
||||
AF_RDS = 21, /* RDS sockets */
|
||||
AF_SNA = 22, /* Linux SNA Project (nutters!) */
|
||||
AF_IRDA = 23, /* IRDA sockets */
|
||||
AF_PPPOX = 24, /* PPPoX sockets */
|
||||
AF_WANPIPE = 25, /* Wanpipe API Sockets */
|
||||
AF_LLC = 26, /* Linux LLC */
|
||||
AF_IB = 27, /* Native InfiniBand address */
|
||||
AF_MPLS = 28, /* MPLS */
|
||||
AF_CAN = 29, /* Controller Area Network */
|
||||
AF_TIPC = 30, /* TIPC sockets */
|
||||
AF_BLUETOOTH = 31, /* Bluetooth sockets */
|
||||
AF_IUCV = 32, /* IUCV sockets */
|
||||
AF_RXRPC = 33, /* RxRPC sockets */
|
||||
AF_ISDN = 34, /* mISDN sockets */
|
||||
AF_PHONET = 35, /* Phonet sockets */
|
||||
AF_IEEE802154 = 36, /* IEEE802154 sockets */
|
||||
AF_CAIF = 37, /* CAIF sockets */
|
||||
AF_ALG = 38, /* Algorithm sockets */
|
||||
AF_NFC = 39, /* NFC sockets */
|
||||
AF_VSOCK = 40, /* vSockets */
|
||||
AF_KCM = 41, /* Kernel Connection Multiplexor*/
|
||||
AF_QIPCRTR = 42, /* Qualcomm IPC Router */
|
||||
AF_SMC = 43, /* smc sockets: reserve number for
|
||||
* PF_SMC protocol family that
|
||||
* reuses AF_INET address family
|
||||
*/
|
||||
AF_XDP = 44, /* XDP sockets */
|
||||
AF_MCTP = 45, /* Management component
|
||||
* transport protocol
|
||||
*/
|
||||
AF_MAX = 46, /* For now.. */
|
||||
}
|
||||
|
||||
impl From<CInetAddr> for Ipv4Address {
|
||||
fn from(value: CInetAddr) -> Self {
|
||||
let addr = value.as_bytes();
|
||||
Ipv4Address::from_bytes(addr)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Ipv4Address> for CInetAddr {
|
||||
fn from(value: Ipv4Address) -> Self {
|
||||
let bytes = value.as_bytes();
|
||||
CInetAddr::from_bytes(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CSocketAddrInet> for SocketAddr {
|
||||
fn from(value: CSocketAddrInet) -> Self {
|
||||
let port = value.sin_port_t.as_u16();
|
||||
let addr = Ipv4Address::from(value.sin_addr);
|
||||
SocketAddr::IPv4(addr, port)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&UnixSocketAddr> for CSocketAddrUnix {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: &UnixSocketAddr) -> Result<Self> {
|
||||
let mut sun_path = [0u8; SOCKET_ADDR_UNIX_LEN];
|
||||
match value {
|
||||
UnixSocketAddr::Path(path) => {
|
||||
let bytes = path.as_bytes();
|
||||
let copy_len = bytes.len().min(SOCKET_ADDR_UNIX_LEN - 1);
|
||||
sun_path[..copy_len].copy_from_slice(&bytes[..copy_len]);
|
||||
Ok(CSocketAddrUnix {
|
||||
sun_family: CSocketAddrFamily::AF_UNIX as u16,
|
||||
sun_path,
|
||||
})
|
||||
}
|
||||
UnixSocketAddr::Abstract(_) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
270
kernel/aster-nix/src/util/net/addr/family.rs
Normal file
270
kernel/aster-nix/src/util/net/addr/family.rs
Normal file
@ -0,0 +1,270 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::cmp::min;
|
||||
|
||||
use super::{ip::CSocketAddrInet, unix, vsock::CSocketAddrVm};
|
||||
use crate::{
|
||||
net::socket::SocketAddr,
|
||||
prelude::*,
|
||||
util::{read_bytes_from_user, read_val_from_user, write_bytes_to_user, write_val_to_user},
|
||||
};
|
||||
|
||||
/// Address family.
|
||||
///
|
||||
/// See <https://elixir.bootlin.com/linux/v6.0.9/source/include/linux/socket.h>.
|
||||
#[repr(i32)]
|
||||
#[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(dead_code)]
|
||||
pub enum CSocketAddrFamily {
|
||||
AF_UNSPEC = 0,
|
||||
/// Unix domain sockets
|
||||
AF_UNIX = 1,
|
||||
// POSIX name for AF_UNIX
|
||||
// AF_LOCAL = 1,
|
||||
/// Internet IP Protocol
|
||||
AF_INET = 2,
|
||||
/// Amateur Radio AX.25
|
||||
AF_AX25 = 3,
|
||||
/// Novell IPX
|
||||
AF_IPX = 4,
|
||||
/// AppleTalk DDP
|
||||
AF_APPLETALK = 5,
|
||||
/// Amateur Radio NET/ROM
|
||||
AF_NETROM = 6,
|
||||
/// Multiprotocol bridge
|
||||
AF_BRIDGE = 7,
|
||||
/// ATM PVCs
|
||||
AF_ATMPVC = 8,
|
||||
/// Reserved for X.25 project
|
||||
AF_X25 = 9,
|
||||
/// IP version 6,
|
||||
AF_INET6 = 10,
|
||||
/// Amateur Radio X.25 PLP
|
||||
AF_ROSE = 11,
|
||||
/// Reserved for DECnet project
|
||||
AF_DECnet = 12,
|
||||
/// Reserved for 802.2LLC project
|
||||
AF_NETBEUI = 13,
|
||||
/// Security callback pseudo AF
|
||||
AF_SECURITY = 14,
|
||||
/// PF_KEY key management API
|
||||
AF_KEY = 15,
|
||||
AF_NETLINK = 16,
|
||||
// Alias to emulate 4.4BSD
|
||||
// AF_ROUTE = AF_NETLINK
|
||||
/// Packet family
|
||||
AF_PACKET = 17,
|
||||
/// Ash
|
||||
AF_ASH = 18,
|
||||
/// Acorn Econet
|
||||
AF_ECONET = 19,
|
||||
/// ATM SVCs
|
||||
AF_ATMSVC = 20,
|
||||
/// RDS sockets
|
||||
AF_RDS = 21,
|
||||
/// Linux SNA Project (nutters!)
|
||||
AF_SNA = 22,
|
||||
/// IRDA sockets
|
||||
AF_IRDA = 23,
|
||||
/// PPPoX sockets
|
||||
AF_PPPOX = 24,
|
||||
/// Wanpipe API Sockets
|
||||
AF_WANPIPE = 25,
|
||||
/// Linux LLC
|
||||
AF_LLC = 26,
|
||||
/// Native InfiniBand address
|
||||
AF_IB = 27,
|
||||
/// MPLS
|
||||
AF_MPLS = 28,
|
||||
/// Controller Area Network
|
||||
AF_CAN = 29,
|
||||
/// TIPC sockets
|
||||
AF_TIPC = 30,
|
||||
/// Bluetooth sockets
|
||||
AF_BLUETOOTH = 31,
|
||||
/// IUCV sockets
|
||||
AF_IUCV = 32,
|
||||
/// RxRPC sockets
|
||||
AF_RXRPC = 33,
|
||||
/// mISDN sockets
|
||||
AF_ISDN = 34,
|
||||
/// Phonet sockets
|
||||
AF_PHONET = 35,
|
||||
/// IEEE802154 sockets
|
||||
AF_IEEE802154 = 36,
|
||||
/// CAIF sockets
|
||||
AF_CAIF = 37,
|
||||
/// Algorithm sockets
|
||||
AF_ALG = 38,
|
||||
/// NFC sockets
|
||||
AF_NFC = 39,
|
||||
/// vSockets
|
||||
AF_VSOCK = 40,
|
||||
/// Kernel Connection Multiplexor
|
||||
AF_KCM = 41,
|
||||
/// Qualcomm IPC Router
|
||||
AF_QIPCRTR = 42,
|
||||
/// smc sockets: reserve number for
|
||||
/// PF_SMC protocol family that
|
||||
/// reuses AF_INET address family
|
||||
AF_SMC = 43,
|
||||
/// XDP sockets
|
||||
AF_XDP = 44,
|
||||
/// Management component transport protocol
|
||||
AF_MCTP = 45,
|
||||
}
|
||||
|
||||
const ADDR_MAX_LEN: usize = 128;
|
||||
|
||||
/// Storage that can contain _any_ socket addresses.
|
||||
///
|
||||
/// The size and layout of this structure is specified by RFC 3493. For details, see
|
||||
/// <https://datatracker.ietf.org/doc/html/rfc3493#section-3.10>.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
struct Storage {
|
||||
sa_family: u16,
|
||||
bytes: [u8; ADDR_MAX_LEN - 2],
|
||||
_align: [u64; 0],
|
||||
}
|
||||
|
||||
/// Reads a socket address from userspace.
|
||||
///
|
||||
/// This method returns `Err(EINVAL)` for invalid socket address lengths and `Err(EAFNOSUPPORT)`
|
||||
/// for unsupported address families.
|
||||
///
|
||||
/// These error codes may be different from the Linux ones, but the difference is tricky and hard
|
||||
/// to fix. The main reason for this is that in Linux it's up to each protocol to decide how to
|
||||
/// intercept the bytes that represent socket addresses, but here this method is designed to parse
|
||||
/// socket addresses before diving deep into protocol-specific code.
|
||||
pub fn read_socket_addr_from_user(addr: Vaddr, addr_len: usize) -> Result<SocketAddr> {
|
||||
if addr_len > ADDR_MAX_LEN {
|
||||
return_errno_with_message!(Errno::EINVAL, "the socket address length is too large");
|
||||
}
|
||||
|
||||
if addr_len < 2 {
|
||||
return_errno_with_message!(Errno::EINVAL, "the socket address length is too small");
|
||||
}
|
||||
|
||||
let mut storage = Storage::new_zeroed();
|
||||
read_bytes_from_user(
|
||||
addr,
|
||||
&mut VmWriter::from(&mut storage.as_bytes_mut()[..addr_len]),
|
||||
)?;
|
||||
|
||||
let result = match CSocketAddrFamily::try_from(storage.sa_family as i32) {
|
||||
Ok(CSocketAddrFamily::AF_INET) => {
|
||||
if addr_len < size_of::<CSocketAddrInet>() {
|
||||
return_errno_with_message!(Errno::EINVAL, "the socket address length is too small");
|
||||
}
|
||||
let (addr, port) = CSocketAddrInet::from_bytes(storage.as_bytes()).into();
|
||||
SocketAddr::IPv4(addr, port)
|
||||
}
|
||||
Ok(CSocketAddrFamily::AF_UNIX) => {
|
||||
let addr = unix::from_c_bytes(&storage.as_bytes()[..addr_len])?;
|
||||
SocketAddr::Unix(addr)
|
||||
}
|
||||
Ok(CSocketAddrFamily::AF_VSOCK) => {
|
||||
if addr_len < size_of::<CSocketAddrVm>() {
|
||||
return_errno_with_message!(Errno::EINVAL, "the socket address length is too small");
|
||||
}
|
||||
let addr = CSocketAddrVm::from_bytes(storage.as_bytes());
|
||||
SocketAddr::Vsock(addr.into())
|
||||
}
|
||||
_ => {
|
||||
return_errno_with_message!(
|
||||
Errno::EAFNOSUPPORT,
|
||||
"the specified address family is not supported"
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Writes a socket address and its length to userspace.
|
||||
///
|
||||
/// Similar to [`write_socket_addr_with_max_len`], the socket address may be truncated if the
|
||||
/// buffer is not long enough. Even if truncation occurs, the actual length of the socket address
|
||||
/// is written to userspace. See <https://man7.org/linux/man-pages/man3/recvmsg.3p.html> for
|
||||
/// details on this behavior.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This method will panic if the socket address cannot be validly mapped to the corresponding
|
||||
/// Linux C structures. Currently, the only possible example is that the pathname in the UNIX
|
||||
/// domain socket address is too long.
|
||||
///
|
||||
/// It is guaranteed that all socket addresses returned by [`read_socket_addr_from_user`] have
|
||||
/// valid representations for the corresponding C structures, so passing them to this method will
|
||||
/// not cause panic.
|
||||
pub fn write_socket_addr_to_user(
|
||||
socket_addr: &SocketAddr,
|
||||
dest: Vaddr,
|
||||
max_len_ptr: Vaddr,
|
||||
) -> Result<()> {
|
||||
let max_len = read_val_from_user::<i32>(max_len_ptr)?;
|
||||
|
||||
let actual_len = write_socket_addr_with_max_len(socket_addr, dest, max_len)?;
|
||||
|
||||
write_val_to_user(max_len_ptr, &actual_len)
|
||||
}
|
||||
|
||||
/// Writes a socket address to the user space.
|
||||
///
|
||||
/// If the specified maximum length for the socket address is not enough, the socket address is
|
||||
/// truncated to the specified maximum length. This method returns the _actual_ length of the
|
||||
/// socket address, regardless of whether the truncation occurs or not.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This method will panic if the socket address cannot be validly mapped to the corresponding
|
||||
/// Linux C structures. Currently, the only possible example is that the pathname in the UNIX
|
||||
/// domain socket address is too long.
|
||||
///
|
||||
/// It is guaranteed that all socket addresses returned by [`read_socket_addr_from_user`] have
|
||||
/// valid representations for the corresponding C structures, so passing them to this method will
|
||||
/// not cause panic.
|
||||
pub fn write_socket_addr_with_max_len(
|
||||
socket_addr: &SocketAddr,
|
||||
dest: Vaddr,
|
||||
max_len: i32,
|
||||
) -> Result<i32> {
|
||||
if max_len < 0 {
|
||||
return_errno_with_message!(
|
||||
Errno::EINVAL,
|
||||
"the socket address length cannot be negative"
|
||||
);
|
||||
}
|
||||
|
||||
let actual_len = match socket_addr {
|
||||
SocketAddr::IPv4(addr, port) => {
|
||||
let socket_addr = CSocketAddrInet::from((*addr, *port));
|
||||
let actual_len = size_of::<CSocketAddrInet>();
|
||||
let written_len = min(actual_len, max_len as _);
|
||||
write_bytes_to_user(
|
||||
dest,
|
||||
&mut VmReader::from(&socket_addr.as_bytes()[..written_len]),
|
||||
)?;
|
||||
actual_len
|
||||
}
|
||||
SocketAddr::Unix(addr) => unix::into_c_bytes_and(addr, |bytes| {
|
||||
let written_len = min(bytes.len(), max_len as _);
|
||||
write_bytes_to_user(dest, &mut VmReader::from(&bytes[..written_len]))?;
|
||||
Ok::<usize, Error>(bytes.len())
|
||||
})?,
|
||||
SocketAddr::Vsock(addr) => {
|
||||
let socket_addr = CSocketAddrVm::from(*addr);
|
||||
let actual_len = size_of::<CSocketAddrVm>();
|
||||
let written_len = min(actual_len, max_len as _);
|
||||
write_bytes_to_user(
|
||||
dest,
|
||||
&mut VmReader::from(&socket_addr.as_bytes()[..written_len]),
|
||||
)?;
|
||||
actual_len
|
||||
}
|
||||
};
|
||||
|
||||
Ok(actual_len as i32)
|
||||
}
|
84
kernel/aster-nix/src/util/net/addr/ip.rs
Normal file
84
kernel/aster-nix/src/util/net/addr/ip.rs
Normal file
@ -0,0 +1,84 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::family::CSocketAddrFamily;
|
||||
use crate::{
|
||||
net::socket::ip::{Ipv4Address, PortNum},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
/// IPv4 socket address.
|
||||
///
|
||||
/// See <https://www.man7.org/linux/man-pages/man7/ip.7.html>.
|
||||
///
|
||||
/// The pad bytes (namely `sin_zero`) do not appear in the man pages, but are actually required by
|
||||
/// the Linux implementation. See
|
||||
/// <https://elixir.bootlin.com/linux/v6.10.2/source/include/uapi/linux/in.h#L256>.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
pub(super) struct CSocketAddrInet {
|
||||
/// Address family (AF_INET).
|
||||
sin_family: u16,
|
||||
/// Port number.
|
||||
sin_port: CPortNum,
|
||||
/// IPv4 address.
|
||||
sin_addr: CInetAddr,
|
||||
/// Pad bytes to 16-byte `struct sockaddr`.
|
||||
sin_zero: [u8; 8],
|
||||
}
|
||||
|
||||
impl From<(Ipv4Address, PortNum)> for CSocketAddrInet {
|
||||
fn from(value: (Ipv4Address, PortNum)) -> Self {
|
||||
Self {
|
||||
sin_family: CSocketAddrFamily::AF_INET as u16,
|
||||
sin_port: value.1.into(),
|
||||
sin_addr: value.0.into(),
|
||||
sin_zero: [0; 8],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CSocketAddrInet> for (Ipv4Address, PortNum) {
|
||||
fn from(value: CSocketAddrInet) -> Self {
|
||||
(value.sin_addr.into(), value.sin_port.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// IPv4 4-byte address.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
struct CInetAddr {
|
||||
s_addr: [u8; 4],
|
||||
}
|
||||
|
||||
impl From<Ipv4Address> for CInetAddr {
|
||||
fn from(value: Ipv4Address) -> Self {
|
||||
Self { s_addr: value.0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CInetAddr> for Ipv4Address {
|
||||
fn from(value: CInetAddr) -> Self {
|
||||
Self(value.s_addr)
|
||||
}
|
||||
}
|
||||
|
||||
/// TCP/UDP port number.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
struct CPortNum {
|
||||
port: [u8; 2],
|
||||
}
|
||||
|
||||
impl From<PortNum> for CPortNum {
|
||||
fn from(value: PortNum) -> Self {
|
||||
Self {
|
||||
port: value.to_be_bytes(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CPortNum> for PortNum {
|
||||
fn from(value: CPortNum) -> Self {
|
||||
Self::from_be_bytes(value.port)
|
||||
}
|
||||
}
|
11
kernel/aster-nix/src/util/net/addr/mod.rs
Normal file
11
kernel/aster-nix/src/util/net/addr/mod.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
pub use family::{
|
||||
read_socket_addr_from_user, write_socket_addr_to_user, write_socket_addr_with_max_len,
|
||||
CSocketAddrFamily,
|
||||
};
|
||||
|
||||
mod family;
|
||||
mod ip;
|
||||
mod unix;
|
||||
mod vsock;
|
106
kernel/aster-nix/src/util/net/addr/unix.rs
Normal file
106
kernel/aster-nix/src/util/net/addr/unix.rs
Normal file
@ -0,0 +1,106 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::{ffi::CStr, mem::offset_of};
|
||||
|
||||
use super::family::CSocketAddrFamily;
|
||||
use crate::{net::socket::unix::UnixSocketAddr, prelude::*};
|
||||
|
||||
/// UNIX domain socket address.
|
||||
///
|
||||
/// See <https://www.man7.org/linux/man-pages/man7/unix.7.html>.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
pub(super) struct CSocketAddrUnix {
|
||||
/// Address family (AF_UNIX).
|
||||
sun_family: u16,
|
||||
/// Pathname.
|
||||
sun_path: [u8; Self::PATH_MAX_LEN],
|
||||
}
|
||||
|
||||
impl CSocketAddrUnix {
|
||||
const PATH_MAX_LEN: usize = 108;
|
||||
|
||||
const PATH_OFFSET: usize = offset_of!(Self, sun_path);
|
||||
|
||||
const MIN_LEN: usize = Self::PATH_OFFSET;
|
||||
const MAX_LEN: usize = size_of::<Self>();
|
||||
}
|
||||
|
||||
/// Converts a [`UnixSocketAddr`] to bytes representing a [`CSocketAddrUnix`].
|
||||
///
|
||||
/// We don't actually create a [`CSocketAddrUnix`]. Instead, we create its byte representation
|
||||
/// directly for ease of operation.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This method will panic if the pathname in [`UnixSocketAddr`] is too long to be stored in
|
||||
/// the `sun_path` field of `CUnixSocketAddr`.
|
||||
pub(super) fn into_c_bytes_and<R, F>(value: &UnixSocketAddr, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&[u8]) -> R,
|
||||
{
|
||||
// We need to reserve one byte for the null terminator. Because of this, the number of
|
||||
// bytes may exceed the size of `CSocketAddrUnix`. This is to match the Linux
|
||||
// implementation. See the "BUGS" section at
|
||||
// <https://man7.org/linux/man-pages/man7/unix.7.html>.
|
||||
let mut bytes: [u8; CSocketAddrUnix::MAX_LEN + 1] = Pod::new_zeroed();
|
||||
|
||||
bytes[..2].copy_from_slice(&(CSocketAddrFamily::AF_UNIX as u16).to_ne_bytes());
|
||||
#[allow(clippy::assertions_on_constants)]
|
||||
const { assert!(CSocketAddrUnix::PATH_OFFSET == 2) };
|
||||
|
||||
let sun_path = &mut bytes[CSocketAddrUnix::PATH_OFFSET..];
|
||||
|
||||
let copied = match value {
|
||||
UnixSocketAddr::Unnamed => 0,
|
||||
UnixSocketAddr::Path(path) => {
|
||||
let bytes = path.as_bytes();
|
||||
let len = bytes.len();
|
||||
sun_path[..len].copy_from_slice(bytes);
|
||||
sun_path[len] = 0;
|
||||
len + 1
|
||||
}
|
||||
UnixSocketAddr::Abstract(name) => {
|
||||
let len = name.len();
|
||||
sun_path[0] = 0;
|
||||
sun_path[1..len + 1].copy_from_slice(&name[..]);
|
||||
len + 1
|
||||
}
|
||||
};
|
||||
|
||||
f(&bytes[..CSocketAddrUnix::PATH_OFFSET + copied])
|
||||
}
|
||||
|
||||
/// Converts bytes representing a [`CSocketAddrUnix`] to a [`UnixSocketAddr`].
|
||||
///
|
||||
/// We accept the byte representation of a [`CSocketAddrUnix`] directly, instead of
|
||||
/// [`CSocketAddrUnix`] itself, for ease of operation.
|
||||
pub(super) fn from_c_bytes(bytes: &[u8]) -> Result<UnixSocketAddr> {
|
||||
if bytes.len() < CSocketAddrUnix::MIN_LEN {
|
||||
return_errno_with_message!(Errno::EINVAL, "the socket address length is too small");
|
||||
}
|
||||
|
||||
if bytes.len() > CSocketAddrUnix::MAX_LEN {
|
||||
return_errno_with_message!(Errno::EINVAL, "the socket address length is too small");
|
||||
}
|
||||
|
||||
let sun_path = &bytes[CSocketAddrUnix::PATH_OFFSET..];
|
||||
|
||||
if sun_path.is_empty() {
|
||||
return Ok(UnixSocketAddr::Unnamed);
|
||||
}
|
||||
|
||||
if sun_path[0] == 0 {
|
||||
return Ok(UnixSocketAddr::Abstract(Vec::from(&sun_path[1..])));
|
||||
}
|
||||
|
||||
// Again, Linux always appends a null terminator to the pathname if none is supplied. So we
|
||||
// need to deal with the case where `CStr::from_bytes_until_nul` fails.
|
||||
if let Ok(c_str) = CStr::from_bytes_until_nul(sun_path) {
|
||||
Ok(UnixSocketAddr::Path(c_str.to_string_lossy().to_string()))
|
||||
} else {
|
||||
Ok(UnixSocketAddr::Path(
|
||||
String::from_utf8_lossy(sun_path).to_string(),
|
||||
))
|
||||
}
|
||||
}
|
41
kernel/aster-nix/src/util/net/addr/vsock.rs
Normal file
41
kernel/aster-nix/src/util/net/addr/vsock.rs
Normal file
@ -0,0 +1,41 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::family::CSocketAddrFamily;
|
||||
use crate::{net::socket::vsock::VsockSocketAddr, prelude::*};
|
||||
|
||||
/// VSOCK socket address.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
pub(super) struct CSocketAddrVm {
|
||||
/// Address family (AF_VSOCK).
|
||||
svm_family: u16,
|
||||
/// Reserved (always zero).
|
||||
svm_reserved1: u16,
|
||||
/// Port number in host byte order.
|
||||
svm_port: u32,
|
||||
/// Address in host byte order.
|
||||
svm_cid: u32,
|
||||
/// Pad bytes to 16-byte `struct sockaddr` (always zero).
|
||||
svm_zero: [u8; 4],
|
||||
}
|
||||
|
||||
impl From<VsockSocketAddr> for CSocketAddrVm {
|
||||
fn from(value: VsockSocketAddr) -> Self {
|
||||
Self {
|
||||
svm_family: CSocketAddrFamily::AF_VSOCK as u16,
|
||||
svm_reserved1: 0,
|
||||
svm_port: value.port,
|
||||
svm_cid: value.cid,
|
||||
svm_zero: [0; 4],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CSocketAddrVm> for VsockSocketAddr {
|
||||
fn from(value: CSocketAddrVm) -> Self {
|
||||
Self {
|
||||
cid: value.svm_cid,
|
||||
port: value.svm_port,
|
||||
}
|
||||
}
|
||||
}
|
@ -85,7 +85,10 @@ FN_TEST(getsockname)
|
||||
{
|
||||
struct sockaddr_in saddr = { .sin_port = 0xbeef };
|
||||
struct sockaddr *psaddr = (struct sockaddr *)&saddr;
|
||||
socklen_t addrlen = sizeof(saddr);
|
||||
socklen_t addrlen = 0;
|
||||
|
||||
TEST_RES(getsockname(sk_unbound, psaddr, &addrlen),
|
||||
addrlen == sizeof(saddr) && saddr.sin_port == 0xbeef);
|
||||
|
||||
TEST_RES(getsockname(sk_unbound, psaddr, &addrlen),
|
||||
addrlen == sizeof(saddr) && saddr.sin_port == 0);
|
||||
@ -190,6 +193,8 @@ FN_TEST(bind)
|
||||
struct sockaddr *psaddr = (struct sockaddr *)&sk_addr;
|
||||
socklen_t addrlen = sizeof(sk_addr);
|
||||
|
||||
TEST_ERRNO(bind(sk_unbound, psaddr, addrlen - 1), EINVAL);
|
||||
|
||||
TEST_ERRNO(bind(sk_bound, psaddr, addrlen), EINVAL);
|
||||
|
||||
TEST_ERRNO(bind(sk_listen, psaddr, addrlen), EINVAL);
|
||||
|
@ -57,7 +57,10 @@ FN_TEST(getsockname)
|
||||
{
|
||||
struct sockaddr_in saddr = { .sin_port = 0xbeef };
|
||||
struct sockaddr *psaddr = (struct sockaddr *)&saddr;
|
||||
socklen_t addrlen = sizeof(saddr);
|
||||
socklen_t addrlen = 0;
|
||||
|
||||
TEST_RES(getsockname(sk_unbound, psaddr, &addrlen),
|
||||
addrlen == sizeof(saddr) && saddr.sin_port == 0xbeef);
|
||||
|
||||
TEST_RES(getsockname(sk_unbound, psaddr, &addrlen),
|
||||
addrlen == sizeof(saddr) && saddr.sin_port == 0);
|
||||
@ -143,6 +146,8 @@ FN_TEST(bind)
|
||||
struct sockaddr *psaddr = (struct sockaddr *)&sk_addr;
|
||||
socklen_t addrlen = sizeof(sk_addr);
|
||||
|
||||
TEST_ERRNO(bind(sk_unbound, psaddr, addrlen - 1), EINVAL);
|
||||
|
||||
TEST_ERRNO(bind(sk_bound, psaddr, addrlen), EINVAL);
|
||||
|
||||
TEST_ERRNO(bind(sk_connected, psaddr, addrlen), EINVAL);
|
||||
|
78
test/apps/network/unix_err.c
Normal file
78
test/apps/network/unix_err.c
Normal file
@ -0,0 +1,78 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/poll.h>
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "test.h"
|
||||
|
||||
#define PATH_OFFSET offsetof(struct sockaddr_un, sun_path)
|
||||
|
||||
FN_TEST(socket_addresses)
|
||||
{
|
||||
int sk;
|
||||
socklen_t addrlen;
|
||||
struct sockaddr_un addr;
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#define MAKE_TEST(path, path_copy_len, path_len_to_kernel, path_buf_len, \
|
||||
path_len_from_kernel, path_from_kernel) \
|
||||
sk = TEST_SUCC(socket(PF_UNIX, SOCK_STREAM, 0)); \
|
||||
\
|
||||
memset(&addr, 0, sizeof(addr)); \
|
||||
addr.sun_family = AF_UNIX; \
|
||||
memcpy(addr.sun_path, path, path_copy_len); \
|
||||
\
|
||||
TEST_SUCC(bind(sk, (struct sockaddr *)&addr, \
|
||||
PATH_OFFSET + path_len_to_kernel)); \
|
||||
\
|
||||
memset(&addr, 0, sizeof(addr)); \
|
||||
\
|
||||
addrlen = path_buf_len + PATH_OFFSET; \
|
||||
TEST_RES( \
|
||||
getsockname(sk, (struct sockaddr *)&addr, &addrlen), \
|
||||
addrlen == PATH_OFFSET + path_len_from_kernel && \
|
||||
0 == memcmp(addr.sun_path, path_from_kernel, \
|
||||
MIN(path_buf_len, path_len_from_kernel))); \
|
||||
\
|
||||
TEST_SUCC(close(sk));
|
||||
|
||||
#define LONG_PATH \
|
||||
"/tmp/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
_Static_assert(sizeof(LONG_PATH) == sizeof(addr.sun_path),
|
||||
"LONG_PATH has a wrong length");
|
||||
|
||||
MAKE_TEST("/tmp/R0", 8, 8, 8, 8, "/tmp/R0");
|
||||
|
||||
MAKE_TEST("/tmp/R1", 8, 9, 8, 8, "/tmp/R1");
|
||||
|
||||
MAKE_TEST("/tmp/R2", 6, 6, 8, 7, "/tmp/R");
|
||||
|
||||
MAKE_TEST("/tmp/R3", 7, 7, 8, 8, "/tmp/R3");
|
||||
|
||||
MAKE_TEST("/tmp/R4", 7, 7, 7, 8, "/tmp/R4");
|
||||
|
||||
MAKE_TEST("/tmp/R5", 7, 7, 6, 8, "/tmp/R");
|
||||
|
||||
MAKE_TEST("/tmp/R6", 7, 7, 0, 8, "");
|
||||
|
||||
MAKE_TEST(LONG_PATH, 107, 107, 108, 108, LONG_PATH);
|
||||
|
||||
MAKE_TEST(LONG_PATH "a", 108, 108, 108, 109, LONG_PATH "a");
|
||||
|
||||
#undef LONG_PATH
|
||||
#undef MAKE_TEST
|
||||
|
||||
sk = TEST_SUCC(socket(PF_UNIX, SOCK_STREAM, 0));
|
||||
|
||||
TEST_ERRNO(bind(sk, (struct sockaddr *)&addr, -1), EINVAL);
|
||||
TEST_ERRNO(bind(sk, (struct sockaddr *)&addr, PATH_OFFSET - 1), EINVAL);
|
||||
TEST_ERRNO(bind(sk, (struct sockaddr *)&addr, sizeof(addr) + 1),
|
||||
EINVAL);
|
||||
|
||||
TEST_SUCC(close(sk));
|
||||
}
|
||||
END_TEST()
|
@ -23,5 +23,6 @@ echo "Start network test......"
|
||||
./http_client
|
||||
./tcp_err
|
||||
./udp_err
|
||||
./unix_err
|
||||
|
||||
echo "All network test passed"
|
||||
|
Loading…
x
Reference in New Issue
Block a user