1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#[cfg(feature = "native-mux")]
use super::native_mux_impl;

#[cfg(feature = "process-mux")]
use std::ffi::OsStr;

use std::borrow::Cow;
use std::fmt;
use std::net::{self, SocketAddr};
use std::path::{Path, PathBuf};

/// Type of forwarding
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ForwardType {
    /// Forward requests to a port on the local machine to remote machine.
    Local,

    /// Forward requests to a port on the remote machine to local machine.
    Remote,
}

#[cfg(feature = "native-mux")]
impl From<ForwardType> for native_mux_impl::ForwardType {
    fn from(fwd_type: ForwardType) -> Self {
        use native_mux_impl::ForwardType::*;

        match fwd_type {
            ForwardType::Local => Local,
            ForwardType::Remote => Remote,
        }
    }
}

/// TCP/Unix socket
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Socket<'a> {
    /// Unix socket.
    #[cfg(unix)]
    #[cfg_attr(docsrs, doc(cfg(unix)))]
    UnixSocket {
        /// Filesystem path
        path: Cow<'a, Path>,
    },

    /// Tcp socket.
    TcpSocket {
        /// Hostname.
        host: Cow<'a, str>,
        /// Port.
        port: u16,
    },
}

impl From<SocketAddr> for Socket<'static> {
    fn from(addr: SocketAddr) -> Self {
        Socket::TcpSocket {
            host: addr.ip().to_string().into(),
            port: addr.port(),
        }
    }
}

macro_rules! impl_from_addr {
    ($ip:ty) => {
        impl From<($ip, u16)> for Socket<'static> {
            fn from((ip, port): ($ip, u16)) -> Self {
                SocketAddr::new(ip.into(), port).into()
            }
        }
    };
}

impl_from_addr!(net::IpAddr);
impl_from_addr!(net::Ipv4Addr);
impl_from_addr!(net::Ipv6Addr);

impl<'a> From<Cow<'a, Path>> for Socket<'a> {
    fn from(path: Cow<'a, Path>) -> Self {
        Socket::UnixSocket { path }
    }
}

impl<'a> From<&'a Path> for Socket<'a> {
    fn from(path: &'a Path) -> Self {
        Socket::UnixSocket {
            path: Cow::Borrowed(path),
        }
    }
}

impl From<PathBuf> for Socket<'static> {
    fn from(path: PathBuf) -> Self {
        Socket::UnixSocket {
            path: Cow::Owned(path),
        }
    }
}

impl From<Box<Path>> for Socket<'static> {
    fn from(path: Box<Path>) -> Self {
        Socket::UnixSocket {
            path: Cow::Owned(path.into()),
        }
    }
}

impl Socket<'_> {
    /// Create a new TcpSocket
    pub fn new<'a, S>(host: S, port: u16) -> Socket<'a>
    where
        S: Into<Cow<'a, str>>,
    {
        Socket::TcpSocket {
            host: host.into(),
            port,
        }
    }

    #[cfg(feature = "process-mux")]
    pub(crate) fn as_os_str(&self) -> Cow<'_, OsStr> {
        match self {
            #[cfg(unix)]
            Socket::UnixSocket { path } => Cow::Borrowed(path.as_os_str()),
            Socket::TcpSocket { host, port } => Cow::Owned(format!("{host}:{port}").into()),
        }
    }
}

#[cfg(feature = "native-mux")]
impl<'a> From<Socket<'a>> for native_mux_impl::Socket<'a> {
    fn from(socket: Socket<'a>) -> Self {
        use native_mux_impl::Socket::*;

        match socket {
            #[cfg(unix)]
            Socket::UnixSocket { path } => UnixSocket { path },
            Socket::TcpSocket { host, port } => TcpSocket {
                host,
                port: port as u32,
            },
        }
    }
}

impl<'a> fmt::Display for Socket<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            #[cfg(unix)]
            Socket::UnixSocket { path } => {
                write!(f, "{}", path.display())
            }
            Socket::TcpSocket { host, port } => write!(f, "{host}:{port}"),
        }
    }
}