From 7cb29b1117d8ee942e48ce305e952680e8ed3d7e Mon Sep 17 00:00:00 2001 From: lc Date: Sun, 16 Nov 2025 18:43:31 +0800 Subject: [PATCH] add ice-servers config --- src/config.rs | 2 ++ src/socket_client.rs | 4 +-- src/webrtc.rs | 82 ++++++++++++++++++++++++++++++-------------- 3 files changed, 61 insertions(+), 27 deletions(-) diff --git a/src/config.rs b/src/config.rs index 5166749..212a22f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2550,6 +2550,7 @@ pub mod keys { pub const OPTION_TRACKPAD_SPEED: &str = "trackpad-speed"; pub const OPTION_REGISTER_DEVICE: &str = "register-device"; pub const OPTION_RELAY_SERVER: &str = "relay-server"; + pub const OPTION_ICE_SERVERS: &str = "ice-servers"; pub const OPTION_DISABLE_UDP: &str = "disable-udp"; pub const OPTION_ALLOW_INSECURE_TLS_FALLBACK: &str = "allow-insecure-tls-fallback"; pub const OPTION_SHOW_VIRTUAL_MOUSE: &str = "show-virtual-mouse"; @@ -2746,6 +2747,7 @@ pub mod keys { OPTION_ENABLE_ANDROID_SOFTWARE_ENCODING_HALF_SCALE, OPTION_ENABLE_TRUSTED_DEVICES, OPTION_RELAY_SERVER, + OPTION_ICE_SERVERS, OPTION_DISABLE_UDP, OPTION_ALLOW_INSECURE_TLS_FALLBACK, ]; diff --git a/src/socket_client.rs b/src/socket_client.rs index 0e898b8..9178b74 100644 --- a/src/socket_client.rs +++ b/src/socket_client.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "webrtc")] +use crate::webrtc::{self, is_webrtc_endpoint}; use crate::{ config::{Config, NetworkType}, tcp::FramedStream, @@ -5,8 +7,6 @@ use crate::{ websocket::{self, check_ws, is_ws_endpoint}, ResultType, Stream, }; -#[cfg(feature = "webrtc")] -use crate::webrtc::{self, is_webrtc_endpoint}; use anyhow::Context; use std::{net::SocketAddr, sync::Arc}; use tokio::net::{ToSocketAddrs, UdpSocket}; diff --git a/src/webrtc.rs b/src/webrtc.rs index 7cdfc25..c0b5be9 100644 --- a/src/webrtc.rs +++ b/src/webrtc.rs @@ -138,14 +138,15 @@ impl WebRTCStream { } #[inline] - fn get_turn_server_from_url(url: &str) -> Option { + fn get_ice_server_from_url(url: &str) -> Option { // standard url format with turn scheme: turn://user:pass@host:port match Url::parse(url) { Ok(u) => { - if u.scheme() == "turn" { + if u.scheme() == "turn" || u.scheme() == "stun" { Some(RTCIceServer { urls: vec![format!( - "turn:{}:{}", + "{}:{}:{}", + u.scheme(), u.host_str().unwrap_or_default(), u.port().unwrap_or(3478) )], @@ -161,6 +162,24 @@ impl WebRTCStream { } } + #[inline] + fn get_ice_servers() -> Vec { + let mut ice_servers = Vec::new(); + let cfg = config::Config::get_option(config::keys::OPTION_ICE_SERVERS); + for url in cfg.split(',').map(str::trim) { + if let Some(ice_server) = Self::get_ice_server_from_url(url) { + ice_servers.push(ice_server); + } + } + if ice_servers.is_empty() { + ice_servers.push(RTCIceServer { + urls: DEFAULT_ICE_SERVERS.iter().map(|s| s.to_string()).collect(), + ..Default::default() + }); + } + ice_servers + } + pub async fn new( remote_endpoint: &str, force_relay: bool, @@ -191,21 +210,10 @@ impl WebRTCStream { // Create the API object let api = APIBuilder::new().with_setting_engine(s).build(); - let mut ice_servers = vec![RTCIceServer { - urls: DEFAULT_ICE_SERVERS.iter().map(|s| s.to_string()).collect(), - ..Default::default() - }]; - if start_local_offer { - // only offer needs TURN server - let relay_server = config::Config::get_option(config::keys::OPTION_RELAY_SERVER); - if let Some(turn_server) = Self::get_turn_server_from_url(&relay_server) { - ice_servers.push(turn_server); - } - } - // Prepare the configuration + // Prepare the configuration, get ICE servers from config let config = RTCConfiguration { - ice_servers, + ice_servers: Self::get_ice_servers(), ice_transport_policy: if force_relay { RTCIceTransportPolicy::Relay } else { @@ -458,55 +466,79 @@ pub fn is_webrtc_endpoint(endpoint: &str) -> bool { #[cfg(test)] mod tests { + use crate::config; + use crate::webrtc::DEFAULT_ICE_SERVERS; use crate::webrtc::WebRTCStream; use webrtc::peer_connection::sdp::session_description::RTCSessionDescription; #[test] - fn test_webrtc_turn_url() { + fn test_webrtc_ice_url() { assert_eq!( - WebRTCStream::get_turn_server_from_url("turn://example.com:3478") + WebRTCStream::get_ice_server_from_url("turn://example.com:3478") .unwrap_or_default() .urls[0], "turn:example.com:3478" ); assert_eq!( - WebRTCStream::get_turn_server_from_url("turn://example.com") + WebRTCStream::get_ice_server_from_url("turn://example.com") .unwrap_or_default() .urls[0], "turn:example.com:3478" ); assert_eq!( - WebRTCStream::get_turn_server_from_url("turn://123@example.com") + WebRTCStream::get_ice_server_from_url("turn://123@example.com") .unwrap_or_default() .username, "123" ); assert_eq!( - WebRTCStream::get_turn_server_from_url("turn://123@example.com") + WebRTCStream::get_ice_server_from_url("turn://123@example.com") .unwrap_or_default() .credential, "" ); assert_eq!( - WebRTCStream::get_turn_server_from_url("turn://123:321@example.com") + WebRTCStream::get_ice_server_from_url("turn://123:321@example.com") .unwrap_or_default() .credential, "321" ); assert_eq!( - WebRTCStream::get_turn_server_from_url("stun://example.com:3478"), - None + WebRTCStream::get_ice_server_from_url("stun://example.com:3478") + .unwrap_or_default() + .urls[0], + "stun:example.com:3478" ); assert_eq!( - WebRTCStream::get_turn_server_from_url("http://123:123@example.com:3478"), + WebRTCStream::get_ice_server_from_url("http://123:123@example.com:3478"), None ); + + config::Config::set_option("ice-servers".to_string(), "".to_string()); + assert_eq!( + WebRTCStream::get_ice_servers()[0].urls[0], + DEFAULT_ICE_SERVERS[0].to_string() + ); + + config::Config::set_option("ice-servers".to_string(), ",stun://example.com,turn://example.com,sdf".to_string()); + assert_eq!( + WebRTCStream::get_ice_servers()[0].urls[0], + "stun:example.com:3478" + ); + assert_eq!( + WebRTCStream::get_ice_servers()[1].urls[0], + "turn:example.com:3478" + ); + assert_eq!( + WebRTCStream::get_ice_servers().len(), + 2 + ); } #[test]