Skip to content

Commit d04ae28

Browse files
authored
Merge pull request #137 from YinMo19/main
[enhance] Add websocket support.
2 parents ebb4d4a + d8f907a commit d04ae28

File tree

7 files changed

+341
-20
lines changed

7 files changed

+341
-20
lines changed

Cargo.toml

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,25 +46,36 @@ httparse = "1.10"
4646
base64 = "0.22"
4747
url = "2.5"
4848
sha2 = "0.10"
49-
tokio-tungstenite = "0.26"
49+
tokio-tungstenite = { version = "0.26.2" }
50+
tungstenite = { version = "0.26.2" }
51+
5052

5153
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
5254
mac_address = "1.1"
5355
default_net = { git = "https://github.com/rustdesk-org/default_net" }
5456
machine-uid = { git = "https://github.com/rustdesk-org/machine-uid" }
5557
[target.'cfg(not(any(target_os = "macos", target_os = "windows")))'.dependencies]
56-
tokio-rustls = { version = "0.26", features = ["logging", "tls12", "ring"], default-features = false }
58+
tokio-rustls = { version = "0.26", features = [
59+
"logging",
60+
"tls12",
61+
"ring",
62+
], default-features = false }
5763
rustls-platform-verifier = "0.5"
5864
rustls-pki-types = "1.11"
5965
[target.'cfg(any(target_os = "macos", target_os = "windows"))'.dependencies]
60-
tokio-native-tls ="0.3"
66+
tokio-native-tls = "0.3"
6167

6268
[build-dependencies]
6369
protobuf-codegen = { version = "3.7" }
6470

6571
[target.'cfg(target_os = "windows")'.dependencies]
66-
winapi = { version = "0.3", features = ["winuser", "synchapi", "pdh", "memoryapi", "sysinfoapi"] }
72+
winapi = { version = "0.3", features = [
73+
"winuser",
74+
"synchapi",
75+
"pdh",
76+
"memoryapi",
77+
"sysinfoapi",
78+
] }
6779

6880
[target.'cfg(target_os = "macos")'.dependencies]
6981
osascript = "0.3"
70-

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,10 @@ pub use toml;
5757
pub use uuid;
5858
pub mod fingerprint;
5959
pub use flexi_logger;
60+
pub mod websocket;
61+
pub mod stream;
62+
pub use stream::Stream;
6063

61-
pub type Stream = tcp::FramedStream;
6264
pub type SessionID = uuid::Uuid;
6365

6466
#[inline]

src/proxy.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const MAXIMUM_RESPONSE_HEADERS: usize = 16;
5656
const DEFINE_TIME_OUT: u64 = 600;
5757

5858
pub trait IntoUrl {
59-
59+
6060
// Besides parsing as a valid `Url`, the `Url` must be a valid
6161
// `http::Uri`, in that it makes sense to use in a network request.
6262
fn into_url(self) -> Result<Url, ProxyError>;

src/socket_client.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::{
22
config::{Config, NetworkType},
33
tcp::FramedStream,
44
udp::FramedSocket,
5-
ResultType,
5+
websocket, ResultType, Stream,
66
};
77
use anyhow::Context;
88
use std::net::SocketAddr;
@@ -102,7 +102,7 @@ pub async fn connect_tcp<
102102
>(
103103
target: T,
104104
ms_timeout: u64,
105-
) -> ResultType<FramedStream> {
105+
) -> ResultType<crate::Stream> {
106106
connect_tcp_local(target, None, ms_timeout).await
107107
}
108108

@@ -113,19 +113,35 @@ pub async fn connect_tcp_local<
113113
target: T,
114114
local: Option<SocketAddr>,
115115
ms_timeout: u64,
116-
) -> ResultType<FramedStream> {
117-
if let Some(conf) = Config::get_socks() {
118-
return FramedStream::connect(target, local, &conf, ms_timeout).await;
119-
}
120-
if let Some(target) = target.resolve() {
121-
if let Some(local) = local {
122-
if local.is_ipv6() && target.is_ipv4() {
123-
let target = query_nip_io(target).await?;
124-
return FramedStream::new(target, Some(local), ms_timeout).await;
116+
) -> ResultType<Stream> {
117+
let target_str = target.to_string();
118+
119+
if target_str.starts_with("ws://") || target_str.starts_with("wss://") {
120+
Ok(Stream::WebSocket(
121+
websocket::WsFramedStream::new(target_str, local, None, ms_timeout).await?,
122+
))
123+
} else {
124+
if let Some(conf) = Config::get_socks() {
125+
return Ok(Stream::Tcp(
126+
FramedStream::connect(target, local, &conf, ms_timeout).await?,
127+
));
128+
}
129+
130+
if let Some(target_addr) = target.resolve() {
131+
if let Some(local_addr) = local {
132+
if local_addr.is_ipv6() && target_addr.is_ipv4() {
133+
let resolved_target = query_nip_io(target_addr).await?;
134+
return Ok(Stream::Tcp(
135+
FramedStream::new(resolved_target, Some(local_addr), ms_timeout).await?,
136+
));
137+
}
125138
}
126139
}
140+
141+
Ok(Stream::Tcp(
142+
FramedStream::new(target, local, ms_timeout).await?,
143+
))
127144
}
128-
FramedStream::new(target, local, ms_timeout).await
129145
}
130146

131147
#[inline]

src/stream.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
use crate::{config, tcp, websocket, ResultType};
2+
use sodiumoxide::crypto::secretbox::Key;
3+
use std::net::SocketAddr;
4+
5+
// support Websocket and tcp.
6+
pub enum Stream {
7+
WebSocket(websocket::WsFramedStream),
8+
Tcp(tcp::FramedStream),
9+
}
10+
11+
impl Stream {
12+
#[inline]
13+
pub fn set_send_timeout(&mut self, ms: u64) {
14+
match self {
15+
Stream::WebSocket(s) => s.set_send_timeout(ms),
16+
Stream::Tcp(s) => s.set_send_timeout(ms),
17+
}
18+
}
19+
20+
#[inline]
21+
pub fn set_raw(&mut self) {
22+
match self {
23+
Stream::WebSocket(s) => s.set_raw(),
24+
Stream::Tcp(s) => s.set_raw(),
25+
}
26+
}
27+
28+
#[inline]
29+
pub async fn send_bytes(&mut self, bytes: bytes::Bytes) -> ResultType<()> {
30+
match self {
31+
Stream::WebSocket(s) => s.send_bytes(bytes).await,
32+
Stream::Tcp(s) => s.send_bytes(bytes).await,
33+
}
34+
}
35+
36+
#[inline]
37+
pub async fn send_raw(&mut self, bytes: Vec<u8>) -> ResultType<()> {
38+
match self {
39+
Stream::WebSocket(s) => s.send_raw(bytes).await,
40+
Stream::Tcp(s) => s.send_raw(bytes).await,
41+
}
42+
}
43+
44+
#[inline]
45+
pub fn set_key(&mut self, key: Key) {
46+
match self {
47+
Stream::WebSocket(s) => s.set_key(key),
48+
Stream::Tcp(s) => s.set_key(key),
49+
}
50+
}
51+
52+
#[inline]
53+
pub fn is_secured(&self) -> bool {
54+
match self {
55+
Stream::WebSocket(s) => s.is_secured(),
56+
Stream::Tcp(s) => s.is_secured(),
57+
}
58+
}
59+
60+
#[inline]
61+
pub async fn next_timeout(
62+
&mut self,
63+
timeout: u64,
64+
) -> Option<Result<bytes::BytesMut, std::io::Error>> {
65+
match self {
66+
Stream::WebSocket(s) => s.next_timeout(timeout).await,
67+
Stream::Tcp(s) => s.next_timeout(timeout).await,
68+
}
69+
}
70+
71+
/// establish connect from websocket
72+
#[inline]
73+
pub async fn connect_websocket(
74+
url: impl AsRef<str>,
75+
local_addr: Option<SocketAddr>,
76+
proxy_conf: Option<&config::Socks5Server>,
77+
timeout_ms: u64,
78+
) -> ResultType<Self> {
79+
let ws_stream =
80+
websocket::WsFramedStream::new(url, local_addr, proxy_conf, timeout_ms).await?;
81+
log::debug!("WebSocket connection established");
82+
Ok(Self::WebSocket(ws_stream))
83+
}
84+
85+
/// send message
86+
#[inline]
87+
pub async fn send(&mut self, msg: &impl protobuf::Message) -> ResultType<()> {
88+
match self {
89+
Self::WebSocket(ws) => ws.send(msg).await,
90+
Self::Tcp(tcp) => tcp.send(msg).await,
91+
}
92+
}
93+
94+
/// receive message
95+
#[inline]
96+
pub async fn next(&mut self) -> Option<Result<bytes::BytesMut, std::io::Error>> {
97+
match self {
98+
Self::WebSocket(ws) => ws.next().await,
99+
Self::Tcp(tcp) => tcp.next().await,
100+
}
101+
}
102+
103+
#[inline]
104+
pub fn local_addr(&self) -> SocketAddr {
105+
match self {
106+
Self::WebSocket(ws) => ws.local_addr(),
107+
Self::Tcp(tcp) => tcp.local_addr(),
108+
}
109+
}
110+
}

src/tcp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub trait TcpStreamTrait: AsyncRead + AsyncWrite + Unpin {}
2525
pub struct DynTcpStream(pub(crate) Box<dyn TcpStreamTrait + Send + Sync>);
2626

2727
#[derive(Clone)]
28-
pub struct Encrypt(Key, u64, u64);
28+
pub struct Encrypt(pub Key, pub u64, pub u64);
2929

3030
pub struct FramedStream(
3131
pub(crate) Framed<DynTcpStream, BytesCodec>,

0 commit comments

Comments
 (0)