Skip to main content

a7n_platform/
local_socket.rs

1// SPDX-License-Identifier: GPL-3.0-or-later
2
3//! Per-user local sockets. Endpoint permissions belong here, not in IPC framing.
4
5use std::path::{Path, PathBuf};
6
7pub use interprocess::local_socket::tokio::{Listener, Stream};
8
9#[cfg(unix)]
10#[path = "local_socket/unix.rs"]
11mod imp;
12#[cfg(windows)]
13#[path = "local_socket/windows.rs"]
14mod imp;
15
16/// Explicit filesystem socket path on Unix, or pipe basename on Windows.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct SocketLocation(PathBuf);
19
20impl SocketLocation {
21    /// Unix paths must be absolute and their parent directory must be private.
22    #[must_use]
23    pub fn new(location: impl Into<PathBuf>) -> Self {
24        Self(location.into())
25    }
26
27    #[must_use]
28    pub fn as_path(&self) -> &Path {
29        &self.0
30    }
31}
32
33/// Endpoint setup or connection failure.
34#[derive(Debug, thiserror::Error)]
35pub enum SocketError {
36    #[error("no per-user runtime/cache directory or username is available")]
37    NoUserLocation,
38    #[error("socket path must be absolute and at most {max_bytes} bytes: {path}")]
39    InvalidPath { path: PathBuf, max_bytes: usize },
40    #[error("socket directory must be a real directory owned by this user with mode 0700: {0}")]
41    InsecureDirectory(PathBuf),
42    #[error("refusing to replace a socket path that is not a socket owned by this user: {0}")]
43    InsecureSocket(PathBuf),
44    #[error("local socket operation timed out")]
45    Timeout,
46    #[error(transparent)]
47    Io(#[from] std::io::Error),
48}
49
50/// Select the current user's endpoint without creating it.
51///
52/// # Errors
53/// Returns an error if the user's location cannot be determined or is too long.
54pub fn default_location() -> Result<SocketLocation, SocketError> {
55    imp::default_location()
56}
57
58/// Bind an endpoint accessible only to its owner.
59///
60/// # Errors
61/// Refuses unsafe directories/files and live listeners; propagates OS failures.
62pub async fn bind_user_only(location: &SocketLocation) -> Result<Listener, SocketError> {
63    imp::bind_user_only(location).await
64}
65
66/// Connect to a per-user endpoint with a bounded connection attempt.
67///
68/// # Errors
69/// Returns invalid-location, timeout or OS connection errors.
70pub async fn connect(location: &SocketLocation) -> Result<Stream, SocketError> {
71    imp::connect(location).await
72}