shadowsocks_service/local/loadbalancing/
server_data.rs

1//! Identifier of server
2
3use std::{
4    fmt::{self, Debug},
5    net::SocketAddr,
6    sync::{
7        Arc,
8        atomic::{AtomicU32, Ordering},
9    },
10    time::Duration,
11};
12
13use shadowsocks::{ServerConfig, net::ConnectOpts};
14use tokio::sync::Mutex;
15
16use crate::{config::ServerInstanceConfig, local::context::ServiceContext};
17
18use super::server_stat::{Score, ServerStat, ServerStatData};
19
20/// Server's statistic score
21pub struct ServerScore {
22    stat_data: Mutex<ServerStat>,
23    score: AtomicU32,
24}
25
26impl ServerScore {
27    /// Create a `ServerScore`
28    pub fn new(user_weight: f32, max_server_rtt: Duration, check_window: Duration) -> Self {
29        let max_server_rtt = max_server_rtt.as_millis() as u32;
30        assert!(max_server_rtt > 0);
31
32        Self {
33            stat_data: Mutex::new(ServerStat::new(user_weight, max_server_rtt, check_window)),
34            score: AtomicU32::new(u32::MAX),
35        }
36    }
37
38    /// Get server's current statistic scores
39    pub fn score(&self) -> u32 {
40        self.score.load(Ordering::Acquire)
41    }
42
43    /// Append a `Score` into statistic and recalculate score of the server
44    pub async fn push_score(&self, score: Score) -> u32 {
45        let updated_score = {
46            let mut stat = self.stat_data.lock().await;
47            stat.push_score(score)
48        };
49        self.score.store(updated_score, Ordering::Release);
50        updated_score
51    }
52
53    /// Append a `Score` into statistic and recalculate score of the server
54    pub async fn push_score_fetch_statistic(&self, score: Score) -> (u32, ServerStatData) {
55        let (updated_score, data) = {
56            let mut stat = self.stat_data.lock().await;
57            (stat.push_score(score), *stat.data())
58        };
59        self.score.store(updated_score, Ordering::Release);
60        (updated_score, data)
61    }
62
63    /// Report request failure of this server, which will eventually records an `Errored` score
64    pub async fn report_failure(&self) -> u32 {
65        self.push_score(Score::Errored).await
66    }
67
68    /// Get statistic data
69    pub async fn stat_data(&self) -> ServerStatData {
70        *self.stat_data.lock().await.data()
71    }
72}
73
74impl Debug for ServerScore {
75    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76        f.debug_struct("ServerScore").field("score", &self.score()).finish()
77    }
78}
79
80/// Identifer for a server
81#[derive(Debug)]
82pub struct ServerIdent {
83    tcp_score: ServerScore,
84    udp_score: ServerScore,
85    svr_cfg: ServerInstanceConfig,
86    connect_opts: ConnectOpts,
87}
88
89impl ServerIdent {
90    /// Create a `ServerIdent`
91    pub fn new(
92        context: Arc<ServiceContext>,
93        svr_cfg: ServerInstanceConfig,
94        max_server_rtt: Duration,
95        check_window: Duration,
96    ) -> Self {
97        let mut connect_opts = context.connect_opts_ref().clone();
98
99        #[cfg(any(target_os = "linux", target_os = "android"))]
100        if let Some(fwmark) = svr_cfg.outbound_fwmark {
101            connect_opts.fwmark = Some(fwmark);
102        }
103
104        #[cfg(target_os = "freebsd")]
105        if let Some(user_cookie) = svr_cfg.outbound_user_cookie {
106            connect_opts.user_cookie = Some(user_cookie);
107        }
108
109        if let Some(bind_local_addr) = svr_cfg.outbound_bind_addr {
110            connect_opts.bind_local_addr = Some(SocketAddr::new(bind_local_addr, 0));
111        }
112
113        if let Some(ref bind_interface) = svr_cfg.outbound_bind_interface {
114            connect_opts.bind_interface = Some(bind_interface.clone());
115        }
116
117        Self {
118            tcp_score: ServerScore::new(svr_cfg.config.weight().tcp_weight(), max_server_rtt, check_window),
119            udp_score: ServerScore::new(svr_cfg.config.weight().udp_weight(), max_server_rtt, check_window),
120            svr_cfg,
121            connect_opts,
122        }
123    }
124
125    pub fn connect_opts_ref(&self) -> &ConnectOpts {
126        &self.connect_opts
127    }
128
129    pub fn server_config(&self) -> &ServerConfig {
130        &self.svr_cfg.config
131    }
132
133    pub fn server_config_mut(&mut self) -> &mut ServerConfig {
134        &mut self.svr_cfg.config
135    }
136
137    pub fn server_instance_config(&self) -> &ServerInstanceConfig {
138        &self.svr_cfg
139    }
140
141    pub fn tcp_score(&self) -> &ServerScore {
142        &self.tcp_score
143    }
144
145    pub fn udp_score(&self) -> &ServerScore {
146        &self.udp_score
147    }
148}