pueue_lib/network_blocking/socket/
mod.rs

1//! Socket handling is platform specific code.
2//!
3//! The submodules of this module represent the different implementations for
4//! each supported platform.
5//! Depending on the target, the respective platform is read and loaded into this scope.
6
7use std::io::{Read, Write};
8use std::net::TcpStream;
9#[cfg(not(target_os = "windows"))]
10use std::path::PathBuf;
11
12use rustls::pki_types::CertificateDer;
13use rustls_connector::{RustlsConnector as TlsConnector, RustlsConnectorConfig};
14
15use crate::error::Error;
16#[cfg(feature = "settings")]
17use crate::{settings::Shared, tls::load_ca};
18
19/// Shared socket logic
20#[cfg_attr(not(target_os = "windows"), path = "unix.rs")]
21#[cfg_attr(target_os = "windows", path = "windows.rs")]
22mod platform;
23pub use platform::*;
24
25/// A new trait, which can be used to represent Unix- and TcpListeners. \
26/// This is necessary to easily write generic functions where both types can be used.
27pub trait BlockingListener: Sync + Send {
28    fn accept(&self) -> Result<GenericBlockingStream, Error>;
29}
30
31/// Convenience type, so we don't have type write `Box<dyn Listener>` all the time.
32pub type GenericBlockingListener = Box<dyn BlockingListener>;
33/// Convenience type, so we don't have type write `Box<dyn Stream>` all the time. \
34/// This also prevents name collisions, since `Stream` is imported in many preludes.
35pub type GenericBlockingStream = Box<dyn BlockingStream>;
36
37/// Describe how a client should connect to the daemon.
38pub enum ConnectionSettings<'a> {
39    #[cfg(not(target_os = "windows"))]
40    UnixSocket { path: PathBuf },
41    TlsTcpSocket {
42        host: String,
43        port: String,
44        certificate: CertificateDer<'a>,
45    },
46}
47
48/// Convenience conversion from [Shared] to [ConnectionSettings].
49#[cfg(feature = "settings")]
50impl TryFrom<Shared> for ConnectionSettings<'_> {
51    type Error = crate::error::Error;
52
53    fn try_from(value: Shared) -> Result<Self, Self::Error> {
54        // Unix socket handling
55        #[cfg(not(target_os = "windows"))]
56        {
57            if value.use_unix_socket {
58                return Ok(ConnectionSettings::UnixSocket {
59                    path: value.unix_socket_path(),
60                });
61            }
62        }
63
64        let cert = load_ca(&value.daemon_cert())?;
65        Ok(ConnectionSettings::TlsTcpSocket {
66            host: value.host,
67            port: value.port,
68            certificate: cert,
69        })
70    }
71}
72
73pub trait BlockingStream: Read + Write {}
74impl BlockingStream for rustls_connector::TlsStream<TcpStream> {}
75
76/// Initialize our client [TlsConnector]. \
77/// 1. Trust our own CA. ONLY our own CA.
78/// 2. Set the client certificate and key
79pub fn get_tls_connector(cert: CertificateDer<'_>) -> Result<TlsConnector, Error> {
80    let mut config = RustlsConnectorConfig::default();
81    config.add_parsable_certificates(vec![cert]);
82    let connector = config.connector_with_no_client_auth();
83
84    Ok(connector)
85}