Skip to main content

running_process_platform_internal/platform/
ipc.rs

1//! Local endpoint, listener, connection, peer, handoff, and security primitives.
2//!
3//! Endpoint strings and protocol policy remain with callers. These opaque
4//! values own the selected host transport so callers never name Unix sockets,
5//! Windows named pipes, `interprocess` types, file descriptors, or handles.
6
7#[cfg(feature = "ipc")]
8pub use crate::{
9    ipc_current_user_id as current_user_id, IpcEndpoint as Endpoint, IpcListener as Listener,
10    IpcListenerNonblockingMode as ListenerNonblockingMode, IpcPeerIdentity as PeerIdentity,
11    IpcStream as Stream,
12};
13
14#[cfg(feature = "ipc-async")]
15pub use crate::{
16    IpcAsyncListener as AsyncListener, IpcAsyncStream as AsyncStream,
17    IpcIntoAsyncListener as IntoAsyncListener, IpcIntoAsyncStream as IntoAsyncStream,
18};
19
20#[cfg(all(test, feature = "ipc"))]
21mod tests {
22    use std::io::{Read, Write};
23
24    use super::{current_user_id, Endpoint, Listener, Stream};
25
26    #[test]
27    fn endpoint_lifecycle_mechanics_are_facade_owned() {
28        let endpoint = Endpoint::test("lifecycle").expect("test endpoint");
29        endpoint.retire().expect("retire absent endpoint");
30
31        let listener = Listener::bind(&endpoint).expect("bind endpoint");
32
33        drop(listener);
34        endpoint.retire().expect("retire endpoint");
35    }
36
37    #[test]
38    fn sync_bind_accept_connect_and_peer_identity_round_trip() {
39        let endpoint = Endpoint::test("sync-roundtrip").expect("test endpoint");
40        let listener = Listener::bind(&endpoint).expect("bind");
41        let expected_user = current_user_id().expect("current user identity");
42        let server = std::thread::spawn(move || {
43            let mut stream = listener.accept().expect("accept");
44            let peer = stream.peer_identity().expect("peer identity");
45            assert_eq!(peer.user_id, expected_user);
46            let mut request = [0_u8; 4];
47            stream.read_exact(&mut request).expect("read request");
48            assert_eq!(&request, b"ping");
49            stream.write_all(b"pong").expect("write response");
50        });
51
52        let mut client = Stream::connect(&endpoint).expect("connect");
53        client.write_all(b"ping").expect("write request");
54        let mut response = [0_u8; 4];
55        client.read_exact(&mut response).expect("read response");
56        assert_eq!(&response, b"pong");
57        server.join().expect("server thread");
58    }
59
60    #[cfg(feature = "ipc-async")]
61    #[tokio::test]
62    async fn async_bind_accept_connect_and_peer_identity_round_trip() {
63        use super::{AsyncListener, AsyncStream};
64        use tokio::io::{AsyncReadExt, AsyncWriteExt};
65
66        let endpoint = Endpoint::test("async-roundtrip").expect("test endpoint");
67        let listener = AsyncListener::bind(&endpoint).expect("bind");
68        let expected_user = current_user_id().expect("current user identity");
69        let server = tokio::spawn(async move {
70            let mut stream = listener.accept().await.expect("accept");
71            let peer = stream.peer_identity().expect("peer identity");
72            assert_eq!(peer.user_id, expected_user);
73            let mut request = [0_u8; 4];
74            stream.read_exact(&mut request).await.expect("read request");
75            assert_eq!(&request, b"ping");
76            stream.write_all(b"pong").await.expect("write response");
77        });
78
79        let mut client = AsyncStream::connect(&endpoint).await.expect("connect");
80        client.write_all(b"ping").await.expect("write request");
81        let mut response = [0_u8; 4];
82        client
83            .read_exact(&mut response)
84            .await
85            .expect("read response");
86        assert_eq!(&response, b"pong");
87        server.await.expect("server task");
88    }
89}