nuclei/net/
unix_socket.rs1use std::io;
9use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
10use std::os::unix::net::{UnixDatagram, UnixListener};
11use std::path::Path;
12
13use crate::io::source::Kind;
14use crate::io::{Handle, sys};
15
16pub struct UnixSocket {
36 socket: OwnedFd,
37 datagrams: bool,
38}
39
40impl UnixSocket {
41 pub fn new_stream() -> io::Result<UnixSocket> {
47 Self::new(false)
48 }
49
50 pub fn new_datagram() -> io::Result<UnixSocket> {
56 Self::new(true)
57 }
58
59 fn new(datagrams: bool) -> io::Result<UnixSocket> {
60 let ty = if datagrams {
61 libc::SOCK_DGRAM
62 } else {
63 libc::SOCK_STREAM
64 };
65 Ok(UnixSocket {
66 socket: sys::socket(libc::AF_UNIX, ty)?,
67 datagrams,
68 })
69 }
70
71 pub fn bind(&self, path: impl AsRef<Path>) -> io::Result<()> {
77 sys::bind_unix(
78 self.socket.as_raw_fd(),
79 &sys::UnixAddr::path(path.as_ref())?,
80 )
81 }
82
83 pub fn listen(self, backlog: u32) -> io::Result<super::UnixListener> {
90 if self.datagrams {
91 return Err(wrong_kind("a socket of datagrams cannot listen"));
92 }
93 sys::listen(self.socket.as_raw_fd(), backlog)?;
94 Ok(Handle::from_nonblocking(
95 UnixListener::from(self.socket),
96 Kind::UnixListener,
97 ))
98 }
99
100 pub async fn connect(self, path: impl AsRef<Path>) -> io::Result<super::UnixStream> {
106 if self.datagrams {
107 return Err(wrong_kind(
108 "a socket of datagrams connects as a datagram socket",
109 ));
110 }
111 super::unix::connect(self.socket, &sys::UnixAddr::path(path.as_ref())?).await
112 }
113
114 pub fn datagram(self) -> io::Result<super::UnixDatagram> {
120 if !self.datagrams {
121 return Err(wrong_kind("a socket of streams is not a datagram socket"));
122 }
123 Ok(Handle::from_nonblocking(
124 UnixDatagram::from(self.socket),
125 Kind::UnixDatagram,
126 ))
127 }
128}
129
130fn wrong_kind(what: &'static str) -> io::Error {
131 io::Error::new(io::ErrorKind::InvalidInput, what)
132}
133
134impl core::fmt::Debug for UnixSocket {
135 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
136 f.debug_struct("UnixSocket")
137 .field("fd", &self.socket.as_raw_fd())
138 .field("datagrams", &self.datagrams)
139 .finish()
140 }
141}
142
143impl AsRawFd for UnixSocket {
144 fn as_raw_fd(&self) -> RawFd {
145 self.socket.as_raw_fd()
146 }
147}
148
149impl AsFd for UnixSocket {
150 fn as_fd(&self) -> BorrowedFd<'_> {
151 self.socket.as_fd()
152 }
153}
154
155impl IntoRawFd for UnixSocket {
156 fn into_raw_fd(self) -> RawFd {
157 self.socket.into_raw_fd()
158 }
159}
160
161impl FromRawFd for UnixSocket {
162 unsafe fn from_raw_fd(fd: RawFd) -> UnixSocket {
167 let socket = unsafe { OwnedFd::from_raw_fd(fd) };
169 let mut ty: libc::c_int = 0;
170 let mut len = size_of::<libc::c_int>() as libc::socklen_t;
171 let r = unsafe {
173 libc::getsockopt(
174 fd,
175 libc::SOL_SOCKET,
176 libc::SO_TYPE,
177 core::ptr::from_mut(&mut ty).cast(),
178 &mut len,
179 )
180 };
181 UnixSocket {
182 socket,
183 datagrams: r == 0 && ty == libc::SOCK_DGRAM,
184 }
185 }
186}