1
//! Implement RPC functionality for finding what ports are running as proxies.
2

            
3
use std::{net::SocketAddr, sync::Arc};
4
use tor_error::{ErrorKind, HasKind};
5
use tor_rpcbase::{self as rpc};
6

            
7
use super::session::ArtiRpcSession;
8

            
9
/// Representation of a single proxy, as delivered by the RPC API.
10
#[derive(serde::Serialize, Clone, Debug)]
11
#[cfg_attr(test, derive(PartialEq, Eq))]
12
pub(super) struct Proxy {
13
    /// Where the proxy is listening, what protocol it speaks,
14
    /// and what protocol-specific options it expects.
15
    pub(super) listener: ProxyListener,
16
}
17

            
18
/// Representation of a single proxy's listener location, as delivered by the RPC API.
19
#[derive(serde::Serialize, Clone, Debug)]
20
#[cfg_attr(test, derive(PartialEq, Eq))]
21
pub(super) enum ProxyListener {
22
    /// A SOCKS5 proxy.
23
    #[serde(rename = "socks5")]
24
    Socks5 {
25
        /// The address at which we're listening for SOCKS connections.
26
        tcp_address: Option<SocketAddr>,
27
    },
28
    /// An HTTP CONNECT proxy.
29
    #[cfg(feature = "http-connect")]
30
    #[serde(rename = "http_connect")]
31
    HttpConnect {
32
        /// The address at which we're listening for HTTP CONNECT connections.
33
        tcp_address: Option<SocketAddr>,
34
    },
35
}
36

            
37
/// A representation of the set of proxy addresses available from the RPC API.
38
#[derive(serde::Serialize, Clone, Debug)]
39
#[cfg_attr(test, derive(PartialEq, Eq))]
40
pub(super) struct ProxyInfo {
41
    /// A list of the supported proxies.
42
    pub(super) proxies: Vec<Proxy>,
43
}
44

            
45
/// Get a list of all the currently running proxies.
46
///
47
/// This method should not be used when deciding which proxy
48
/// an RPC application should connect to.
49
/// Instead, the application should use
50
/// [`arti:get_rpc_proxy_info`](GetRpcProxyInfo).
51
#[derive(Debug, serde::Deserialize, derive_deftly::Deftly)]
52
#[derive_deftly(rpc::DynMethod)]
53
#[deftly(rpc(method_name = "arti:get_proxy_info"))]
54
struct GetProxyInfo {}
55

            
56
/// Get a list of the currently running proxies
57
/// that are integrated with the RPC system.
58
///
59
/// This method returns a list of proxies.
60
/// The RPC application may be not be able to use all proxies from the list,
61
/// and may prefer some proxies over other.
62
/// When multiple proxies are equally preferred,
63
/// the application SHOULD use whichever appears first in the list.
64
///
65
/// You typically won't need to invoke this method yourself:
66
/// your RPC library (like `arti-rpc-client-core`)
67
/// should take care if it for you.
68
#[derive(Debug, serde::Deserialize, derive_deftly::Deftly)]
69
#[derive_deftly(rpc::DynMethod)]
70
#[deftly(rpc(method_name = "arti:get_rpc_proxy_info"))]
71
struct GetRpcProxyInfo {}
72

            
73
impl rpc::RpcMethod for GetProxyInfo {
74
    type Output = ProxyInfo;
75
    type Update = rpc::NoUpdates;
76
}
77

            
78
impl rpc::RpcMethod for GetRpcProxyInfo {
79
    type Output = ProxyInfo;
80
    type Update = rpc::NoUpdates;
81
}
82

            
83
/// An error encountered while asking for the proxy addresses.
84
#[derive(Clone, Debug, thiserror::Error)]
85
enum GetProxyInfoError {
86
    /// The Sender was dropped without setting any proxy info;
87
    /// likely, Arti is shutting down.
88
    #[error("Arti appears to be shutting down")]
89
    Shutdown,
90
}
91
impl HasKind for GetProxyInfoError {
92
    fn kind(&self) -> ErrorKind {
93
        use GetProxyInfoError as E;
94
        match self {
95
            E::Shutdown => ErrorKind::ArtiShuttingDown,
96
        }
97
    }
98
}
99

            
100
/// Implementation for GetProxyInfo on ArtiRpcSession.
101
async fn rpc_session_get_proxy_info(
102
    session: Arc<ArtiRpcSession>,
103
    _method: Box<GetProxyInfo>,
104
    _ctx: Arc<dyn rpc::Context>,
105
) -> Result<ProxyInfo, GetProxyInfoError> {
106
    let proxy_info = session.arti_state.get_proxy_info().await;
107

            
108
    match proxy_info {
109
        Ok(info) => Ok((*info).clone()),
110
        Err(()) => Err(GetProxyInfoError::Shutdown),
111
    }
112
}
113
rpc::static_rpc_invoke_fn! {rpc_session_get_proxy_info;}
114

            
115
/// Implementation for GetProxyInfo on ArtiRpcSession.
116
async fn rpc_session_get_rpc_proxy_info(
117
    session: Arc<ArtiRpcSession>,
118
    _method: Box<GetRpcProxyInfo>,
119
    _ctx: Arc<dyn rpc::Context>,
120
) -> Result<ProxyInfo, GetProxyInfoError> {
121
    let proxy_info = session.arti_state.get_proxy_info().await;
122

            
123
    match proxy_info {
124
        Ok(info) => Ok((*info).clone()),
125
        Err(()) => Err(GetProxyInfoError::Shutdown),
126
    }
127
}
128
rpc::static_rpc_invoke_fn! {rpc_session_get_rpc_proxy_info;}