@desklink/host 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -18
- package/bin/desklink-host.mjs +5 -1
- package/dist/bridge.d.ts +7 -0
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js +55 -7
- package/dist/bridge.js.map +1 -1
- package/dist/engineProcess.d.ts +9 -2
- package/dist/engineProcess.d.ts.map +1 -1
- package/dist/engineProcess.js +26 -15
- package/dist/engineProcess.js.map +1 -1
- package/dist/protocol.d.ts +1 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +1 -1
- package/dist/protocol.js.map +1 -1
- package/docs/BOUNDARY.md +4 -1
- package/docs/PROTOCOL.md +20 -5
- package/engine/Cargo.lock +6 -8
- package/engine/Cargo.toml +13 -1
- package/engine/src/clipboard.rs +0 -34
- package/engine/src/convert.rs +0 -170
- package/engine/src/cursor.rs +0 -23
- package/engine/src/input.rs +0 -65
- package/engine/src/input_mac.rs +0 -11
- package/engine/src/keeper.rs +0 -137
- package/engine/src/keymap.rs +0 -107
- package/engine/src/keymap_mac.rs +0 -25
- package/engine/src/mac.rs +0 -28
- package/engine/src/main.rs +3 -2
- package/engine/src/peer.rs +231 -1
- package/engine/src/portal.rs +0 -18
- package/engine/src/protocol.rs +0 -162
- package/engine/src/session.rs +37 -1
- package/engine/src/x11.rs +0 -13
- package/engine/vendor/rtc-ice/Cargo.toml +137 -0
- package/engine/vendor/rtc-ice/DESKLINK-PATCH.md +59 -0
- package/engine/vendor/rtc-ice/LICENSE-APACHE +201 -0
- package/engine/vendor/rtc-ice/LICENSE-MIT +21 -0
- package/engine/vendor/rtc-ice/README.md +30 -0
- package/engine/vendor/rtc-ice/examples/ping_pong.rs +376 -0
- package/engine/vendor/rtc-ice/src/agent/agent_config.rs +126 -0
- package/engine/vendor/rtc-ice/src/agent/agent_proto.rs +172 -0
- package/engine/vendor/rtc-ice/src/agent/agent_selector.rs +566 -0
- package/engine/vendor/rtc-ice/src/agent/agent_stats.rs +292 -0
- package/engine/vendor/rtc-ice/src/agent/agent_test.rs +3388 -0
- package/engine/vendor/rtc-ice/src/agent/mod.rs +1662 -0
- package/engine/vendor/rtc-ice/src/attributes/control/control_test.rs +168 -0
- package/engine/vendor/rtc-ice/src/attributes/control/mod.rs +142 -0
- package/engine/vendor/rtc-ice/src/attributes/mod.rs +6 -0
- package/engine/vendor/rtc-ice/src/attributes/priority/mod.rs +37 -0
- package/engine/vendor/rtc-ice/src/attributes/priority/priority_test.rs +39 -0
- package/engine/vendor/rtc-ice/src/attributes/use_candidate/mod.rs +33 -0
- package/engine/vendor/rtc-ice/src/attributes/use_candidate/use_candidate_test.rs +19 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_host.rs +53 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_pair.rs +215 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_pair_test.rs +201 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_peer_reflexive.rs +49 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_relay.rs +53 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_relay_test.rs +114 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_server_reflexive.rs +53 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_server_reflexive_test.rs +91 -0
- package/engine/vendor/rtc-ice/src/candidate/candidate_test.rs +540 -0
- package/engine/vendor/rtc-ice/src/candidate/mod.rs +679 -0
- package/engine/vendor/rtc-ice/src/lib.rs +85 -0
- package/engine/vendor/rtc-ice/src/mdns/mdns_test.rs +150 -0
- package/engine/vendor/rtc-ice/src/mdns/mod.rs +69 -0
- package/engine/vendor/rtc-ice/src/network_type/mod.rs +162 -0
- package/engine/vendor/rtc-ice/src/network_type/network_type_test.rs +95 -0
- package/engine/vendor/rtc-ice/src/rand/mod.rs +91 -0
- package/engine/vendor/rtc-ice/src/rand/rand_test.rs +115 -0
- package/engine/vendor/rtc-ice/src/state/mod.rs +106 -0
- package/engine/vendor/rtc-ice/src/state/state_test.rs +46 -0
- package/engine/vendor/rtc-ice/src/stats/mod.rs +166 -0
- package/engine/vendor/rtc-ice/src/tcp_type/mod.rs +47 -0
- package/engine/vendor/rtc-ice/src/tcp_type/tcp_type_test.rs +18 -0
- package/engine/vendor/rtc-ice/src/url/mod.rs +266 -0
- package/engine/vendor/rtc-ice/src/url/url_test.rs +142 -0
- package/package.json +8 -3
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
use bytes::BytesMut;
|
|
2
|
+
use clap::Parser;
|
|
3
|
+
use futures::StreamExt;
|
|
4
|
+
use hyper::service::{make_service_fn, service_fn};
|
|
5
|
+
use hyper::{Body, Client, Method, Request, Response, Server, StatusCode};
|
|
6
|
+
use rtc_ice::agent::Agent;
|
|
7
|
+
use rtc_ice::agent::agent_config::AgentConfig;
|
|
8
|
+
use rtc_ice::candidate::candidate_host::CandidateHostConfig;
|
|
9
|
+
use rtc_ice::candidate::*;
|
|
10
|
+
use rtc_ice::crypto;
|
|
11
|
+
use rtc_ice::state::*;
|
|
12
|
+
use rtc_ice::{Credentials, Event};
|
|
13
|
+
use sansio::Protocol;
|
|
14
|
+
use shared::error::Error;
|
|
15
|
+
use shared::{TransportContext, TransportMessage, TransportProtocol};
|
|
16
|
+
use std::io;
|
|
17
|
+
use std::io::Write;
|
|
18
|
+
use std::str::FromStr;
|
|
19
|
+
use std::sync::Arc;
|
|
20
|
+
use std::time::{Duration, Instant};
|
|
21
|
+
use tokio::net::UdpSocket;
|
|
22
|
+
use tokio::sync::{Mutex, mpsc, watch};
|
|
23
|
+
|
|
24
|
+
#[macro_use]
|
|
25
|
+
extern crate lazy_static;
|
|
26
|
+
|
|
27
|
+
type SenderType = Arc<Mutex<mpsc::Sender<String>>>;
|
|
28
|
+
type ReceiverType = Arc<Mutex<mpsc::Receiver<String>>>;
|
|
29
|
+
|
|
30
|
+
lazy_static! {
|
|
31
|
+
// ErrUnknownType indicates an error with Unknown info.
|
|
32
|
+
static ref REMOTE_AUTH_CHANNEL: (SenderType, ReceiverType ) = {
|
|
33
|
+
let (tx, rx) = mpsc::channel::<String>(3);
|
|
34
|
+
(Arc::new(Mutex::new(tx)), Arc::new(Mutex::new(rx)))
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
static ref REMOTE_CAND_CHANNEL: (SenderType, ReceiverType) = {
|
|
38
|
+
let (tx, rx) = mpsc::channel::<String>(10);
|
|
39
|
+
(Arc::new(Mutex::new(tx)), Arc::new(Mutex::new(rx)))
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// HTTP Listener to get ICE Credentials/Candidate from remote Peer
|
|
44
|
+
async fn remote_handler(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
|
|
45
|
+
//println!("received {:?}", req);
|
|
46
|
+
match (req.method(), req.uri().path()) {
|
|
47
|
+
(&Method::POST, "/remoteAuth") => {
|
|
48
|
+
let full_body =
|
|
49
|
+
match std::str::from_utf8(&hyper::body::to_bytes(req.into_body()).await?) {
|
|
50
|
+
Ok(s) => s.to_owned(),
|
|
51
|
+
Err(err) => panic!("{}", err),
|
|
52
|
+
};
|
|
53
|
+
let tx = REMOTE_AUTH_CHANNEL.0.lock().await;
|
|
54
|
+
//println!("body: {:?}", full_body);
|
|
55
|
+
let _ = tx.send(full_body).await;
|
|
56
|
+
|
|
57
|
+
let mut response = Response::new(Body::empty());
|
|
58
|
+
*response.status_mut() = StatusCode::OK;
|
|
59
|
+
Ok(response)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
(&Method::POST, "/remoteCandidate") => {
|
|
63
|
+
let full_body =
|
|
64
|
+
match std::str::from_utf8(&hyper::body::to_bytes(req.into_body()).await?) {
|
|
65
|
+
Ok(s) => s.to_owned(),
|
|
66
|
+
Err(err) => panic!("{}", err),
|
|
67
|
+
};
|
|
68
|
+
let tx = REMOTE_CAND_CHANNEL.0.lock().await;
|
|
69
|
+
//println!("body: {:?}", full_body);
|
|
70
|
+
let _ = tx.send(full_body).await;
|
|
71
|
+
|
|
72
|
+
let mut response = Response::new(Body::empty());
|
|
73
|
+
*response.status_mut() = StatusCode::OK;
|
|
74
|
+
Ok(response)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Return the 404 Not Found for other routes.
|
|
78
|
+
_ => {
|
|
79
|
+
let mut not_found = Response::default();
|
|
80
|
+
*not_found.status_mut() = StatusCode::NOT_FOUND;
|
|
81
|
+
Ok(not_found)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Controlled Agent:
|
|
87
|
+
// cargo run --color=always --package webrtc-ice --example ping_pong
|
|
88
|
+
// Controlling Agent:
|
|
89
|
+
// cargo run --color=always --package webrtc-ice --example ping_pong -- --controlling
|
|
90
|
+
|
|
91
|
+
#[derive(Parser)]
|
|
92
|
+
#[command(name = "ICE Ping Pong")]
|
|
93
|
+
#[command(author = "Rusty Rain <y@ngr.tc>")]
|
|
94
|
+
#[command(version = "0.1.0")]
|
|
95
|
+
#[command(about = "An example of ICE", long_about = None)]
|
|
96
|
+
struct Cli {
|
|
97
|
+
#[arg(short, long)]
|
|
98
|
+
controlling: bool,
|
|
99
|
+
|
|
100
|
+
#[arg(short, long)]
|
|
101
|
+
debug: bool,
|
|
102
|
+
#[arg(long, default_value_t = format!("INFO"))]
|
|
103
|
+
log_level: String,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
#[tokio::main]
|
|
107
|
+
async fn main() -> Result<(), Error> {
|
|
108
|
+
let cli = Cli::parse();
|
|
109
|
+
if cli.debug {
|
|
110
|
+
let log_level = log::LevelFilter::from_str(&cli.log_level).unwrap();
|
|
111
|
+
env_logger::Builder::new()
|
|
112
|
+
.format(|buf, record| {
|
|
113
|
+
writeln!(
|
|
114
|
+
buf,
|
|
115
|
+
"{}:{} [{}] {} - {}",
|
|
116
|
+
record.file().unwrap_or("unknown"),
|
|
117
|
+
record.line().unwrap_or(0),
|
|
118
|
+
record.level(),
|
|
119
|
+
chrono::Local::now().format("%H:%M:%S.%6f"),
|
|
120
|
+
record.args()
|
|
121
|
+
)
|
|
122
|
+
})
|
|
123
|
+
.filter(None, log_level)
|
|
124
|
+
.init();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let (local_http_port, remote_http_port) = if cli.controlling {
|
|
128
|
+
(9000, 9001)
|
|
129
|
+
} else {
|
|
130
|
+
(9001, 9000)
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
let (done_tx, mut done_rx) = watch::channel(());
|
|
134
|
+
|
|
135
|
+
println!("Listening on http://localhost:{local_http_port}");
|
|
136
|
+
let mut done_http_server = done_rx.clone();
|
|
137
|
+
tokio::spawn(async move {
|
|
138
|
+
let addr = ([0, 0, 0, 0], local_http_port).into();
|
|
139
|
+
let service =
|
|
140
|
+
make_service_fn(|_| async { Ok::<_, hyper::Error>(service_fn(remote_handler)) });
|
|
141
|
+
let server = Server::bind(&addr).serve(service);
|
|
142
|
+
tokio::select! {
|
|
143
|
+
_ = done_http_server.changed() => {
|
|
144
|
+
println!("receive cancel http server!");
|
|
145
|
+
}
|
|
146
|
+
result = server => {
|
|
147
|
+
// Run this server for... forever!
|
|
148
|
+
if let Err(e) = result {
|
|
149
|
+
eprintln!("server error: {e}");
|
|
150
|
+
}
|
|
151
|
+
println!("exit http server!");
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
if cli.controlling {
|
|
157
|
+
println!("Local Agent is controlling");
|
|
158
|
+
} else {
|
|
159
|
+
println!("Local Agent is controlled");
|
|
160
|
+
};
|
|
161
|
+
println!("Press 'Enter' when both processes have started");
|
|
162
|
+
let mut input = String::new();
|
|
163
|
+
let _ = io::stdin().read_line(&mut input)?;
|
|
164
|
+
|
|
165
|
+
let port = if cli.controlling { 4000 } else { 4001 };
|
|
166
|
+
let udp_socket = UdpSocket::bind(("0.0.0.0", port)).await?;
|
|
167
|
+
let mut ice_agent = Agent::new(
|
|
168
|
+
Instant::now(),
|
|
169
|
+
Arc::new(AgentConfig {
|
|
170
|
+
disconnected_timeout: Some(Duration::from_secs(5)),
|
|
171
|
+
failed_timeout: Some(Duration::from_secs(5)),
|
|
172
|
+
..Default::default()
|
|
173
|
+
}),
|
|
174
|
+
crypto::default_provider().map_err(|e| Error::Other(e.to_string()))?,
|
|
175
|
+
)?;
|
|
176
|
+
|
|
177
|
+
let client = Arc::new(Client::new());
|
|
178
|
+
|
|
179
|
+
// When we have gathered a new ICE Candidate send it to the remote peer
|
|
180
|
+
let client2 = Arc::clone(&client);
|
|
181
|
+
let on_candidate = |c: Candidate| {
|
|
182
|
+
let client3 = Arc::clone(&client2);
|
|
183
|
+
Box::pin(async move {
|
|
184
|
+
println!("posting remoteCandidate with {}", c.marshal());
|
|
185
|
+
|
|
186
|
+
let req = match Request::builder()
|
|
187
|
+
.method(Method::POST)
|
|
188
|
+
.uri(format!(
|
|
189
|
+
"http://localhost:{remote_http_port}/remoteCandidate"
|
|
190
|
+
))
|
|
191
|
+
.body(Body::from(c.marshal()))
|
|
192
|
+
{
|
|
193
|
+
Ok(req) => req,
|
|
194
|
+
Err(err) => {
|
|
195
|
+
println!("{err}");
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
let resp = match client3.request(req).await {
|
|
200
|
+
Ok(resp) => resp,
|
|
201
|
+
Err(err) => {
|
|
202
|
+
println!("{err}");
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
println!("Response from remoteCandidate: {}", resp.status());
|
|
207
|
+
})
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
// Get the local auth details and send to remote peer
|
|
211
|
+
let Credentials {
|
|
212
|
+
ufrag: local_ufrag,
|
|
213
|
+
pwd: local_pwd,
|
|
214
|
+
} = ice_agent.get_local_credentials();
|
|
215
|
+
|
|
216
|
+
println!("posting remoteAuth with {local_ufrag}:{local_pwd}");
|
|
217
|
+
let req = match Request::builder()
|
|
218
|
+
.method(Method::POST)
|
|
219
|
+
.uri(format!("http://localhost:{remote_http_port}/remoteAuth"))
|
|
220
|
+
.body(Body::from(format!("{local_ufrag}:{local_pwd}")))
|
|
221
|
+
{
|
|
222
|
+
Ok(req) => req,
|
|
223
|
+
Err(err) => return Err(Error::Other(format!("{err}"))),
|
|
224
|
+
};
|
|
225
|
+
let resp = match client.request(req).await {
|
|
226
|
+
Ok(resp) => resp,
|
|
227
|
+
Err(err) => return Err(Error::Other(format!("{err}"))),
|
|
228
|
+
};
|
|
229
|
+
println!("Response from remoteAuth: {}", resp.status());
|
|
230
|
+
|
|
231
|
+
let (remote_ufrag, remote_pwd) = {
|
|
232
|
+
let mut rx = REMOTE_AUTH_CHANNEL.1.lock().await;
|
|
233
|
+
if let Some(s) = rx.recv().await {
|
|
234
|
+
println!("received: {s}");
|
|
235
|
+
let fields: Vec<String> = s.split(':').map(|s| s.to_string()).collect();
|
|
236
|
+
(fields[0].clone(), fields[1].clone())
|
|
237
|
+
} else {
|
|
238
|
+
panic!("rx.recv() empty");
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
println!("remote_ufrag: {remote_ufrag}, remote_pwd: {remote_pwd}");
|
|
242
|
+
|
|
243
|
+
// gather_candidates
|
|
244
|
+
println!("gathering candidates...");
|
|
245
|
+
let local_candidate = CandidateHostConfig {
|
|
246
|
+
base_config: CandidateConfig {
|
|
247
|
+
network: "udp".to_owned(),
|
|
248
|
+
address: udp_socket.local_addr()?.ip().to_string(),
|
|
249
|
+
port: udp_socket.local_addr()?.port(),
|
|
250
|
+
component: 1,
|
|
251
|
+
..Default::default()
|
|
252
|
+
},
|
|
253
|
+
..Default::default()
|
|
254
|
+
}
|
|
255
|
+
.new_candidate_host()?;
|
|
256
|
+
on_candidate(local_candidate.clone()).await;
|
|
257
|
+
ice_agent.add_local_candidate(local_candidate)?;
|
|
258
|
+
|
|
259
|
+
let remote_candidate = {
|
|
260
|
+
let mut rx = REMOTE_CAND_CHANNEL.1.lock().await;
|
|
261
|
+
if let Some(s) = rx.recv().await {
|
|
262
|
+
println!("received remote_candidate: {s}");
|
|
263
|
+
unmarshal_candidate(&s)?
|
|
264
|
+
} else {
|
|
265
|
+
panic!("rx.recv() empty");
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
let peer_addr = remote_candidate.addr();
|
|
269
|
+
ice_agent.add_remote_candidate(remote_candidate)?;
|
|
270
|
+
|
|
271
|
+
ice_agent.start_connectivity_checks(
|
|
272
|
+
Instant::now(),
|
|
273
|
+
cli.controlling,
|
|
274
|
+
remote_ufrag,
|
|
275
|
+
remote_pwd,
|
|
276
|
+
)?;
|
|
277
|
+
|
|
278
|
+
println!("Enter bye to stop");
|
|
279
|
+
let (mut tx, mut rx) = futures::channel::mpsc::channel(8);
|
|
280
|
+
std::thread::spawn(move || {
|
|
281
|
+
let mut buffer = String::new();
|
|
282
|
+
while io::stdin().read_line(&mut buffer).is_ok() {
|
|
283
|
+
match buffer.trim_end() {
|
|
284
|
+
"" => break,
|
|
285
|
+
line => {
|
|
286
|
+
if line == "bye" {
|
|
287
|
+
let _ = done_tx.send(());
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
if tx.try_send(line.to_string()).is_err() {
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
buffer.clear();
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// Start the ICE Agent. One side must be controlled, and the other must be controlling
|
|
300
|
+
let mut buf = vec![0u8; 2048];
|
|
301
|
+
loop {
|
|
302
|
+
while let Some(transmit) = ice_agent.poll_write() {
|
|
303
|
+
udp_socket
|
|
304
|
+
.send_to(&transmit.message[..], transmit.transport.peer_addr)
|
|
305
|
+
.await?;
|
|
306
|
+
}
|
|
307
|
+
let mut is_failed = false;
|
|
308
|
+
while let Some(event) = ice_agent.poll_event() {
|
|
309
|
+
match event.event {
|
|
310
|
+
Event::ConnectionStateChange(cs) => {
|
|
311
|
+
println!("ConnectionStateChange with {}", cs);
|
|
312
|
+
match cs {
|
|
313
|
+
ConnectionState::Failed => {
|
|
314
|
+
is_failed = true;
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
_ => {}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
_ => {}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if is_failed {
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
let d = if let Some(eto) = ice_agent.poll_timeout() {
|
|
328
|
+
eto.duration_since(Instant::now())
|
|
329
|
+
} else {
|
|
330
|
+
Duration::from_millis(100)
|
|
331
|
+
};
|
|
332
|
+
let timeout = tokio::time::sleep(d);
|
|
333
|
+
tokio::pin!(timeout);
|
|
334
|
+
|
|
335
|
+
tokio::select! {
|
|
336
|
+
_ = done_rx.changed() => {
|
|
337
|
+
println!("exit ICE loop");
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
_ = timeout.as_mut() => {
|
|
341
|
+
ice_agent.handle_timeout(Instant::now())?;
|
|
342
|
+
}
|
|
343
|
+
res = udp_socket.recv_from(&mut buf) => {
|
|
344
|
+
if let Ok((n, remote_addr)) = res {
|
|
345
|
+
if n == 0 {
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if stun::message::is_stun_message(&buf[0..n]) {
|
|
350
|
+
ice_agent.handle_read(TransportMessage::<BytesMut>{
|
|
351
|
+
now: Instant::now(),
|
|
352
|
+
transport: TransportContext{
|
|
353
|
+
local_addr: udp_socket.local_addr()?,
|
|
354
|
+
peer_addr: remote_addr,
|
|
355
|
+
ecn: None,
|
|
356
|
+
transport_protocol: TransportProtocol::UDP,
|
|
357
|
+
},
|
|
358
|
+
message:BytesMut::from(&buf[0..n]),
|
|
359
|
+
})?;
|
|
360
|
+
} else {
|
|
361
|
+
println!("{}", String::from_utf8((&buf[0..n]).to_vec())?);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
res = rx.next() => {
|
|
366
|
+
if let Some(line) = res {
|
|
367
|
+
udp_socket.send_to(line.as_bytes(), peer_addr).await?;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
ice_agent.close()?;
|
|
374
|
+
|
|
375
|
+
Ok(())
|
|
376
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
use std::net::IpAddr;
|
|
2
|
+
use std::time::Duration;
|
|
3
|
+
|
|
4
|
+
use super::*;
|
|
5
|
+
use crate::mdns::*;
|
|
6
|
+
use crate::network_type::NetworkType;
|
|
7
|
+
use crate::url::*;
|
|
8
|
+
|
|
9
|
+
/// The interval at which the agent performs candidate checks in the connecting phase.
|
|
10
|
+
pub(crate) const DEFAULT_CHECK_INTERVAL: Duration = Duration::from_millis(200);
|
|
11
|
+
|
|
12
|
+
/// The interval used to keep candidates alive.
|
|
13
|
+
pub(crate) const DEFAULT_KEEPALIVE_INTERVAL: Duration = Duration::from_secs(2);
|
|
14
|
+
|
|
15
|
+
/// The default time till an Agent transitions disconnected.
|
|
16
|
+
pub(crate) const DEFAULT_DISCONNECTED_TIMEOUT: Duration = Duration::from_secs(5);
|
|
17
|
+
|
|
18
|
+
/// The default time till an Agent transitions to failed after disconnected.
|
|
19
|
+
pub(crate) const DEFAULT_FAILED_TIMEOUT: Duration = Duration::from_secs(25);
|
|
20
|
+
|
|
21
|
+
/// Wait time before nominating a host candidate.
|
|
22
|
+
pub(crate) const DEFAULT_HOST_ACCEPTANCE_MIN_WAIT: Duration = Duration::from_secs(0);
|
|
23
|
+
|
|
24
|
+
/// Wait time before nominating a srflx candidate.
|
|
25
|
+
pub(crate) const DEFAULT_SRFLX_ACCEPTANCE_MIN_WAIT: Duration = Duration::from_millis(500);
|
|
26
|
+
|
|
27
|
+
/// Wait time before nominating a prflx candidate.
|
|
28
|
+
pub(crate) const DEFAULT_PRFLX_ACCEPTANCE_MIN_WAIT: Duration = Duration::from_millis(1000);
|
|
29
|
+
|
|
30
|
+
/// Wait time before nominating a relay candidate.
|
|
31
|
+
pub(crate) const DEFAULT_RELAY_ACCEPTANCE_MIN_WAIT: Duration = Duration::from_millis(2000);
|
|
32
|
+
|
|
33
|
+
/// Max binding request before considering a pair failed.
|
|
34
|
+
pub(crate) const DEFAULT_MAX_BINDING_REQUESTS: u16 = 7;
|
|
35
|
+
|
|
36
|
+
/// The number of bytes that can be buffered before we start to error.
|
|
37
|
+
pub(crate) const MAX_BUFFER_SIZE: usize = 1000 * 1000; // 1MB
|
|
38
|
+
|
|
39
|
+
/// Wait time before binding requests can be deleted.
|
|
40
|
+
pub(crate) const MAX_BINDING_REQUEST_TIMEOUT: Duration = Duration::from_millis(4000);
|
|
41
|
+
|
|
42
|
+
pub(crate) fn default_candidate_types() -> Vec<CandidateType> {
|
|
43
|
+
vec![
|
|
44
|
+
CandidateType::Host,
|
|
45
|
+
CandidateType::ServerReflexive,
|
|
46
|
+
CandidateType::Relay,
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// Collects the arguments to `ice::Agent` construction into a single structure, for
|
|
51
|
+
/// future-proofness of the interface.
|
|
52
|
+
#[derive(Default)]
|
|
53
|
+
pub struct AgentConfig {
|
|
54
|
+
/// The STUN and TURN servers to gather reflexive and relay candidates from.
|
|
55
|
+
pub urls: Vec<Url>,
|
|
56
|
+
|
|
57
|
+
/// It is used to perform connectivity checks. The values MUST be unguessable, with at least
|
|
58
|
+
/// 128 bits of random number generator output used to generate the password, and at least 24
|
|
59
|
+
/// bits of output to generate the username fragment.
|
|
60
|
+
pub local_ufrag: String,
|
|
61
|
+
/// It is used to perform connectivity checks. The values MUST be unguessable, with at least
|
|
62
|
+
/// 128 bits of random number generator output used to generate the password, and at least 24
|
|
63
|
+
/// bits of output to generate the username fragment.
|
|
64
|
+
pub local_pwd: String,
|
|
65
|
+
|
|
66
|
+
/// Controls mDNS query timeout
|
|
67
|
+
/// If the duration is 0, we will never go to failed.
|
|
68
|
+
pub multicast_dns_query_timeout: Option<Duration>,
|
|
69
|
+
|
|
70
|
+
/// Controls mDNS behavior for the ICE agent.
|
|
71
|
+
pub multicast_dns_mode: MulticastDnsMode,
|
|
72
|
+
|
|
73
|
+
/// Controls the local name for this agent. If none is specified a random one will be generated.
|
|
74
|
+
pub multicast_dns_local_name: String,
|
|
75
|
+
|
|
76
|
+
/// Control mDNS local IP address
|
|
77
|
+
pub multicast_dns_local_ip: Option<IpAddr>,
|
|
78
|
+
|
|
79
|
+
/// Defaults to 5 seconds when this property is nil.
|
|
80
|
+
/// If the duration is 0, the ICE Agent will never go to disconnected.
|
|
81
|
+
pub disconnected_timeout: Option<Duration>,
|
|
82
|
+
|
|
83
|
+
/// Defaults to 25 seconds when this property is nil.
|
|
84
|
+
/// If the duration is 0, we will never go to failed.
|
|
85
|
+
pub failed_timeout: Option<Duration>,
|
|
86
|
+
|
|
87
|
+
/// Determines how often should we send ICE keepalives (should be less than connection timeout
|
|
88
|
+
/// above) when this is nil, it defaults to 10 seconds.
|
|
89
|
+
/// A keepalive interval of 0 means we never send keepalive packets
|
|
90
|
+
pub keepalive_interval: Option<Duration>,
|
|
91
|
+
|
|
92
|
+
/// An optional configuration for disabling or enabling support for specific candidate types.
|
|
93
|
+
pub candidate_types: Vec<CandidateType>,
|
|
94
|
+
|
|
95
|
+
/// An optional configuration for disabling or enabling support for specific network types.
|
|
96
|
+
/// If empty, all network types are supported.
|
|
97
|
+
pub network_types: Vec<NetworkType>,
|
|
98
|
+
|
|
99
|
+
/// Controls how often our internal task loop runs when in the connecting state.
|
|
100
|
+
/// Only useful for testing.
|
|
101
|
+
pub check_interval: Duration,
|
|
102
|
+
|
|
103
|
+
/// The max amount of binding requests the agent will send over a candidate pair for validation
|
|
104
|
+
/// or nomination, if after max_binding_requests the candidate is yet to answer a binding
|
|
105
|
+
/// request or a nomination we set the pair as failed.
|
|
106
|
+
pub max_binding_requests: Option<u16>,
|
|
107
|
+
|
|
108
|
+
/// Whether this agent takes the controlling role.
|
|
109
|
+
pub is_controlling: bool,
|
|
110
|
+
|
|
111
|
+
/// lite agents do not perform connectivity check and only provide host candidates.
|
|
112
|
+
pub lite: bool,
|
|
113
|
+
|
|
114
|
+
/// Specify a minimum wait time before selecting host candidates.
|
|
115
|
+
pub host_acceptance_min_wait: Option<Duration>,
|
|
116
|
+
/// Specify a minimum wait time before selecting srflx candidates.
|
|
117
|
+
pub srflx_acceptance_min_wait: Option<Duration>,
|
|
118
|
+
/// Specify a minimum wait time before selecting prflx candidates.
|
|
119
|
+
pub prflx_acceptance_min_wait: Option<Duration>,
|
|
120
|
+
/// Specify a minimum wait time before selecting relay candidates.
|
|
121
|
+
pub relay_acceptance_min_wait: Option<Duration>,
|
|
122
|
+
|
|
123
|
+
/// Controls if self-signed certificates are accepted when connecting to TURN servers via TLS or
|
|
124
|
+
/// DTLS.
|
|
125
|
+
pub insecure_skip_verify: bool,
|
|
126
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
use super::*;
|
|
2
|
+
use mdns::{MDNS_PORT, MdnsEvent};
|
|
3
|
+
|
|
4
|
+
impl sansio::Protocol<TaggedBytesMut, (), ()> for Agent {
|
|
5
|
+
type Rout = TaggedBytesMut;
|
|
6
|
+
type Wout = TaggedBytesMut;
|
|
7
|
+
type Eout = TaggedEvent;
|
|
8
|
+
type Error = Error;
|
|
9
|
+
type Time = Instant;
|
|
10
|
+
|
|
11
|
+
fn handle_read(&mut self, msg: TaggedBytesMut) -> Result<()> {
|
|
12
|
+
// demuxing mDNS packet from STUN packet whether peer addr port is MDNS_PORT
|
|
13
|
+
if msg.transport.peer_addr.port() == MDNS_PORT {
|
|
14
|
+
let remote_candidates = if let Some(mdns_conn) = &mut self.mdns {
|
|
15
|
+
mdns_conn.handle_read(msg)?;
|
|
16
|
+
|
|
17
|
+
let mut remote_candidates = vec![];
|
|
18
|
+
// After mdns handle_read, check any query result
|
|
19
|
+
while let Some(event) = mdns_conn.poll_event() {
|
|
20
|
+
match event {
|
|
21
|
+
MdnsEvent::QueryAnswered(id, addr) => {
|
|
22
|
+
if let Some(mut c) = self.mdns_queries.remove(&id)
|
|
23
|
+
&& c.set_ip(&addr).is_ok()
|
|
24
|
+
{
|
|
25
|
+
debug!(
|
|
26
|
+
"mDNS query id {} answered Candidate {} with resolved_addr {} is added into remote candidates",
|
|
27
|
+
id,
|
|
28
|
+
c,
|
|
29
|
+
c.addr()
|
|
30
|
+
);
|
|
31
|
+
remote_candidates.push(c);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
MdnsEvent::QueryTimeout(id) => {
|
|
35
|
+
if let Some(c) = self.mdns_queries.remove(&id) {
|
|
36
|
+
error!("mDNS Query {} timed out for {}", id, c.address());
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
_ => {}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
remote_candidates
|
|
43
|
+
} else {
|
|
44
|
+
vec![]
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
self.trigger_request_connectivity_check(remote_candidates);
|
|
48
|
+
|
|
49
|
+
Ok(())
|
|
50
|
+
} else if let Some(local_index) =
|
|
51
|
+
self.find_local_candidate(msg.transport.local_addr, msg.transport.transport_protocol)
|
|
52
|
+
{
|
|
53
|
+
self.handle_inbound_candidate_msg(local_index, msg)
|
|
54
|
+
} else {
|
|
55
|
+
warn!(
|
|
56
|
+
"[{}]: Discarded message, not a valid local candidate from {:?}:{}",
|
|
57
|
+
self.get_name(),
|
|
58
|
+
msg.transport.transport_protocol,
|
|
59
|
+
msg.transport.local_addr,
|
|
60
|
+
);
|
|
61
|
+
Err(Error::ErrUnhandledStunpacket)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
fn poll_read(&mut self) -> Option<Self::Rout> {
|
|
66
|
+
None
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
fn handle_write(&mut self, _msg: ()) -> std::result::Result<(), Self::Error> {
|
|
70
|
+
Ok(())
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fn poll_write(&mut self) -> Option<Self::Wout> {
|
|
74
|
+
if let Some(mdns_conn) = &mut self.mdns {
|
|
75
|
+
while let Some(msg) = mdns_conn.poll_write() {
|
|
76
|
+
self.write_outs.push_back(msg);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
self.write_outs.pop_front()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
fn handle_event(&mut self, _evt: ()) -> std::result::Result<(), Self::Error> {
|
|
84
|
+
Ok(())
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
fn poll_event(&mut self) -> Option<Self::Eout> {
|
|
88
|
+
self.event_outs.pop_front()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
fn handle_timeout(&mut self, now: Self::Time) -> std::result::Result<(), Self::Error> {
|
|
92
|
+
let remote_candidates = if let Some(mdns_conn) = &mut self.mdns {
|
|
93
|
+
let _ = mdns_conn.handle_timeout(now);
|
|
94
|
+
|
|
95
|
+
let mut remote_candidates = vec![];
|
|
96
|
+
// After mdns handle_timeout, check any query result
|
|
97
|
+
while let Some(event) = mdns_conn.poll_event() {
|
|
98
|
+
match event {
|
|
99
|
+
MdnsEvent::QueryAnswered(id, addr) => {
|
|
100
|
+
if let Some(mut c) = self.mdns_queries.remove(&id)
|
|
101
|
+
&& c.set_ip(&addr).is_ok()
|
|
102
|
+
{
|
|
103
|
+
debug!(
|
|
104
|
+
"mDNS query id {} answered Candidate {} with resolved_addr {} is added into remote candidates",
|
|
105
|
+
id,
|
|
106
|
+
c,
|
|
107
|
+
c.addr()
|
|
108
|
+
);
|
|
109
|
+
remote_candidates.push(c);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
MdnsEvent::QueryTimeout(id) => {
|
|
113
|
+
if let Some(c) = self.mdns_queries.remove(&id) {
|
|
114
|
+
error!("mDNS Query {} timed out for {}", id, c.address());
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
_ => {}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
remote_candidates
|
|
121
|
+
} else {
|
|
122
|
+
vec![]
|
|
123
|
+
};
|
|
124
|
+
self.trigger_request_connectivity_check(remote_candidates);
|
|
125
|
+
|
|
126
|
+
if self.ufrag_pwd.remote_credentials.is_some()
|
|
127
|
+
&& (self.force_candidate_contact
|
|
128
|
+
|| self.last_checking_time + self.get_timeout_interval() <= now)
|
|
129
|
+
{
|
|
130
|
+
self.contact(now);
|
|
131
|
+
}
|
|
132
|
+
Ok(())
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
fn poll_timeout(&mut self) -> Option<Self::Time> {
|
|
136
|
+
let mdns_timeout = if let Some(mdns_conn) = &mut self.mdns {
|
|
137
|
+
mdns_conn.poll_timeout()
|
|
138
|
+
} else {
|
|
139
|
+
None
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
let ice_timeout = if self.ufrag_pwd.remote_credentials.is_some()
|
|
143
|
+
&& !matches!(
|
|
144
|
+
self.connection_state,
|
|
145
|
+
ConnectionState::Failed | ConnectionState::Closed
|
|
146
|
+
) {
|
|
147
|
+
if self.force_candidate_contact {
|
|
148
|
+
// A connectivity check was requested; ask the driver to call
|
|
149
|
+
// `handle_timeout` as soon as possible. `last_checking_time` is in the
|
|
150
|
+
// past, so the resulting deadline is immediate.
|
|
151
|
+
Some(self.last_checking_time)
|
|
152
|
+
} else {
|
|
153
|
+
Some(self.last_checking_time + self.get_timeout_interval())
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
None
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// This treats the two options as a collection and picks the minimum
|
|
160
|
+
[mdns_timeout, ice_timeout].into_iter().flatten().min()
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
fn close(&mut self) -> std::result::Result<(), Self::Error> {
|
|
164
|
+
self.set_selected_pair(None, None);
|
|
165
|
+
self.delete_all_candidates(false);
|
|
166
|
+
self.update_connection_state(None, ConnectionState::Closed);
|
|
167
|
+
if let Some(mdns_conn) = &mut self.mdns {
|
|
168
|
+
mdns_conn.close()?;
|
|
169
|
+
}
|
|
170
|
+
Ok(())
|
|
171
|
+
}
|
|
172
|
+
}
|