uds_fork/seqpacket.rs
1#[cfg(any(
2 target_vendor="apple", target_os="freebsd",
3 target_os="netbsd",
4 target_os="illumos", target_os="solaris",
5 ))]
6use std::io::ErrorKind;
7use std::
8{
9 io::{self, IoSlice, IoSliceMut},
10 net::Shutdown,
11 os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd},
12 path::Path,
13 time::Duration
14};
15
16use libc::{MSG_EOR, MSG_PEEK, c_void, send, recv};
17
18//use crate::addr::*;
19use crate::{UnixSocketAddr, helpers::*};
20use crate::ancillary::*;
21use crate::credentials::*;
22
23/// An unix domain sequential packet connection.
24///
25/// Sequential-packet connections have an interface similar to streams,
26/// but behave more like connected datagram sockets.
27///
28/// They have guaranteed in-order and reliable delivery,
29/// which unix datagrams technically doesn't.
30///
31/// # Operating system support
32///
33/// Sequential-packet sockets are supported by Linux, FreeBSD, NetBSD
34/// and Illumos, but not by for example macOS or OpenBSD.
35///
36/// # Zero-length packets
37///
38/// ... are best avoided:
39/// On Linux and FreeBSD zero-length packets can be sent and received,
40/// but there is no way to distinguish receiving one from reaching
41/// end of connection unless the packet has an ancillary payload.
42/// Also beware of trying to receive with a zero-length buffer,
43/// as that will on FreeBSD (and probably other BSDs with seqpacket sockets)
44/// always succeed even if there is no packet waiting.
45///
46/// Illumos and Solaris doesn't support receiving zero-length packets at all:
47/// writes succeed but recv() will block.
48///
49/// # Examples
50///
51/// What is sent separately is received separately:
52///
53#[cfg_attr(not(target_vendor="apple"), doc="```")]
54#[cfg_attr(target_vendor="apple", doc="```no_run")]
55/// let (a, b) = uds_fork::UnixSeqpacketConn::pair().expect("Cannot create seqpacket pair");
56///
57/// a.send(b"first").unwrap();
58/// a.send(b"second").unwrap();
59///
60/// let mut buffer_big_enough_for_both = [0; 20];
61/// let len = b.recv(&mut buffer_big_enough_for_both).unwrap();
62/// assert_eq!(&buffer_big_enough_for_both[..len], b"first");
63/// let len = b.recv(&mut buffer_big_enough_for_both).unwrap();
64/// assert_eq!(&buffer_big_enough_for_both[..len], b"second");
65/// ```
66///
67/// Connect to a listener on a socket file and write to it:
68///
69#[cfg_attr(not(target_vendor="apple"), doc="```")]
70#[cfg_attr(target_vendor="apple", doc="```no_run")]
71/// use uds_fork::{UnixSeqpacketListener, UnixSeqpacketConn};
72///
73/// # let _ = std::fs::remove_file("/tmp/seqpacket.socket"); // pre-emptively delete just in case
74/// let listener = UnixSeqpacketListener::bind("/tmp/seqpacket.socket")
75/// .expect("create seqpacket listener");
76/// let conn = UnixSeqpacketConn::connect("/tmp/seqpacket.socket")
77/// .expect("connect to seqpacket listener");
78///
79/// let message = "Hello, listener";
80/// let sent = conn.send(message.as_bytes()).unwrap();
81/// assert_eq!(sent, message.len());
82///
83/// std::fs::remove_file("/tmp/seqpacket.socket").unwrap(); // clean up after ourselves
84/// ```
85///
86/// Connect to a listener on an abstract address:
87///
88#[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
89#[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
90/// use uds_fork::{UnixSeqpacketListener, UnixSeqpacketConn, UnixSocketAddr};
91///
92/// let addr = UnixSocketAddr::new("@seqpacket example").unwrap();
93/// let listener = UnixSeqpacketListener::bind_unix_addr(&addr)
94/// .expect("create abstract seqpacket listener");
95/// let _client = UnixSeqpacketConn::connect_unix_addr(&addr)
96/// .expect("connect to abstract seqpacket listener");
97/// let (_server, _addr) = listener.accept_unix_addr().unwrap();
98/// ```
99#[derive(Debug)]
100#[repr(transparent)]
101pub struct UnixSeqpacketConn
102{
103 fd: OwnedFd,
104}
105
106impl From<UnixSeqpacketConn> for OwnedFd
107{
108 fn from(value: UnixSeqpacketConn) -> Self
109 {
110 return value.fd;
111 }
112}
113
114impl FromRawFd for UnixSeqpacketConn
115{
116 unsafe
117 fn from_raw_fd(fd: RawFd) -> Self
118 {
119 return
120 UnixSeqpacketConn { fd: unsafe { OwnedFd::from_raw_fd(fd) } };
121 }
122}
123
124impl AsRawFd for UnixSeqpacketConn
125{
126 fn as_raw_fd(&self) -> RawFd
127 {
128 self.fd.as_raw_fd()
129 }
130}
131impl IntoRawFd for UnixSeqpacketConn
132{
133 fn into_raw_fd(self) -> RawFd
134 {
135 self.fd.into_raw_fd()
136 }
137}
138
139impl AsFd for UnixSeqpacketConn
140{
141 fn as_fd(&self) -> BorrowedFd<'_>
142 {
143 self.fd.as_fd()
144 }
145}
146
147impl UnixSeqpacketConn
148{
149 /// Connects to an unix seqpacket server listening at `path`.
150 ///
151 /// This is a wrapper around [`connect_unix_addr()`](#method.connect_unix_addr)
152 /// for convenience and compatibility with std.
153 pub
154 fn connect<P: AsRef<Path>>(path: P) -> Result<Self, io::Error>
155 {
156 let addr = UnixSocketAddr::from_path(&path)?;
157 Self::connect_unix_addr(&addr)
158 }
159
160 /// Connects to an unix seqpacket server listening at `addr`.
161 pub
162 fn connect_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error>
163 {
164 let socket = Socket::<SocketSeqPkt>::new(false)?;
165 socket.set_unix_addr(SetAddr::PEER, addr)?;
166
167 return Ok(UnixSeqpacketConn { fd: socket.into() });
168 }
169
170 /// Binds to an address before connecting to a listening seqpacet socket.
171 pub
172 fn connect_from_to_unix_addr(from: &UnixSocketAddr, to: &UnixSocketAddr) -> Result<Self, io::Error>
173 {
174 let socket = Socket::<SocketSeqPkt>::new(false)?;
175 socket.set_unix_addr(SetAddr::LOCAL, from)?;
176 socket.set_unix_addr(SetAddr::PEER, to)?;
177
178 return Ok(UnixSeqpacketConn { fd: socket.into() });
179 }
180
181 /// Creates a pair of unix-domain seqpacket conneections connected to each other.
182 ///
183 /// # Examples
184 ///
185 #[cfg_attr(not(target_vendor="apple"), doc="```")]
186 #[cfg_attr(target_vendor="apple", doc="```no_run")]
187 /// let (a, b) = uds_fork::UnixSeqpacketConn::pair().unwrap();
188 /// assert!(a.local_unix_addr().unwrap().is_unnamed());
189 /// assert!(b.local_unix_addr().unwrap().is_unnamed());
190 ///
191 /// a.send(b"hello").unwrap();
192 /// b.recv(&mut[0; 20]).unwrap();
193 /// ```
194 pub
195 fn pair() -> Result<(Self, Self), io::Error>
196 {
197 let pair = Socket::<SocketSeqPkt>::pair(false)?;
198
199 return Ok(
200 (
201 UnixSeqpacketConn { fd: pair.0.into() },
202 UnixSeqpacketConn { fd: pair.1.into() }
203 )
204 );
205 }
206
207 /// Returns the address of this side of the connection.
208 pub
209 fn local_unix_addr(&self) -> Result<UnixSocketAddr, io::Error>
210 {
211 get_unix_addr(&self, GetAddr::LOCAL)
212 }
213
214 /// Returns the address of the other side of the connection.
215 pub
216 fn peer_unix_addr(&self) -> Result<UnixSocketAddr, io::Error>
217 {
218 get_unix_addr(&self, GetAddr::PEER)
219 }
220
221 /// Returns information about the process of the peer when the connection was established.
222 ///
223 /// See documentation of the returned type for details.
224 pub
225 fn initial_peer_credentials(&self) -> Result<ConnCredentials, io::Error>
226 {
227 peer_credentials(&self)
228 }
229
230 /// Returns the SELinux security context of the process that created the other
231 /// end of this connection.
232 ///
233 /// Will return an error on other operating systems than Linux or Android,
234 /// and also if running inside kubernetes.
235 /// On success the number of bytes used is returned. (like `Read`)
236 ///
237 /// The default security context is `unconfined`, without any trailing NUL.
238 /// A buffor of 50 bytes is probably always big enough.
239 pub
240 fn initial_peer_selinux_context(&self, buf: &mut[u8]) -> Result<usize, io::Error>
241 {
242 selinux_context(&self, buf)
243 }
244
245
246 /// Sends a packet to the peer.
247 pub
248 fn send(&self, packet: &[u8]) -> Result<usize, io::Error>
249 {
250 let ptr = packet.as_ptr() as *const c_void;
251 let flags = MSG_NOSIGNAL | MSG_EOR;
252 let sent = cvt_r!(unsafe { send(self.fd.as_raw_fd(), ptr, packet.len(), flags) })?;
253 Ok(sent as usize)
254 }
255
256 /// Sends a packet to the peer.
257 pub
258 fn send_flags(&self, packet: &[u8], flags: i32) -> Result<usize, io::Error>
259 {
260 let ptr = packet.as_ptr() as *const c_void;
261 let sent = cvt_r!(unsafe { send(self.fd.as_raw_fd(), ptr, packet.len(), flags) })?;
262 Ok(sent as usize)
263 }
264
265 /// Receives a packet from the peer.
266 pub
267 fn recv(&self, buffer: &mut[u8]) -> Result<usize, io::Error>
268 {
269 let ptr = buffer.as_ptr() as *mut c_void;
270 let received = cvt_r!(unsafe { recv(self.fd.as_raw_fd(), ptr, buffer.len(), MSG_NOSIGNAL) })?;
271 Ok(received as usize)
272 }
273
274 /// Sends a packet assembled from multiple byte slices.
275 pub
276 fn send_vectored(&self, slices: &[IoSlice]) -> Result<usize, io::Error>
277 {
278 // Can't use writev() because we need to pass flags,
279 // and the flags accepted by pwritev2() aren't the one we need to pass.
280 send_ancillary(&self, None, MSG_EOR, slices, Vec::new(), None)
281 }
282 /// Reads a packet into multiple buffers.
283 ///
284 /// The returned `bool` indicates whether the packet was truncated due to
285 /// too short buffers.
286 pub
287 fn recv_vectored(&self, buffers: &mut[IoSliceMut]) -> Result<(usize, bool), io::Error>
288 {
289 recv_ancillary(&self, None, 0, buffers, &mut[])
290 .map(|(bytes, ancillary)| (bytes, ancillary.message_truncated()) )
291 }
292
293 /// Sends a packet with associated file descriptors.
294 pub
295 fn send_fds(&self, bytes: &[u8], fds: Vec<OwnedFd>) -> Result<usize, io::Error>
296 {
297 send_ancillary(&self, None, MSG_EOR, &[IoSlice::new(bytes)], fds, None)
298 }
299
300 /// Receives a packet and associated file descriptors.
301 pub
302 fn recv_fds(&self, byte_buffer: &mut[u8], fd_buffer: &mut Vec<OwnedFd>) -> Result<(usize, bool, usize), io::Error>
303 {
304 recv_fds(&self, None, &mut[IoSliceMut::new(byte_buffer)], Some(fd_buffer))
305 }
306
307 /// Receives a packet without removing it from the incoming queue.
308 ///
309 /// # Examples
310 ///
311 #[cfg_attr(not(target_vendor="apple"), doc="```")]
312 #[cfg_attr(target_vendor="apple", doc="```no_run")]
313 /// let (a, b) = uds_fork::UnixSeqpacketConn::pair().unwrap();
314 /// a.send(b"hello").unwrap();
315 /// let mut buf = [0u8; 10];
316 /// assert_eq!(b.peek(&mut buf[..1]).unwrap(), 1);
317 /// assert_eq!(&buf[..2], &[b'h', 0]);
318 /// assert_eq!(b.peek(&mut buf).unwrap(), 5);
319 /// assert_eq!(&buf[..5], b"hello");
320 /// assert_eq!(b.recv(&mut buf).unwrap(), 5);
321 /// assert_eq!(&buf[..5], b"hello");
322 /// ```
323 pub
324 fn peek(&self, buffer: &mut[u8]) -> Result<usize, io::Error>
325 {
326 let ptr = buffer.as_ptr() as *mut c_void;
327 let flags = MSG_NOSIGNAL | MSG_PEEK;
328 let received = cvt_r!(unsafe { recv(self.fd.as_raw_fd(), ptr, buffer.len(), flags) })?;
329 Ok(received as usize)
330 }
331
332 /// Receives a packet without removing it from the incoming queue.
333 ///
334 /// The returned `bool` indicates whether the packet was truncated due to
335 /// the combined buffers being too small.
336 pub
337 fn peek_vectored(&self, buffers: &mut[IoSliceMut]) -> Result<(usize, bool), io::Error>
338 {
339 recv_ancillary(&self, None, MSG_PEEK, buffers, &mut[])
340 .map(|(bytes, ancillary)| (bytes, ancillary.message_truncated()) )
341 }
342
343 /// Returns the value of the `SO_ERROR` option.
344 ///
345 /// This might only provide errors generated from nonblocking `connect()`s,
346 /// which this library doesn't support. It is therefore unlikely to be
347 /// useful, but is provided for parity with stream counterpart in std.
348 ///
349 /// # Examples
350 ///
351 #[cfg_attr(not(target_vendor="apple"), doc="```")]
352 #[cfg_attr(target_vendor="apple", doc="```no_run")]
353 /// let (a, b) = uds_fork::UnixSeqpacketConn::pair().unwrap();
354 /// drop(b);
355 ///
356 /// assert!(a.send(b"anyone there?").is_err());
357 /// assert!(a.take_error().unwrap().is_none());
358 /// ```
359 pub
360 fn take_error(&self) -> Result<Option<io::Error>, io::Error>
361 {
362 take_error(&self)
363 }
364
365
366 /// Creates a new file descriptor also pointing to this side of this connection.
367 ///
368 /// # Examples
369 ///
370 /// Both new and old can send and receive, and share queues:
371 ///
372 #[cfg_attr(not(target_vendor="apple"), doc="```")]
373 #[cfg_attr(target_vendor="apple", doc="```no_run")]
374 /// let (a1, b) = uds_fork::nonblocking::UnixSeqpacketConn::pair().unwrap();
375 /// let a2 = a1.try_clone().unwrap();
376 ///
377 /// a1.send(b"first").unwrap();
378 /// a2.send(b"second").unwrap();
379 ///
380 /// let mut buf = [0u8; 20];
381 /// let len = b.recv(&mut buf).unwrap();
382 /// assert_eq!(&buf[..len], b"first");
383 /// b.send(b"hello first").unwrap();
384 /// let len = b.recv(&mut buf).unwrap();
385 /// assert_eq!(&buf[..len], b"second");
386 /// b.send(b"hello second").unwrap();
387 ///
388 /// let len = a2.recv(&mut buf).unwrap();
389 /// assert_eq!(&buf[..len], b"hello first");
390 /// let len = a1.recv(&mut buf).unwrap();
391 /// assert_eq!(&buf[..len], b"hello second");
392 /// ```
393 ///
394 /// Clone can still be used after the first one has been closed:
395 ///
396 #[cfg_attr(not(target_vendor="apple"), doc="```")]
397 #[cfg_attr(target_vendor="apple", doc="```no_run")]
398 /// let (a, b1) = uds_fork::nonblocking::UnixSeqpacketConn::pair().unwrap();
399 /// a.send(b"hello").unwrap();
400 ///
401 /// let b2 = b1.try_clone().unwrap();
402 /// drop(b1);
403 /// assert_eq!(b2.recv(&mut[0; 10]).unwrap(), "hello".len());
404 /// ```
405 pub
406 fn try_clone(&self) -> Result<Self, io::Error>
407 {
408 let cloned = Socket::<SocketSeqPkt>::try_clone_from(self)?;
409
410 return Ok(UnixSeqpacketConn { fd: cloned.into() });
411 }
412
413 /// Sets the read timeout to the duration specified.
414 ///
415 /// If the value specified is `None`, then `recv()` and its variants will
416 /// block indefinitely.
417 /// An error is returned if the duration is zero.
418 ///
419 /// The duration is rounded to microsecond precission.
420 /// Currently it's rounded down except if that would make it all zero.
421 ///
422 /// # Operating System Support
423 ///
424 /// On Illumos (and pressumably also Solaris) timeouts appears not to work
425 /// for unix domain sockets.
426 ///
427 /// # Examples
428 ///
429 #[cfg_attr(not(any(target_vendor="apple", target_os="illumos", target_os="solaris")), doc="```")]
430 #[cfg_attr(any(target_vendor="apple", target_os="illumos", target_os="solaris"), doc="```no_run")]
431 /// use std::io::ErrorKind;
432 /// use std::time::Duration;
433 /// use uds_fork::UnixSeqpacketConn;
434 ///
435 /// let (a, b) = UnixSeqpacketConn::pair().unwrap();
436 /// a.set_read_timeout(Some(Duration::new(0, 2_000_000))).unwrap();
437 /// let error = a.recv(&mut[0; 1024]).unwrap_err();
438 /// assert_eq!(error.kind(), ErrorKind::WouldBlock);
439 /// ```
440 pub
441 fn set_read_timeout(&self, timeout: Option<Duration>) -> Result<(), io::Error>
442 {
443 set_timeout(self.fd.as_fd(), TimeoutDirection::READ, timeout)
444 }
445 /// Returns the read timeout of this socket.
446 ///
447 /// `None` is returned if there is no timeout.
448 ///
449 /// Note that subsecond parts might have been be rounded by the OS
450 /// (in addition to the rounding to microsecond in `set_read_timeout()`).
451 ///
452 /// # Examples
453 ///
454 #[cfg_attr(not(any(target_vendor="apple", target_os="illumos", target_os="solaris")), doc="```")]
455 #[cfg_attr(any(target_vendor="apple", target_os="illumos", target_os="solaris"), doc="```no_run")]
456 /// use uds_fork::UnixSeqpacketConn;
457 /// use std::time::Duration;
458 ///
459 /// let timeout = Some(Duration::new(2, 0));
460 /// let conn = UnixSeqpacketConn::pair().unwrap().0;
461 /// conn.set_read_timeout(timeout).unwrap();
462 /// assert_eq!(conn.read_timeout().unwrap(), timeout);
463 /// ```
464 pub
465 fn read_timeout(&self) -> Result<Option<Duration>, io::Error>
466 {
467 get_timeout(self.fd.as_fd(), TimeoutDirection::READ)
468 }
469
470 /// Sets the write timeout to the duration specified.
471 ///
472 /// If the value specified is `None`, then `send()` and its variants will
473 /// block indefinitely.
474 /// An error is returned if the duration is zero.
475 ///
476 /// # Operating System Support
477 ///
478 /// On Illumos (and pressumably also Solaris) timeouts appears not to work
479 /// for unix domain sockets.
480 ///
481 /// # Examples
482 ///
483 #[cfg_attr(not(any(target_vendor="apple", target_os="illumos", target_os="solaris")), doc="```")]
484 #[cfg_attr(any(target_vendor="apple", target_os="illumos", target_os="solaris"), doc="```no_run")]
485 /// # use std::io::ErrorKind;
486 /// # use std::time::Duration;
487 /// # use uds_fork::UnixSeqpacketConn;
488 /// #
489 /// let (conn, _other) = UnixSeqpacketConn::pair().unwrap();
490 /// conn.set_write_timeout(Some(Duration::new(0, 500 * 1000))).unwrap();
491 /// loop {
492 /// if let Err(e) = conn.send(&[0; 1000]) {
493 /// assert_eq!(e.kind(), ErrorKind::WouldBlock, "{}", e);
494 /// break
495 /// }
496 /// }
497 /// ```
498 pub
499 fn set_write_timeout(&self, timeout: Option<Duration>)-> Result<(), io::Error>
500 {
501 set_timeout(self.fd.as_fd(), TimeoutDirection::WRITE, timeout)
502 }
503
504 /// Returns the write timeout of this socket.
505 ///
506 /// `None` is returned if there is no timeout.
507 ///
508 /// # Examples
509 ///
510 #[cfg_attr(not(target_vendor="apple"), doc="```")]
511 #[cfg_attr(target_vendor="apple", doc="```no_run")]
512 /// let conn = uds_fork::UnixSeqpacketConn::pair().unwrap().0;
513 /// assert!(conn.write_timeout().unwrap().is_none());
514 /// ```
515 pub
516 fn write_timeout(&self) -> Result<Option<Duration>, io::Error>
517 {
518 get_timeout(self.fd.as_fd(), TimeoutDirection::WRITE)
519 }
520
521 /// Enables or disables nonblocking mode.
522 ///
523 /// Consider using the nonblocking variant of this type instead.
524 /// This method mainly exists for feature parity with std's `UnixStream`.
525 ///
526 /// # Examples
527 ///
528 /// Trying to receive when there are no packets waiting:
529 ///
530 #[cfg_attr(not(target_vendor="apple"), doc="```")]
531 #[cfg_attr(target_vendor="apple", doc="```no_run")]
532 /// # use std::io::ErrorKind;
533 /// # use uds_fork::UnixSeqpacketConn;
534 /// let (a, b) = UnixSeqpacketConn::pair().expect("create seqpacket pair");
535 /// a.set_nonblocking(true).unwrap();
536 /// assert_eq!(a.recv(&mut[0; 20]).unwrap_err().kind(), ErrorKind::WouldBlock);
537 /// ```
538 ///
539 /// Trying to send when the OS buffer for the connection is full:
540 ///
541 #[cfg_attr(not(target_vendor="apple"), doc="```")]
542 #[cfg_attr(target_vendor="apple", doc="```no_run")]
543 /// # use std::io::ErrorKind;
544 /// # use uds_fork::UnixSeqpacketConn;
545 /// let (a, b) = UnixSeqpacketConn::pair().expect("create seqpacket pair");
546 /// a.set_nonblocking(true).unwrap();
547 /// loop {
548 /// if let Err(error) = a.send(&[b'#'; 1000]) {
549 /// assert_eq!(error.kind(), ErrorKind::WouldBlock);
550 /// break;
551 /// }
552 /// }
553 /// ```
554 pub
555 fn set_nonblocking(&self, nonblocking: bool) -> Result<(), io::Error>
556 {
557 set_nonblocking(&self, nonblocking)
558 }
559
560 /// Shuts down the read, write, or both halves of this connection.
561 pub
562 fn shutdown(&self, how: Shutdown) -> io::Result<()>
563 {
564 let how = match how {
565 Shutdown::Read => libc::SHUT_RD,
566 Shutdown::Write => libc::SHUT_WR,
567 Shutdown::Both => libc::SHUT_RDWR,
568 };
569 unsafe { cvt!(libc::shutdown(self.as_raw_fd(), how)) }?;
570 Ok(())
571 }
572}
573
574
575
576/// An unix domain listener for sequential packet connections.
577///
578/// See [`UnixSeqpacketConn`](struct.UnixSeqpacketConn.html) for a description
579/// of this type of connection.
580///
581/// # Examples
582///
583#[cfg_attr(not(target_vendor="apple"), doc="```")]
584#[cfg_attr(target_vendor="apple", doc="```no_run")]
585/// # let _ = std::fs::remove_file("/tmp/seqpacket_listener.socket");
586/// let listener = uds_fork::UnixSeqpacketListener::bind("/tmp/seqpacket_listener.socket")
587/// .expect("Create seqpacket listener");
588/// let _client = uds_fork::UnixSeqpacketConn::connect("/tmp/seqpacket_listener.socket").unwrap();
589/// let (conn, _addr) = listener.accept_unix_addr().unwrap();
590/// conn.send(b"Welcome").unwrap();
591/// # std::fs::remove_file("/tmp/seqpacket_listener.socket").unwrap();
592/// ```
593#[derive(Debug)]
594#[repr(transparent)]
595pub struct UnixSeqpacketListener
596{
597 fd: OwnedFd
598}
599
600
601impl FromRawFd for UnixSeqpacketListener
602{
603 unsafe
604 fn from_raw_fd(fd: RawFd) -> Self
605 {
606 return
607 Self{ fd: unsafe { OwnedFd::from_raw_fd(fd) } };
608 }
609}
610
611impl AsRawFd for UnixSeqpacketListener
612{
613 fn as_raw_fd(&self) -> RawFd
614 {
615 self.fd.as_raw_fd()
616 }
617}
618
619impl IntoRawFd for UnixSeqpacketListener
620{
621 fn into_raw_fd(self) -> RawFd
622 {
623 self.fd.into_raw_fd()
624 }
625}
626
627impl AsFd for UnixSeqpacketListener
628{
629 fn as_fd(&self) -> BorrowedFd<'_>
630 {
631 self.fd.as_fd()
632 }
633}
634
635impl UnixSeqpacketListener
636{
637 /// Creates a socket that listens for seqpacket connections on the specified socket file.
638 pub
639 fn bind<P: AsRef<Path>>(path: P) -> Result<Self, io::Error>
640 {
641 let addr = UnixSocketAddr::from_path(path.as_ref())?;
642
643 return Self::bind_unix_addr(&addr);
644 }
645
646 /// Creates a socket that listens for seqpacket connections on the specified address.
647 pub
648 fn bind_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error>
649 {
650 let socket = Socket::<SocketSeqPkt>::new(false)?;
651
652 socket.set_unix_addr(SetAddr::LOCAL, addr)?;
653 socket.start_listening()?;
654
655 return Ok(UnixSeqpacketListener { fd: socket.into() });
656 }
657
658 /// Returns the address the socket is listening on.
659 pub
660 fn local_unix_addr(&self) -> Result<UnixSocketAddr, io::Error>
661 {
662 get_unix_addr(&self, GetAddr::LOCAL)
663 }
664
665 /// Accepts a new incoming connection to this listener.
666 pub
667 fn accept_unix_addr(&self)-> Result<(UnixSeqpacketConn, UnixSocketAddr), io::Error>
668 {
669 let (socket, addr) = Socket::<SocketSeqPkt>::accept_from(&self, false)?;
670 let conn = UnixSeqpacketConn { fd: socket.into() };
671
672 return Ok((conn, addr));
673 }
674
675 /// Returns the value of the `SO_ERROR` option.
676 ///
677 /// This might never produce any errors for listeners. It is therefore
678 /// unlikely to be useful, but is provided for parity with
679 /// `std::unix::net::UnixListener`.
680 pub
681 fn take_error(&self) -> Result<Option<io::Error>, io::Error>
682 {
683 take_error(&self)
684 }
685
686 /// Creates a new file descriptor listening for the same connections.
687 pub
688 fn try_clone(&self) -> Result<Self, io::Error>
689 {
690 let cloned = Socket::<SocketSeqPkt>::try_clone_from(&self)?;
691
692 return Ok(UnixSeqpacketListener { fd: cloned.into() });
693 }
694
695 /// Sets a maximum duration to wait in a single `accept()` on this socket.
696 ///
697 /// `None` disables a previously set timeout.
698 /// An error is returned if the duration is zero.
699 ///
700 /// # Operating System Support
701 ///
702 /// Only Linux appers to apply timeouts to `accept()`.
703 /// On macOS, FreeBSD and NetBSD, timeouts are silently ignored.
704 /// On Illumos setting timeouts for all unix domain sockets silently fails.
705 ///
706 /// On OSes where timeouts are known to not work, this function will
707 /// return an error even if setting the timeout didn't fail.
708 ///
709 /// # Examples
710 ///
711 #[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
712 #[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
713 /// # use uds_fork::{UnixSeqpacketListener, UnixSocketAddr};
714 /// # use std::io::ErrorKind;
715 /// # use std::time::Duration;
716 /// #
717 /// # let addr = UnixSocketAddr::new("@set_timeout").unwrap();
718 /// let listener = UnixSeqpacketListener::bind_unix_addr(&addr).unwrap();
719 /// listener.set_timeout(Some(Duration::new(0, 200_000_000))).unwrap();
720 /// let err = listener.accept_unix_addr().unwrap_err();
721 /// assert_eq!(err.kind(), ErrorKind::WouldBlock);
722 /// ```
723 pub
724 fn set_timeout(&self, timeout: Option<Duration>) -> Result<(), io::Error>
725 {
726 let res = set_timeout(&self, TimeoutDirection::READ, timeout);
727
728 #[cfg(any(
729 target_vendor="apple", target_os="freebsd",
730 target_os="netbsd",
731 target_os="illumos", target_os="solaris",
732 ))]
733 {
734 if res.is_ok() == true && timeout.is_some() == true
735 {
736 return Err(
737 io::Error::new(
738 ErrorKind::InvalidInput,
739 "listener timeouts are not supported on this OS"
740 )
741 );
742 }
743 }
744
745 return res;
746 }
747
748 /// Returns the timeout for `accept()` on this socket.
749 ///
750 /// `None` is returned if there is no timeout.
751 ///
752 /// Even if a timeout has is set, it is ignored by `accept()` on
753 /// most operating systems except Linux.
754 ///
755 /// # Examples
756 ///
757 #[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
758 #[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
759 /// # use uds_fork::{UnixSeqpacketListener, UnixSocketAddr};
760 /// # use std::time::Duration;
761 /// #
762 /// # let addr = UnixSocketAddr::new("@timeout").unwrap();
763 /// let listener = UnixSeqpacketListener::bind_unix_addr(&addr).unwrap();
764 /// assert_eq!(listener.timeout().unwrap(), None);
765 /// let timeout = Some(Duration::new(2, 0));
766 /// listener.set_timeout(timeout).unwrap();
767 /// assert_eq!(listener.timeout().unwrap(), timeout);
768 /// ```
769 pub
770 fn timeout(&self) -> Result<Option<Duration>, io::Error>
771 {
772 get_timeout(&self, TimeoutDirection::READ)
773 }
774
775 /// Enables or disables nonblocking-ness of [`accept_unix_addr()`](#method.accept_unix addr).
776 ///
777 /// The returned connnections will still be in blocking mode regardsless.
778 ///
779 /// Consider using the nonblocking variant of this type instead;
780 /// this method mostly exists for feature parity with std's `UnixListener`.
781 ///
782 /// # Examples
783 ///
784 #[cfg_attr(not(target_vendor="apple"), doc="```")]
785 #[cfg_attr(target_vendor="apple", doc="```no_run")]
786 /// # use std::io::ErrorKind;
787 /// # use uds_fork::{UnixSocketAddr, UnixSeqpacketListener};
788 /// #
789 /// # let addr = UnixSocketAddr::from_path("/tmp/nonblocking_seqpacket_listener.socket").unwrap();
790 /// # let _ = std::fs::remove_file("/tmp/nonblocking_seqpacket_listener.socket");
791 /// let listener = UnixSeqpacketListener::bind_unix_addr(&addr).expect("create listener");
792 /// listener.set_nonblocking(true).expect("enable noblocking mode");
793 /// assert_eq!(listener.accept_unix_addr().unwrap_err().kind(), ErrorKind::WouldBlock);
794 /// # std::fs::remove_file("/tmp/nonblocking_seqpacket_listener.socket").expect("delete socket file");
795 /// ```
796 pub
797 fn set_nonblocking(&self, nonblocking: bool) -> Result<(), io::Error>
798 {
799 set_nonblocking(&self, nonblocking)
800 }
801}
802
803
804
805/// A non-blocking unix domain sequential-packet connection.
806///
807/// Differs from [`uds_fork::UnixSeqpacketConn`](../struct.UnixSeqpacketConn.html)
808/// in that all operations that send or receive data will return an `Error` of
809/// kind `ErrorKind::WouldBlock` instead of blocking.
810/// This is done by creating the socket as non-blocking, and not by passing
811/// `MSG_DONTWAIT`. If creating this type from a raw file descriptor, ensure
812/// the fd is set to nonblocking before using it through this type.
813///
814/// # Examples
815///
816/// Sending or receiving when it would block a normal socket:
817///
818#[cfg_attr(not(target_vendor="apple"), doc="```")]
819#[cfg_attr(target_vendor="apple", doc="```no_run")]
820/// use uds_fork::nonblocking::UnixSeqpacketConn;
821/// use std::io::ErrorKind;
822///
823/// let (a, b) = UnixSeqpacketConn::pair().expect("create nonblocking seqpacket pair");
824///
825/// // trying to receive when there are no packets waiting
826/// assert_eq!(a.recv(&mut[0]).unwrap_err().kind(), ErrorKind::WouldBlock);
827///
828/// // trying to send when the OS buffer for the connection is full
829/// loop {
830/// if let Err(error) = a.send(&[0u8; 1000]) {
831/// assert_eq!(error.kind(), ErrorKind::WouldBlock);
832/// break;
833/// }
834/// }
835/// ```
836#[derive(Debug)]
837#[repr(transparent)]
838pub struct NonblockingUnixSeqpacketConn
839{
840 fd: OwnedFd,
841}
842
843impl From<NonblockingUnixSeqpacketConn> for OwnedFd
844{
845 fn from(value: NonblockingUnixSeqpacketConn) -> Self
846 {
847 return value.fd;
848 }
849}
850
851impl FromRawFd for NonblockingUnixSeqpacketConn
852{
853 unsafe
854 fn from_raw_fd(fd: RawFd) -> Self
855 {
856 return
857 Self{ fd: unsafe { OwnedFd::from_raw_fd(fd) } };
858 }
859}
860
861impl AsRawFd for NonblockingUnixSeqpacketConn
862{
863 fn as_raw_fd(&self) -> RawFd
864 {
865 self.fd.as_raw_fd()
866 }
867}
868impl IntoRawFd for NonblockingUnixSeqpacketConn
869{
870 fn into_raw_fd(self) -> RawFd
871 {
872 self.fd.into_raw_fd()
873 }
874}
875
876impl AsFd for NonblockingUnixSeqpacketConn
877{
878 fn as_fd(&self) -> BorrowedFd<'_>
879 {
880 self.fd.as_fd()
881 }
882}
883
884
885// can't Deref<Target=UnixSeqpacketConn> because that would include try_clone()
886// and later set_(read|write)_timeout()
887impl NonblockingUnixSeqpacketConn
888{
889 /// Connects to an unix seqpacket server listening at `path`.
890 ///
891 /// This is a wrapper around [`connect_unix_addr()`](#method.connect_unix_addr)
892 /// for convenience and compatibility with std.
893 pub
894 fn connect<P: AsRef<Path>>(path: P) -> Result<Self, io::Error>
895 {
896 let addr = UnixSocketAddr::from_path(&path)?;
897
898 return Self::connect_unix_addr(&addr);
899 }
900
901 /// Connects to an unix seqpacket server listening at `addr`.
902 pub
903 fn connect_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error>
904 {
905 let socket = Socket::<SocketSeqPkt>::new(true)?;
906 socket.set_unix_addr(SetAddr::PEER, addr)?;
907
908 return Ok(NonblockingUnixSeqpacketConn { fd: socket.into() });
909 }
910
911 /// Binds to an address before connecting to a listening seqpacket socket.
912 pub
913 fn connect_from_to_unix_addr(from: &UnixSocketAddr, to: &UnixSocketAddr) -> Result<Self, io::Error>
914 {
915 let socket = Socket::<SocketSeqPkt>::new(true)?;
916 socket.set_unix_addr(SetAddr::LOCAL, from)?;
917 socket.set_unix_addr(SetAddr::PEER, to)?;
918
919 return Ok(NonblockingUnixSeqpacketConn { fd: socket.into() });
920 }
921
922 /// Creates a pair of nonblocking unix-domain seqpacket conneections connected to each other.
923 ///
924 /// # Examples
925 ///
926 #[cfg_attr(not(target_vendor="apple"), doc="```")]
927 #[cfg_attr(target_vendor="apple", doc="```no_run")]
928 /// let (a, b) = uds_fork::nonblocking::UnixSeqpacketConn::pair().unwrap();
929 /// assert!(a.local_unix_addr().unwrap().is_unnamed());
930 /// assert!(b.local_unix_addr().unwrap().is_unnamed());
931 /// assert_eq!(b.recv(&mut[0; 20]).unwrap_err().kind(), std::io::ErrorKind::WouldBlock);
932 /// a.send(b"hello").unwrap();
933 /// assert_eq!(b.recv(&mut[0; 20]).unwrap(), 5);
934 /// ```
935 pub
936 fn pair() -> Result<(Self, Self), io::Error>
937 {
938 let pair = Socket::<SocketSeqPkt>::pair(true)?;
939
940 return Ok(
941 (
942 NonblockingUnixSeqpacketConn { fd: pair.0.into() },
943 NonblockingUnixSeqpacketConn { fd: pair.1.into() }
944 )
945 );
946 }
947
948 /// Returns the address of this side of the connection.
949 pub
950 fn local_unix_addr(&self) -> Result<UnixSocketAddr, io::Error>
951 {
952 get_unix_addr(&self, GetAddr::LOCAL)
953 }
954
955 /// Returns the address of the other side of the connection.
956 pub
957 fn peer_unix_addr(&self) -> Result<UnixSocketAddr, io::Error>
958 {
959 get_unix_addr(&self, GetAddr::PEER)
960 }
961
962 /// Returns information about the process of the peer when the connection was established.
963 ///
964 /// See documentation of the returned type for details.
965 pub
966 fn initial_peer_credentials(&self) -> Result<ConnCredentials, io::Error>
967 {
968 peer_credentials(&self)
969 }
970
971 /// Returns the SELinux security context of the process that created the other
972 /// end of this connection.
973 ///
974 /// Will return an error on other operating systems than Linux or Android,
975 /// and also if running inside kubernetes.
976 /// On success the number of bytes used is returned. (like `Read`)
977 ///
978 /// The default security context is `unconfined`, without any trailing NUL.
979 /// A buffor of 50 bytes is probably always big enough.
980 pub
981 fn initial_peer_selinux_context(&self, buf: &mut[u8]) -> Result<usize, io::Error>
982 {
983 selinux_context(&self, buf)
984 }
985
986 /// Sends a packet to the peer.
987 pub
988 fn send(&self, packet: &[u8]) -> Result<usize, io::Error>
989 {
990 let ptr = packet.as_ptr() as *const c_void;
991 let flags = MSG_NOSIGNAL | MSG_EOR;
992 let sent = cvt_r!(unsafe { send(self.fd.as_raw_fd(), ptr, packet.len(), flags) })?;
993
994 return Ok(sent as usize);
995 }
996
997 pub
998 fn send_flags(&self, packet: &[u8], flags: i32) -> Result<usize, io::Error>
999 {
1000 let ptr = packet.as_ptr() as *const c_void;
1001 let sent = cvt_r!(unsafe { send(self.fd.as_raw_fd(), ptr, packet.len(), flags) })?;
1002
1003 return Ok(sent as usize);
1004 }
1005
1006 /// Receives a packet from the peer.
1007 pub
1008 fn recv(&self, buffer: &mut[u8]) -> Result<usize, io::Error>
1009 {
1010 let ptr = buffer.as_ptr() as *mut c_void;
1011 let received = cvt_r!(unsafe { recv(self.fd.as_raw_fd(), ptr, buffer.len(), MSG_NOSIGNAL) })?;
1012
1013 return Ok(received as usize);
1014 }
1015 /// Sends a packet assembled from multiple byte slices.
1016 pub
1017 fn send_vectored(&self, slices: &[IoSlice]) -> Result<usize, io::Error>
1018 {
1019 // Can't use writev() because we need to pass flags,
1020 // and the flags accepted by pwritev2() aren't the one we need to pass.
1021 send_ancillary(&self, None, MSG_EOR, slices, Vec::new(), None)
1022 }
1023
1024 /// Reads a packet into multiple buffers.
1025 ///
1026 /// The returned `bool` indicates whether the packet was truncated due to
1027 /// too short buffers.
1028 pub
1029 fn recv_vectored(&self, buffers: &mut[IoSliceMut]) -> Result<(usize, bool), io::Error>
1030 {
1031 recv_ancillary(&self, None, 0, buffers, &mut[])
1032 .map(|(bytes, ancillary)| (bytes, ancillary.message_truncated()) )
1033 }
1034
1035 /// Sends a packet with associated file descriptors.
1036 pub
1037 fn send_fds(&self, bytes: &[u8], fds: Vec<OwnedFd>) -> Result<usize, io::Error>
1038 {
1039 send_ancillary(&self, None, MSG_EOR, &[IoSlice::new(bytes)], fds, None)
1040 }
1041
1042 /// Receives a packet and associated file descriptors.
1043 pub
1044 fn recv_fds(&self, byte_buffer: &mut[u8], fd_buffer: &mut Vec<OwnedFd>) -> Result<(usize, bool, usize), io::Error>
1045 {
1046 recv_fds(&self, None, &mut[IoSliceMut::new(byte_buffer)], Some(fd_buffer))
1047 }
1048
1049 /// Receives a packet without removing it from the incoming queue.
1050 ///
1051 /// # Examples
1052 ///
1053 #[cfg_attr(not(target_vendor="apple"), doc="```")]
1054 #[cfg_attr(target_vendor="apple", doc="```no_run")]
1055 /// # use std::io::ErrorKind::*;
1056 /// let (a, b) = uds_fork::nonblocking::UnixSeqpacketConn::pair().unwrap();
1057 /// let mut buf = [0u8; 10];
1058 /// assert_eq!(b.peek(&mut buf).unwrap_err().kind(), WouldBlock);
1059 /// a.send(b"hello").unwrap();
1060 /// assert_eq!(b.peek(&mut buf).unwrap(), 5);
1061 /// assert_eq!(&buf[..5], b"hello");
1062 /// assert_eq!(b.recv(&mut buf).unwrap(), 5);
1063 /// assert_eq!(&buf[..5], b"hello");
1064 /// assert_eq!(b.peek(&mut buf).unwrap_err().kind(), WouldBlock);
1065 /// ```
1066 pub
1067 fn peek(&self, buffer: &mut[u8]) -> Result<usize, io::Error>
1068 {
1069 let ptr = buffer.as_ptr() as *mut c_void;
1070 let flags = MSG_NOSIGNAL | MSG_PEEK;
1071 let received = cvt_r!(unsafe { recv(self.fd.as_raw_fd(), ptr, buffer.len(), flags) })?;
1072
1073 return Ok(received as usize);
1074 }
1075
1076 /// Receives a packet without removing it from the incoming queue.
1077 ///
1078 /// The returned `bool` indicates whether the packet was truncated due to
1079 /// the combined buffers being too small.
1080 pub
1081 fn peek_vectored(&self, buffers: &mut[IoSliceMut]) -> Result<(usize, bool), io::Error>
1082 {
1083 recv_ancillary(&self, None, MSG_PEEK, buffers, &mut[])
1084 .map(|(bytes, ancillary)| (bytes, ancillary.message_truncated()) )
1085 }
1086
1087 /// Returns the value of the `SO_ERROR` option.
1088 ///
1089 /// This might only provide errors generated from nonblocking `connect()`s,
1090 /// which this library doesn't support. It is therefore unlikely to be
1091 /// useful, but is provided for parity with `mio`s `UnixStream`.
1092 ///
1093 /// # Examples
1094 ///
1095 #[cfg_attr(not(target_vendor="apple"), doc="```")]
1096 #[cfg_attr(target_vendor="apple", doc="```no_run")]
1097 /// let (a, _b) = uds_fork::nonblocking::UnixSeqpacketConn::pair().unwrap();
1098 ///
1099 /// assert!(a.recv(&mut[0u8; 1024]).is_err());
1100 /// assert!(a.take_error().unwrap().is_none());
1101 /// ```
1102 pub
1103 fn take_error(&self) -> Result<Option<io::Error>, io::Error>
1104 {
1105 take_error(&self)
1106 }
1107
1108 // note: freebsd reports error on line
1109 // assert_eq!(a1.recv(&mut[0u8; 10]).unwrap_err().kind(), ErrorKind::Woul ... recv
1110 // thread 'main' (105211) panicked at /tmp/rustdoctestEFy1yO/doctest_bundle_2024.rs:283:35:
1111 // called `Result::unwrap_err()` on an `Ok` value: 10
1112
1113 /// Creates a new file descriptor also pointing to this side of this connection.
1114 ///
1115 /// # Examples
1116 ///
1117 #[cfg_attr(not(target_vendor="apple"), doc="```")]
1118 #[cfg_attr(any(target_vendor="apple", target_os = "freebsd"), doc="```no_run")]
1119 /// # use uds_fork::nonblocking::UnixSeqpacketConn;
1120 /// # use std::io::ErrorKind;
1121 /// #
1122 /// let (a1, b) = UnixSeqpacketConn::pair().unwrap();
1123 /// b.send(b"first come first serve").unwrap();
1124 /// let a2 = a1.try_clone().unwrap();
1125 /// a2.recv(&mut[0u8; 10]).unwrap();
1126 /// assert_eq!(a1.recv(&mut[0u8; 10]).unwrap_err().kind(), ErrorKind::WouldBlock);
1127 ///
1128 /// b.send(b"more").unwrap();
1129 /// a1.recv(&mut[0u8; 10]).unwrap();
1130 /// assert_eq!(a2.recv(&mut[0u8; 10]).unwrap_err().kind(), ErrorKind::WouldBlock);
1131 /// ```
1132 pub
1133 fn try_clone(&self) -> Result<Self, io::Error>
1134 {
1135 let cloned = Socket::<SocketSeqPkt>::try_clone_from(&self)?;
1136 // nonblockingness is shared and therefore inherited
1137
1138 return Ok(NonblockingUnixSeqpacketConn { fd: cloned.into() });
1139 }
1140
1141 /// Shuts down the read, write, or both halves of this connection.
1142 pub
1143 fn shutdown(&self, how: Shutdown) -> io::Result<()>
1144 {
1145 let how =
1146 match how
1147 {
1148 Shutdown::Read => libc::SHUT_RD,
1149 Shutdown::Write => libc::SHUT_WR,
1150 Shutdown::Both => libc::SHUT_RDWR,
1151 };
1152
1153 unsafe { cvt!(libc::shutdown(self.as_raw_fd(), how)) }?;
1154
1155 return Ok(());
1156 }
1157}
1158
1159
1160/// A non-blocking unix domain listener for sequential-packet connections.
1161///
1162/// Differs from [`UnixSeqpacketListener`](../struct.UnixSeqpacketListener.html)
1163/// in that [`accept()`](struct.NonblockingUnixSeqpacketListener.html#method.accept)
1164/// returns non-blocking [connection sockets](struct.NonblockingUnixSeqpacketConn.html)
1165/// and doesn't block if no client `connect()`ions are pending.
1166///
1167/// This type can be used with mio if the `mio_08` feature is enabled:
1168///
1169/// ```toml
1170/// uds = { version = "x.y", features=["mio_08"] }
1171/// ```
1172///
1173/// # Examples
1174///
1175#[cfg_attr(not(target_vendor="apple"), doc="```")]
1176#[cfg_attr(target_vendor="apple", doc="```no_run")]
1177/// use uds_fork::nonblocking::{UnixSeqpacketListener, UnixSeqpacketConn};
1178/// use std::io::ErrorKind;
1179///
1180/// # let _ = std::fs::remove_file("/tmp/nonblocking_seqpacket_listener.socket");
1181/// let listener = UnixSeqpacketListener::bind("/tmp/nonblocking_seqpacket_listener.socket")
1182/// .expect("Cannot create nonblocking seqpacket listener");
1183///
1184/// // doesn't block if no connections are waiting:
1185/// assert_eq!(listener.accept_unix_addr().unwrap_err().kind(), ErrorKind::WouldBlock);
1186///
1187/// // returned connections are nonblocking:
1188/// let _client = UnixSeqpacketConn::connect("/tmp/nonblocking_seqpacket_listener.socket").unwrap();
1189/// let (conn, _addr) = listener.accept_unix_addr().unwrap();
1190/// assert_eq!(conn.recv(&mut[0u8; 20]).unwrap_err().kind(), ErrorKind::WouldBlock);
1191/// #
1192/// # std::fs::remove_file("/tmp/nonblocking_seqpacket_listener.socket").unwrap();
1193/// ```
1194#[derive(Debug)]
1195#[repr(transparent)]
1196pub struct NonblockingUnixSeqpacketListener
1197{
1198 fd: OwnedFd
1199}
1200
1201impl FromRawFd for NonblockingUnixSeqpacketListener
1202{
1203 unsafe
1204 fn from_raw_fd(fd: RawFd) -> Self
1205 {
1206 return
1207 Self{ fd: unsafe { OwnedFd::from_raw_fd(fd) } };
1208 }
1209}
1210
1211impl AsRawFd for NonblockingUnixSeqpacketListener
1212{
1213 fn as_raw_fd(&self) -> RawFd
1214 {
1215 self.fd.as_raw_fd()
1216 }
1217}
1218
1219impl IntoRawFd for NonblockingUnixSeqpacketListener
1220{
1221 fn into_raw_fd(self) -> RawFd
1222 {
1223 self.fd.into_raw_fd()
1224 }
1225}
1226
1227impl AsFd for NonblockingUnixSeqpacketListener
1228{
1229 fn as_fd(&self) -> BorrowedFd<'_>
1230 {
1231 self.fd.as_fd()
1232 }
1233}
1234
1235impl NonblockingUnixSeqpacketListener
1236{
1237 /// Creates a socket that listens for seqpacket connections on the specified socket file.
1238 pub
1239 fn bind<P: AsRef<Path>>(path: P) -> Result<Self, io::Error>
1240 {
1241 let addr = UnixSocketAddr::from_path(&path)?;
1242
1243 return Self::bind_unix_addr(&addr);
1244 }
1245
1246 /// Creates a socket that listens for seqpacket connections on the specified address.
1247 pub
1248 fn bind_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error>
1249 {
1250 let socket = Socket::<SocketSeqPkt>::new(true)?;
1251 socket.set_unix_addr(SetAddr::LOCAL, addr)?;
1252 socket.start_listening()?;
1253
1254 return Ok(NonblockingUnixSeqpacketListener { fd: socket.into() });
1255 }
1256
1257 /// Returns the address this listener was bound to.
1258 pub
1259 fn local_unix_addr(&self) -> Result<UnixSocketAddr, io::Error>
1260 {
1261 get_unix_addr(&self, GetAddr::LOCAL)
1262 }
1263
1264 /// Accepts a non-blocking connection, non-blockingly.
1265 ///
1266 /// # Examples
1267 ///
1268 /// Doesn't block if no connections are waiting:
1269 ///
1270 #[cfg_attr(not(target_vendor="apple"), doc="```")]
1271 #[cfg_attr(target_vendor="apple", doc="```no_run")]
1272 /// # use uds_fork::nonblocking::UnixSeqpacketListener;
1273 /// # use std::io::ErrorKind;
1274 /// #
1275 /// let _ = std::fs::remove_file("/tmp/nonblocking_seqpacket_listener.socket");
1276 /// let listener = UnixSeqpacketListener::bind("/tmp/nonblocking_seqpacket_listener.socket")
1277 /// .expect("Cannot create nonblocking seqpacket listener");
1278 /// assert_eq!(listener.accept_unix_addr().unwrap_err().kind(), ErrorKind::WouldBlock);
1279 /// std::fs::remove_file("/tmp/nonblocking_seqpacket_listener.socket").unwrap();
1280 /// ```
1281 pub
1282 fn accept_unix_addr(&self) -> Result<(NonblockingUnixSeqpacketConn, UnixSocketAddr), io::Error>
1283 {
1284 let (socket, addr) = Socket::<SocketSeqPkt>::accept_from(&self, true)?;
1285 let conn = NonblockingUnixSeqpacketConn { fd: socket.into() };
1286
1287 return Ok((conn, addr));
1288 }
1289
1290 /// Returns the value of the `SO_ERROR` option.
1291 ///
1292 /// This might never produce any errors for listeners. It is therefore
1293 /// unlikely to be useful, but is provided for parity with `mio`s
1294 /// `UnixListener`.
1295 ///
1296 /// # Examples
1297 ///
1298 #[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
1299 #[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
1300 /// let listener = uds_fork::nonblocking::UnixSeqpacketListener::bind_unix_addr(
1301 /// &uds_fork::UnixSocketAddr::new("@nonblocking_take_error").unwrap()
1302 /// ).unwrap();
1303 ///
1304 /// assert!(listener.accept_unix_addr().is_err());
1305 /// assert!(listener.take_error().unwrap().is_none());
1306 /// ```
1307 pub
1308 fn take_error(&self) -> Result<Option<io::Error>, io::Error>
1309 {
1310 take_error(&self)
1311 }
1312
1313 /// Creates a new file descriptor listening for the same connections.
1314 pub
1315 fn try_clone(&self) -> Result<Self, io::Error>
1316 {
1317 let cloned = Socket::<SocketSeqPkt>::try_clone_from(&self)?;
1318 // nonblockingness is shared and therefore inherited
1319
1320 return Ok(NonblockingUnixSeqpacketListener { fd: cloned.into() });
1321 }
1322}