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, and what protocol-specific options it expects.
14
    pub(super) listener: ProxyListener,
15
}
16

            
17
/// Representation of a single proxy's listener location, as delivered by the RPC API.
18
#[derive(serde::Serialize, Clone, Debug)]
19
#[cfg_attr(test, derive(PartialEq, Eq))]
20
pub(super) enum ProxyListener {
21
    /// A SOCKS5 proxy.
22
    #[serde(rename = "socks5")]
23
    Socks5 {
24
        /// The address at which we're listening for SOCKS connections.
25
        tcp_address: Option<SocketAddr>,
26
    },
27
}
28

            
29
/// A representation of the set of proxy addresses available from the RPC API.
30
#[derive(serde::Serialize, Clone, Debug)]
31
#[cfg_attr(test, derive(PartialEq, Eq))]
32
pub(super) struct ProxyInfo {
33
    /// A list of the supported proxies.
34
    ///
35
    /// (So far, only SOCKS proxies are listed, but other kinds may be listed in the future.)
36
    pub(super) proxies: Vec<Proxy>,
37
}
38

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

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

            
67
impl rpc::RpcMethod for GetProxyInfo {
68
    type Output = ProxyInfo;
69
    type Update = rpc::NoUpdates;
70
}
71

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

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

            
94
/// Implementation for GetProxyInfo on ArtiRpcSession.
95
async fn rpc_session_get_proxy_info(
96
    session: Arc<ArtiRpcSession>,
97
    _method: Box<GetProxyInfo>,
98
    _ctx: Arc<dyn rpc::Context>,
99
) -> Result<ProxyInfo, GetProxyInfoError> {
100
    let proxy_info = session.arti_state.get_proxy_info().await;
101

            
102
    match proxy_info {
103
        Ok(info) => Ok((*info).clone()),
104
        Err(()) => Err(GetProxyInfoError::Shutdown),
105
    }
106
}
107
rpc::static_rpc_invoke_fn! {rpc_session_get_proxy_info;}
108

            
109
/// Implementation for GetProxyInfo on ArtiRpcSession.
110
async fn rpc_session_get_rpc_proxy_info(
111
    session: Arc<ArtiRpcSession>,
112
    _method: Box<GetRpcProxyInfo>,
113
    _ctx: Arc<dyn rpc::Context>,
114
) -> Result<ProxyInfo, GetProxyInfoError> {
115
    let proxy_info = session.arti_state.get_proxy_info().await;
116

            
117
    match proxy_info {
118
        Ok(info) => Ok((*info).clone()),
119
        Err(()) => Err(GetProxyInfoError::Shutdown),
120
    }
121
}
122
rpc::static_rpc_invoke_fn! {rpc_session_get_rpc_proxy_info;}