posix_socket/address/
mod.rs

1use std::os::raw::c_int;
2
3mod inet4;
4mod inet6;
5mod unix;
6
7pub use inet4::*;
8pub use inet6::*;
9pub use unix::*;
10
11// TODO: implement Debug in a nice manner for the types.
12
13/// A socket address that supports multiple address families at runtime.
14pub trait GenericSocketAddress: AsSocketAddress {}
15
16/// A socket address that only supports one specific family.
17pub trait SpecificSocketAddress: AsSocketAddress {
18	/// The address family supported by this socket address.
19	fn static_family() -> libc::sa_family_t;
20}
21
22/// A type that is binary compatible with a socket address.
23///
24/// # Safety
25/// It must be valid to construct a new address as [`std::mem::MaybeUninit::new_zeroed()`]
26/// and then write the socket address to the pointer returned by [`as_sockaddr_mut()`].
27pub unsafe trait AsSocketAddress: Sized {
28	/// Get a pointer to the socket address.
29	///
30	/// In reality, this should point to a struct that is compatible with [`libc::sockaddr`],
31	/// but is not [`libc::sockaddr`] itself.
32	fn as_sockaddr(&self) -> *const libc::sockaddr;
33
34	/// Get the lengths of the socket address.
35	///
36	/// This is the length of the entire socket address, including the `sa_family` field.
37	fn len(&self) -> libc::socklen_t;
38
39	/// Get the address family of the socket address.
40	fn family(&self) -> libc::sa_family_t {
41		unsafe {
42			(*self.as_sockaddr()).sa_family
43		}
44	}
45
46	/// Get a mutable pointer to the socket address.
47	///
48	/// In reality, this should point to a struct that is compatible with [`libc::sockaddr`],
49	/// but is not [`libc::sockaddr`] itself.
50	fn as_sockaddr_mut(address: &mut std::mem::MaybeUninit<Self>) -> *mut libc::sockaddr;
51
52	/// Get the maximum size of for the socket address.
53	///
54	/// This is used to tell the kernel how much it is allowed to write to the memory
55	/// pointed at by [`as_sockaddr_mut()`](AsSocketAddress::as_sockaddr_mut).
56	fn max_len() -> libc::socklen_t;
57
58	/// Finalize a socket address that has been written into by the kernel.
59	///
60	/// This should check the address family and the length to ensure the address is valid.
61	/// The length is the length of the entire socket address, including the `sa_family` field.
62	fn finalize(address: std::mem::MaybeUninit<Self>, len: libc::socklen_t) -> std::io::Result<Self>;
63}
64
65/// Generic socket address, large enough to hold any valid address.
66#[derive(Clone)]
67#[repr(C)]
68pub struct SocketAddress {
69	/// The inner C-compatible socket address.
70	inner: libc::sockaddr_storage,
71
72	/// The length of the socket address.
73	len: libc::socklen_t,
74}
75
76impl SocketAddress {
77	/// Create a [`SocketAddress`] from a [`libc::sockaddr_storage`] and a length.
78	pub fn from_raw(inner: libc::sockaddr_storage, len: libc::socklen_t) -> Self {
79		Self { inner, len }
80	}
81
82	/// Create a generic [`SocketAddress`] by copying data from another address.
83	pub fn from_other<Address: AsSocketAddress>(other: &Address) -> Self {
84		unsafe {
85			let mut output = std::mem::MaybeUninit::zeroed();
86			std::ptr::copy(
87				other.as_sockaddr(),
88				AsSocketAddress::as_sockaddr_mut(&mut output),
89				other.len() as usize
90			);
91			AsSocketAddress::finalize(output, other.len()).unwrap()
92		}
93	}
94
95	/// Convert the [`SocketAddress`] into raw [`libc`] parts.
96	pub fn into_raw(self) -> (libc::sockaddr_storage, libc::socklen_t) {
97		(self.inner, self.len)
98	}
99
100	/// Get the address family.
101	pub fn family(&self) -> c_int {
102		self.inner.ss_family as c_int
103	}
104
105	/// Get the address as an IPv4 socket address.
106	///
107	/// Returns [`None`] if the address is not an IPv4 socket address.
108	pub fn as_inet4(&self) -> Option<Inet4SocketAddress> {
109		if self.family() == libc::AF_INET {
110			let addr: &libc::sockaddr_in = unsafe { std::mem::transmute(&self.inner) };
111			Some(Inet4SocketAddress::from_raw(*addr))
112		} else {
113			None
114		}
115	}
116
117	/// Get the address as an IPv6 socket address.
118	///
119	/// Returns [`None`] if the address is not an IPv6 socket address.
120	pub fn as_inet6(&self) -> Option<Inet6SocketAddress> {
121		if self.family() == libc::AF_INET6 {
122			let addr: &libc::sockaddr_in6 = unsafe { std::mem::transmute(&self.inner) };
123			Some(Inet6SocketAddress::from_raw(*addr))
124		} else {
125			None
126		}
127	}
128
129	/// Get the address as an unix socket address.
130	///
131	/// Returns [`None`] if the address is not a unix socket address.
132	pub fn as_unix(&self) -> Option<UnixSocketAddress> {
133		if self.family() == libc::AF_LOCAL {
134			let addr: &libc::sockaddr_un = unsafe { std::mem::transmute(&self.inner) };
135			Some(UnixSocketAddress::from_raw(*addr, self.len))
136		} else {
137			None
138		}
139	}
140}
141
142unsafe impl AsSocketAddress for SocketAddress {
143	fn as_sockaddr(&self) -> *const libc::sockaddr {
144		&self.inner as *const _ as *const _
145	}
146
147	fn as_sockaddr_mut(address: &mut std::mem::MaybeUninit<Self>) -> *mut libc::sockaddr {
148		unsafe { &mut address.as_mut_ptr().as_mut().unwrap().inner as *mut _ as *mut _ }
149	}
150
151	fn len(&self) -> libc::socklen_t {
152		self.len
153	}
154
155	fn finalize(address: std::mem::MaybeUninit<Self>, len: libc::socklen_t) -> std::io::Result<Self> {
156		unsafe {
157			let mut address = address.assume_init();
158			if len > Self::max_len() {
159				return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "address too large"));
160			}
161			address.len = len;
162			Ok(address)
163		}
164	}
165
166	fn max_len() -> libc::socklen_t {
167		std::mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t
168	}
169}
170
171impl GenericSocketAddress for SocketAddress {}