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}