Skip to main content

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