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
use std::{net::SocketAddr, sync::Arc, time::Duration};

use smol::{future::Boxed, net::TcpStream};

use crate::{runtime, tcp::TcpClientBackhaul, Session, StatsGatherer};

mod inner;

/// Configuration of a client.
#[derive(Clone)]
pub struct ClientConfig {
    pub server_addr: SocketAddr,
    pub server_pk: x25519_dalek::PublicKey,
    pub gather: Arc<StatsGatherer>,
    pub protocol: Protocol,
    pub shard_count: usize,
    pub reset_interval: Option<Duration>,
}

impl ClientConfig {
    /// Creates a new ClientConfig.
    pub fn new(
        protocol: Protocol,
        server_addr: SocketAddr,
        server_pk: x25519_dalek::PublicKey,
        gather: Arc<StatsGatherer>,
    ) -> Self {
        Self {
            server_addr,
            server_pk,
            gather,
            protocol,
            shard_count: 1,
            reset_interval: None,
        }
    }

    /// Builds a Session out of this ClientConfig.
    pub async fn connect(self) -> std::io::Result<Session> {
        let server_addr = self.server_addr;
        let server_pk = self.server_pk;
        inner::connect_custom(inner::LowlevelClientConfig {
            server_addr,
            server_pubkey: server_pk,
            backhaul_gen: match self.protocol {
                Protocol::DirectTcp => Arc::new(move || {
                    Arc::new(TcpClientBackhaul::new(None).add_remote_key(server_addr, server_pk))
                }),
                Protocol::ProxiedTcp(cnctr) => Arc::new(move || {
                    Arc::new(
                        TcpClientBackhaul::new(Some(cnctr.clone()))
                            .add_remote_key(server_addr, server_pk),
                    )
                }),
                Protocol::DirectUdp => Arc::new(|| {
                    Arc::new(
                        runtime::new_udp_socket_bind("0.0.0.0:0".parse::<SocketAddr>().unwrap())
                            .unwrap(),
                    )
                }),
            },
            num_shards: self.shard_count,
            reset_interval: self.reset_interval,
            gather: self.gather,
        })
        .await
    }
}

/// Underlying protocol for a sosistab session.
#[derive(Clone)]
pub enum Protocol {
    /// "Direct" TCP that does not go through a proxy.
    DirectTcp,
    /// "Proxied" TCP that instead calls a function that returns a TCP connection.
    ProxiedTcp(Connector),
    /// "Direct UDP that does not go through a proxy.
    DirectUdp,
}

pub type Connector =
    Arc<dyn Fn(SocketAddr) -> Boxed<std::io::Result<TcpStream>> + Send + Sync + 'static>;

/// Connects to a remote server over UDP.
#[deprecated]
pub async fn connect_udp(
    server_addr: SocketAddr,
    pubkey: x25519_dalek::PublicKey,
    gather: Arc<StatsGatherer>,
) -> std::io::Result<Session> {
    inner::connect_custom(inner::LowlevelClientConfig {
        server_addr,
        server_pubkey: pubkey,
        backhaul_gen: Arc::new(|| {
            Arc::new(
                runtime::new_udp_socket_bind("0.0.0.0:0".parse::<SocketAddr>().unwrap()).unwrap(),
            )
        }),
        num_shards: 4,
        reset_interval: Some(Duration::from_secs(3)),
        gather,
    })
    .await
}

/// Connects to a remote server over UDP.
#[deprecated]
pub async fn connect_tcp(
    server_addr: SocketAddr,
    pubkey: x25519_dalek::PublicKey,
    gather: Arc<StatsGatherer>,
) -> std::io::Result<Session> {
    inner::connect_custom(inner::LowlevelClientConfig {
        server_addr,
        server_pubkey: pubkey,
        backhaul_gen: Arc::new(move || {
            Arc::new(TcpClientBackhaul::new(None).add_remote_key(server_addr, pubkey))
        }),
        num_shards: 16,
        reset_interval: None,
        gather,
    })
    .await
}