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 is_configured_websocket_adjacency(
50 &self,
51 addr: &TransportAddr,
52 handshake_is_initiator: bool,
53 ) -> bool {
54 match self {
55 TransportHandle::WebSocket(transport) => {
56 transport.is_configured_adjacency(addr, handshake_is_initiator)
57 }
58 _ => false,
59 }
60 }
61
62 pub(crate) fn canonical_addr(
66 &self,
67 addr: &TransportAddr,
68 ) -> Result<TransportAddr, TransportError> {
69 match self {
70 #[cfg(feature = "webrtc-transport")]
71 TransportHandle::WebRtc(_) => super::webrtc::canonical_webrtc_addr(addr),
72 _ => Ok(addr.clone()),
73 }
74 }
75
76 #[cfg(feature = "webrtc-transport")]
79 pub(crate) fn drain_link_negotiations(
80 &mut self,
81 limit: usize,
82 ) -> Vec<super::link_negotiation::OutboundLinkNegotiation> {
83 match self {
84 TransportHandle::WebRtc(transport) => transport.drain_link_negotiations(limit),
85 _ => Vec::new(),
86 }
87 }
88
89 #[cfg(feature = "webrtc-transport")]
91 pub(crate) fn ingest_link_negotiation(
92 &self,
93 source: secp256k1::PublicKey,
94 message: super::link_negotiation::LinkNegotiationMessage,
95 ) -> Result<(), TransportError> {
96 match self {
97 TransportHandle::WebRtc(transport) if message.link_type == "webrtc" => {
98 transport.ingest_link_negotiation(source, message)
99 }
100 _ => Err(TransportError::NotSupported(
101 "no enabled adapter accepts this link negotiation".into(),
102 )),
103 }
104 }
105
106 pub async fn start(&mut self) -> Result<(), TransportError> {
108 match self {
109 TransportHandle::Udp(t) => t.start_async().await,
110 #[cfg(feature = "sim-transport")]
111 TransportHandle::Sim(t) => t.start_async().await,
112 #[cfg(any(target_os = "linux", target_os = "macos"))]
113 TransportHandle::Ethernet(t) => t.start_async().await,
114 TransportHandle::Tcp(t) => t.start_async().await,
115 TransportHandle::WebSocket(t) => t.start_async().await,
116 TransportHandle::Tor(t) => t.start_async().await,
117 #[cfg(feature = "webrtc-transport")]
118 TransportHandle::WebRtc(t) => t.start_async().await,
119 #[cfg(target_os = "linux")]
120 TransportHandle::Ble(t) => t.start_async().await,
121 }
122 }
123
124 pub async fn stop(&mut self) -> Result<(), TransportError> {
126 match self {
127 TransportHandle::Udp(t) => t.stop_async().await,
128 #[cfg(feature = "sim-transport")]
129 TransportHandle::Sim(t) => t.stop_async().await,
130 #[cfg(any(target_os = "linux", target_os = "macos"))]
131 TransportHandle::Ethernet(t) => t.stop_async().await,
132 TransportHandle::Tcp(t) => t.stop_async().await,
133 TransportHandle::WebSocket(t) => t.stop_async().await,
134 TransportHandle::Tor(t) => t.stop_async().await,
135 #[cfg(feature = "webrtc-transport")]
136 TransportHandle::WebRtc(t) => t.stop_async().await,
137 #[cfg(target_os = "linux")]
138 TransportHandle::Ble(t) => t.stop_async().await,
139 }
140 }
141
142 pub async fn send(&self, addr: &TransportAddr, data: &[u8]) -> Result<usize, TransportError> {
144 match self {
145 TransportHandle::Udp(t) => t.send_async(addr, data).await,
146 #[cfg(feature = "sim-transport")]
147 TransportHandle::Sim(t) => t.send_async(addr, data).await,
148 #[cfg(any(target_os = "linux", target_os = "macos"))]
149 TransportHandle::Ethernet(t) => t.send_async(addr, data).await,
150 TransportHandle::Tcp(t) => t.send_async(addr, data).await,
151 TransportHandle::WebSocket(t) => t.send_async(addr, data).await,
152 TransportHandle::Tor(t) => t.send_async(addr, data).await,
153 #[cfg(feature = "webrtc-transport")]
154 TransportHandle::WebRtc(t) => Box::pin(t.send_async(addr, data)).await,
156 #[cfg(target_os = "linux")]
157 TransportHandle::Ble(t) => t.send_async(addr, data).await,
158 }
159 }
160
161 pub(crate) async fn send_with_timeout(
162 &self,
163 addr: &TransportAddr,
164 data: &[u8],
165 timeout: std::time::Duration,
166 ) -> Result<usize, TransportError> {
167 match self {
168 TransportHandle::Tcp(transport) => {
169 transport.send_async_with_timeout(addr, data, timeout).await
170 }
171 _ => self.send(addr, data).await,
172 }
173 }
174
175 pub fn transport_id(&self) -> TransportId {
177 match self {
178 TransportHandle::Udp(t) => t.transport_id(),
179 #[cfg(feature = "sim-transport")]
180 TransportHandle::Sim(t) => t.transport_id(),
181 #[cfg(any(target_os = "linux", target_os = "macos"))]
182 TransportHandle::Ethernet(t) => t.transport_id(),
183 TransportHandle::Tcp(t) => t.transport_id(),
184 TransportHandle::WebSocket(t) => t.transport_id(),
185 TransportHandle::Tor(t) => t.transport_id(),
186 #[cfg(feature = "webrtc-transport")]
187 TransportHandle::WebRtc(t) => t.transport_id(),
188 #[cfg(target_os = "linux")]
189 TransportHandle::Ble(t) => t.transport_id(),
190 }
191 }
192
193 pub(crate) fn uses_fips_byte_stream_framing(&self) -> bool {
195 matches!(self, TransportHandle::Tcp(_) | TransportHandle::Tor(_))
196 }
197
198 pub fn name(&self) -> Option<&str> {
200 match self {
201 TransportHandle::Udp(t) => t.name(),
202 #[cfg(feature = "sim-transport")]
203 TransportHandle::Sim(t) => t.name(),
204 #[cfg(any(target_os = "linux", target_os = "macos"))]
205 TransportHandle::Ethernet(t) => t.name(),
206 TransportHandle::Tcp(t) => t.name(),
207 TransportHandle::WebSocket(t) => t.name(),
208 TransportHandle::Tor(t) => t.name(),
209 #[cfg(feature = "webrtc-transport")]
210 TransportHandle::WebRtc(t) => t.name(),
211 #[cfg(target_os = "linux")]
212 TransportHandle::Ble(t) => t.name(),
213 }
214 }
215
216 pub fn transport_type(&self) -> &TransportType {
218 match self {
219 TransportHandle::Udp(t) => t.transport_type(),
220 #[cfg(feature = "sim-transport")]
221 TransportHandle::Sim(t) => t.transport_type(),
222 #[cfg(any(target_os = "linux", target_os = "macos"))]
223 TransportHandle::Ethernet(t) => t.transport_type(),
224 TransportHandle::Tcp(t) => t.transport_type(),
225 TransportHandle::WebSocket(t) => t.transport_type(),
226 TransportHandle::Tor(t) => t.transport_type(),
227 #[cfg(feature = "webrtc-transport")]
228 TransportHandle::WebRtc(t) => t.transport_type(),
229 #[cfg(target_os = "linux")]
230 TransportHandle::Ble(t) => t.transport_type(),
231 }
232 }
233
234 pub fn state(&self) -> TransportState {
236 match self {
237 TransportHandle::Udp(t) => t.state(),
238 #[cfg(feature = "sim-transport")]
239 TransportHandle::Sim(t) => t.state(),
240 #[cfg(any(target_os = "linux", target_os = "macos"))]
241 TransportHandle::Ethernet(t) => t.state(),
242 TransportHandle::Tcp(t) => t.state(),
243 TransportHandle::WebSocket(t) => t.state(),
244 TransportHandle::Tor(t) => t.state(),
245 #[cfg(feature = "webrtc-transport")]
246 TransportHandle::WebRtc(t) => t.state(),
247 #[cfg(target_os = "linux")]
248 TransportHandle::Ble(t) => t.state(),
249 }
250 }
251
252 pub fn mtu(&self) -> u16 {
254 match self {
255 TransportHandle::Udp(t) => t.mtu(),
256 #[cfg(feature = "sim-transport")]
257 TransportHandle::Sim(t) => t.mtu(),
258 #[cfg(any(target_os = "linux", target_os = "macos"))]
259 TransportHandle::Ethernet(t) => t.mtu(),
260 TransportHandle::Tcp(t) => t.mtu(),
261 TransportHandle::WebSocket(t) => t.mtu(),
262 TransportHandle::Tor(t) => t.mtu(),
263 #[cfg(feature = "webrtc-transport")]
264 TransportHandle::WebRtc(t) => t.mtu(),
265 #[cfg(target_os = "linux")]
266 TransportHandle::Ble(t) => t.mtu(),
267 }
268 }
269
270 pub fn link_mtu(&self, addr: &TransportAddr) -> u16 {
275 match self {
276 TransportHandle::Udp(t) => t.link_mtu(addr),
277 #[cfg(feature = "sim-transport")]
278 TransportHandle::Sim(t) => t.link_mtu(addr),
279 #[cfg(any(target_os = "linux", target_os = "macos"))]
280 TransportHandle::Ethernet(t) => t.link_mtu(addr),
281 TransportHandle::Tcp(t) => t.link_mtu(addr),
282 TransportHandle::WebSocket(t) => t.link_mtu(addr),
283 TransportHandle::Tor(t) => t.link_mtu(addr),
284 #[cfg(feature = "webrtc-transport")]
285 TransportHandle::WebRtc(t) => t.link_mtu(addr),
286 #[cfg(target_os = "linux")]
287 TransportHandle::Ble(t) => t.link_mtu(addr),
288 }
289 }
290
291 pub fn local_addr(&self) -> Option<std::net::SocketAddr> {
293 match self {
294 TransportHandle::Udp(t) => t.local_addr(),
295 #[cfg(feature = "sim-transport")]
296 TransportHandle::Sim(_) => None,
297 #[cfg(any(target_os = "linux", target_os = "macos"))]
298 TransportHandle::Ethernet(_) => None,
299 TransportHandle::Tcp(t) => t.local_addr(),
300 TransportHandle::WebSocket(t) => t.local_addr(),
301 TransportHandle::Tor(_) => None,
302 #[cfg(feature = "webrtc-transport")]
303 TransportHandle::WebRtc(_) => None,
304 #[cfg(target_os = "linux")]
305 TransportHandle::Ble(_) => None,
306 }
307 }
308
309 pub(crate) fn resolved_udp_socket_addr_if_cached(
314 &self,
315 addr: &TransportAddr,
316 ) -> Option<std::net::SocketAddr> {
317 match self {
318 TransportHandle::Udp(t) => t.resolved_socket_addr_if_cached(addr),
319 _ => None,
320 }
321 }
322
323 pub fn interface_name(&self) -> Option<&str> {
325 match self {
326 TransportHandle::Udp(_) => None,
327 #[cfg(feature = "sim-transport")]
328 TransportHandle::Sim(_) => None,
329 #[cfg(any(target_os = "linux", target_os = "macos"))]
330 TransportHandle::Ethernet(t) => Some(t.interface_name()),
331 TransportHandle::Tcp(_) => None,
332 TransportHandle::WebSocket(_) => None,
333 TransportHandle::Tor(_) => None,
334 #[cfg(feature = "webrtc-transport")]
335 TransportHandle::WebRtc(_) => None,
336 #[cfg(target_os = "linux")]
337 TransportHandle::Ble(_) => None,
338 }
339 }
340
341 pub fn onion_address(&self) -> Option<&str> {
343 match self {
344 TransportHandle::Tor(t) => t.onion_address(),
345 _ => None,
346 }
347 }
348
349 pub fn tor_monitoring(&self) -> Option<TorMonitoringInfo> {
351 match self {
352 TransportHandle::Tor(t) => t.cached_monitoring(),
353 _ => None,
354 }
355 }
356
357 pub fn tor_mode(&self) -> Option<&str> {
359 match self {
360 TransportHandle::Tor(t) => Some(t.mode()),
361 _ => None,
362 }
363 }
364
365 pub fn discover(&self) -> Result<Vec<DiscoveredPeer>, TransportError> {
367 match self {
368 TransportHandle::Udp(t) => t.discover(),
369 #[cfg(feature = "sim-transport")]
370 TransportHandle::Sim(t) => t.discover(),
371 #[cfg(any(target_os = "linux", target_os = "macos"))]
372 TransportHandle::Ethernet(t) => t.discover(),
373 TransportHandle::Tcp(t) => t.discover(),
374 TransportHandle::WebSocket(t) => t.discover(),
375 TransportHandle::Tor(t) => t.discover(),
376 #[cfg(feature = "webrtc-transport")]
377 TransportHandle::WebRtc(t) => t.discover(),
378 #[cfg(target_os = "linux")]
379 TransportHandle::Ble(t) => t.discover(),
380 }
381 }
382
383 pub fn auto_connect(&self) -> bool {
385 match self {
386 TransportHandle::Udp(t) => t.auto_connect(),
387 #[cfg(feature = "sim-transport")]
388 TransportHandle::Sim(t) => t.auto_connect(),
389 #[cfg(any(target_os = "linux", target_os = "macos"))]
390 TransportHandle::Ethernet(t) => t.auto_connect(),
391 TransportHandle::Tcp(t) => t.auto_connect(),
392 TransportHandle::WebSocket(t) => t.auto_connect(),
393 TransportHandle::Tor(t) => t.auto_connect(),
394 #[cfg(feature = "webrtc-transport")]
395 TransportHandle::WebRtc(t) => t.auto_connect(),
396 #[cfg(target_os = "linux")]
397 TransportHandle::Ble(t) => t.auto_connect(),
398 }
399 }
400
401 pub fn accept_connections(&self) -> bool {
403 match self {
404 TransportHandle::Udp(t) => t.accept_connections(),
405 #[cfg(feature = "sim-transport")]
406 TransportHandle::Sim(t) => t.accept_connections(),
407 #[cfg(any(target_os = "linux", target_os = "macos"))]
408 TransportHandle::Ethernet(t) => t.accept_connections(),
409 TransportHandle::Tcp(t) => t.accept_connections(),
410 TransportHandle::WebSocket(t) => t.accept_connections(),
411 TransportHandle::Tor(t) => t.accept_connections(),
412 #[cfg(feature = "webrtc-transport")]
413 TransportHandle::WebRtc(t) => t.accept_connections(),
414 #[cfg(target_os = "linux")]
415 TransportHandle::Ble(t) => t.accept_connections(),
416 }
417 }
418
419 pub async fn connect(&self, addr: &TransportAddr) -> Result<(), TransportError> {
427 match self {
428 TransportHandle::Udp(_) => Ok(()), #[cfg(feature = "sim-transport")]
430 TransportHandle::Sim(_) => Ok(()), #[cfg(any(target_os = "linux", target_os = "macos"))]
432 TransportHandle::Ethernet(_) => Ok(()), TransportHandle::Tcp(t) => t.connect_async(addr).await,
434 TransportHandle::WebSocket(t) => t.connect_async(addr).await,
435 TransportHandle::Tor(t) => t.connect_async(addr).await,
436 #[cfg(feature = "webrtc-transport")]
437 TransportHandle::WebRtc(t) => t.connect_async(addr).await,
438 #[cfg(target_os = "linux")]
439 TransportHandle::Ble(t) => t.connect_async(addr).await,
440 }
441 }
442
443 pub fn connection_state(&self, addr: &TransportAddr) -> ConnectionState {
449 match self {
450 TransportHandle::Udp(_) => ConnectionState::Connected,
451 #[cfg(feature = "sim-transport")]
452 TransportHandle::Sim(_) => ConnectionState::Connected,
453 #[cfg(any(target_os = "linux", target_os = "macos"))]
454 TransportHandle::Ethernet(_) => ConnectionState::Connected,
455 TransportHandle::Tcp(t) => t.connection_state_sync(addr),
456 TransportHandle::WebSocket(t) => t.connection_state_sync(addr),
457 TransportHandle::Tor(t) => t.connection_state_sync(addr),
458 #[cfg(feature = "webrtc-transport")]
459 TransportHandle::WebRtc(t) => t.connection_state_sync(addr),
460 #[cfg(target_os = "linux")]
461 TransportHandle::Ble(t) => t.connection_state_sync(addr),
462 }
463 }
464
465 pub async fn close_connection(&self, addr: &TransportAddr) {
470 match self {
471 TransportHandle::Udp(t) => t.close_connection(addr),
472 #[cfg(feature = "sim-transport")]
473 TransportHandle::Sim(t) => t.close_connection(addr),
474 #[cfg(any(target_os = "linux", target_os = "macos"))]
475 TransportHandle::Ethernet(t) => t.close_connection(addr),
476 TransportHandle::Tcp(t) => t.close_connection_async(addr).await,
477 TransportHandle::WebSocket(t) => t.close_connection_async(addr).await,
478 TransportHandle::Tor(t) => t.close_connection_async(addr).await,
479 #[cfg(feature = "webrtc-transport")]
480 TransportHandle::WebRtc(t) => t.close_connection_async(addr).await,
481 #[cfg(target_os = "linux")]
482 TransportHandle::Ble(t) => t.close_connection_async(addr).await,
483 }
484 }
485
486 pub fn close_connection_detached(&self, _addr: &TransportAddr) {
488 #[cfg(feature = "webrtc-transport")]
489 if let TransportHandle::WebRtc(transport) = self {
490 transport.close_connection_detached(_addr);
491 }
492 }
493
494 pub fn is_operational(&self) -> bool {
496 self.state().is_operational()
497 }
498
499 pub fn congestion(&self) -> TransportCongestion {
505 match self {
506 TransportHandle::Udp(t) => t.congestion(),
507 #[cfg(feature = "sim-transport")]
508 TransportHandle::Sim(_) => TransportCongestion::default(),
509 #[cfg(any(target_os = "linux", target_os = "macos"))]
510 TransportHandle::Ethernet(_) => TransportCongestion::default(),
511 TransportHandle::Tcp(_) => TransportCongestion::default(),
512 TransportHandle::WebSocket(_) => TransportCongestion::default(),
513 TransportHandle::Tor(_) => TransportCongestion::default(),
514 #[cfg(feature = "webrtc-transport")]
515 TransportHandle::WebRtc(_) => TransportCongestion::default(),
516 #[cfg(target_os = "linux")]
517 TransportHandle::Ble(_) => TransportCongestion::default(),
518 }
519 }
520
521 pub fn transport_stats(&self) -> serde_json::Value {
525 match self {
526 TransportHandle::Udp(t) => {
527 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
528 }
529 #[cfg(feature = "sim-transport")]
530 TransportHandle::Sim(t) => serde_json::to_value(t.stats()).unwrap_or_default(),
531 #[cfg(any(target_os = "linux", target_os = "macos"))]
532 TransportHandle::Ethernet(t) => {
533 let snap = t.stats().snapshot();
534 serde_json::json!({
535 "frames_sent": snap.frames_sent,
536 "frames_recv": snap.frames_recv,
537 "bytes_sent": snap.bytes_sent,
538 "bytes_recv": snap.bytes_recv,
539 "send_errors": snap.send_errors,
540 "recv_errors": snap.recv_errors,
541 "beacons_sent": snap.beacons_sent,
542 "beacons_recv": snap.beacons_recv,
543 "frames_too_short": snap.frames_too_short,
544 "frames_too_long": snap.frames_too_long,
545 })
546 }
547 TransportHandle::Tcp(t) => {
548 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
549 }
550 TransportHandle::WebSocket(t) => serde_json::to_value(t.stats()).unwrap_or_default(),
551 TransportHandle::Tor(t) => {
552 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
553 }
554 #[cfg(feature = "webrtc-transport")]
555 TransportHandle::WebRtc(t) => serde_json::json!({
556 "mtu": t.mtu(),
557 "state": t.state().to_string(),
558 }),
559 #[cfg(target_os = "linux")]
560 TransportHandle::Ble(t) => {
561 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
562 }
563 }
564 }
565}