1#[cfg(target_os = "linux")]
4use super::ble::DefaultBleTransport;
5#[cfg(any(target_os = "linux", target_os = "macos"))]
6use super::ethernet::EthernetTransport;
7#[cfg(feature = "sim-transport")]
8use super::sim::SimTransport;
9use super::tcp::TcpTransport;
10use super::tor::TorTransport;
11use super::tor::control::TorMonitoringInfo;
12use super::udp::UdpTransport;
13#[cfg(feature = "webrtc-transport")]
14use super::webrtc::WebRtcTransport;
15use super::websocket::WebSocketTransport;
16use super::{
17 ConnectionState, DiscoveredPeer, Transport, TransportAddr, TransportCongestion, TransportError,
18 TransportId, TransportState, TransportType,
19};
20
21pub enum TransportHandle {
26 Udp(UdpTransport),
28 #[cfg(feature = "sim-transport")]
30 Sim(SimTransport),
31 #[cfg(any(target_os = "linux", target_os = "macos"))]
33 Ethernet(EthernetTransport),
34 Tcp(TcpTransport),
36 WebSocket(Box<WebSocketTransport>),
38 Tor(TorTransport),
40 #[cfg(feature = "webrtc-transport")]
42 WebRtc(Box<WebRtcTransport>),
43 #[cfg(target_os = "linux")]
45 Ble(DefaultBleTransport),
46}
47
48impl TransportHandle {
49 pub(crate) fn canonical_addr(
53 &self,
54 addr: &TransportAddr,
55 ) -> Result<TransportAddr, TransportError> {
56 match self {
57 #[cfg(feature = "webrtc-transport")]
58 TransportHandle::WebRtc(_) => super::webrtc::canonical_webrtc_addr(addr),
59 _ => Ok(addr.clone()),
60 }
61 }
62
63 #[cfg(feature = "webrtc-transport")]
66 pub(crate) fn drain_link_negotiations(
67 &mut self,
68 limit: usize,
69 ) -> Vec<super::link_negotiation::OutboundLinkNegotiation> {
70 match self {
71 TransportHandle::WebRtc(transport) => transport.drain_link_negotiations(limit),
72 _ => Vec::new(),
73 }
74 }
75
76 #[cfg(feature = "webrtc-transport")]
78 pub(crate) fn ingest_link_negotiation(
79 &self,
80 source: secp256k1::PublicKey,
81 message: super::link_negotiation::LinkNegotiationMessage,
82 ) -> Result<(), TransportError> {
83 match self {
84 TransportHandle::WebRtc(transport) if message.link_type == "webrtc" => {
85 transport.ingest_link_negotiation(source, message)
86 }
87 _ => Err(TransportError::NotSupported(
88 "no enabled adapter accepts this link negotiation".into(),
89 )),
90 }
91 }
92
93 pub async fn start(&mut self) -> Result<(), TransportError> {
95 match self {
96 TransportHandle::Udp(t) => t.start_async().await,
97 #[cfg(feature = "sim-transport")]
98 TransportHandle::Sim(t) => t.start_async().await,
99 #[cfg(any(target_os = "linux", target_os = "macos"))]
100 TransportHandle::Ethernet(t) => t.start_async().await,
101 TransportHandle::Tcp(t) => t.start_async().await,
102 TransportHandle::WebSocket(t) => t.start_async().await,
103 TransportHandle::Tor(t) => t.start_async().await,
104 #[cfg(feature = "webrtc-transport")]
105 TransportHandle::WebRtc(t) => t.start_async().await,
106 #[cfg(target_os = "linux")]
107 TransportHandle::Ble(t) => t.start_async().await,
108 }
109 }
110
111 pub async fn stop(&mut self) -> Result<(), TransportError> {
113 match self {
114 TransportHandle::Udp(t) => t.stop_async().await,
115 #[cfg(feature = "sim-transport")]
116 TransportHandle::Sim(t) => t.stop_async().await,
117 #[cfg(any(target_os = "linux", target_os = "macos"))]
118 TransportHandle::Ethernet(t) => t.stop_async().await,
119 TransportHandle::Tcp(t) => t.stop_async().await,
120 TransportHandle::WebSocket(t) => t.stop_async().await,
121 TransportHandle::Tor(t) => t.stop_async().await,
122 #[cfg(feature = "webrtc-transport")]
123 TransportHandle::WebRtc(t) => t.stop_async().await,
124 #[cfg(target_os = "linux")]
125 TransportHandle::Ble(t) => t.stop_async().await,
126 }
127 }
128
129 pub async fn send(&self, addr: &TransportAddr, data: &[u8]) -> Result<usize, TransportError> {
131 match self {
132 TransportHandle::Udp(t) => t.send_async(addr, data).await,
133 #[cfg(feature = "sim-transport")]
134 TransportHandle::Sim(t) => t.send_async(addr, data).await,
135 #[cfg(any(target_os = "linux", target_os = "macos"))]
136 TransportHandle::Ethernet(t) => t.send_async(addr, data).await,
137 TransportHandle::Tcp(t) => t.send_async(addr, data).await,
138 TransportHandle::WebSocket(t) => t.send_async(addr, data).await,
139 TransportHandle::Tor(t) => t.send_async(addr, data).await,
140 #[cfg(feature = "webrtc-transport")]
141 TransportHandle::WebRtc(t) => Box::pin(t.send_async(addr, data)).await,
143 #[cfg(target_os = "linux")]
144 TransportHandle::Ble(t) => t.send_async(addr, data).await,
145 }
146 }
147
148 pub(crate) async fn send_with_timeout(
149 &self,
150 addr: &TransportAddr,
151 data: &[u8],
152 timeout: std::time::Duration,
153 ) -> Result<usize, TransportError> {
154 match self {
155 TransportHandle::Tcp(transport) => {
156 transport.send_async_with_timeout(addr, data, timeout).await
157 }
158 _ => self.send(addr, data).await,
159 }
160 }
161
162 pub fn transport_id(&self) -> TransportId {
164 match self {
165 TransportHandle::Udp(t) => t.transport_id(),
166 #[cfg(feature = "sim-transport")]
167 TransportHandle::Sim(t) => t.transport_id(),
168 #[cfg(any(target_os = "linux", target_os = "macos"))]
169 TransportHandle::Ethernet(t) => t.transport_id(),
170 TransportHandle::Tcp(t) => t.transport_id(),
171 TransportHandle::WebSocket(t) => t.transport_id(),
172 TransportHandle::Tor(t) => t.transport_id(),
173 #[cfg(feature = "webrtc-transport")]
174 TransportHandle::WebRtc(t) => t.transport_id(),
175 #[cfg(target_os = "linux")]
176 TransportHandle::Ble(t) => t.transport_id(),
177 }
178 }
179
180 pub(crate) fn uses_fips_byte_stream_framing(&self) -> bool {
182 matches!(self, TransportHandle::Tcp(_) | TransportHandle::Tor(_))
183 }
184
185 pub fn name(&self) -> Option<&str> {
187 match self {
188 TransportHandle::Udp(t) => t.name(),
189 #[cfg(feature = "sim-transport")]
190 TransportHandle::Sim(t) => t.name(),
191 #[cfg(any(target_os = "linux", target_os = "macos"))]
192 TransportHandle::Ethernet(t) => t.name(),
193 TransportHandle::Tcp(t) => t.name(),
194 TransportHandle::WebSocket(t) => t.name(),
195 TransportHandle::Tor(t) => t.name(),
196 #[cfg(feature = "webrtc-transport")]
197 TransportHandle::WebRtc(t) => t.name(),
198 #[cfg(target_os = "linux")]
199 TransportHandle::Ble(t) => t.name(),
200 }
201 }
202
203 pub fn transport_type(&self) -> &TransportType {
205 match self {
206 TransportHandle::Udp(t) => t.transport_type(),
207 #[cfg(feature = "sim-transport")]
208 TransportHandle::Sim(t) => t.transport_type(),
209 #[cfg(any(target_os = "linux", target_os = "macos"))]
210 TransportHandle::Ethernet(t) => t.transport_type(),
211 TransportHandle::Tcp(t) => t.transport_type(),
212 TransportHandle::WebSocket(t) => t.transport_type(),
213 TransportHandle::Tor(t) => t.transport_type(),
214 #[cfg(feature = "webrtc-transport")]
215 TransportHandle::WebRtc(t) => t.transport_type(),
216 #[cfg(target_os = "linux")]
217 TransportHandle::Ble(t) => t.transport_type(),
218 }
219 }
220
221 pub fn state(&self) -> TransportState {
223 match self {
224 TransportHandle::Udp(t) => t.state(),
225 #[cfg(feature = "sim-transport")]
226 TransportHandle::Sim(t) => t.state(),
227 #[cfg(any(target_os = "linux", target_os = "macos"))]
228 TransportHandle::Ethernet(t) => t.state(),
229 TransportHandle::Tcp(t) => t.state(),
230 TransportHandle::WebSocket(t) => t.state(),
231 TransportHandle::Tor(t) => t.state(),
232 #[cfg(feature = "webrtc-transport")]
233 TransportHandle::WebRtc(t) => t.state(),
234 #[cfg(target_os = "linux")]
235 TransportHandle::Ble(t) => t.state(),
236 }
237 }
238
239 pub fn mtu(&self) -> u16 {
241 match self {
242 TransportHandle::Udp(t) => t.mtu(),
243 #[cfg(feature = "sim-transport")]
244 TransportHandle::Sim(t) => t.mtu(),
245 #[cfg(any(target_os = "linux", target_os = "macos"))]
246 TransportHandle::Ethernet(t) => t.mtu(),
247 TransportHandle::Tcp(t) => t.mtu(),
248 TransportHandle::WebSocket(t) => t.mtu(),
249 TransportHandle::Tor(t) => t.mtu(),
250 #[cfg(feature = "webrtc-transport")]
251 TransportHandle::WebRtc(t) => t.mtu(),
252 #[cfg(target_os = "linux")]
253 TransportHandle::Ble(t) => t.mtu(),
254 }
255 }
256
257 pub fn link_mtu(&self, addr: &TransportAddr) -> u16 {
262 match self {
263 TransportHandle::Udp(t) => t.link_mtu(addr),
264 #[cfg(feature = "sim-transport")]
265 TransportHandle::Sim(t) => t.link_mtu(addr),
266 #[cfg(any(target_os = "linux", target_os = "macos"))]
267 TransportHandle::Ethernet(t) => t.link_mtu(addr),
268 TransportHandle::Tcp(t) => t.link_mtu(addr),
269 TransportHandle::WebSocket(t) => t.link_mtu(addr),
270 TransportHandle::Tor(t) => t.link_mtu(addr),
271 #[cfg(feature = "webrtc-transport")]
272 TransportHandle::WebRtc(t) => t.link_mtu(addr),
273 #[cfg(target_os = "linux")]
274 TransportHandle::Ble(t) => t.link_mtu(addr),
275 }
276 }
277
278 pub fn local_addr(&self) -> Option<std::net::SocketAddr> {
280 match self {
281 TransportHandle::Udp(t) => t.local_addr(),
282 #[cfg(feature = "sim-transport")]
283 TransportHandle::Sim(_) => None,
284 #[cfg(any(target_os = "linux", target_os = "macos"))]
285 TransportHandle::Ethernet(_) => None,
286 TransportHandle::Tcp(t) => t.local_addr(),
287 TransportHandle::WebSocket(t) => t.local_addr(),
288 TransportHandle::Tor(_) => None,
289 #[cfg(feature = "webrtc-transport")]
290 TransportHandle::WebRtc(_) => None,
291 #[cfg(target_os = "linux")]
292 TransportHandle::Ble(_) => None,
293 }
294 }
295
296 pub(crate) fn resolved_udp_socket_addr_if_cached(
301 &self,
302 addr: &TransportAddr,
303 ) -> Option<std::net::SocketAddr> {
304 match self {
305 TransportHandle::Udp(t) => t.resolved_socket_addr_if_cached(addr),
306 _ => None,
307 }
308 }
309
310 pub fn interface_name(&self) -> Option<&str> {
312 match self {
313 TransportHandle::Udp(_) => None,
314 #[cfg(feature = "sim-transport")]
315 TransportHandle::Sim(_) => None,
316 #[cfg(any(target_os = "linux", target_os = "macos"))]
317 TransportHandle::Ethernet(t) => Some(t.interface_name()),
318 TransportHandle::Tcp(_) => None,
319 TransportHandle::WebSocket(_) => None,
320 TransportHandle::Tor(_) => None,
321 #[cfg(feature = "webrtc-transport")]
322 TransportHandle::WebRtc(_) => None,
323 #[cfg(target_os = "linux")]
324 TransportHandle::Ble(_) => None,
325 }
326 }
327
328 pub fn onion_address(&self) -> Option<&str> {
330 match self {
331 TransportHandle::Tor(t) => t.onion_address(),
332 _ => None,
333 }
334 }
335
336 pub fn tor_monitoring(&self) -> Option<TorMonitoringInfo> {
338 match self {
339 TransportHandle::Tor(t) => t.cached_monitoring(),
340 _ => None,
341 }
342 }
343
344 pub fn tor_mode(&self) -> Option<&str> {
346 match self {
347 TransportHandle::Tor(t) => Some(t.mode()),
348 _ => None,
349 }
350 }
351
352 pub fn discover(&self) -> Result<Vec<DiscoveredPeer>, TransportError> {
354 match self {
355 TransportHandle::Udp(t) => t.discover(),
356 #[cfg(feature = "sim-transport")]
357 TransportHandle::Sim(t) => t.discover(),
358 #[cfg(any(target_os = "linux", target_os = "macos"))]
359 TransportHandle::Ethernet(t) => t.discover(),
360 TransportHandle::Tcp(t) => t.discover(),
361 TransportHandle::WebSocket(t) => t.discover(),
362 TransportHandle::Tor(t) => t.discover(),
363 #[cfg(feature = "webrtc-transport")]
364 TransportHandle::WebRtc(t) => t.discover(),
365 #[cfg(target_os = "linux")]
366 TransportHandle::Ble(t) => t.discover(),
367 }
368 }
369
370 pub fn auto_connect(&self) -> bool {
372 match self {
373 TransportHandle::Udp(t) => t.auto_connect(),
374 #[cfg(feature = "sim-transport")]
375 TransportHandle::Sim(t) => t.auto_connect(),
376 #[cfg(any(target_os = "linux", target_os = "macos"))]
377 TransportHandle::Ethernet(t) => t.auto_connect(),
378 TransportHandle::Tcp(t) => t.auto_connect(),
379 TransportHandle::WebSocket(t) => t.auto_connect(),
380 TransportHandle::Tor(t) => t.auto_connect(),
381 #[cfg(feature = "webrtc-transport")]
382 TransportHandle::WebRtc(t) => t.auto_connect(),
383 #[cfg(target_os = "linux")]
384 TransportHandle::Ble(t) => t.auto_connect(),
385 }
386 }
387
388 pub fn accept_connections(&self) -> bool {
390 match self {
391 TransportHandle::Udp(t) => t.accept_connections(),
392 #[cfg(feature = "sim-transport")]
393 TransportHandle::Sim(t) => t.accept_connections(),
394 #[cfg(any(target_os = "linux", target_os = "macos"))]
395 TransportHandle::Ethernet(t) => t.accept_connections(),
396 TransportHandle::Tcp(t) => t.accept_connections(),
397 TransportHandle::WebSocket(t) => t.accept_connections(),
398 TransportHandle::Tor(t) => t.accept_connections(),
399 #[cfg(feature = "webrtc-transport")]
400 TransportHandle::WebRtc(t) => t.accept_connections(),
401 #[cfg(target_os = "linux")]
402 TransportHandle::Ble(t) => t.accept_connections(),
403 }
404 }
405
406 pub async fn connect(&self, addr: &TransportAddr) -> Result<(), TransportError> {
414 match self {
415 TransportHandle::Udp(_) => Ok(()), #[cfg(feature = "sim-transport")]
417 TransportHandle::Sim(_) => Ok(()), #[cfg(any(target_os = "linux", target_os = "macos"))]
419 TransportHandle::Ethernet(_) => Ok(()), TransportHandle::Tcp(t) => t.connect_async(addr).await,
421 TransportHandle::WebSocket(t) => t.connect_async(addr).await,
422 TransportHandle::Tor(t) => t.connect_async(addr).await,
423 #[cfg(feature = "webrtc-transport")]
424 TransportHandle::WebRtc(t) => t.connect_async(addr).await,
425 #[cfg(target_os = "linux")]
426 TransportHandle::Ble(t) => t.connect_async(addr).await,
427 }
428 }
429
430 pub fn connection_state(&self, addr: &TransportAddr) -> ConnectionState {
436 match self {
437 TransportHandle::Udp(_) => ConnectionState::Connected,
438 #[cfg(feature = "sim-transport")]
439 TransportHandle::Sim(_) => ConnectionState::Connected,
440 #[cfg(any(target_os = "linux", target_os = "macos"))]
441 TransportHandle::Ethernet(_) => ConnectionState::Connected,
442 TransportHandle::Tcp(t) => t.connection_state_sync(addr),
443 TransportHandle::WebSocket(t) => t.connection_state_sync(addr),
444 TransportHandle::Tor(t) => t.connection_state_sync(addr),
445 #[cfg(feature = "webrtc-transport")]
446 TransportHandle::WebRtc(t) => t.connection_state_sync(addr),
447 #[cfg(target_os = "linux")]
448 TransportHandle::Ble(t) => t.connection_state_sync(addr),
449 }
450 }
451
452 pub async fn close_connection(&self, addr: &TransportAddr) {
457 match self {
458 TransportHandle::Udp(t) => t.close_connection(addr),
459 #[cfg(feature = "sim-transport")]
460 TransportHandle::Sim(t) => t.close_connection(addr),
461 #[cfg(any(target_os = "linux", target_os = "macos"))]
462 TransportHandle::Ethernet(t) => t.close_connection(addr),
463 TransportHandle::Tcp(t) => t.close_connection_async(addr).await,
464 TransportHandle::WebSocket(t) => t.close_connection_async(addr).await,
465 TransportHandle::Tor(t) => t.close_connection_async(addr).await,
466 #[cfg(feature = "webrtc-transport")]
467 TransportHandle::WebRtc(t) => t.close_connection_async(addr).await,
468 #[cfg(target_os = "linux")]
469 TransportHandle::Ble(t) => t.close_connection_async(addr).await,
470 }
471 }
472
473 pub fn close_connection_detached(&self, _addr: &TransportAddr) {
475 #[cfg(feature = "webrtc-transport")]
476 if let TransportHandle::WebRtc(transport) = self {
477 transport.close_connection_detached(_addr);
478 }
479 }
480
481 pub fn is_operational(&self) -> bool {
483 self.state().is_operational()
484 }
485
486 pub fn congestion(&self) -> TransportCongestion {
492 match self {
493 TransportHandle::Udp(t) => t.congestion(),
494 #[cfg(feature = "sim-transport")]
495 TransportHandle::Sim(_) => TransportCongestion::default(),
496 #[cfg(any(target_os = "linux", target_os = "macos"))]
497 TransportHandle::Ethernet(_) => TransportCongestion::default(),
498 TransportHandle::Tcp(_) => TransportCongestion::default(),
499 TransportHandle::WebSocket(_) => TransportCongestion::default(),
500 TransportHandle::Tor(_) => TransportCongestion::default(),
501 #[cfg(feature = "webrtc-transport")]
502 TransportHandle::WebRtc(_) => TransportCongestion::default(),
503 #[cfg(target_os = "linux")]
504 TransportHandle::Ble(_) => TransportCongestion::default(),
505 }
506 }
507
508 pub fn transport_stats(&self) -> serde_json::Value {
512 match self {
513 TransportHandle::Udp(t) => {
514 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
515 }
516 #[cfg(feature = "sim-transport")]
517 TransportHandle::Sim(t) => serde_json::to_value(t.stats()).unwrap_or_default(),
518 #[cfg(any(target_os = "linux", target_os = "macos"))]
519 TransportHandle::Ethernet(t) => {
520 let snap = t.stats().snapshot();
521 serde_json::json!({
522 "frames_sent": snap.frames_sent,
523 "frames_recv": snap.frames_recv,
524 "bytes_sent": snap.bytes_sent,
525 "bytes_recv": snap.bytes_recv,
526 "send_errors": snap.send_errors,
527 "recv_errors": snap.recv_errors,
528 "beacons_sent": snap.beacons_sent,
529 "beacons_recv": snap.beacons_recv,
530 "frames_too_short": snap.frames_too_short,
531 "frames_too_long": snap.frames_too_long,
532 })
533 }
534 TransportHandle::Tcp(t) => {
535 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
536 }
537 TransportHandle::WebSocket(t) => serde_json::to_value(t.stats()).unwrap_or_default(),
538 TransportHandle::Tor(t) => {
539 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
540 }
541 #[cfg(feature = "webrtc-transport")]
542 TransportHandle::WebRtc(t) => serde_json::json!({
543 "mtu": t.mtu(),
544 "state": t.state().to_string(),
545 }),
546 #[cfg(target_os = "linux")]
547 TransportHandle::Ble(t) => {
548 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
549 }
550 }
551 }
552}