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///
81/// let file_path = "/tmp/seqpacket.socket";
82/// let _ = std::fs::remove_file(file_path); // pre-emptively delete just in case
83/// let listener = UnixSeqpacketListener::bind(file_path)
84/// .expect("create seqpacket listener");
85/// let conn = UnixSeqpacketConn::connect(file_path)
86/// .expect("connect to seqpacket listener");
87///
88/// let message = "Hello, listener";
89/// let sent = conn.send(message.as_bytes()).unwrap();
90/// assert_eq!(sent, message.len());
91///
92/// std::fs::remove_file(file_path).unwrap(); // clean up after ourselves
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/// let file_path = "/tmp/seqpacket_listener.socket";
737/// let _ = std::fs::remove_file(file_path);
738/// let listener = uds_fork::UnixSeqpacketListener::bind(file_path)
739/// .expect("Create seqpacket listener");
740/// let _client = uds_fork::UnixSeqpacketConn::connect(file_path).unwrap();
741/// let (conn, _addr) = listener.accept_unix_addr().unwrap();
742/// conn.send(b"Welcome").unwrap();
743/// # std::fs::remove_file(file_path).unwrap();
744/// ```
745///
746/// ### Xio
747///
748/// ```ignore
749/// let listener = uds_fork::UnixSeqpacketListener::bind(file_path).unwrap();
750///
751/// let mut reg = XioPollRegistry::<ESS>::new().unwrap();
752/// let mut event_buf = XioPollRegistry::<ESS>::allocate_events(128.try_into().unwrap());
753///
754/// // either
755/// let a_wrapped =
756/// reg.get_registry()
757/// .en_register_wrap(listener, XioEventUid::manual(1), XioChannel::INPUT)
758/// .unwrap();
759///
760/// // or
761/// reg.get_registry()
762/// .en_register&mut listener, XioEventUid::manual(1), XioChannel::INPUT)
763/// .unwrap();
764///
765/// // so depending on the method, use either:
766/// a_wrapped.inner();
767///
768/// // or continue using a directly
769/// ```
770///
771/// ### Mio:
772///
773/// ```ignore
774/// let listener = uds_fork::UnixSeqpacketListener::bind(file_path).unwrap();
775///
776/// let mut poll = Poll::new().expect("create mio poll");
777/// let mut events = Events::with_capacity(10);
778///
779/// poll.registry()
780/// .register(&mut listener, Token(1), Interest::READABLE)
781/// .unwrap();
782/// // ...
783/// ```
784#[derive(Debug)]
785#[repr(transparent)]
786pub struct UnixSeqpacketListener
787{
788 fd: OwnedFd
789}
790
791
792impl From<OwnedFd> for UnixSeqpacketListener
793{
794 fn from(ofd: OwnedFd) -> Self
795 {
796 let sa_fam = get_socket_family(&ofd).unwrap();
797 let sa_type = get_socket_type(&ofd).unwrap() & 0x00000FFF;
798
799 if sa_fam as i32 != libc::AF_UNIX || sa_type != libc::SOCK_SEQPACKET
800 {
801 panic!("assertion trap: provided FD is not AF_UNIX & SOCK_SEQPACKET, {} {}",
802 sa_fam, sa_type);
803 }
804
805 return UnixSeqpacketListener{ fd: ofd };
806 }
807}
808
809impl From<UnixSeqpacketListener> for OwnedFd
810{
811 fn from(value: UnixSeqpacketListener) -> Self
812 {
813 return value.fd;
814 }
815}
816
817impl FromRawFd for UnixSeqpacketListener
818{
819 unsafe
820 fn from_raw_fd(fd: RawFd) -> Self
821 {
822 UnixSeqpacketListener::from( unsafe { OwnedFd::from_raw_fd(fd) } )
823 }
824}
825
826impl AsRawFd for UnixSeqpacketListener
827{
828 fn as_raw_fd(&self) -> RawFd
829 {
830 self.fd.as_raw_fd()
831 }
832}
833
834impl IntoRawFd for UnixSeqpacketListener
835{
836 fn into_raw_fd(self) -> RawFd
837 {
838 self.fd.into_raw_fd()
839 }
840}
841
842impl AsFd for UnixSeqpacketListener
843{
844 fn as_fd(&self) -> BorrowedFd<'_>
845 {
846 self.fd.as_fd()
847 }
848}
849
850#[cfg(feature = "mio")]
851pub mod mio_listener_enabled
852{
853 use std::{io, os::fd::AsRawFd};
854
855 use mio::{event::Source, unix::SourceFd};
856 use crate::UnixSeqpacketListener;
857
858 impl Source for UnixSeqpacketListener
859 {
860 fn register(
861 &mut self,
862 registry: &mio::Registry,
863 token: mio::Token,
864 interests: mio::Interest,
865 ) -> io::Result<()>
866 {
867 self.set_nonblocking(true)?;
868
869 SourceFd(&self.fd.as_raw_fd()).register(registry, token, interests)
870 }
871
872 fn reregister(
873 &mut self,
874 registry: &mio::Registry,
875 token: mio::Token,
876 interests: mio::Interest,
877 ) -> io::Result<()>
878 {
879 SourceFd(&self.fd.as_raw_fd()).reregister(registry, token, interests)
880 }
881
882 fn deregister(&mut self, registry: &mio::Registry) -> io::Result<()>
883 {
884 SourceFd(&self.fd.as_raw_fd()).deregister(registry)
885 }
886 }
887}
888
889#[cfg(feature = "xio-rs")]
890pub mod xio_listener_enabled
891{
892 use xio_rs::{EsInterfaceRegistry, XioChannel, XioEventPipe, XioEventUid, XioResult, event_registry::XioRegistry};
893
894 use crate::UnixSeqpacketListener;
895
896 impl<ESSR: EsInterfaceRegistry> XioEventPipe<ESSR, Self> for UnixSeqpacketListener
897 {
898 fn connect_event_pipe(&mut self, ess: &XioRegistry<ESSR>, ev_uid: XioEventUid, channel: XioChannel) -> XioResult<()>
899 {
900 self.set_nonblocking(true)?;
901
902 ess.get_ev_sys().en_register(&self.fd, ev_uid, channel)
903 }
904
905 fn modify_event_pipe(&mut self, ess: &XioRegistry<ESSR>, ev_uid: XioEventUid, channel: XioChannel) -> XioResult<()>
906 {
907 ess.get_ev_sys().re_register(&self.fd, ev_uid, channel)
908 }
909
910 fn disconnect_event_pipe(&mut self, ess: &XioRegistry<ESSR>) -> XioResult<()>
911 {
912 ess.get_ev_sys().de_register(&self.fd)
913 }
914 }
915}
916
917impl UnixSeqpacketListener
918{
919 /// Creates a socket that listens for seqpacket connections on the specified socket file.
920 pub
921 fn bind<P: AsRef<Path>>(path: P) -> Result<Self, io::Error>
922 {
923 let addr = UnixSocketAddr::from_path(path.as_ref())?;
924
925 return Self::bind_unix_addr(&addr);
926 }
927
928 /// Creates a socket that listens for seqpacket connections on the specified address.
929 pub
930 fn bind_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error>
931 {
932 let socket = Socket::<SocketSeqPkt>::new(false)?;
933
934 socket.set_unix_local_addr(addr)?;
935 socket.start_listening()?;
936
937 return Ok(UnixSeqpacketListener { fd: socket.into() });
938 }
939
940 /// Returns the address the socket is listening on.
941 pub
942 fn local_unix_addr(&self) -> Result<UnixSocketAddr, io::Error>
943 {
944 get_unix_local_addr(&self)
945 }
946
947 /// Accepts a new incoming connection to this listener.
948 ///
949 /// Rustdocs:
950 /// > This function will block the calling thread until a new Unix connection
951 /// > is established. When established, the corresponding [`UnixSeqpacketConn`] and
952 /// > the remote peer's address will be returned.
953 ///
954 /// [`UnixSeqpacketConn`]: uds_fork::UnixSeqpacketConn
955 ///
956 /// # Examples
957 ///
958 /// ```no_run
959 /// use uds_fork::UnixSeqpacketListener;
960 ///
961 /// fn main() -> std::io::Result<()>
962 /// {
963 /// let listener = UnixSeqpacketListener::bind("/path/to/the/socket")?;
964 ///
965 /// match listener.accept()
966 /// {
967 /// Ok((socket, addr)) =>
968 /// println!("Got a client: {addr:?}"),
969 /// Err(e) =>
970 /// println!("accept function failed: {e:?}"),
971 /// }
972 ///
973 /// return Ok(());
974 /// }
975 /// ```
976 #[inline]
977 pub
978 fn accept(&self)-> Result<(UnixSeqpacketConn, UnixSocketAddr), io::Error>
979 {
980 self.accept_unix_addr()
981 }
982
983 /// Accepts a new incoming connection to this listener.
984 ///
985 /// See [Self::accept].
986 pub
987 fn accept_unix_addr(&self)-> Result<(UnixSeqpacketConn, UnixSocketAddr), io::Error>
988 {
989 let (socket, addr) = Socket::<SocketSeqPkt>::accept_from(&self, false)?;
990 let conn = UnixSeqpacketConn { fd: socket.into() };
991
992 return Ok((conn, addr));
993 }
994
995 /// Returns the value of the `SO_ERROR` option.
996 ///
997 /// This might never produce any errors for listeners. It is therefore
998 /// unlikely to be useful, but is provided for parity with
999 /// `std::unix::net::UnixListener`.
1000 pub
1001 fn take_error(&self) -> Result<Option<io::Error>, io::Error>
1002 {
1003 take_error(&self)
1004 }
1005
1006 /// Creates a new file descriptor listening for the same connections.
1007 pub
1008 fn try_clone(&self) -> Result<Self, io::Error>
1009 {
1010 let cloned = Socket::<SocketSeqPkt>::try_clone_from(&self)?;
1011
1012 return Ok(UnixSeqpacketListener { fd: cloned.into() });
1013 }
1014
1015 /// Sets a maximum duration to wait in a single `accept()` on this socket.
1016 ///
1017 /// `None` disables a previously set timeout.
1018 /// An error is returned if the duration is zero.
1019 ///
1020 /// # Operating System Support
1021 ///
1022 /// Only Linux appers to apply timeouts to `accept()`.
1023 /// On macOS, FreeBSD and NetBSD, timeouts are silently ignored.
1024 /// On Illumos setting timeouts for all unix domain sockets silently fails.
1025 ///
1026 /// On OSes where timeouts are known to not work, this function will
1027 /// return an error even if setting the timeout didn't fail.
1028 ///
1029 /// # Examples
1030 ///
1031 #[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
1032 #[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
1033 /// # use uds_fork::{UnixSeqpacketListener, UnixSocketAddr};
1034 /// # use std::io::ErrorKind;
1035 /// # use std::time::Duration;
1036 /// #
1037 /// # let addr = UnixSocketAddr::new("@set_timeout").unwrap();
1038 /// let listener = UnixSeqpacketListener::bind_unix_addr(&addr).unwrap();
1039 /// listener.set_timeout(Some(Duration::new(0, 200_000_000))).unwrap();
1040 /// let err = listener.accept_unix_addr().unwrap_err();
1041 /// assert_eq!(err.kind(), ErrorKind::WouldBlock);
1042 /// ```
1043 pub
1044 fn set_timeout(&self, timeout: Option<Duration>) -> Result<(), io::Error>
1045 {
1046 let res = set_timeout(&self, TimeoutDirection::Read, timeout);
1047
1048 #[cfg(any(
1049 target_vendor="apple", target_os="freebsd",
1050 target_os="netbsd",
1051 target_os="illumos", target_os="solaris",
1052 ))]
1053 {
1054 if res.is_ok() == true && timeout.is_some() == true
1055 {
1056 return Err(
1057 io::Error::new(
1058 ErrorKind::InvalidInput,
1059 "listener timeouts are not supported on this OS"
1060 )
1061 );
1062 }
1063 }
1064
1065 return res;
1066 }
1067
1068 /// Returns the timeout for `accept()` on this socket.
1069 ///
1070 /// `None` is returned if there is no timeout.
1071 ///
1072 /// Even if a timeout has is set, it is ignored by `accept()` on
1073 /// most operating systems except Linux.
1074 ///
1075 /// # Examples
1076 ///
1077 #[cfg_attr(any(target_os="linux", target_os="android"), doc="```")]
1078 #[cfg_attr(not(any(target_os="linux", target_os="android")), doc="```no_run")]
1079 /// # use uds_fork::{UnixSeqpacketListener, UnixSocketAddr};
1080 /// # use std::time::Duration;
1081 /// #
1082 /// # let addr = UnixSocketAddr::new("@timeout").unwrap();
1083 /// let listener = UnixSeqpacketListener::bind_unix_addr(&addr).unwrap();
1084 /// assert_eq!(listener.timeout().unwrap(), None);
1085 /// let timeout = Some(Duration::new(2, 0));
1086 /// listener.set_timeout(timeout).unwrap();
1087 /// assert_eq!(listener.timeout().unwrap(), timeout);
1088 /// ```
1089 pub
1090 fn timeout(&self) -> Result<Option<Duration>, io::Error>
1091 {
1092 get_timeout(&self, TimeoutDirection::Read)
1093 }
1094
1095 /// Enables or disables nonblocking-ness of [`accept_unix_addr()`](#method.accept_unix addr).
1096 ///
1097 /// The returned connnections will still be in blocking mode regardsless.
1098 ///
1099 /// Consider using the nonblocking variant of this type instead;
1100 /// this method mostly exists for feature parity with std's `UnixListener`.
1101 ///
1102 /// # Examples
1103 ///
1104 #[cfg_attr(not(target_vendor="apple"), doc="```")]
1105 #[cfg_attr(target_vendor="apple", doc="```no_run")]
1106 /// # use std::io::ErrorKind;
1107 /// # use uds_fork::{UnixSocketAddr, UnixSeqpacketListener};
1108 ///
1109 /// let file_path = "/tmp/nonblocking_seqpacket_listener1.socket";
1110 /// let addr = UnixSocketAddr::from_path(file_path).unwrap();
1111 /// let _ = std::fs::remove_file(file_path);
1112 /// let listener = UnixSeqpacketListener::bind_unix_addr(&addr).expect("create listener");
1113 /// listener.set_nonblocking(true).expect("enable noblocking mode");
1114 /// assert_eq!(listener.accept_unix_addr().unwrap_err().kind(), ErrorKind::WouldBlock);
1115 /// # std::fs::remove_file(file_path).expect("delete socket file");
1116 /// ```
1117 pub
1118 fn set_nonblocking(&self, nonblocking: bool) -> Result<(), io::Error>
1119 {
1120 set_nonblocking(&self, nonblocking)
1121 }
1122
1123 /// Returns an iterator over incoming connections.
1124 ///
1125 /// Rustdoc:
1126 /// > The iterator will never return [`None`] and will also not yield the
1127 /// > peer's [`UnixSocketAddr`] structure.
1128 ///
1129 /// ```no_run
1130 /// use std::thread;
1131 /// use uds_fork::{UnixSeqpacketConn, UnixSeqpacketListener};
1132 ///
1133 /// fn handle_client(stream: UnixSeqpacketConn)
1134 /// {
1135 /// // ...
1136 /// }
1137 ///
1138 /// fn main() -> std::io::Result<()>
1139 /// {
1140 /// let listener = UnixSeqpacketListener::bind("/path/to/the/socket")?;
1141 ///
1142 /// for stream in listener.incoming()
1143 /// {
1144 /// match stream
1145 /// {
1146 /// Ok(stream) =>
1147 /// {
1148 /// thread::spawn(|| handle_client(stream));
1149 /// },
1150 /// Err(err) =>
1151 /// {
1152 /// break;
1153 /// }
1154 /// }
1155 /// }
1156 ///
1157 /// return Ok(());
1158 /// }
1159 /// ```
1160 pub
1161 fn incoming(&self) -> Incoming<'_>
1162 {
1163 Incoming { listener: self }
1164 }
1165}
1166
1167/// A rust std API.
1168///
1169/// From Rustdocs:
1170/// > An iterator over incoming connections to a [`UnixListener`].
1171/// >
1172/// > It will never return [`None`].
1173///
1174/// # Examples
1175///
1176/// ```no_run
1177/// use std::thread;
1178/// use uds_fork::{UnixSeqpacketConn, UnixSeqpacketListener};
1179///
1180/// fn handle_client(stream: UnixSeqpacketConn) {
1181/// // ...
1182/// }
1183///
1184/// fn main() -> std::io::Result<()>
1185/// {
1186/// let listener = UnixSeqpacketListener::bind("/path/to/the/socket")?;
1187///
1188/// for stream in listener.incoming()
1189/// {
1190/// match stream
1191/// {
1192/// Ok(stream) =>
1193/// {
1194/// thread::spawn(|| handle_client(stream));
1195/// }
1196/// Err(err) =>
1197/// {
1198/// break;
1199/// }
1200/// }
1201/// }
1202/// return Ok(());
1203/// }
1204/// ```
1205#[derive(Debug)]
1206pub struct Incoming<'a>
1207{
1208 listener: &'a UnixSeqpacketListener,
1209}
1210
1211impl<'a> Iterator for Incoming<'a>
1212{
1213 type Item = io::Result<UnixSeqpacketConn>;
1214
1215 fn next(&mut self) -> Option<io::Result<UnixSeqpacketConn>>
1216 {
1217 Some(self.listener.accept().map(|s| s.0))
1218 }
1219
1220 fn size_hint(&self) -> (usize, Option<usize>)
1221 {
1222 (usize::MAX, None)
1223 }
1224}
1225
1226impl<'a> IntoIterator for &'a UnixSeqpacketListener
1227{
1228 type Item = io::Result<UnixSeqpacketConn>;
1229 type IntoIter = Incoming<'a>;
1230
1231 fn into_iter(self) -> Incoming<'a>
1232 {
1233 self.incoming()
1234 }
1235}
1236
1237
1238
1239/// A non-blocking unix domain sequential-packet connection.
1240///
1241/// Differs from [`uds_fork::UnixSeqpacketConn`](../struct.UnixSeqpacketConn.html)
1242/// in that all operations that send or receive data will return an `Error` of
1243/// kind `ErrorKind::WouldBlock` instead of blocking.
1244/// This is done by creating the socket as non-blocking, and not by passing
1245/// `MSG_DONTWAIT`. If creating this type from a raw file descriptor, ensure
1246/// the fd is set to nonblocking before using it through this type.
1247///
1248/// # Registering with Xio (xio-rs) a feature = "xio-rs"
1249///
1250/// A `XioEventPipe` is implemented on this function. See [UnixSeqpacketConn]
1251/// for an examples.
1252///
1253/// See examples below.
1254///
1255/// # Registering with Mio (mio) a feature = "mio"
1256///
1257/// A `Source` is implemented on the instance. See [UnixSeqpacketConn]
1258/// for an examples.
1259///
1260/// # Examples
1261///
1262/// Sending or receiving when it would block a normal socket:
1263///
1264#[cfg_attr(not(target_vendor="apple"), doc="```")]
1265#[cfg_attr(target_vendor="apple", doc="```no_run")]
1266/// use uds_fork::nonblocking::UnixSeqpacketConn;
1267/// use std::io::ErrorKind;
1268///
1269/// let (a, b) = UnixSeqpacketConn::pair().expect("create nonblocking seqpacket pair");
1270///
1271/// // trying to receive when there are no packets waiting
1272/// assert_eq!(a.recv(&mut[0]).unwrap_err().kind(), ErrorKind::WouldBlock);
1273///
1274/// // trying to send when the OS buffer for the connection is full
1275/// loop {
1276/// if let Err(error) = a.send(&[0u8; 1000]) {
1277/// assert_eq!(error.kind(), ErrorKind::WouldBlock);
1278/// break;
1279/// }
1280/// }
1281/// ```
1282//#[deprecated = "Use UnixSeqpacketListener set_nonblocking(true)!"]
1283#[derive(Debug)]
1284#[repr(transparent)]
1285pub struct NonblockingUnixSeqpacketConn
1286{
1287 usc: UnixSeqpacketConn,
1288}
1289
1290impl From<OwnedFd> for NonblockingUnixSeqpacketConn
1291{
1292 fn from(value: OwnedFd) -> Self
1293 {
1294 let usc = UnixSeqpacketConn::from(value);
1295 usc.set_nonblocking(true).unwrap();
1296
1297 return Self{ usc: usc };
1298 }
1299}
1300
1301impl From<NonblockingUnixSeqpacketConn> for OwnedFd
1302{
1303 fn from(value: NonblockingUnixSeqpacketConn) -> Self
1304 {
1305 return value.usc.fd;
1306 }
1307}
1308
1309impl FromRawFd for NonblockingUnixSeqpacketConn
1310{
1311 unsafe
1312 fn from_raw_fd(fd: RawFd) -> Self
1313 {
1314 let usc = unsafe{ UnixSeqpacketConn::from_raw_fd(fd) };
1315 usc.set_nonblocking(true).unwrap();
1316
1317 return Self{ usc: usc };
1318 }
1319}
1320
1321impl AsRawFd for NonblockingUnixSeqpacketConn
1322{
1323 fn as_raw_fd(&self) -> RawFd
1324 {
1325 self.usc.as_raw_fd()
1326 }
1327}
1328impl IntoRawFd for NonblockingUnixSeqpacketConn
1329{
1330 fn into_raw_fd(self) -> RawFd
1331 {
1332 self.usc.into_raw_fd()
1333 }
1334}
1335
1336impl AsFd for NonblockingUnixSeqpacketConn
1337{
1338 fn as_fd(&self) -> BorrowedFd<'_>
1339 {
1340 self.usc.as_fd()
1341 }
1342}
1343
1344impl Deref for NonblockingUnixSeqpacketConn
1345{
1346 type Target = UnixSeqpacketConn;
1347
1348 fn deref(&self) -> &Self::Target
1349 {
1350 &self.usc
1351 }
1352}
1353
1354impl DerefMut for NonblockingUnixSeqpacketConn
1355{
1356 fn deref_mut(&mut self) -> &mut Self::Target
1357 {
1358 &mut self.usc
1359 }
1360}
1361
1362
1363#[cfg(feature = "mio")]
1364pub mod mio_non_blk_conn_enabled
1365{
1366 use std::io;
1367
1368 use mio::event::Source;
1369 use super::NonblockingUnixSeqpacketConn;
1370
1371 impl Source for NonblockingUnixSeqpacketConn
1372 {
1373 fn register(
1374 &mut self,
1375 registry: &mio::Registry,
1376 token: mio::Token,
1377 interests: mio::Interest,
1378 ) -> io::Result<()>
1379 {
1380 self.usc.register(registry, token, interests)
1381 }
1382
1383 fn reregister(
1384 &mut self,
1385 registry: &mio::Registry,
1386 token: mio::Token,
1387 interests: mio::Interest,
1388 ) -> io::Result<()>
1389 {
1390 self.usc.reregister(registry, token, interests)
1391 }
1392
1393 fn deregister(&mut self, registry: &mio::Registry) -> io::Result<()>
1394 {
1395 self.usc.deregister(registry)
1396 }
1397 }
1398}
1399
1400#[cfg(feature = "xio-rs")]
1401pub mod xio_non_blk_conn_enabled
1402{
1403 use xio_rs::{EsInterfaceRegistry, XioChannel, XioEventPipe, XioEventUid, XioResult, event_registry::XioRegistry};
1404
1405 use super::NonblockingUnixSeqpacketConn;
1406
1407 impl<ESSR: EsInterfaceRegistry> XioEventPipe<ESSR, Self> for NonblockingUnixSeqpacketConn
1408 {
1409 fn connect_event_pipe(&mut self, ess: &XioRegistry<ESSR>, ev_uid: XioEventUid, channel: XioChannel) -> XioResult<()>
1410 {
1411 self.usc.connect_event_pipe(ess, ev_uid, channel)
1412 }
1413
1414 fn modify_event_pipe(&mut self, ess: &XioRegistry<ESSR>, ev_uid: XioEventUid, channel: XioChannel) -> XioResult<()>
1415 {
1416 self.usc.modify_event_pipe(ess, ev_uid, channel)
1417 }
1418
1419 fn disconnect_event_pipe(&mut self, ess: &XioRegistry<ESSR>) -> XioResult<()>
1420 {
1421 self.usc.disconnect_event_pipe(ess)
1422 }
1423 }
1424}
1425
1426// can't Deref<Target=UnixSeqpacketConn> because that would include try_clone()
1427// and later set_(read|write)_timeout()
1428impl NonblockingUnixSeqpacketConn
1429{
1430 /// Connects to an unix seqpacket server listening at `path`.
1431 ///
1432 /// This is a wrapper around [`connect_unix_addr()`](#method.connect_unix_addr)
1433 /// for convenience and compatibility with std.
1434 pub
1435 fn connect<P: AsRef<Path>>(path: P) -> Result<Self, io::Error>
1436 {
1437 let addr = UnixSocketAddr::from_path(&path)?;
1438
1439 return Self::connect_unix_addr(&addr);
1440 }
1441
1442 /// Connects to an unix seqpacket server listening at `addr`.
1443 pub
1444 fn connect_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error>
1445 {
1446 let socket = Socket::<SocketSeqPkt>::new(true)?;
1447 socket.set_unix_peer_addr(addr)?;
1448
1449 return Ok(
1450 NonblockingUnixSeqpacketConn
1451 {
1452 usc: UnixSeqpacketConn { fd: socket.into() }
1453 }
1454 );
1455 }
1456
1457 /// Binds to an address before connecting to a listening seqpacet socket.
1458 pub
1459 fn connect_from_to_unix_addr(from: &UnixSocketAddr, to: &UnixSocketAddr) -> Result<Self, io::Error>
1460 {
1461 let socket = Socket::<SocketSeqPkt>::new(true)?;
1462 socket.set_unix_local_addr(from)?;
1463 socket.set_unix_peer_addr(to)?;
1464
1465 return Ok(
1466 NonblockingUnixSeqpacketConn
1467 {
1468 usc: UnixSeqpacketConn { fd: socket.into() }
1469 }
1470 );
1471 }
1472
1473 /// Creates a pair of unix-domain seqpacket conneections connected to each other.
1474 ///
1475 /// # Examples
1476 ///
1477 #[cfg_attr(not(target_vendor="apple"), doc="```")]
1478 #[cfg_attr(target_vendor="apple", doc="```no_run")]
1479 /// let (a, b) = uds_fork::UnixSeqpacketConn::pair().unwrap();
1480 /// assert!(a.local_unix_addr().unwrap().is_unnamed());
1481 /// assert!(b.local_unix_addr().unwrap().is_unnamed());
1482 ///
1483 /// a.send(b"hello").unwrap();
1484 /// b.recv(&mut[0; 20]).unwrap();
1485 /// ```
1486 pub
1487 fn pair() -> Result<(Self, Self), io::Error>
1488 {
1489 let pair = Socket::<SocketSeqPkt>::pair(true)?;
1490
1491 return Ok(
1492 (
1493 Self{ usc: UnixSeqpacketConn { fd: pair.0.into() } },
1494 Self{ usc: UnixSeqpacketConn { fd: pair.1.into() } },
1495 )
1496 );
1497 }
1498
1499 pub
1500 fn try_clone(&self) -> Result<Self, io::Error>
1501 {
1502 let cloned = Socket::<SocketSeqPkt>::try_clone_from(self)?;
1503
1504 return Ok(
1505 NonblockingUnixSeqpacketConn
1506 {
1507 usc: UnixSeqpacketConn { fd: cloned.into() }
1508 }
1509 );
1510 }
1511}
1512
1513
1514/// A non-blocking unix domain listener for sequential-packet connections.
1515///
1516/// Differs from [`UnixSeqpacketListener`](../struct.UnixSeqpacketListener.html)
1517/// in that [`accept()`](struct.NonblockingUnixSeqpacketListener.html#method.accept)
1518/// returns non-blocking [connection sockets](struct.NonblockingUnixSeqpacketConn.html)
1519/// and doesn't block if no client `connect()`ions are pending.
1520///
1521/// # Registering with Xio (xio-rs) a feature = "xio-rs"
1522///
1523/// A `XioEventPipe` is implemented on this function. See [UnixSeqpacketListener]
1524/// for an examples.
1525///
1526/// See examples below.
1527///
1528/// # Registering with Mio (mio) a feature = "mio"
1529///
1530/// A `Source` is implemented on the instance. See [UnixSeqpacketListener]
1531/// for an examples.
1532///
1533/// # Examples
1534///
1535#[cfg_attr(not(target_vendor="apple"), doc="```")]
1536#[cfg_attr(target_vendor="apple", doc="```no_run")]
1537/// use uds_fork::nonblocking::{UnixSeqpacketListener, UnixSeqpacketConn};
1538/// use std::io::ErrorKind;
1539///
1540/// let file_path = "/tmp/nonblocking_seqpacket_listener2.socket";
1541///
1542/// let _ = std::fs::remove_file(file_path);
1543/// let listener = UnixSeqpacketListener::bind(file_path)
1544/// .expect("Cannot create nonblocking seqpacket listener");
1545///
1546/// // doesn't block if no connections are waiting:
1547/// assert_eq!(listener.accept_unix_addr().unwrap_err().kind(), ErrorKind::WouldBlock);
1548///
1549/// // returned connections are nonblocking:
1550/// let _client = UnixSeqpacketConn::connect(file_path).unwrap();
1551/// let (conn, _addr) = listener.accept_unix_addr().unwrap();
1552/// assert_eq!(conn.recv(&mut[0u8; 20]).unwrap_err().kind(), ErrorKind::WouldBlock);
1553/// #
1554/// # std::fs::remove_file(file_path).unwrap();
1555/// ```
1556#[derive(Debug)]
1557#[repr(transparent)]
1558pub struct NonblockingUnixSeqpacketListener
1559{
1560 usl: UnixSeqpacketListener,
1561}
1562
1563impl From<OwnedFd> for NonblockingUnixSeqpacketListener
1564{
1565 fn from(ofd: OwnedFd) -> Self
1566 {
1567 let usl = UnixSeqpacketListener::from(ofd);
1568 usl.set_nonblocking(true).unwrap();
1569
1570 return Self{ usl };
1571 }
1572}
1573
1574impl FromRawFd for NonblockingUnixSeqpacketListener
1575{
1576 unsafe
1577 fn from_raw_fd(fd: RawFd) -> Self
1578 {
1579 let usl = unsafe{ UnixSeqpacketListener::from_raw_fd(fd) };
1580 usl.set_nonblocking(true).unwrap();
1581
1582 return Self{ usl };
1583 }
1584}
1585
1586
1587impl From<NonblockingUnixSeqpacketListener> for OwnedFd
1588{
1589 fn from(value: NonblockingUnixSeqpacketListener) -> Self
1590 {
1591 return value.usl.fd;
1592 }
1593}
1594
1595
1596impl AsRawFd for NonblockingUnixSeqpacketListener
1597{
1598 fn as_raw_fd(&self) -> RawFd
1599 {
1600 self.usl.as_raw_fd()
1601 }
1602}
1603
1604impl IntoRawFd for NonblockingUnixSeqpacketListener
1605{
1606 fn into_raw_fd(self) -> RawFd
1607 {
1608 self.usl.into_raw_fd()
1609 }
1610}
1611
1612impl AsFd for NonblockingUnixSeqpacketListener
1613{
1614 fn as_fd(&self) -> BorrowedFd<'_>
1615 {
1616 self.usl.as_fd()
1617 }
1618}
1619
1620
1621impl Deref for NonblockingUnixSeqpacketListener
1622{
1623 type Target = UnixSeqpacketListener;
1624
1625 fn deref(&self) -> &Self::Target
1626 {
1627 &self.usl
1628 }
1629}
1630
1631impl DerefMut for NonblockingUnixSeqpacketListener
1632{
1633 fn deref_mut(&mut self) -> &mut Self::Target
1634 {
1635 &mut self.usl
1636 }
1637}
1638
1639impl NonblockingUnixSeqpacketListener
1640{
1641 /// Creates a socket that listens for seqpacket connections on the specified socket file.
1642 pub
1643 fn bind<P: AsRef<Path>>(path: P) -> Result<Self, io::Error>
1644 {
1645 let addr = UnixSocketAddr::from_path(&path)?;
1646
1647 return Self::bind_unix_addr(&addr);
1648 }
1649
1650 /// Creates a socket that listens for seqpacket connections on the specified address.
1651 pub
1652 fn bind_unix_addr(addr: &UnixSocketAddr) -> Result<Self, io::Error>
1653 {
1654 let socket = Socket::<SocketSeqPkt>::new(true)?;
1655 socket.set_unix_local_addr(addr)?;
1656 socket.start_listening()?;
1657
1658 return Ok( Self{ usl: UnixSeqpacketListener{ fd: socket.into() }} );
1659 }
1660
1661 /// Accepts a non-blocking connection, non-blockingly.
1662 ///
1663 /// # Examples
1664 ///
1665 /// Doesn't block if no connections are waiting:
1666 ///
1667 #[cfg_attr(not(target_vendor="apple"), doc="```")]
1668 #[cfg_attr(target_vendor="apple", doc="```no_run")]
1669 /// # use uds_fork::nonblocking::UnixSeqpacketListener;
1670 /// # use std::io::ErrorKind;
1671 /// #
1672 /// let file_path = "/tmp/nonblocking_seqpacket_listener3.socket";
1673 /// let _ = std::fs::remove_file(file_path);
1674 /// let listener = UnixSeqpacketListener::bind(file_path)
1675 /// .expect("Cannot create nonblocking seqpacket listener");
1676 /// assert_eq!(listener.accept_unix_addr().unwrap_err().kind(), ErrorKind::WouldBlock);
1677 /// std::fs::remove_file(file_path).unwrap();
1678 /// ```
1679 pub
1680 fn accept_unix_addr(&self) -> Result<(NonblockingUnixSeqpacketConn, UnixSocketAddr), io::Error>
1681 {
1682 let (socket, addr) = Socket::<SocketSeqPkt>::accept_from(&self, true)?;
1683 let conn = NonblockingUnixSeqpacketConn { usc: UnixSeqpacketConn{ fd: socket.into() }};
1684
1685 return Ok((conn, addr));
1686 }
1687}
1688
1689#[cfg(feature = "mio")]
1690pub mod mio_non_blk_listener_enabled
1691{
1692 use std::{io, os::fd::AsRawFd};
1693
1694 use mio::{event::Source, unix::SourceFd};
1695 use super::NonblockingUnixSeqpacketListener;
1696
1697 impl Source for NonblockingUnixSeqpacketListener
1698 {
1699 fn register(
1700 &mut self,
1701 registry: &mio::Registry,
1702 token: mio::Token,
1703 interests: mio::Interest,
1704 ) -> io::Result<()>
1705 {
1706 self.usl.register(registry, token, interests)
1707 }
1708
1709 fn reregister(
1710 &mut self,
1711 registry: &mio::Registry,
1712 token: mio::Token,
1713 interests: mio::Interest,
1714 ) -> io::Result<()>
1715 {
1716 self.usl.reregister(registry, token, interests)
1717 }
1718
1719 fn deregister(&mut self, registry: &mio::Registry) -> io::Result<()>
1720 {
1721 self.usl.deregister(registry)
1722 }
1723 }
1724}
1725
1726#[cfg(feature = "xio-rs")]
1727pub mod xio_non_blk_listener_enabled
1728{
1729 use xio_rs::{EsInterfaceRegistry, XioChannel, XioEventPipe, XioEventUid, XioResult, event_registry::XioRegistry};
1730
1731 use super::NonblockingUnixSeqpacketListener;
1732
1733 impl<ESSR: EsInterfaceRegistry> XioEventPipe<ESSR, Self> for NonblockingUnixSeqpacketListener
1734 {
1735 fn connect_event_pipe(&mut self, ess: &XioRegistry<ESSR>, ev_uid: XioEventUid, channel: XioChannel) -> XioResult<()>
1736 {
1737
1738 self.usl.connect_event_pipe(ess, ev_uid, channel)
1739 }
1740
1741 fn modify_event_pipe(&mut self, ess: &XioRegistry<ESSR>, ev_uid: XioEventUid, channel: XioChannel) -> XioResult<()>
1742 {
1743 self.usl.modify_event_pipe(ess, ev_uid, channel)
1744 }
1745
1746 fn disconnect_event_pipe(&mut self, ess: &XioRegistry<ESSR>) -> XioResult<()>
1747 {
1748 self.usl.disconnect_event_pipe(ess)
1749 }
1750 }
1751}