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}, net::Shutdown, ops::{Deref, DerefMut}, os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}, path::Path, time::Duration
10};
11
12use libc::{MSG_EOR, MSG_PEEK, c_void, send, recv};
13
14//use crate::addr::*;
15use crate::{UnixSocketAddr, helpers::*};
16use crate::ancillary::*;
17use crate::credentials::*;
18
19/// An unix domain sequential packet connection.
20///
21/// Sequential-packet connections have an interface similar to streams,
22/// but behave more like connected datagram sockets.
23///
24/// They have guaranteed in-order and reliable delivery,
25/// which unix datagrams technically doesn't.
26///
27/// # Operating system support
28///
29/// Sequential-packet sockets are supported by Linux, FreeBSD, NetBSD
30/// and Illumos, but not by for example macOS or OpenBSD.
31///
32/// # Zero-length packets
33///
34/// ... are best avoided:
35/// On Linux and FreeBSD zero-length packets can be sent and received,
36/// but there is no way to distinguish receiving one from reaching
37/// end of connection unless the packet has an ancillary payload.
38/// Also beware of trying to receive with a zero-length buffer,
39/// as that will on FreeBSD (and probably other BSDs with seqpacket sockets)
40/// always succeed even if there is no packet waiting.
41///
42/// Illumos and Solaris doesn't support receiving zero-length packets at all:
43/// writes succeed but recv() will block.
44///
45/// # Registering with Xio (xio-rs) a feature = "xio-rs"
46///
47/// A `XioEventPipe` is implemented on this function. During initial registration
48/// an attempt set `nonblocking` mode is performed during initial registration.
49///
50/// See examples below.
51///
52/// # Registering with Mio (mio) a feature = "mio"
53///
54/// A `Source` is implemented on the instance.During initial registration
55/// an attempt set `nonblocking` mode is performed during initial registration.
56///
57/// # Examples
58///
59/// What is sent separately is received separately:
60///
61#[cfg_attr(not(target_vendor="apple"), doc="```")]
62#[cfg_attr(target_vendor="apple", doc="```no_run")]
63/// let (a, b) = uds_fork::UnixSeqpacketConn::pair().expect("Cannot create seqpacket pair");
64///
65/// a.send(b"first").unwrap();
66/// a.send(b"second").unwrap();
67///
68/// let mut buffer_big_enough_for_both = [0; 20];
69/// let len = b.recv(&mut buffer_big_enough_for_both).unwrap();
70/// assert_eq!(&buffer_big_enough_for_both[..len], b"first");
71/// let len = b.recv(&mut buffer_big_enough_for_both).unwrap();
72/// assert_eq!(&buffer_big_enough_for_both[..len], b"second");
73/// ```
74///
75/// Connect to a listener on a socket file and write to it:
76///
77#[cfg_attr(not(target_vendor="apple"), doc="```")]
78#[cfg_attr(target_vendor="apple", doc="```no_run")]
79/// use uds_fork::{UnixSeqpacketListener, UnixSeqpacketConn};
80/// use tempfile::TempDir;
81///
82/// let dir = tempfile::tempdir().unwrap();
83/// let mut file_path = dir.path().join("seqpacket.socket");
84///
85/// let listener = UnixSeqpacketListener::bind(&file_path)
86/// .expect("create seqpacket listener");
87/// let conn = UnixSeqpacketConn::connect(&file_path)
88/// .expect("connect to seqpacket listener");
89///
90/// let message = "Hello, listener";
91/// let sent = conn.send(message.as_bytes()).unwrap();
92/// assert_eq!(sent, message.len());
93/// ```
94///
95/// Connect to a listener on an abstract address:
96///
97#[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
98#[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
99/// use uds_fork::{UnixSeqpacketListener, UnixSeqpacketConn, UnixSocketAddr};
100///
101/// let addr = UnixSocketAddr::new("@seqpacket example").unwrap();
102/// let listener = UnixSeqpacketListener::bind_unix_addr(&addr)
103/// .expect("create abstract seqpacket listener");
104/// let _client = UnixSeqpacketConn::connect_unix_addr(&addr)
105/// .expect("connect to abstract seqpacket listener");
106/// let (_server, _addr) = listener.accept_unix_addr().unwrap();
107/// ```
108///
109/// ### Xio
110///
111/// ```ignore
112/// let (mut a, b) = UnixSeqpacketConn::pair().unwrap();
113///
114/// let mut reg = XioPollRegistry::<ESS>::new().unwrap();
115/// let mut event_buf = XioPollRegistry::<ESS>::allocate_events(128.try_into().unwrap());
116///
117/// // either
118/// let a_wrapped =
119/// reg.get_registry()
120/// .en_register_wrap(a, XioEventUid::manual(1), XioChannel::INPUT)
121/// .unwrap();
122///
123/// // or
124/// reg.get_registry()
125/// .en_register&mut a, XioEventUid::manual(1), XioChannel::INPUT)
126/// .unwrap();
127///
128/// // so depending on the method, use either:
129/// a_wrapped.inner();
130///
131/// // or continue using a directly
132/// ```
133///
134/// ### Mio:
135///
136/// ```ignore
137/// let (mut a, b) = UnixSeqpacketConn::pair().unwrap();
138///
139/// let mut poll = Poll::new().expect("create mio poll");
140/// let mut events = Events::with_capacity(10);
141///
142/// poll.registry()
143/// .register(&mut a, Token(1), Interest::READABLE)
144/// .unwrap();
145/// // ...
146/// ```
147#[derive(Debug)]
148#[repr(transparent)]
149pub struct UnixSeqpacketConn
150{
151 fd: OwnedFd,
152}
153
154impl From<OwnedFd> for UnixSeqpacketConn
155{
156 fn from(ofd: OwnedFd) -> Self
157 {
158 let sa_fam = get_socket_family(&ofd).unwrap();
159 let sa_type = get_socket_type(&ofd).unwrap() & 0x00000FFF;
160
161 if sa_fam as i32 != libc::AF_UNIX || sa_type != libc::SOCK_SEQPACKET
162 {
163 panic!("assertion trap: provided FD is not AF_UNIX & SOCK_SEQPACKET, {} {}",
164 sa_fam, sa_type);
165 }
166
167 return UnixSeqpacketConn{ fd: ofd };
168 }
169}
170
171impl From<UnixSeqpacketConn> for OwnedFd
172{
173 fn from(value: UnixSeqpacketConn) -> Self
174 {
175 return value.fd;
176 }
177}
178
179impl FromRawFd for UnixSeqpacketConn
180{
181 unsafe
182 fn from_raw_fd(fd: RawFd) -> Self
183 {
184 UnixSeqpacketConn::from( unsafe { OwnedFd::from_raw_fd(fd) } )
185 }
186}
187
188impl AsRawFd for UnixSeqpacketConn
189{
190 fn as_raw_fd(&self) -> RawFd
191 {
192 self.fd.as_raw_fd()
193 }
194}
195impl IntoRawFd for UnixSeqpacketConn
196{
197 fn into_raw_fd(self) -> RawFd
198 {
199 self.fd.into_raw_fd()
200 }
201}
202
203impl AsFd for UnixSeqpacketConn
204{
205 fn as_fd(&self) -> BorrowedFd<'_>
206 {
207 self.fd.as_fd()
208 }
209}
210
211#[cfg(feature = "mio")]
212pub mod mio_conn_enabled
213{
214 use mio::{event::Source, unix::SourceFd};
215 use super::*;
216
217 impl Source for UnixSeqpacketConn
218 {
219 fn register(
220 &mut self,
221 registry: &mio::Registry,
222 token: mio::Token,
223 interests: mio::Interest,
224 ) -> io::Result<()>
225 {
226 self.set_nonblocking(true)?;
227
228 SourceFd(&self.fd.as_raw_fd()).register(registry, token, interests)
229 }
230
231 fn reregister(
232 &mut self,
233 registry: &mio::Registry,
234 token: mio::Token,
235 interests: mio::Interest,
236 ) -> io::Result<()>
237 {
238 SourceFd(&self.fd.as_raw_fd()).reregister(registry, token, interests)
239 }
240
241 fn deregister(&mut self, registry: &mio::Registry) -> io::Result<()>
242 {
243 SourceFd(&self.fd.as_raw_fd()).deregister(registry)
244 }
245 }
246}
247
248#[cfg(feature = "xio-rs")]
249pub mod xio_conn_enabled
250{
251 use xio_rs::{EsInterfaceRegistry, XioChannel, XioEventPipe, XioEventUid, XioResult, event_registry::XioRegistry};
252
253 use crate::UnixSeqpacketConn;
254
255 impl<ESSR: EsInterfaceRegistry> XioEventPipe<ESSR, Self> for UnixSeqpacketConn
256 {
257 fn connect_event_pipe(&mut self, ess: &XioRegistry<ESSR>, ev_uid: XioEventUid, channel: XioChannel) -> XioResult<()>
258 {
259 self.set_nonblocking(true)?;
260
261 ess.get_ev_sys().en_register(&self.fd, ev_uid, channel)
262 }
263
264 fn modify_event_pipe(&mut self, ess: &XioRegistry<ESSR>, ev_uid: XioEventUid, channel: XioChannel) -> XioResult<()>
265 {
266 ess.get_ev_sys().re_register(&self.fd, ev_uid, channel)
267 }
268
269 fn disconnect_event_pipe(&mut self, ess: &XioRegistry<ESSR>) -> XioResult<()>
270 {
271 ess.get_ev_sys().de_register(&self.fd)
272 }
273 }
274}
275
276impl UnixSeqpacketConn
277{
278 /// Connects to an unix seqpacket server listening at `path`.
279 ///
280 /// This is a wrapper around [`connect_unix_addr()`](#method.connect_unix_addr)
281 /// for convenience and compatibility with std.
282 pub
283 fn connect<P: AsRef<Path>>(path: P) -> Result<Self, io::Error>
284 {
285 let addr = UnixSocketAddr::from_path(&path)?;
286
287 return Self::connect_unix_addr(&addr);
288 }
289
290 /// Connects to an unix seqpacket server listening at `addr`.
291 pub
292 fn connect_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error>
293 {
294 let socket = Socket::<SocketSeqPkt>::new(false)?;
295 socket.set_unix_peer_addr(addr)?;
296
297 return Ok(UnixSeqpacketConn { fd: socket.into() });
298 }
299
300 /// Binds to an address before connecting to a listening seqpacet socket.
301 pub
302 fn connect_from_to_unix_addr(from: &UnixSocketAddr, to: &UnixSocketAddr) -> Result<Self, io::Error>
303 {
304 let socket = Socket::<SocketSeqPkt>::new(false)?;
305 socket.set_unix_local_addr(from)?;
306 socket.set_unix_peer_addr(to)?;
307
308 return Ok(UnixSeqpacketConn{ fd: socket.into() });
309 }
310
311 /// Creates a pair of unix-domain seqpacket conneections connected to each other.
312 ///
313 /// # Examples
314 ///
315 #[cfg_attr(not(target_vendor="apple"), doc="```")]
316 #[cfg_attr(target_vendor="apple", doc="```no_run")]
317 /// let (a, b) = uds_fork::UnixSeqpacketConn::pair().unwrap();
318 /// assert!(a.local_unix_addr().unwrap().is_unnamed());
319 /// assert!(b.local_unix_addr().unwrap().is_unnamed());
320 ///
321 /// a.send(b"hello").unwrap();
322 /// b.recv(&mut[0; 20]).unwrap();
323 /// ```
324 pub
325 fn pair() -> Result<(Self, Self), io::Error>
326 {
327 let pair = Socket::<SocketSeqPkt>::pair(false)?;
328
329 return Ok(
330 (
331 UnixSeqpacketConn { fd: pair.0.into() },
332 UnixSeqpacketConn { fd: pair.1.into() }
333 )
334 );
335 }
336
337 /// Returns the address of this side of the connection.
338 pub
339 fn local_unix_addr(&self) -> Result<UnixSocketAddr, io::Error>
340 {
341 get_unix_local_addr(&self)
342 }
343
344 /// Returns the address of the other side of the connection.
345 pub
346 fn peer_unix_addr(&self) -> Result<UnixSocketAddr, io::Error>
347 {
348 get_unix_peer_addr(&self)
349 }
350
351 /// Returns information about the process of the peer when the connection was established.
352 ///
353 /// See documentation of the returned type for details.
354 pub
355 fn initial_peer_credentials(&self) -> Result<ConnCredentials, io::Error>
356 {
357 peer_credentials(&self)
358 }
359
360 /// Returns the SELinux security context of the process that created the other
361 /// end of this connection.
362 ///
363 /// Will return an error on other operating systems than Linux or Android,
364 /// and also if running inside kubernetes.
365 /// On success the number of bytes used is returned. (like `Read`)
366 ///
367 /// The default security context is `unconfined`, without any trailing NUL.
368 /// A buffor of 50 bytes is probably always big enough.
369 pub
370 fn initial_peer_selinux_context(&self, buf: &mut[u8]) -> Result<usize, io::Error>
371 {
372 selinux_context(&self, buf)
373 }
374
375
376 /// Sends a packet to the peer.
377 pub
378 fn send(&self, packet: &[u8]) -> Result<usize, io::Error>
379 {
380 let ptr = packet.as_ptr() as *const c_void;
381 let flags = MSG_NOSIGNAL | MSG_EOR;
382 let sent = cvt_r!(unsafe { send(self.fd.as_raw_fd(), ptr, packet.len(), flags) })?;
383
384
385 return Ok(sent as usize);
386 }
387
388 /// Sends a packet to the peer.
389 pub
390 fn send_flags(&self, packet: &[u8], flags: i32) -> Result<usize, io::Error>
391 {
392 let ptr = packet.as_ptr() as *const c_void;
393 let sent = cvt_r!(unsafe { send(self.fd.as_raw_fd(), ptr, packet.len(), flags) })?;
394
395 return Ok(sent as usize);
396 }
397
398 /// Receives a packet from the peer.
399 pub
400 fn recv(&self, buffer: &mut[u8]) -> Result<usize, io::Error>
401 {
402 let ptr = buffer.as_ptr() as *mut c_void;
403 let received = cvt_r!(unsafe { recv(self.fd.as_raw_fd(), ptr, buffer.len(), MSG_NOSIGNAL) })?;
404
405 return Ok(received as usize);
406 }
407
408 /// Sends a packet assembled from multiple byte slices.
409 pub
410 fn send_vectored(&self, slices: &[IoSlice]) -> Result<usize, io::Error>
411 {
412 // Can't use writev() because we need to pass flags,
413 // and the flags accepted by pwritev2() aren't the one we need to pass.
414 send_ancillary(&self, None, MSG_EOR, slices, Vec::new(), None)
415 }
416 /// Reads a packet into multiple buffers.
417 ///
418 /// The returned `bool` indicates whether the packet was truncated due to
419 /// too short buffers.
420 pub
421 fn recv_vectored(&self, buffers: &mut[IoSliceMut]) -> Result<(usize, bool), io::Error>
422 {
423 recv_ancillary(&self, None, 0, buffers, &mut[])
424 .map(|(bytes, ancillary)| (bytes, ancillary.message_truncated()) )
425 }
426
427 /// Sends a packet with associated file descriptors.
428 pub
429 fn send_fds(&self, bytes: &[u8], fds: Vec<OwnedFd>) -> Result<usize, io::Error>
430 {
431 send_ancillary(&self, None, MSG_EOR, &[IoSlice::new(bytes)], fds, None)
432 }
433
434 /// Receives a packet and associated file descriptors.
435 pub
436 fn recv_fds(&self, byte_buffer: &mut[u8], fd_buffer: &mut Vec<OwnedFd>) -> Result<(usize, bool, usize), io::Error>
437 {
438 recv_fds(&self, None, &mut[IoSliceMut::new(byte_buffer)], Some(fd_buffer))
439 }
440
441 /// Receives a packet without removing it from the incoming queue.
442 ///
443 /// # Examples
444 ///
445 #[cfg_attr(not(target_vendor="apple"), doc="```")]
446 #[cfg_attr(target_vendor="apple", doc="```no_run")]
447 /// let (a, b) = uds_fork::UnixSeqpacketConn::pair().unwrap();
448 /// a.send(b"hello").unwrap();
449 /// let mut buf = [0u8; 10];
450 /// assert_eq!(b.peek(&mut buf[..1]).unwrap(), 1);
451 /// assert_eq!(&buf[..2], &[b'h', 0]);
452 /// assert_eq!(b.peek(&mut buf).unwrap(), 5);
453 /// assert_eq!(&buf[..5], b"hello");
454 /// assert_eq!(b.recv(&mut buf).unwrap(), 5);
455 /// assert_eq!(&buf[..5], b"hello");
456 /// ```
457 pub
458 fn peek(&self, buffer: &mut[u8]) -> Result<usize, io::Error>
459 {
460 let ptr = buffer.as_ptr() as *mut c_void;
461 let flags = MSG_NOSIGNAL | MSG_PEEK;
462 let received = cvt_r!(unsafe { recv(self.fd.as_raw_fd(), ptr, buffer.len(), flags) })?;
463
464 return Ok(received as usize);
465 }
466
467 /// Receives a packet without removing it from the incoming queue.
468 ///
469 /// The returned `bool` indicates whether the packet was truncated due to
470 /// the combined buffers being too small.
471 pub
472 fn peek_vectored(&self, buffers: &mut[IoSliceMut]) -> Result<(usize, bool), io::Error>
473 {
474 recv_ancillary(&self, None, MSG_PEEK, buffers, &mut[])
475 .map(|(bytes, ancillary)| (bytes, ancillary.message_truncated()) )
476 }
477
478 /// Returns the value of the `SO_ERROR` option.
479 ///
480 /// This might only provide errors generated from nonblocking `connect()`s,
481 /// which this library doesn't support. It is therefore unlikely to be
482 /// useful, but is provided for parity with stream counterpart in std.
483 ///
484 /// # Examples
485 ///
486 #[cfg_attr(not(target_vendor="apple"), doc="```")]
487 #[cfg_attr(target_vendor="apple", doc="```no_run")]
488 /// let (a, b) = uds_fork::UnixSeqpacketConn::pair().unwrap();
489 /// drop(b);
490 ///
491 /// assert!(a.send(b"anyone there?").is_err());
492 /// assert!(a.take_error().unwrap().is_none());
493 /// ```
494 pub
495 fn take_error(&self) -> Result<Option<io::Error>, io::Error>
496 {
497 take_error(&self)
498 }
499
500
501 /// Creates a new file descriptor also pointing to this side of this connection.
502 ///
503 /// # Examples
504 ///
505 /// Both new and old can send and receive, and share queues:
506 ///
507 #[cfg_attr(not(target_vendor="apple"), doc="```")]
508 #[cfg_attr(target_vendor="apple", doc="```no_run")]
509 /// let (a1, b) = uds_fork::nonblocking::UnixSeqpacketConn::pair().unwrap();
510 /// let a2 = a1.try_clone().unwrap();
511 ///
512 /// a1.send(b"first").unwrap();
513 /// a2.send(b"second").unwrap();
514 ///
515 /// let mut buf = [0u8; 20];
516 /// let len = b.recv(&mut buf).unwrap();
517 /// assert_eq!(&buf[..len], b"first");
518 /// b.send(b"hello first").unwrap();
519 /// let len = b.recv(&mut buf).unwrap();
520 /// assert_eq!(&buf[..len], b"second");
521 /// b.send(b"hello second").unwrap();
522 ///
523 /// let len = a2.recv(&mut buf).unwrap();
524 /// assert_eq!(&buf[..len], b"hello first");
525 /// let len = a1.recv(&mut buf).unwrap();
526 /// assert_eq!(&buf[..len], b"hello second");
527 /// ```
528 ///
529 /// Clone can still be used after the first one has been closed:
530 ///
531 #[cfg_attr(not(target_vendor="apple"), doc="```")]
532 #[cfg_attr(target_vendor="apple", doc="```no_run")]
533 /// let (a, b1) = uds_fork::nonblocking::UnixSeqpacketConn::pair().unwrap();
534 /// a.send(b"hello").unwrap();
535 ///
536 /// let b2 = b1.try_clone().unwrap();
537 /// drop(b1);
538 /// assert_eq!(b2.recv(&mut[0; 10]).unwrap(), "hello".len());
539 /// ```
540 pub
541 fn try_clone(&self) -> Result<Self, io::Error>
542 {
543 let cloned = Socket::<SocketSeqPkt>::try_clone_from(self)?;
544
545 return Ok(UnixSeqpacketConn { fd: cloned.into() });
546 }
547
548 /// Sets the read timeout to the duration specified.
549 ///
550 /// If the value specified is `None`, then `recv()` and its variants will
551 /// block indefinitely.
552 /// An error is returned if the duration is zero.
553 ///
554 /// The duration is rounded to microsecond precission.
555 /// Currently it's rounded down except if that would make it all zero.
556 ///
557 /// # Operating System Support
558 ///
559 /// On Illumos (and pressumably also Solaris) timeouts appears not to work
560 /// for unix domain sockets.
561 ///
562 /// # Examples
563 ///
564 #[cfg_attr(not(any(target_vendor="apple", target_os="illumos", target_os="solaris")), doc="```")]
565 #[cfg_attr(any(target_vendor="apple", target_os="illumos", target_os="solaris"), doc="```no_run")]
566 /// use std::io::ErrorKind;
567 /// use std::time::Duration;
568 /// use uds_fork::UnixSeqpacketConn;
569 ///
570 /// let (a, b) = UnixSeqpacketConn::pair().unwrap();
571 /// a.set_read_timeout(Some(Duration::new(0, 2_000_000))).unwrap();
572 /// let error = a.recv(&mut[0; 1024]).unwrap_err();
573 /// assert_eq!(error.kind(), ErrorKind::WouldBlock);
574 /// ```
575 pub
576 fn set_read_timeout(&self, timeout: Option<Duration>) -> Result<(), io::Error>
577 {
578 set_timeout(self.fd.as_fd(), TimeoutDirection::Read, timeout)
579 }
580
581 /// Returns the read timeout of this socket.
582 ///
583 /// `None` is returned if there is no timeout.
584 ///
585 /// Note that subsecond parts might have been be rounded by the OS
586 /// (in addition to the rounding to microsecond in `set_read_timeout()`).
587 ///
588 /// # Examples
589 ///
590 #[cfg_attr(not(any(target_vendor="apple", target_os="illumos", target_os="solaris")), doc="```")]
591 #[cfg_attr(any(target_vendor="apple", target_os="illumos", target_os="solaris"), doc="```no_run")]
592 /// use uds_fork::UnixSeqpacketConn;
593 /// use std::time::Duration;
594 ///
595 /// let timeout = Some(Duration::new(2, 0));
596 /// let conn = UnixSeqpacketConn::pair().unwrap().0;
597 /// conn.set_read_timeout(timeout).unwrap();
598 /// assert_eq!(conn.read_timeout().unwrap(), timeout);
599 /// ```
600 pub
601 fn read_timeout(&self) -> Result<Option<Duration>, io::Error>
602 {
603 get_timeout(self.fd.as_fd(), TimeoutDirection::Read)
604 }
605
606 /// Sets the write timeout to the duration specified.
607 ///
608 /// If the value specified is `None`, then `send()` and its variants will
609 /// block indefinitely.
610 /// An error is returned if the duration is zero.
611 ///
612 /// # Operating System Support
613 ///
614 /// On Illumos (and pressumably also Solaris) timeouts appears not to work
615 /// for unix domain sockets.
616 ///
617 /// # Examples
618 ///
619 #[cfg_attr(not(any(target_vendor="apple", target_os="illumos", target_os="solaris")), doc="```")]
620 #[cfg_attr(any(target_vendor="apple", target_os="illumos", target_os="solaris"), doc="```no_run")]
621 /// # use std::io::ErrorKind;
622 /// # use std::time::Duration;
623 /// # use uds_fork::UnixSeqpacketConn;
624 /// #
625 /// let (conn, _other) = UnixSeqpacketConn::pair().unwrap();
626 /// conn.set_write_timeout(Some(Duration::new(0, 500 * 1000))).unwrap();
627 /// loop {
628 /// if let Err(e) = conn.send(&[0; 1000]) {
629 /// assert_eq!(e.kind(), ErrorKind::WouldBlock, "{}", e);
630 /// break
631 /// }
632 /// }
633 /// ```
634 pub
635 fn set_write_timeout(&self, timeout: Option<Duration>)-> Result<(), io::Error>
636 {
637 set_timeout(self.fd.as_fd(), TimeoutDirection::Write, timeout)
638 }
639
640 /// Returns the write timeout of this socket.
641 ///
642 /// `None` is returned if there is no timeout.
643 ///
644 /// # Examples
645 ///
646 #[cfg_attr(not(target_vendor="apple"), doc="```")]
647 #[cfg_attr(target_vendor="apple", doc="```no_run")]
648 /// let conn = uds_fork::UnixSeqpacketConn::pair().unwrap().0;
649 /// assert!(conn.write_timeout().unwrap().is_none());
650 /// ```
651 pub
652 fn write_timeout(&self) -> Result<Option<Duration>, io::Error>
653 {
654 get_timeout(self.fd.as_fd(), TimeoutDirection::Write)
655 }
656
657 /// Enables or disables nonblocking mode.
658 ///
659 /// Consider using the nonblocking variant of this type instead.
660 /// This method mainly exists for feature parity with std's `UnixStream`.
661 ///
662 /// # Examples
663 ///
664 /// Trying to receive when there are no packets waiting:
665 ///
666 #[cfg_attr(not(target_vendor="apple"), doc="```")]
667 #[cfg_attr(target_vendor="apple", doc="```no_run")]
668 /// # use std::io::ErrorKind;
669 /// # use uds_fork::UnixSeqpacketConn;
670 /// let (a, b) = UnixSeqpacketConn::pair().expect("create seqpacket pair");
671 /// a.set_nonblocking(true).unwrap();
672 /// assert_eq!(a.recv(&mut[0; 20]).unwrap_err().kind(), ErrorKind::WouldBlock);
673 /// ```
674 ///
675 /// Trying to send when the OS buffer for the connection is full:
676 ///
677 #[cfg_attr(not(target_vendor="apple"), doc="```")]
678 #[cfg_attr(target_vendor="apple", doc="```no_run")]
679 /// # use std::io::ErrorKind;
680 /// # use uds_fork::UnixSeqpacketConn;
681 /// let (a, b) = UnixSeqpacketConn::pair().expect("create seqpacket pair");
682 /// a.set_nonblocking(true).unwrap();
683 /// loop {
684 /// if let Err(error) = a.send(&[b'#'; 1000]) {
685 /// assert_eq!(error.kind(), ErrorKind::WouldBlock);
686 /// break;
687 /// }
688 /// }
689 /// ```
690 pub
691 fn set_nonblocking(&self, nonblocking: bool) -> Result<(), io::Error>
692 {
693 set_nonblocking(&self, nonblocking)
694 }
695
696 /// Shuts down the read, write, or both halves of this connection.
697 pub
698 fn shutdown(&self, how: Shutdown) -> io::Result<()>
699 {
700 let how =
701 match how
702 {
703 Shutdown::Read => libc::SHUT_RD,
704 Shutdown::Write => libc::SHUT_WR,
705 Shutdown::Both => libc::SHUT_RDWR,
706 };
707
708 unsafe { cvt!(libc::shutdown(self.as_raw_fd(), how)) }?;
709
710 return Ok(());
711 }
712}
713
714
715/// An unix domain listener for sequential packet connections.
716///
717/// See [`UnixSeqpacketConn`](struct.UnixSeqpacketConn.html) for a description
718/// of this type of connection.
719///
720/// # Registering with Xio (xio-rs) a feature = "xio-rs"
721///
722/// A `XioEventPipe` is implemented on this function. During initial registration
723/// an attempt set `nonblocking` mode is performed during initial registration.
724///
725/// See examples below.
726///
727/// # Registering with Mio (mio) a feature = "mio"
728///
729/// A `Source` is implemented on the instance.During initial registration
730/// an attempt set `nonblocking` mode is performed during initial registration.
731///
732/// # Examples
733///
734#[cfg_attr(not(target_vendor="apple"), doc="```")]
735#[cfg_attr(target_vendor="apple", doc="```no_run")]
736/// use tempfile::TempDir;
737///
738/// let dir = tempfile::tempdir().unwrap();
739/// let mut file_path = dir.path().join("seqpacket_listener.socket");
740///
741/// let listener = uds_fork::UnixSeqpacketListener::bind(&file_path)
742/// .expect("Create seqpacket listener");
743/// let _client = uds_fork::UnixSeqpacketConn::connect(&file_path).unwrap();
744/// let (conn, _addr) = listener.accept_unix_addr().unwrap();
745/// conn.send(b"Welcome").unwrap();
746/// ```
747///
748/// ### Xio
749///
750/// ```ignore
751/// let listener = uds_fork::UnixSeqpacketListener::bind(file_path).unwrap();
752///
753/// let mut reg = XioPollRegistry::<ESS>::new().unwrap();
754/// let mut event_buf = XioPollRegistry::<ESS>::allocate_events(128.try_into().unwrap());
755///
756/// // either
757/// let a_wrapped =
758/// reg.get_registry()
759/// .en_register_wrap(listener, XioEventUid::manual(1), XioChannel::INPUT)
760/// .unwrap();
761///
762/// // or
763/// reg.get_registry()
764/// .en_register&mut listener, XioEventUid::manual(1), XioChannel::INPUT)
765/// .unwrap();
766///
767/// // so depending on the method, use either:
768/// a_wrapped.inner();
769///
770/// // or continue using a directly
771/// ```
772///
773/// ### Mio:
774///
775/// ```ignore
776/// let listener = uds_fork::UnixSeqpacketListener::bind(file_path).unwrap();
777///
778/// let mut poll = Poll::new().expect("create mio poll");
779/// let mut events = Events::with_capacity(10);
780///
781/// poll.registry()
782/// .register(&mut listener, Token(1), Interest::READABLE)
783/// .unwrap();
784/// // ...
785/// ```
786#[derive(Debug)]
787#[repr(transparent)]
788pub struct UnixSeqpacketListener
789{
790 fd: OwnedFd
791}
792
793
794impl From<OwnedFd> for UnixSeqpacketListener
795{
796 fn from(ofd: OwnedFd) -> Self
797 {
798 let sa_fam = get_socket_family(&ofd).unwrap();
799 let sa_type = get_socket_type(&ofd).unwrap() & 0x00000FFF;
800
801 if sa_fam as i32 != libc::AF_UNIX || sa_type != libc::SOCK_SEQPACKET
802 {
803 panic!("assertion trap: provided FD is not AF_UNIX & SOCK_SEQPACKET, {} {}",
804 sa_fam, sa_type);
805 }
806
807 return UnixSeqpacketListener{ fd: ofd };
808 }
809}
810
811impl From<UnixSeqpacketListener> for OwnedFd
812{
813 fn from(value: UnixSeqpacketListener) -> Self
814 {
815 return value.fd;
816 }
817}
818
819impl FromRawFd for UnixSeqpacketListener
820{
821 unsafe
822 fn from_raw_fd(fd: RawFd) -> Self
823 {
824 UnixSeqpacketListener::from( unsafe { OwnedFd::from_raw_fd(fd) } )
825 }
826}
827
828impl AsRawFd for UnixSeqpacketListener
829{
830 fn as_raw_fd(&self) -> RawFd
831 {
832 self.fd.as_raw_fd()
833 }
834}
835
836impl IntoRawFd for UnixSeqpacketListener
837{
838 fn into_raw_fd(self) -> RawFd
839 {
840 self.fd.into_raw_fd()
841 }
842}
843
844impl AsFd for UnixSeqpacketListener
845{
846 fn as_fd(&self) -> BorrowedFd<'_>
847 {
848 self.fd.as_fd()
849 }
850}
851
852#[cfg(feature = "mio")]
853pub mod mio_listener_enabled
854{
855 use std::{io, os::fd::AsRawFd};
856
857 use mio::{event::Source, unix::SourceFd};
858 use crate::UnixSeqpacketListener;
859
860 impl Source for UnixSeqpacketListener
861 {
862 fn register(
863 &mut self,
864 registry: &mio::Registry,
865 token: mio::Token,
866 interests: mio::Interest,
867 ) -> io::Result<()>
868 {
869 self.set_nonblocking(true)?;
870
871 SourceFd(&self.fd.as_raw_fd()).register(registry, token, interests)
872 }
873
874 fn reregister(
875 &mut self,
876 registry: &mio::Registry,
877 token: mio::Token,
878 interests: mio::Interest,
879 ) -> io::Result<()>
880 {
881 SourceFd(&self.fd.as_raw_fd()).reregister(registry, token, interests)
882 }
883
884 fn deregister(&mut self, registry: &mio::Registry) -> io::Result<()>
885 {
886 SourceFd(&self.fd.as_raw_fd()).deregister(registry)
887 }
888 }
889}
890
891#[cfg(feature = "xio-rs")]
892pub mod xio_listener_enabled
893{
894 use xio_rs::{EsInterfaceRegistry, XioChannel, XioEventPipe, XioEventUid, XioResult, event_registry::XioRegistry};
895
896 use crate::UnixSeqpacketListener;
897
898 impl<ESSR: EsInterfaceRegistry> XioEventPipe<ESSR, Self> for UnixSeqpacketListener
899 {
900 fn connect_event_pipe(&mut self, ess: &XioRegistry<ESSR>, ev_uid: XioEventUid, channel: XioChannel) -> XioResult<()>
901 {
902 self.set_nonblocking(true)?;
903
904 ess.get_ev_sys().en_register(&self.fd, ev_uid, channel)
905 }
906
907 fn modify_event_pipe(&mut self, ess: &XioRegistry<ESSR>, ev_uid: XioEventUid, channel: XioChannel) -> XioResult<()>
908 {
909 ess.get_ev_sys().re_register(&self.fd, ev_uid, channel)
910 }
911
912 fn disconnect_event_pipe(&mut self, ess: &XioRegistry<ESSR>) -> XioResult<()>
913 {
914 ess.get_ev_sys().de_register(&self.fd)
915 }
916 }
917}
918
919impl UnixSeqpacketListener
920{
921 /// Creates a socket that listens for seqpacket connections on the specified socket file.
922 pub
923 fn bind<P: AsRef<Path>>(path: P) -> Result<Self, io::Error>
924 {
925 let addr = UnixSocketAddr::from_path(path.as_ref())?;
926
927 return Self::bind_unix_addr(&addr);
928 }
929
930 /// Creates a socket that listens for seqpacket connections on the specified address.
931 pub
932 fn bind_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error>
933 {
934 let socket = Socket::<SocketSeqPkt>::new(false)?;
935
936 socket.set_unix_local_addr(addr)?;
937 socket.start_listening()?;
938
939 return Ok(UnixSeqpacketListener { fd: socket.into() });
940 }
941
942 /// Returns the address the socket is listening on.
943 pub
944 fn local_unix_addr(&self) -> Result<UnixSocketAddr, io::Error>
945 {
946 get_unix_local_addr(&self)
947 }
948
949 /// Accepts a new incoming connection to this listener.
950 ///
951 /// Rustdocs:
952 /// > This function will block the calling thread until a new Unix connection
953 /// > is established. When established, the corresponding [`UnixSeqpacketConn`] and
954 /// > the remote peer's address will be returned.
955 ///
956 /// [`UnixSeqpacketConn`]: uds_fork::UnixSeqpacketConn
957 ///
958 /// # Examples
959 ///
960 /// ```no_run
961 /// use uds_fork::UnixSeqpacketListener;
962 ///
963 /// fn main() -> std::io::Result<()>
964 /// {
965 /// let listener = UnixSeqpacketListener::bind("/path/to/the/socket")?;
966 ///
967 /// match listener.accept()
968 /// {
969 /// Ok((socket, addr)) =>
970 /// println!("Got a client: {addr:?}"),
971 /// Err(e) =>
972 /// println!("accept function failed: {e:?}"),
973 /// }
974 ///
975 /// return Ok(());
976 /// }
977 /// ```
978 #[inline]
979 pub
980 fn accept(&self)-> Result<(UnixSeqpacketConn, UnixSocketAddr), io::Error>
981 {
982 self.accept_unix_addr()
983 }
984
985 /// Accepts a new incoming connection to this listener.
986 ///
987 /// See [Self::accept].
988 pub
989 fn accept_unix_addr(&self)-> Result<(UnixSeqpacketConn, UnixSocketAddr), io::Error>
990 {
991 let (socket, addr) = Socket::<SocketSeqPkt>::accept_from(&self, false)?;
992 let conn = UnixSeqpacketConn { fd: socket.into() };
993
994 return Ok((conn, addr));
995 }
996
997 /// Returns the value of the `SO_ERROR` option.
998 ///
999 /// This might never produce any errors for listeners. It is therefore
1000 /// unlikely to be useful, but is provided for parity with
1001 /// `std::unix::net::UnixListener`.
1002 pub
1003 fn take_error(&self) -> Result<Option<io::Error>, io::Error>
1004 {
1005 take_error(&self)
1006 }
1007
1008 /// Creates a new file descriptor listening for the same connections.
1009 pub
1010 fn try_clone(&self) -> Result<Self, io::Error>
1011 {
1012 let cloned = Socket::<SocketSeqPkt>::try_clone_from(&self)?;
1013
1014 return Ok(UnixSeqpacketListener { fd: cloned.into() });
1015 }
1016
1017 /// Sets a maximum duration to wait in a single `accept()` on this socket.
1018 ///
1019 /// `None` disables a previously set timeout.
1020 /// An error is returned if the duration is zero.
1021 ///
1022 /// # Operating System Support
1023 ///
1024 /// Only Linux appers to apply timeouts to `accept()`.
1025 /// On macOS, FreeBSD and NetBSD, timeouts are silently ignored.
1026 /// On Illumos setting timeouts for all unix domain sockets silently fails.
1027 ///
1028 /// On OSes where timeouts are known to not work, this function will
1029 /// return an error even if setting the timeout didn't fail.
1030 ///
1031 /// # Examples
1032 ///
1033 #[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
1034 #[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
1035 /// # use uds_fork::{UnixSeqpacketListener, UnixSocketAddr};
1036 /// # use std::io::ErrorKind;
1037 /// # use std::time::Duration;
1038 /// #
1039 /// # let addr = UnixSocketAddr::new("@set_timeout").unwrap();
1040 /// let listener = UnixSeqpacketListener::bind_unix_addr(&addr).unwrap();
1041 /// listener.set_timeout(Some(Duration::new(0, 200_000_000))).unwrap();
1042 /// let err = listener.accept_unix_addr().unwrap_err();
1043 /// assert_eq!(err.kind(), ErrorKind::WouldBlock);
1044 /// ```
1045 pub
1046 fn set_timeout(&self, timeout: Option<Duration>) -> Result<(), io::Error>
1047 {
1048 let res = set_timeout(&self, TimeoutDirection::Read, timeout);
1049
1050 #[cfg(any(
1051 target_vendor="apple", target_os="freebsd",
1052 target_os="netbsd",
1053 target_os="illumos", target_os="solaris",
1054 ))]
1055 {
1056 if res.is_ok() == true && timeout.is_some() == true
1057 {
1058 return Err(
1059 io::Error::new(
1060 ErrorKind::InvalidInput,
1061 "listener timeouts are not supported on this OS"
1062 )
1063 );
1064 }
1065 }
1066
1067 return res;
1068 }
1069
1070 /// Returns the timeout for `accept()` on this socket.
1071 ///
1072 /// `None` is returned if there is no timeout.
1073 ///
1074 /// Even if a timeout has is set, it is ignored by `accept()` on
1075 /// most operating systems except Linux.
1076 ///
1077 /// # Examples
1078 ///
1079 #[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
1080 #[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
1081 /// # use uds_fork::{UnixSeqpacketListener, UnixSocketAddr};
1082 /// # use std::time::Duration;
1083 /// #
1084 /// # let addr = UnixSocketAddr::new("@timeout").unwrap();
1085 /// let listener = UnixSeqpacketListener::bind_unix_addr(&addr).unwrap();
1086 /// assert_eq!(listener.timeout().unwrap(), None);
1087 /// let timeout = Some(Duration::new(2, 0));
1088 /// listener.set_timeout(timeout).unwrap();
1089 /// assert_eq!(listener.timeout().unwrap(), timeout);
1090 /// ```
1091 pub
1092 fn timeout(&self) -> Result<Option<Duration>, io::Error>
1093 {
1094 get_timeout(&self, TimeoutDirection::Read)
1095 }
1096
1097 /// Enables or disables nonblocking-ness of [`accept_unix_addr()`](#method.accept_unix addr).
1098 ///
1099 /// The returned connnections will still be in blocking mode regardsless.
1100 ///
1101 /// Consider using the nonblocking variant of this type instead;
1102 /// this method mostly exists for feature parity with std's `UnixListener`.
1103 ///
1104 /// # Examples
1105 ///
1106 #[cfg_attr(not(target_vendor="apple"), doc="```")]
1107 #[cfg_attr(target_vendor="apple", doc="```no_run")]
1108 /// # use std::io::ErrorKind;
1109 /// # use uds_fork::{UnixSocketAddr, UnixSeqpacketListener};
1110 /// use tempfile::TempDir;
1111 ///
1112 /// let dir = tempfile::tempdir().unwrap();
1113 /// let mut file_path = dir.path().join("nonblocking_seqpacket_listener1.socket");
1114 ///
1115 /// let addr = UnixSocketAddr::from_path(&file_path).unwrap();
1116 /// let listener = UnixSeqpacketListener::bind_unix_addr(&addr).expect("create listener");
1117 /// listener.set_nonblocking(true).expect("enable noblocking mode");
1118 /// assert_eq!(listener.accept_unix_addr().unwrap_err().kind(), ErrorKind::WouldBlock);
1119 /// ```
1120 pub
1121 fn set_nonblocking(&self, nonblocking: bool) -> Result<(), io::Error>
1122 {
1123 set_nonblocking(&self, nonblocking)
1124 }
1125
1126 /// Returns an iterator over incoming connections.
1127 ///
1128 /// Rustdoc:
1129 /// > The iterator will never return [`None`] and will also not yield the
1130 /// > peer's [`UnixSocketAddr`] structure.
1131 ///
1132 /// ```no_run
1133 /// use std::thread;
1134 /// use uds_fork::{UnixSeqpacketConn, UnixSeqpacketListener};
1135 ///
1136 /// fn handle_client(stream: UnixSeqpacketConn)
1137 /// {
1138 /// // ...
1139 /// }
1140 ///
1141 /// fn main() -> std::io::Result<()>
1142 /// {
1143 /// let listener = UnixSeqpacketListener::bind("/path/to/the/socket")?;
1144 ///
1145 /// for stream in listener.incoming()
1146 /// {
1147 /// match stream
1148 /// {
1149 /// Ok(stream) =>
1150 /// {
1151 /// thread::spawn(|| handle_client(stream));
1152 /// },
1153 /// Err(err) =>
1154 /// {
1155 /// break;
1156 /// }
1157 /// }
1158 /// }
1159 ///
1160 /// return Ok(());
1161 /// }
1162 /// ```
1163 pub
1164 fn incoming(&self) -> Incoming<'_>
1165 {
1166 Incoming { listener: self }
1167 }
1168}
1169
1170/// A rust std API.
1171///
1172/// From Rustdocs:
1173/// > An iterator over incoming connections to a [`UnixListener`].
1174/// >
1175/// > It will never return [`None`].
1176///
1177/// # Examples
1178///
1179/// ```no_run
1180/// use std::thread;
1181/// use uds_fork::{UnixSeqpacketConn, UnixSeqpacketListener};
1182///
1183/// fn handle_client(stream: UnixSeqpacketConn) {
1184/// // ...
1185/// }
1186///
1187/// fn main() -> std::io::Result<()>
1188/// {
1189/// let listener = UnixSeqpacketListener::bind("/path/to/the/socket")?;
1190///
1191/// for stream in listener.incoming()
1192/// {
1193/// match stream
1194/// {
1195/// Ok(stream) =>
1196/// {
1197/// thread::spawn(|| handle_client(stream));
1198/// }
1199/// Err(err) =>
1200/// {
1201/// break;
1202/// }
1203/// }
1204/// }
1205/// return Ok(());
1206/// }
1207/// ```
1208#[derive(Debug)]
1209pub struct Incoming<'a>
1210{
1211 listener: &'a UnixSeqpacketListener,
1212}
1213
1214impl<'a> Iterator for Incoming<'a>
1215{
1216 type Item = io::Result<UnixSeqpacketConn>;
1217
1218 fn next(&mut self) -> Option<io::Result<UnixSeqpacketConn>>
1219 {
1220 Some(self.listener.accept().map(|s| s.0))
1221 }
1222
1223 fn size_hint(&self) -> (usize, Option<usize>)
1224 {
1225 (usize::MAX, None)
1226 }
1227}
1228
1229impl<'a> IntoIterator for &'a UnixSeqpacketListener
1230{
1231 type Item = io::Result<UnixSeqpacketConn>;
1232 type IntoIter = Incoming<'a>;
1233
1234 fn into_iter(self) -> Incoming<'a>
1235 {
1236 self.incoming()
1237 }
1238}
1239
1240
1241
1242/// A non-blocking unix domain sequential-packet connection.
1243///
1244/// Differs from [`uds_fork::UnixSeqpacketConn`](../struct.UnixSeqpacketConn.html)
1245/// in that all operations that send or receive data will return an `Error` of
1246/// kind `ErrorKind::WouldBlock` instead of blocking.
1247/// This is done by creating the socket as non-blocking, and not by passing
1248/// `MSG_DONTWAIT`. If creating this type from a raw file descriptor, ensure
1249/// the fd is set to nonblocking before using it through this type.
1250///
1251/// # Registering with Xio (xio-rs) a feature = "xio-rs"
1252///
1253/// A `XioEventPipe` is implemented on this function. See [UnixSeqpacketConn]
1254/// for an examples.
1255///
1256/// See examples below.
1257///
1258/// # Registering with Mio (mio) a feature = "mio"
1259///
1260/// A `Source` is implemented on the instance. See [UnixSeqpacketConn]
1261/// for an examples.
1262///
1263/// # Examples
1264///
1265/// Sending or receiving when it would block a normal socket:
1266///
1267#[cfg_attr(not(target_vendor="apple"), doc="```")]
1268#[cfg_attr(target_vendor="apple", doc="```no_run")]
1269/// use uds_fork::nonblocking::UnixSeqpacketConn;
1270/// use std::io::ErrorKind;
1271///
1272/// let (a, b) = UnixSeqpacketConn::pair().expect("create nonblocking seqpacket pair");
1273///
1274/// // trying to receive when there are no packets waiting
1275/// assert_eq!(a.recv(&mut[0]).unwrap_err().kind(), ErrorKind::WouldBlock);
1276///
1277/// // trying to send when the OS buffer for the connection is full
1278/// loop {
1279/// if let Err(error) = a.send(&[0u8; 1000]) {
1280/// assert_eq!(error.kind(), ErrorKind::WouldBlock);
1281/// break;
1282/// }
1283/// }
1284/// ```
1285//#[deprecated = "Use UnixSeqpacketListener set_nonblocking(true)!"]
1286#[derive(Debug)]
1287#[repr(transparent)]
1288pub struct NonblockingUnixSeqpacketConn
1289{
1290 usc: UnixSeqpacketConn,
1291}
1292
1293impl From<OwnedFd> for NonblockingUnixSeqpacketConn
1294{
1295 fn from(value: OwnedFd) -> Self
1296 {
1297 let usc = UnixSeqpacketConn::from(value);
1298 usc.set_nonblocking(true).unwrap();
1299
1300 return Self{ usc: usc };
1301 }
1302}
1303
1304impl From<NonblockingUnixSeqpacketConn> for OwnedFd
1305{
1306 fn from(value: NonblockingUnixSeqpacketConn) -> Self
1307 {
1308 return value.usc.fd;
1309 }
1310}
1311
1312impl FromRawFd for NonblockingUnixSeqpacketConn
1313{
1314 unsafe
1315 fn from_raw_fd(fd: RawFd) -> Self
1316 {
1317 let usc = unsafe{ UnixSeqpacketConn::from_raw_fd(fd) };
1318 usc.set_nonblocking(true).unwrap();
1319
1320 return Self{ usc: usc };
1321 }
1322}
1323
1324impl AsRawFd for NonblockingUnixSeqpacketConn
1325{
1326 fn as_raw_fd(&self) -> RawFd
1327 {
1328 self.usc.as_raw_fd()
1329 }
1330}
1331impl IntoRawFd for NonblockingUnixSeqpacketConn
1332{
1333 fn into_raw_fd(self) -> RawFd
1334 {
1335 self.usc.into_raw_fd()
1336 }
1337}
1338
1339impl AsFd for NonblockingUnixSeqpacketConn
1340{
1341 fn as_fd(&self) -> BorrowedFd<'_>
1342 {
1343 self.usc.as_fd()
1344 }
1345}
1346
1347impl Deref for NonblockingUnixSeqpacketConn
1348{
1349 type Target = UnixSeqpacketConn;
1350
1351 fn deref(&self) -> &Self::Target
1352 {
1353 &self.usc
1354 }
1355}
1356
1357impl DerefMut for NonblockingUnixSeqpacketConn
1358{
1359 fn deref_mut(&mut self) -> &mut Self::Target
1360 {
1361 &mut self.usc
1362 }
1363}
1364
1365
1366#[cfg(feature = "mio")]
1367pub mod mio_non_blk_conn_enabled
1368{
1369 use std::io;
1370
1371 use mio::event::Source;
1372 use super::NonblockingUnixSeqpacketConn;
1373
1374 impl Source for NonblockingUnixSeqpacketConn
1375 {
1376 fn register(
1377 &mut self,
1378 registry: &mio::Registry,
1379 token: mio::Token,
1380 interests: mio::Interest,
1381 ) -> io::Result<()>
1382 {
1383 self.usc.register(registry, token, interests)
1384 }
1385
1386 fn reregister(
1387 &mut self,
1388 registry: &mio::Registry,
1389 token: mio::Token,
1390 interests: mio::Interest,
1391 ) -> io::Result<()>
1392 {
1393 self.usc.reregister(registry, token, interests)
1394 }
1395
1396 fn deregister(&mut self, registry: &mio::Registry) -> io::Result<()>
1397 {
1398 self.usc.deregister(registry)
1399 }
1400 }
1401}
1402
1403#[cfg(feature = "xio-rs")]
1404pub mod xio_non_blk_conn_enabled
1405{
1406 use xio_rs::{EsInterfaceRegistry, XioChannel, XioEventPipe, XioEventUid, XioResult, event_registry::XioRegistry};
1407
1408 use super::NonblockingUnixSeqpacketConn;
1409
1410 impl<ESSR: EsInterfaceRegistry> XioEventPipe<ESSR, Self> for NonblockingUnixSeqpacketConn
1411 {
1412 fn connect_event_pipe(&mut self, ess: &XioRegistry<ESSR>, ev_uid: XioEventUid, channel: XioChannel) -> XioResult<()>
1413 {
1414 self.usc.connect_event_pipe(ess, ev_uid, channel)
1415 }
1416
1417 fn modify_event_pipe(&mut self, ess: &XioRegistry<ESSR>, ev_uid: XioEventUid, channel: XioChannel) -> XioResult<()>
1418 {
1419 self.usc.modify_event_pipe(ess, ev_uid, channel)
1420 }
1421
1422 fn disconnect_event_pipe(&mut self, ess: &XioRegistry<ESSR>) -> XioResult<()>
1423 {
1424 self.usc.disconnect_event_pipe(ess)
1425 }
1426 }
1427}
1428
1429// can't Deref<Target=UnixSeqpacketConn> because that would include try_clone()
1430// and later set_(read|write)_timeout()
1431impl NonblockingUnixSeqpacketConn
1432{
1433 /// Connects to an unix seqpacket server listening at `path`.
1434 ///
1435 /// This is a wrapper around [`connect_unix_addr()`](#method.connect_unix_addr)
1436 /// for convenience and compatibility with std.
1437 pub
1438 fn connect<P: AsRef<Path>>(path: P) -> Result<Self, io::Error>
1439 {
1440 let addr = UnixSocketAddr::from_path(&path)?;
1441
1442 return Self::connect_unix_addr(&addr);
1443 }
1444
1445 /// Connects to an unix seqpacket server listening at `addr`.
1446 pub
1447 fn connect_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error>
1448 {
1449 let socket = Socket::<SocketSeqPkt>::new(true)?;
1450 socket.set_unix_peer_addr(addr)?;
1451
1452 return Ok(
1453 NonblockingUnixSeqpacketConn
1454 {
1455 usc: UnixSeqpacketConn { fd: socket.into() }
1456 }
1457 );
1458 }
1459
1460 /// Binds to an address before connecting to a listening seqpacet socket.
1461 pub
1462 fn connect_from_to_unix_addr(from: &UnixSocketAddr, to: &UnixSocketAddr) -> Result<Self, io::Error>
1463 {
1464 let socket = Socket::<SocketSeqPkt>::new(true)?;
1465 socket.set_unix_local_addr(from)?;
1466 socket.set_unix_peer_addr(to)?;
1467
1468 return Ok(
1469 NonblockingUnixSeqpacketConn
1470 {
1471 usc: UnixSeqpacketConn { fd: socket.into() }
1472 }
1473 );
1474 }
1475
1476 /// Creates a pair of unix-domain seqpacket conneections connected to each other.
1477 ///
1478 /// # Examples
1479 ///
1480 #[cfg_attr(not(target_vendor="apple"), doc="```")]
1481 #[cfg_attr(target_vendor="apple", doc="```no_run")]
1482 /// let (a, b) = uds_fork::UnixSeqpacketConn::pair().unwrap();
1483 /// assert!(a.local_unix_addr().unwrap().is_unnamed());
1484 /// assert!(b.local_unix_addr().unwrap().is_unnamed());
1485 ///
1486 /// a.send(b"hello").unwrap();
1487 /// b.recv(&mut[0; 20]).unwrap();
1488 /// ```
1489 pub
1490 fn pair() -> Result<(Self, Self), io::Error>
1491 {
1492 let pair = Socket::<SocketSeqPkt>::pair(true)?;
1493
1494 return Ok(
1495 (
1496 Self{ usc: UnixSeqpacketConn { fd: pair.0.into() } },
1497 Self{ usc: UnixSeqpacketConn { fd: pair.1.into() } },
1498 )
1499 );
1500 }
1501
1502 pub
1503 fn try_clone(&self) -> Result<Self, io::Error>
1504 {
1505 let cloned = Socket::<SocketSeqPkt>::try_clone_from(self)?;
1506
1507 return Ok(
1508 NonblockingUnixSeqpacketConn
1509 {
1510 usc: UnixSeqpacketConn { fd: cloned.into() }
1511 }
1512 );
1513 }
1514}
1515
1516
1517/// A non-blocking unix domain listener for sequential-packet connections.
1518///
1519/// Differs from [`UnixSeqpacketListener`](../struct.UnixSeqpacketListener.html)
1520/// in that [`accept()`](struct.NonblockingUnixSeqpacketListener.html#method.accept)
1521/// returns non-blocking [connection sockets](struct.NonblockingUnixSeqpacketConn.html)
1522/// and doesn't block if no client `connect()`ions are pending.
1523///
1524/// # Registering with Xio (xio-rs) a feature = "xio-rs"
1525///
1526/// A `XioEventPipe` is implemented on this function. See [UnixSeqpacketListener]
1527/// for an examples.
1528///
1529/// See examples below.
1530///
1531/// # Registering with Mio (mio) a feature = "mio"
1532///
1533/// A `Source` is implemented on the instance. See [UnixSeqpacketListener]
1534/// for an examples.
1535///
1536/// # Examples
1537///
1538#[cfg_attr(not(target_vendor="apple"), doc="```")]
1539#[cfg_attr(target_vendor="apple", doc="```no_run")]
1540/// use uds_fork::nonblocking::{UnixSeqpacketListener, UnixSeqpacketConn};
1541/// use tempfile::TempDir;
1542/// use std::io::ErrorKind;
1543///
1544/// let dir = tempfile::tempdir().unwrap();
1545/// let mut file_path = dir.path().join("nonblocking_seqpacket_listener2.socket");
1546///
1547/// let listener = UnixSeqpacketListener::bind(&file_path)
1548/// .expect("Cannot create nonblocking seqpacket listener");
1549///
1550/// // doesn't block if no connections are waiting:
1551/// assert_eq!(listener.accept_unix_addr().unwrap_err().kind(), ErrorKind::WouldBlock);
1552///
1553/// // returned connections are nonblocking:
1554/// let _client = UnixSeqpacketConn::connect(&file_path).unwrap();
1555/// let (conn, _addr) = listener.accept_unix_addr().unwrap();
1556/// assert_eq!(conn.recv(&mut[0u8; 20]).unwrap_err().kind(), ErrorKind::WouldBlock);
1557/// ```
1558#[derive(Debug)]
1559#[repr(transparent)]
1560pub struct NonblockingUnixSeqpacketListener
1561{
1562 usl: UnixSeqpacketListener,
1563}
1564
1565impl From<OwnedFd> for NonblockingUnixSeqpacketListener
1566{
1567 fn from(ofd: OwnedFd) -> Self
1568 {
1569 let usl = UnixSeqpacketListener::from(ofd);
1570 usl.set_nonblocking(true).unwrap();
1571
1572 return Self{ usl };
1573 }
1574}
1575
1576impl FromRawFd for NonblockingUnixSeqpacketListener
1577{
1578 unsafe
1579 fn from_raw_fd(fd: RawFd) -> Self
1580 {
1581 let usl = unsafe{ UnixSeqpacketListener::from_raw_fd(fd) };
1582 usl.set_nonblocking(true).unwrap();
1583
1584 return Self{ usl };
1585 }
1586}
1587
1588
1589impl From<NonblockingUnixSeqpacketListener> for OwnedFd
1590{
1591 fn from(value: NonblockingUnixSeqpacketListener) -> Self
1592 {
1593 return value.usl.fd;
1594 }
1595}
1596
1597
1598impl AsRawFd for NonblockingUnixSeqpacketListener
1599{
1600 fn as_raw_fd(&self) -> RawFd
1601 {
1602 self.usl.as_raw_fd()
1603 }
1604}
1605
1606impl IntoRawFd for NonblockingUnixSeqpacketListener
1607{
1608 fn into_raw_fd(self) -> RawFd
1609 {
1610 self.usl.into_raw_fd()
1611 }
1612}
1613
1614impl AsFd for NonblockingUnixSeqpacketListener
1615{
1616 fn as_fd(&self) -> BorrowedFd<'_>
1617 {
1618 self.usl.as_fd()
1619 }
1620}
1621
1622
1623impl Deref for NonblockingUnixSeqpacketListener
1624{
1625 type Target = UnixSeqpacketListener;
1626
1627 fn deref(&self) -> &Self::Target
1628 {
1629 &self.usl
1630 }
1631}
1632
1633impl DerefMut for NonblockingUnixSeqpacketListener
1634{
1635 fn deref_mut(&mut self) -> &mut Self::Target
1636 {
1637 &mut self.usl
1638 }
1639}
1640
1641impl NonblockingUnixSeqpacketListener
1642{
1643 /// Creates a socket that listens for seqpacket connections on the specified socket file.
1644 pub
1645 fn bind<P: AsRef<Path>>(path: P) -> Result<Self, io::Error>
1646 {
1647 let addr = UnixSocketAddr::from_path(&path)?;
1648
1649 return Self::bind_unix_addr(&addr);
1650 }
1651
1652 /// Creates a socket that listens for seqpacket connections on the specified address.
1653 pub
1654 fn bind_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error>
1655 {
1656 let socket = Socket::<SocketSeqPkt>::new(true)?;
1657 socket.set_unix_local_addr(addr)?;
1658 socket.start_listening()?;
1659
1660 return Ok( Self{ usl: UnixSeqpacketListener{ fd: socket.into() }} );
1661 }
1662
1663 /// Accepts a non-blocking connection, non-blockingly.
1664 ///
1665 /// # Examples
1666 ///
1667 /// Doesn't block if no connections are waiting:
1668 ///
1669 #[cfg_attr(not(target_vendor="apple"), doc="```")]
1670 #[cfg_attr(target_vendor="apple", doc="```no_run")]
1671 /// # use uds_fork::nonblocking::UnixSeqpacketListener;
1672 /// # use std::io::ErrorKind;
1673 /// # use tempfile::TempDir;
1674 ///
1675 /// let dir = tempfile::tempdir().unwrap();
1676 /// let mut file_path = dir.path().join("nonblocking_seqpacket_listener3.socket");
1677 ///
1678 /// let listener = UnixSeqpacketListener::bind(&file_path)
1679 /// .expect("Cannot create nonblocking seqpacket listener");
1680 /// assert_eq!(listener.accept_unix_addr().unwrap_err().kind(), ErrorKind::WouldBlock);
1681 /// ```
1682 pub
1683 fn accept_unix_addr(&self) -> Result<(NonblockingUnixSeqpacketConn, UnixSocketAddr), io::Error>
1684 {
1685 let (socket, addr) = Socket::<SocketSeqPkt>::accept_from(&self, true)?;
1686 let conn = NonblockingUnixSeqpacketConn { usc: UnixSeqpacketConn{ fd: socket.into() }};
1687
1688 return Ok((conn, addr));
1689 }
1690}
1691
1692#[cfg(feature = "mio")]
1693pub mod mio_non_blk_listener_enabled
1694{
1695 use std::{io, os::fd::AsRawFd};
1696
1697 use mio::{event::Source, unix::SourceFd};
1698 use super::NonblockingUnixSeqpacketListener;
1699
1700 impl Source for NonblockingUnixSeqpacketListener
1701 {
1702 fn register(
1703 &mut self,
1704 registry: &mio::Registry,
1705 token: mio::Token,
1706 interests: mio::Interest,
1707 ) -> io::Result<()>
1708 {
1709 self.usl.register(registry, token, interests)
1710 }
1711
1712 fn reregister(
1713 &mut self,
1714 registry: &mio::Registry,
1715 token: mio::Token,
1716 interests: mio::Interest,
1717 ) -> io::Result<()>
1718 {
1719 self.usl.reregister(registry, token, interests)
1720 }
1721
1722 fn deregister(&mut self, registry: &mio::Registry) -> io::Result<()>
1723 {
1724 self.usl.deregister(registry)
1725 }
1726 }
1727}
1728
1729#[cfg(feature = "xio-rs")]
1730pub mod xio_non_blk_listener_enabled
1731{
1732 use xio_rs::{EsInterfaceRegistry, XioChannel, XioEventPipe, XioEventUid, XioResult, event_registry::XioRegistry};
1733
1734 use super::NonblockingUnixSeqpacketListener;
1735
1736 impl<ESSR: EsInterfaceRegistry> XioEventPipe<ESSR, Self> for NonblockingUnixSeqpacketListener
1737 {
1738 fn connect_event_pipe(&mut self, ess: &XioRegistry<ESSR>, ev_uid: XioEventUid, channel: XioChannel) -> XioResult<()>
1739 {
1740
1741 self.usl.connect_event_pipe(ess, ev_uid, channel)
1742 }
1743
1744 fn modify_event_pipe(&mut self, ess: &XioRegistry<ESSR>, ev_uid: XioEventUid, channel: XioChannel) -> XioResult<()>
1745 {
1746 self.usl.modify_event_pipe(ess, ev_uid, channel)
1747 }
1748
1749 fn disconnect_event_pipe(&mut self, ess: &XioRegistry<ESSR>) -> XioResult<()>
1750 {
1751 self.usl.disconnect_event_pipe(ess)
1752 }
1753 }
1754}