Compare commits

...

11 Commits

Author SHA1 Message Date
mike 0c49f9a29c proto: backport HttpProxyRequest/Response (tags 27, 28)
Backports the HeaderEntry / HttpProxyRequest / HttpProxyResponse messages
and the corresponding union tags from upstream rustdesk/hbb_common
@87b11a7 onto the OSS server's pinned commit @83419b6 — wire-compatible
with the client-side encoder in rustdesk's src/common.rs::tcp_proxy_request.

Cherry-pick over a full submodule bump because the upstream commit pulls
newer transitive deps (notably tokio) that risk breaking axum 0.5 in the
hbbs HTTP layer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 19:27:57 +02:00
RustDesk 83419b6549 Merge pull request #53 from 21pages/allow-https-21114
buildin option `allow-https-21114`
2025-03-06 09:20:35 +08:00
21pages 6338940d7a buildin option allow-https-21114
Signed-off-by: 21pages <sunboeasy@gmail.com>
2025-03-06 00:05:13 +08:00
RustDesk 7cf11f7b77 Merge pull request #33 from hadfl/illumos
add illumos support
2025-02-23 08:50:46 +08:00
Dominik Hassler 073bae1e73 add illumos support 2025-02-22 19:16:55 +00:00
RustDesk 16900b9b06 Merge pull request #28 from fufesou/refact/optimize_preload_peers
refact: optimize, preload peers.
2025-02-20 16:31:20 +08:00
fufesou 33487a0b14 refact: optimize, preload peers.
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-20 15:33:15 +08:00
RustDesk f94753bddb Merge pull request #27 from fufesou/refact/preload_peers
refact, reload peers
2025-02-20 09:31:50 +08:00
fufesou e608898d08 refact, reload peers
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-20 09:27:57 +08:00
RustDesk 0d7f746291 Merge pull request #24 from fufesou/refact/optimize_preload_peers
refact: optimize, preload peers
2025-02-20 01:14:56 +08:00
fufesou f7f0e19223 refact: optimize, preload peers
Signed-off-by: fufesou <linlong1266@gmail.com>
2025-02-19 23:25:18 +08:00
5 changed files with 181 additions and 50 deletions
+1 -1
View File
@@ -78,7 +78,7 @@ message LoginRequest {
oneof union {
FileTransfer file_transfer = 7;
PortForward port_forward = 8;
ViewCamera view_camera = 9;
ViewCamera view_camera = 15;
}
bool video_ack_required = 9;
uint64 session_id = 10;
+25
View File
@@ -170,6 +170,29 @@ message HealthCheck {
string token = 1;
}
// Backported from upstream rustdesk/hbb_common @ 87b11a7 so the OSS hbbs
// can implement the HTTP-over-rendezvous fallback the client uses when
// OPTION_USE_RAW_TCP_FOR_API=Y. Wire-compatible with the client; only the
// three message types and tags 27/28 are added.
message HeaderEntry {
string name = 1;
string value = 2;
}
message HttpProxyRequest {
string method = 1;
string path = 2;
repeated HeaderEntry headers = 3;
bytes body = 4;
}
message HttpProxyResponse {
int32 status = 1;
repeated HeaderEntry headers = 2;
bytes body = 3;
string error = 4;
}
message RendezvousMessage {
oneof union {
RegisterPeer register_peer = 6;
@@ -193,5 +216,7 @@ message RendezvousMessage {
OnlineResponse online_response = 24;
KeyExchange key_exchange = 25;
HealthCheck hc = 26;
HttpProxyRequest http_proxy_request = 27;
HttpProxyResponse http_proxy_response = 28;
}
}
+147 -45
View File
@@ -1214,7 +1214,7 @@ impl PeerConfig {
}
}
if store {
config.store(id);
config.store_(id);
}
config
}
@@ -1232,6 +1232,10 @@ impl PeerConfig {
pub fn store(&self, id: &str) {
let _lock = CONFIG.read().unwrap();
self.store_(id);
}
fn store_(&self, id: &str) {
let mut config = self.clone();
config.password =
encrypt_vec_or_original(&config.password, PASSWORD_ENC_VERSION, ENCRYPT_MAX_LEN);
@@ -1269,55 +1273,151 @@ impl PeerConfig {
Config::with_extension(Config::path(path))
}
pub fn peers(id_filters: Option<Vec<String>>) -> Vec<(String, SystemTime, PeerConfig)> {
if let Ok(peers) = Config::path(PEERS).read_dir() {
if let Ok(peers) = peers
.map(|res| res.map(|e| e.path()))
.collect::<Result<Vec<_>, _>>()
{
let mut peers: Vec<_> = peers
.iter()
.filter(|p| {
p.is_file()
&& p.extension().map(|p| p.to_str().unwrap_or("")) == Some("toml")
})
.map(|p| {
let id = p
.file_stem()
.map(|p| p.to_str().unwrap_or(""))
.unwrap_or("")
.to_owned();
// The number of peers to load in the first round when showing the peers card list in the main window.
// When there're too many peers, loading all of them at once will take a long time.
// We can load them in two rouds, the first round loads the first 100 peers, and the second round loads the rest.
// Then the UI will show the first 100 peers first, and the rest will be loaded and shown later.
pub const BATCH_LOADING_COUNT: usize = 100;
let id_decoded_string = if id.starts_with("base64_") && id.len() != 7 {
let id_decoded = base64::decode(&id[7..], base64::Variant::Original)
.unwrap_or_default();
String::from_utf8_lossy(&id_decoded).as_ref().to_owned()
pub fn get_vec_id_modified_time_path(
id_filters: &Option<Vec<String>>,
) -> Vec<(String, SystemTime, PathBuf)> {
if let Ok(peers) = Config::path(PEERS).read_dir() {
let mut vec_id_modified_time_path = peers
.into_iter()
.filter_map(|res| match res {
Ok(res) => {
let p = res.path();
if p.is_file()
&& p.extension().map(|p| p.to_str().unwrap_or("")) == Some("toml")
{
Some(p)
} else {
id
};
(id_decoded_string, p)
})
.filter(|(id, _)| {
let Some(filters) = &id_filters else {
return true;
};
filters.contains(id)
})
.map(|(id, p)| {
let t = crate::get_modified_time(p);
let c = PeerConfig::load(&id);
if c.info.platform.is_empty() {
fs::remove_file(p).ok();
None
}
(id, t, c)
})
.filter(|p| !p.2.info.platform.is_empty())
.collect();
peers.sort_unstable_by(|a, b| b.1.cmp(&a.1));
return peers;
}
_ => None,
})
.map(|p| {
let id = p
.file_stem()
.map(|p| p.to_str().unwrap_or(""))
.unwrap_or("")
.to_owned();
let id_decoded_string = if id.starts_with("base64_") && id.len() != 7 {
let id_decoded =
base64::decode(&id[7..], base64::Variant::Original).unwrap_or_default();
String::from_utf8_lossy(&id_decoded).as_ref().to_owned()
} else {
id
};
(id_decoded_string, p)
})
.filter(|(id, _)| {
let Some(filters) = id_filters else {
return true;
};
filters.contains(id)
})
.map(|(id, p)| {
let t = crate::get_modified_time(&p);
(id, t, p)
})
.collect::<Vec<_>>();
vec_id_modified_time_path.sort_unstable_by(|a, b| b.1.cmp(&a.1));
vec_id_modified_time_path
} else {
vec![]
}
}
#[inline]
async fn preload_file_async(path: PathBuf) {
let _ = tokio::fs::File::open(path).await;
}
#[tokio::main(flavor = "current_thread")]
async fn preload_peers_async() {
let now = std::time::Instant::now();
let vec_id_modified_time_path = Self::get_vec_id_modified_time_path(&None);
let total_count = vec_id_modified_time_path.len();
let mut futs = vec![];
for (_, _, path) in vec_id_modified_time_path.into_iter() {
futs.push(Self::preload_file_async(path));
if futs.len() >= Self::BATCH_LOADING_COUNT {
let first_load_start = std::time::Instant::now();
futures::future::join_all(futs).await;
if first_load_start.elapsed().as_millis() < 10 {
// No need to preload the rest if the first load is fast.
return;
}
futs = vec![];
}
}
Default::default()
if !futs.is_empty() {
futures::future::join_all(futs).await;
}
log::info!(
"Preload peers done in {:?}, batch_count: {}, total: {}",
now.elapsed(),
Self::BATCH_LOADING_COUNT,
total_count
);
}
// We have to preload all peers in a background thread.
// Because we find that opening files the first time after the system (Windows) booting will be very slow, up to 200~400ms.
// The reason is that the Windows has "Microsoft Defender Antivirus Service" running in the background, which will scan the file when it's opened the first time.
// So we have to preload all peers in a background thread to avoid the delay when opening the file the first time.
// We can temporarily stop "Microsoft Defender Antivirus Service" or add the fold to the white list, to verify this. But don't do this in the release version.
pub fn preload_peers() {
std::thread::spawn(|| {
Self::preload_peers_async();
});
}
pub fn peers(id_filters: Option<Vec<String>>) -> Vec<(String, SystemTime, PeerConfig)> {
let vec_id_modified_time_path = Self::get_vec_id_modified_time_path(&id_filters);
Self::batch_peers(
&vec_id_modified_time_path,
0,
Some(vec_id_modified_time_path.len()),
)
.0
}
pub fn batch_peers(
all: &Vec<(String, SystemTime, PathBuf)>,
from: usize,
to: Option<usize>,
) -> (Vec<(String, SystemTime, PeerConfig)>, usize) {
if from >= all.len() {
return (vec![], 0);
}
let to = match to {
Some(to) => to.min(all.len()),
None => (from + Self::BATCH_LOADING_COUNT).min(all.len()),
};
// to <= from is unexpected, but we can just return an empty vec in this case.
if to <= from {
return (vec![], from);
}
let peers: Vec<_> = all[from..to]
.iter()
.map(|(id, t, p)| {
let c = PeerConfig::load(&id);
if c.info.platform.is_empty() {
fs::remove_file(p).ok();
}
(id.clone(), t.clone(), c)
})
.filter(|p| !p.2.info.platform.is_empty())
.collect();
(peers, to)
}
pub fn exists(id: &str) -> bool {
@@ -2265,6 +2365,7 @@ pub mod keys {
pub const OPTION_ONE_WAY_CLIPBOARD_REDIRECTION: &str = "one-way-clipboard-redirection";
pub const OPTION_ALLOW_LOGON_SCREEN_PASSWORD: &str = "allow-logon-screen-password";
pub const OPTION_ONE_WAY_FILE_TRANSFER: &str = "one-way-file-transfer";
pub const OPTION_ALLOW_HTTPS_21114: &str = "allow-https-21114";
// flutter local options
pub const OPTION_FLUTTER_REMOTE_MENUBAR_STATE: &str = "remoteMenubarState";
@@ -2417,6 +2518,7 @@ pub mod keys {
OPTION_ONE_WAY_CLIPBOARD_REDIRECTION,
OPTION_ALLOW_LOGON_SCREEN_PASSWORD,
OPTION_ONE_WAY_FILE_TRANSFER,
OPTION_ALLOW_HTTPS_21114,
];
}
+5 -2
View File
@@ -68,10 +68,11 @@ pub(crate) fn new_socket(addr: std::net::SocketAddr, reuse: bool) -> Result<TcpS
std::net::SocketAddr::V6(..) => TcpSocket::new_v6()?,
};
if reuse {
// windows has no reuse_port, but it's reuse_address
// windows has no reuse_port, but its reuse_address
// almost equals to unix's reuse_port + reuse_address,
// though may introduce nondeterministic behavior
#[cfg(unix)]
// illumos has no support for SO_REUSEPORT
#[cfg(all(unix, not(target_os = "illumos")))]
socket.set_reuseport(true).ok();
socket.set_reuseaddr(true).ok();
}
@@ -226,6 +227,8 @@ pub async fn listen_any(port: u16) -> ResultType<TcpListener> {
if let Ok(mut socket) = TcpSocket::new_v6() {
#[cfg(unix)]
{
// illumos has no support for SO_REUSEPORT
#[cfg(not(target_os = "illumos"))]
socket.set_reuseport(true).ok();
socket.set_reuseaddr(true).ok();
use std::os::unix::io::{FromRawFd, IntoRawFd};
+3 -2
View File
@@ -20,10 +20,11 @@ fn new_socket(addr: SocketAddr, reuse: bool, buf_size: usize) -> Result<Socket,
SocketAddr::V6(..) => Socket::new(Domain::ipv6(), Type::dgram(), None),
}?;
if reuse {
// windows has no reuse_port, but it's reuse_address
// windows has no reuse_port, but its reuse_address
// almost equals to unix's reuse_port + reuse_address,
// though may introduce nondeterministic behavior
#[cfg(unix)]
// illumos has no support for SO_REUSEPORT
#[cfg(all(unix, not(target_os = "illumos")))]
socket.set_reuse_port(true).ok();
socket.set_reuse_address(true).ok();
}