mirror of
https://github.com/telemt/telemt.git
synced 2026-11-01 21:31:58 +03:00
Carriers Auto-negotiation Aggressiveness
Co-Authored-By: brekotis <93345790+brekotis@users.noreply.github.com>
This commit is contained in:
@@ -264,6 +264,7 @@ const WEB_CONFIG_KEYS: &[&str] = &[
|
||||
"carrier",
|
||||
"carriers",
|
||||
"carrier_learning",
|
||||
"carrier_negotiation_aggressiveness",
|
||||
"debug",
|
||||
"limits",
|
||||
"timeouts",
|
||||
@@ -278,10 +279,14 @@ const WEB_LIMITS_CONFIG_KEYS: &[&str] = &[
|
||||
"max_frames_per_body",
|
||||
"max_http_connections",
|
||||
"max_http_handlers",
|
||||
"max_lane_open_waits_per_session",
|
||||
"pending_bytes_per_lane",
|
||||
"pending_items_per_lane",
|
||||
"websocket_bytes_global",
|
||||
"websocket_admission_watermark_pct",
|
||||
"websocket_eviction_watermark_pct",
|
||||
"websocket_http_connection_reserve",
|
||||
"max_websocket_evictions_in_flight",
|
||||
"max_carrier_learning_entries",
|
||||
"max_body_readers",
|
||||
"max_body_bytes_global",
|
||||
@@ -332,7 +337,12 @@ const WEB_TIMEOUTS_CONFIG_KEYS: &[&str] = &[
|
||||
"header_secs",
|
||||
"body_secs",
|
||||
"stream_handshake_secs",
|
||||
"stream_first_byte_secs",
|
||||
"long_poll_secs",
|
||||
"lane_open_wait_secs",
|
||||
"carrier_health_secs",
|
||||
"websocket_upgrade_secs",
|
||||
"websocket_open_secs",
|
||||
"websocket_write_secs",
|
||||
"websocket_backpressure_secs",
|
||||
"websocket_eviction_secs",
|
||||
|
||||
@@ -72,9 +72,9 @@ pub(super) fn validate(config: &mut ProxyConfig) -> Result<()> {
|
||||
validate_limits(&config.web.limits)?;
|
||||
debug::validate(&config.web.debug, &config.web.limits)?;
|
||||
let carriers = negotiation::validate(&config.web)?;
|
||||
if carriers.contains(&WebCarrier::HttpsLanes) && config.web.limits.max_http_handlers < 2 {
|
||||
if carriers.contains(&WebCarrier::HttpsLanes) && config.web.limits.max_http_handlers < 4 {
|
||||
return config_error(
|
||||
"WEB https-lanes candidates require web.limits.max_http_handlers >= 2",
|
||||
"WEB https-lanes candidates require web.limits.max_http_handlers >= 4",
|
||||
);
|
||||
}
|
||||
timeouts::validate(&config.web.timeouts)?;
|
||||
@@ -162,6 +162,16 @@ fn validate_limits(limits: &WebLimitsConfig) -> Result<()> {
|
||||
let positive = [
|
||||
("max_http_connections", limits.max_http_connections),
|
||||
("max_http_handlers", limits.max_http_handlers),
|
||||
(
|
||||
"max_lane_open_waits_per_session",
|
||||
limits.max_lane_open_waits_per_session,
|
||||
),
|
||||
("pending_bytes_per_lane", limits.pending_bytes_per_lane),
|
||||
("pending_items_per_lane", limits.pending_items_per_lane),
|
||||
(
|
||||
"max_websocket_evictions_in_flight",
|
||||
limits.max_websocket_evictions_in_flight,
|
||||
),
|
||||
(
|
||||
"max_carrier_learning_entries",
|
||||
limits.max_carrier_learning_entries,
|
||||
@@ -240,6 +250,8 @@ fn validate_limits(limits: &WebLimitsConfig) -> Result<()> {
|
||||
|| limits.max_body_readers > limits.max_http_handlers
|
||||
|| limits.pending_bytes_per_session > limits.pending_bytes_global
|
||||
|| limits.pending_items_per_session > limits.pending_items_global
|
||||
|| limits.pending_bytes_per_lane > limits.pending_bytes_per_session
|
||||
|| limits.pending_items_per_lane > limits.pending_items_per_session
|
||||
|| limits.control_bytes_per_session > limits.control_bytes_global
|
||||
|| limits.control_bytes_per_session > limits.pending_bytes_per_session
|
||||
|| limits.control_bytes_global > limits.pending_bytes_global
|
||||
|
||||
@@ -14,6 +14,14 @@ pub(super) fn validate(config: &WebConfig) -> Result<Vec<WebCarrier>> {
|
||||
}
|
||||
}
|
||||
let candidates = config.carrier_candidates();
|
||||
if config.carrier_negotiation_enabled()
|
||||
&& config.carrier_learning
|
||||
&& config.limits.max_carrier_learning_entries < 3
|
||||
{
|
||||
return config_error(
|
||||
"web.limits.max_carrier_learning_entries must be >= 3 when carrier learning is enabled",
|
||||
);
|
||||
}
|
||||
if candidates.len() > WebCarrier::ALL.len() {
|
||||
return config_error(
|
||||
"web.carriers and the web.carrier fallback must contain at most four carriers",
|
||||
|
||||
@@ -6,7 +6,12 @@ pub(super) fn validate(timeouts: &WebTimeoutsConfig) -> Result<()> {
|
||||
("header_secs", timeouts.header_secs),
|
||||
("body_secs", timeouts.body_secs),
|
||||
("stream_handshake_secs", timeouts.stream_handshake_secs),
|
||||
("stream_first_byte_secs", timeouts.stream_first_byte_secs),
|
||||
("long_poll_secs", timeouts.long_poll_secs),
|
||||
("lane_open_wait_secs", timeouts.lane_open_wait_secs),
|
||||
("carrier_health_secs", timeouts.carrier_health_secs),
|
||||
("websocket_upgrade_secs", timeouts.websocket_upgrade_secs),
|
||||
("websocket_open_secs", timeouts.websocket_open_secs),
|
||||
("websocket_write_secs", timeouts.websocket_write_secs),
|
||||
(
|
||||
"websocket_backpressure_secs",
|
||||
|
||||
+2
-2
@@ -53,8 +53,8 @@ pub use server::{
|
||||
};
|
||||
#[allow(unused_imports)]
|
||||
pub use web::{
|
||||
WebConfig, WebDecoyConfig, WebLimitsConfig, WebProfileConfig, WebSecretMode, WebTimeoutsConfig,
|
||||
WebVhostConfig,
|
||||
WebCarrierNegotiationAggressiveness, WebConfig, WebDecoyConfig, WebLimitsConfig,
|
||||
WebProfileConfig, WebSecretMode, WebTimeoutsConfig, WebVhostConfig,
|
||||
};
|
||||
#[allow(unused_imports)]
|
||||
pub use web_carrier::{WebCarrier, WebCarriers};
|
||||
|
||||
@@ -98,6 +98,15 @@ pub struct WebLimitsConfig {
|
||||
/// Process-wide concurrently executing HTTP handler ceiling.
|
||||
#[serde(default = "default_web_max_http_handlers")]
|
||||
pub max_http_handlers: usize,
|
||||
/// Per-session ceiling for downlink polls waiting for a lane OPEN.
|
||||
#[serde(default = "default_web_max_lane_open_waits_per_session")]
|
||||
pub max_lane_open_waits_per_session: usize,
|
||||
/// Queued and in-flight downlink bytes allowed for one independent lane.
|
||||
#[serde(default = "default_web_pending_bytes_per_lane")]
|
||||
pub pending_bytes_per_lane: usize,
|
||||
/// Queued and in-flight downlink items allowed for one independent lane.
|
||||
#[serde(default = "default_web_pending_items_per_lane")]
|
||||
pub pending_items_per_lane: usize,
|
||||
/// Process-wide transient WebSocket byte sub-budget inside pending bytes.
|
||||
#[serde(default = "default_web_websocket_bytes_global")]
|
||||
pub websocket_bytes_global: usize,
|
||||
@@ -110,6 +119,9 @@ pub struct WebLimitsConfig {
|
||||
/// Accepted HTTP connections that WebSocket upgrades must leave available.
|
||||
#[serde(default = "default_web_websocket_http_connection_reserve")]
|
||||
pub websocket_http_connection_reserve: usize,
|
||||
/// Concurrent pressure-eviction claims allowed process-wide.
|
||||
#[serde(default = "default_web_max_websocket_evictions_in_flight")]
|
||||
pub max_websocket_evictions_in_flight: usize,
|
||||
/// Process-wide bounded carrier-learning evidence entry ceiling.
|
||||
#[serde(default = "default_web_max_carrier_learning_entries")]
|
||||
pub max_carrier_learning_entries: usize,
|
||||
@@ -215,10 +227,15 @@ impl Default for WebLimitsConfig {
|
||||
max_frames_per_body: default_web_max_frames_per_body(),
|
||||
max_http_connections: default_web_max_http_connections(),
|
||||
max_http_handlers: default_web_max_http_handlers(),
|
||||
max_lane_open_waits_per_session: default_web_max_lane_open_waits_per_session(),
|
||||
pending_bytes_per_lane: default_web_pending_bytes_per_lane(),
|
||||
pending_items_per_lane: default_web_pending_items_per_lane(),
|
||||
websocket_bytes_global: default_web_websocket_bytes_global(),
|
||||
websocket_admission_watermark_pct: default_web_websocket_admission_watermark_pct(),
|
||||
websocket_eviction_watermark_pct: default_web_websocket_eviction_watermark_pct(),
|
||||
websocket_http_connection_reserve: default_web_websocket_http_connection_reserve(),
|
||||
max_websocket_evictions_in_flight:
|
||||
default_web_max_websocket_evictions_in_flight(),
|
||||
max_carrier_learning_entries: default_web_max_carrier_learning_entries(),
|
||||
max_body_readers: default_web_max_body_readers(),
|
||||
max_body_bytes_global: default_web_max_body_bytes_global(),
|
||||
@@ -266,9 +283,24 @@ pub struct WebTimeoutsConfig {
|
||||
/// Deadline from the first inner byte through MTProxy authentication.
|
||||
#[serde(default = "default_web_stream_handshake_timeout_secs")]
|
||||
pub stream_handshake_secs: u64,
|
||||
/// Absolute deadline for receiving the first inner MTProxy byte.
|
||||
#[serde(default = "default_web_stream_first_byte_secs")]
|
||||
pub stream_first_byte_secs: u64,
|
||||
/// Maximum wait for one empty downlink long poll.
|
||||
#[serde(default = "default_web_long_poll_timeout_secs")]
|
||||
pub long_poll_secs: u64,
|
||||
/// Grace for a canonical downlink poll that races its lane OPEN.
|
||||
#[serde(default = "default_web_lane_open_wait_secs")]
|
||||
pub lane_open_wait_secs: u64,
|
||||
/// Post-commit observation interval required before learning succeeds.
|
||||
#[serde(default = "default_web_carrier_health_secs")]
|
||||
pub carrier_health_secs: u64,
|
||||
/// Maximum wait for Hyper to transfer an accepted WebSocket upgrade.
|
||||
#[serde(default = "default_web_websocket_upgrade_secs")]
|
||||
pub websocket_upgrade_secs: u64,
|
||||
/// Absolute deadline for the first carrier binary message after upgrade.
|
||||
#[serde(default = "default_web_websocket_open_secs")]
|
||||
pub websocket_open_secs: u64,
|
||||
/// Maximum wait for one WebSocket write to complete.
|
||||
#[serde(default = "default_web_websocket_write_secs")]
|
||||
pub websocket_write_secs: u64,
|
||||
@@ -307,7 +339,12 @@ impl Default for WebTimeoutsConfig {
|
||||
header_secs: default_web_header_timeout_secs(),
|
||||
body_secs: default_web_body_timeout_secs(),
|
||||
stream_handshake_secs: default_web_stream_handshake_timeout_secs(),
|
||||
stream_first_byte_secs: default_web_stream_first_byte_secs(),
|
||||
long_poll_secs: default_web_long_poll_timeout_secs(),
|
||||
lane_open_wait_secs: default_web_lane_open_wait_secs(),
|
||||
carrier_health_secs: default_web_carrier_health_secs(),
|
||||
websocket_upgrade_secs: default_web_websocket_upgrade_secs(),
|
||||
websocket_open_secs: default_web_websocket_open_secs(),
|
||||
websocket_write_secs: default_web_websocket_write_secs(),
|
||||
websocket_backpressure_secs: default_web_websocket_backpressure_secs(),
|
||||
websocket_eviction_secs: default_web_websocket_eviction_secs(),
|
||||
@@ -323,6 +360,19 @@ impl Default for WebTimeoutsConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sensitivity of process-local carrier-learning evidence.
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum WebCarrierNegotiationAggressiveness {
|
||||
/// Require broad evidence and never rank by client IP.
|
||||
#[default]
|
||||
Conservative,
|
||||
/// Use moderate User-Agent, client-IP, and profile thresholds.
|
||||
Balanced,
|
||||
/// React to the first bounded evidence sample.
|
||||
Aggressive,
|
||||
}
|
||||
|
||||
/// WEB ingress, carrier, fallback, and lifecycle configuration.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct WebConfig {
|
||||
@@ -338,6 +388,9 @@ pub struct WebConfig {
|
||||
/// Enables bounded process-local carrier learning for automatic sessions.
|
||||
#[serde(default = "default_web_carrier_learning")]
|
||||
pub carrier_learning: bool,
|
||||
/// Controls the evidence thresholds used by automatic carrier ranking.
|
||||
#[serde(default)]
|
||||
pub carrier_negotiation_aggressiveness: WebCarrierNegotiationAggressiveness,
|
||||
/// Hard process and protocol limits.
|
||||
#[serde(default)]
|
||||
pub limits: WebLimitsConfig,
|
||||
@@ -381,6 +434,8 @@ impl Default for WebConfig {
|
||||
carrier: WebCarrier::default(),
|
||||
carriers: WebCarriers::default(),
|
||||
carrier_learning: default_web_carrier_learning(),
|
||||
carrier_negotiation_aggressiveness:
|
||||
WebCarrierNegotiationAggressiveness::default(),
|
||||
limits: WebLimitsConfig::default(),
|
||||
debug: WebDebugConfig::default(),
|
||||
timeouts: WebTimeoutsConfig::default(),
|
||||
|
||||
@@ -41,10 +41,14 @@ usize_default!(default_web_carrier_batch_bytes, 2 * 1024 * 1024);
|
||||
usize_default!(default_web_max_frames_per_body, 4096);
|
||||
usize_default!(default_web_max_http_connections, 1024);
|
||||
usize_default!(default_web_max_http_handlers, 512);
|
||||
usize_default!(default_web_max_lane_open_waits_per_session, 16);
|
||||
usize_default!(default_web_pending_bytes_per_lane, 8 * 1024 * 1024);
|
||||
usize_default!(default_web_pending_items_per_lane, 1024);
|
||||
usize_default!(default_web_websocket_bytes_global, 256 * 1024 * 1024);
|
||||
u8_default!(default_web_websocket_admission_watermark_pct, 75);
|
||||
u8_default!(default_web_websocket_eviction_watermark_pct, 90);
|
||||
usize_default!(default_web_websocket_http_connection_reserve, 64);
|
||||
usize_default!(default_web_max_websocket_evictions_in_flight, 8);
|
||||
usize_default!(default_web_max_carrier_learning_entries, 4096);
|
||||
usize_default!(default_web_max_body_readers, 32);
|
||||
usize_default!(default_web_max_body_bytes_global, 64 * 1024 * 1024);
|
||||
@@ -79,7 +83,12 @@ u32_default!(default_web_new_streams_burst, 512);
|
||||
u64_default!(default_web_header_timeout_secs, 10);
|
||||
u64_default!(default_web_body_timeout_secs, 30);
|
||||
u64_default!(default_web_stream_handshake_timeout_secs, 10);
|
||||
u64_default!(default_web_stream_first_byte_secs, 30);
|
||||
u64_default!(default_web_long_poll_timeout_secs, 25);
|
||||
u64_default!(default_web_lane_open_wait_secs, 2);
|
||||
u64_default!(default_web_carrier_health_secs, 30);
|
||||
u64_default!(default_web_websocket_upgrade_secs, 5);
|
||||
u64_default!(default_web_websocket_open_secs, 15);
|
||||
u64_default!(default_web_websocket_write_secs, 30);
|
||||
u64_default!(default_web_websocket_backpressure_secs, 30);
|
||||
u64_default!(default_web_websocket_eviction_secs, 1);
|
||||
|
||||
Reference in New Issue
Block a user