Skip to main content

interprocess/
local_socket.rs

1//! Local sockets, a socket-like IPC primitive in which clients access a server through a
2//! filesystem path or an identifier inside a special namespace, with each client having a
3//! private connection to the server.
4//!
5//! ## Implementations and dispatch
6//! Local sockets are not a real IPC primitive implemented by the OS, but rather a construct of
7//! Interprocess that is implemented in terms of an underlying IPC primitive. Different IPC
8//! primitives are available on different platforms and have different capabilities and
9//! limitations. As such, the types representing local sockets that you can find in this
10//! module – [`Listener`], [`Stream`], [`RecvHalf`], [`SendHalf`] – are really enums in the style
11//! of `enum_dispatch` that contain variants for all the different implementations of local
12//! sockets that are available, and the types that they dispatch between are talked to via the
13//! corresponding [`Listener`](traits::Listener), [`Stream`](traits::Stream)
14//! [`RecvHalf`](traits::RecvHalf), [`SendHalf`](traits::SendHalf) traits that you can find in the
15//! [`traits`] module. (Note that this dispatch is currently zero-cost on all platforms, as there
16//! is only one underlying local socket implementation per platform, with Windows only using named
17//! pipe based local sockets and Unix only using Unix-domain socket based local sockets, but this
18//! may change in the future with the introduction of support for
19//! [the Windows implementation of Unix-domain sockets][udswnd]. Even then, the overhead of this
20//! dispatch is insignificant compared to the overhead of making the system calls that perform
21//! the actual communication.)
22//!
23//! [udswnd]: https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/
24//!
25//! The [`prelude`] module is there to make it easier to handle all of this complexity without
26//! suffering from naming collisions. **`use interprocess::local_socket::prelude::*;` is the
27//! recommended way of bringing local sockets into scope.**
28//!
29//! ## Stability
30//! Since interprocess communication cannot happen without agreement on a protocol between two or
31//! more processes, the mapping of local sockets to underlying primitives is stable and
32//! predictable. **The IPC primitive selected depends only on the current platform and the
33//! [name type](NameType) used.** The mapping is trivial unless noted otherwise (in particular,
34//! Interprocess never inserts its own message framing or any other type of metadata into the
35//! stream – the bytes you write are the exact bytes that come out the other end), which means
36//! that the portable API of local sockets is suitable for communicating with programs that do
37//! not use Interprocess themselves, including programs not written in Rust. All you need to do
38//! is use the correct name type for every platform.
39//!
40//! ## Raw handle and file descriptor access
41//! The enum dispatchers purposely omit implementations of `{As,Into,From}Raw{Handle,Fd}`,
42//! `As{Handle,Fd}`, `From<Owned{HandleFd}>` and `Into<Owned{Handle,Fd}>`. To access those trait
43//! implementations on the underlying implementation types, you need to match on the enum. For
44//! instance:
45//! ```no_run
46//! # #[cfg(unix)]
47//! use {interprocess::local_socket::prelude::*, std::os::unix::prelude::*};
48//! # #[cfg(unix)] fn hi(fd: OwnedFd, fd2: OwnedFd) {
49//!
50//! // Creating a stream from a file descriptor
51//! let stream = LocalSocketStream::UdSocket(fd.into());
52//! # let _ = stream;
53//!
54//! // Consuming a stream to get its file descriptor
55//! let fd = match stream {
56//!     LocalSocketStream::UdSocket(s) => OwnedFd::from(s),
57//! };
58//! # let _ = fd;
59//!
60//! # let stream = LocalSocketStream::UdSocket(fd2.into());
61//! // Accessing a stream's file descriptor without taking ownership
62//! let stream_impl = match &stream {
63//!     LocalSocketStream::UdSocket(s) => s,
64//! };
65//! let fd = stream_impl.as_fd();
66//! # let _ = fd;
67//!
68//! // Listener, RecvHalf, and SendHalf work analogously.
69//! // Works just the same on Windows under the replacement of Fd with Handle.
70//! # }
71//! ```
72
73#[macro_use]
74mod enumdef;
75
76mod name;
77mod stream {
78    pub(super) mod r#enum;
79    pub(super) mod options;
80    pub(super) mod r#trait;
81}
82mod listener {
83    pub(super) mod r#enum;
84    pub(super) mod options;
85    pub(super) mod r#trait;
86}
87
88/// Traits representing the interface of local sockets.
89pub mod traits {
90    pub use super::{
91        listener::r#trait::{Listener, ListenerExt},
92        stream::r#trait::*,
93    };
94    /// Traits for the Tokio variants of local socket objects.
95    #[cfg(feature = "tokio")]
96    #[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "tokio")))]
97    pub mod tokio {
98        pub use super::super::tokio::{listener::r#trait::*, stream::r#trait::*};
99    }
100}
101
102pub use {
103    listener::{
104        options::ListenerOptions,
105        r#enum::*,
106        r#trait::{Incoming, ListenerNonblockingMode},
107    },
108    name::*,
109    stream::{options::ConnectOptions, r#enum::*},
110};
111
112/// Re-exports of [traits] done in a way that doesn't pollute the scope, as well as of the
113/// enum-dispatch types with their names prefixed with `LocalSocket`.
114pub mod prelude {
115    pub use super::{
116        name::{NameType as _, ToFsName as _, ToNsName as _},
117        traits::{Listener as _, ListenerExt as _, Stream as _, StreamCommon as _},
118        Listener as LocalSocketListener, Stream as LocalSocketStream,
119    };
120}
121
122/// Asynchronous local sockets which work with the Tokio runtime and event loop.
123///
124/// The Tokio integration allows the local socket streams and listeners to be notified by the OS
125/// kernel whenever they're ready to be received from of sent to, instead of requiring you to
126/// spawn threads just to put them in a wait state of blocking on the I/O.
127///
128/// Everything said in the [documentation for sync local sockets](crate::local_socket) applies to
129/// the Tokio versions of the corresponding items as well. Please read it before using Tokio-based
130/// local sockets.
131///
132/// Types from this module will *not* work with other async runtimes, such as `async-std` or `smol`,
133/// since the Tokio types' methods will panic whenever they're called outside of a Tokio runtime
134/// context. Open an issue if you'd like to see other runtimes supported as well.
135#[cfg(feature = "tokio")]
136#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "tokio")))]
137pub mod tokio {
138    pub(super) mod listener {
139        pub(in super::super) mod r#enum;
140        pub(in super::super) mod r#trait;
141    }
142    pub(super) mod stream {
143        pub(in super::super) mod r#enum;
144        pub(in super::super) mod r#trait;
145    }
146    pub use {listener::r#enum::*, stream::r#enum::*};
147
148    /// Like the [sync local socket prelude](super::prelude), but for Tokio local sockets.
149    pub mod prelude {
150        pub use super::{
151            super::{
152                name::{NameType as _, ToFsName as _, ToNsName as _},
153                traits::{
154                    tokio::{Listener as _, Stream as _},
155                    StreamCommon as _,
156                },
157            },
158            Listener as LocalSocketListener, Stream as LocalSocketStream,
159        };
160    }
161}
162
163mod concurrency_detector;
164pub(crate) use concurrency_detector::*;