1use std::collections::HashMap;
7use std::net::{IpAddr, SocketAddr};
8
9use serde::{Deserialize, Serialize};
10
11fn parse_external_advert_addr(raw: &str, bind_port: u16) -> Option<SocketAddr> {
19 if let Ok(sa) = raw.parse::<SocketAddr>() {
20 return Some(sa);
21 }
22 let ip: IpAddr = raw.parse().ok()?;
23 Some(SocketAddr::new(ip, bind_port))
24}
25
26fn parse_bind_port(raw: &str) -> Option<u16> {
29 raw.parse::<SocketAddr>().ok().map(|sa| sa.port())
30}
31
32const DEFAULT_UDP_BIND_ADDR: &str = "0.0.0.0:2121";
34
35const DEFAULT_UDP_MTU: u16 = 1280;
37
38const DEFAULT_UDP_RECV_BUF: usize = 16 * 1024 * 1024;
52
53const DEFAULT_UDP_SEND_BUF: usize = 8 * 1024 * 1024;
58
59#[derive(Debug, Clone, Default, Serialize, Deserialize)]
61#[serde(deny_unknown_fields)]
62pub struct UdpConfig {
63 #[serde(default, skip_serializing_if = "Option::is_none")]
68 pub bind_addr: Option<String>,
69
70 #[serde(default, skip_serializing_if = "Option::is_none")]
72 pub mtu: Option<u16>,
73
74 #[serde(default, skip_serializing_if = "Option::is_none")]
76 pub recv_buf_size: Option<usize>,
77
78 #[serde(default, skip_serializing_if = "Option::is_none")]
80 pub send_buf_size: Option<usize>,
81
82 #[serde(default, skip_serializing_if = "Option::is_none")]
85 pub advertise_on_nostr: Option<bool>,
86
87 #[serde(default, skip_serializing_if = "Option::is_none")]
93 pub public: Option<bool>,
94 #[serde(default, skip_serializing_if = "Option::is_none")]
103 pub external_addr: Option<String>,
104 #[serde(default, skip_serializing_if = "Option::is_none")]
112 pub outbound_only: Option<bool>,
113
114 #[serde(default, skip_serializing_if = "Option::is_none")]
123 pub accept_connections: Option<bool>,
124}
125
126impl UdpConfig {
127 pub fn bind_addr(&self) -> &str {
132 if self.outbound_only() {
133 "0.0.0.0:0"
134 } else {
135 self.bind_addr.as_deref().unwrap_or(DEFAULT_UDP_BIND_ADDR)
136 }
137 }
138
139 pub fn mtu(&self) -> u16 {
141 self.mtu.unwrap_or(DEFAULT_UDP_MTU)
142 }
143
144 pub fn recv_buf_size(&self) -> usize {
146 self.recv_buf_size.unwrap_or(DEFAULT_UDP_RECV_BUF)
147 }
148
149 pub fn send_buf_size(&self) -> usize {
151 self.send_buf_size.unwrap_or(DEFAULT_UDP_SEND_BUF)
152 }
153
154 pub fn advertise_on_nostr(&self) -> bool {
157 if self.outbound_only() {
158 false
159 } else {
160 self.advertise_on_nostr.unwrap_or(false)
161 }
162 }
163
164 pub fn is_public(&self) -> bool {
166 self.public.unwrap_or(false)
167 }
168
169 pub fn external_advert_addr(&self) -> Option<SocketAddr> {
174 let raw = self.external_addr.as_deref()?;
175 let bind_port = parse_bind_port(self.bind_addr())?;
176 parse_external_advert_addr(raw, bind_port)
177 }
178
179 pub fn outbound_only(&self) -> bool {
181 self.outbound_only.unwrap_or(false)
182 }
183
184 pub fn accept_connections(&self) -> bool {
186 self.accept_connections.unwrap_or(true)
187 }
188}
189
190#[cfg(feature = "sim-transport")]
192const DEFAULT_SIM_MTU: u16 = 1280;
193
194#[cfg(feature = "sim-transport")]
196const DEFAULT_SIM_NETWORK: &str = "default";
197
198#[cfg(feature = "sim-transport")]
205#[derive(Debug, Clone, Default, Serialize, Deserialize)]
206#[serde(deny_unknown_fields)]
207pub struct SimTransportConfig {
208 #[serde(default, skip_serializing_if = "Option::is_none")]
210 pub network: Option<String>,
211
212 #[serde(default, skip_serializing_if = "Option::is_none")]
214 pub addr: Option<String>,
215
216 #[serde(default, skip_serializing_if = "Option::is_none")]
218 pub mtu: Option<u16>,
219
220 #[serde(default, skip_serializing_if = "Option::is_none")]
222 pub auto_connect: Option<bool>,
223
224 #[serde(default, skip_serializing_if = "Option::is_none")]
226 pub accept_connections: Option<bool>,
227}
228
229#[cfg(feature = "sim-transport")]
230impl SimTransportConfig {
231 pub fn network(&self) -> &str {
233 self.network.as_deref().unwrap_or(DEFAULT_SIM_NETWORK)
234 }
235
236 pub fn mtu(&self) -> u16 {
238 self.mtu.unwrap_or(DEFAULT_SIM_MTU)
239 }
240
241 pub fn auto_connect(&self) -> bool {
243 self.auto_connect.unwrap_or(false)
244 }
245
246 pub fn accept_connections(&self) -> bool {
248 self.accept_connections.unwrap_or(true)
249 }
250}
251
252#[derive(Debug, Clone, Serialize, Deserialize)]
271#[serde(untagged)]
272pub enum TransportInstances<T> {
273 Single(T),
275 Named(HashMap<String, T>),
277}
278
279impl<T> TransportInstances<T> {
280 pub fn len(&self) -> usize {
282 match self {
283 TransportInstances::Single(_) => 1,
284 TransportInstances::Named(map) => map.len(),
285 }
286 }
287
288 pub fn is_empty(&self) -> bool {
290 match self {
291 TransportInstances::Single(_) => false,
292 TransportInstances::Named(map) => map.is_empty(),
293 }
294 }
295
296 pub fn iter(&self) -> impl Iterator<Item = (Option<&str>, &T)> {
301 match self {
302 TransportInstances::Single(config) => vec![(None, config)].into_iter(),
303 TransportInstances::Named(map) => map
304 .iter()
305 .map(|(k, v)| (Some(k.as_str()), v))
306 .collect::<Vec<_>>()
307 .into_iter(),
308 }
309 }
310}
311
312impl<T> Default for TransportInstances<T> {
313 fn default() -> Self {
314 TransportInstances::Named(HashMap::new())
315 }
316}
317
318const DEFAULT_ETHERNET_ETHERTYPE: u16 = 0x2121;
320
321const DEFAULT_ETHERNET_RECV_BUF: usize = 2 * 1024 * 1024;
323
324const DEFAULT_ETHERNET_SEND_BUF: usize = 2 * 1024 * 1024;
326
327const DEFAULT_BEACON_INTERVAL_SECS: u64 = 30;
329
330const MIN_BEACON_INTERVAL_SECS: u64 = 10;
332
333#[derive(Debug, Clone, Default, Serialize, Deserialize)]
338#[serde(deny_unknown_fields)]
339pub struct EthernetConfig {
340 pub interface: String,
342
343 #[serde(default, skip_serializing_if = "Option::is_none")]
345 pub ethertype: Option<u16>,
346
347 #[serde(default, skip_serializing_if = "Option::is_none")]
350 pub mtu: Option<u16>,
351
352 #[serde(default, skip_serializing_if = "Option::is_none")]
354 pub recv_buf_size: Option<usize>,
355
356 #[serde(default, skip_serializing_if = "Option::is_none")]
358 pub send_buf_size: Option<usize>,
359
360 #[serde(default, skip_serializing_if = "Option::is_none")]
362 pub discovery: Option<bool>,
363
364 #[serde(default, skip_serializing_if = "Option::is_none")]
366 pub announce: Option<bool>,
367
368 #[serde(default, skip_serializing_if = "Option::is_none")]
370 pub auto_connect: Option<bool>,
371
372 #[serde(default, skip_serializing_if = "Option::is_none")]
374 pub accept_connections: Option<bool>,
375
376 #[serde(default, skip_serializing_if = "Option::is_none")]
382 pub discovery_scope: Option<String>,
383
384 #[serde(default, skip_serializing_if = "Option::is_none")]
386 pub beacon_interval_secs: Option<u64>,
387}
388
389impl EthernetConfig {
390 pub fn ethertype(&self) -> u16 {
392 self.ethertype.unwrap_or(DEFAULT_ETHERNET_ETHERTYPE)
393 }
394
395 pub fn recv_buf_size(&self) -> usize {
397 self.recv_buf_size.unwrap_or(DEFAULT_ETHERNET_RECV_BUF)
398 }
399
400 pub fn send_buf_size(&self) -> usize {
402 self.send_buf_size.unwrap_or(DEFAULT_ETHERNET_SEND_BUF)
403 }
404
405 pub fn discovery(&self) -> bool {
407 self.discovery.unwrap_or(true)
408 }
409
410 pub fn announce(&self) -> bool {
412 self.announce.unwrap_or(false)
413 }
414
415 pub fn auto_connect(&self) -> bool {
417 self.auto_connect.unwrap_or(false)
418 }
419
420 pub fn accept_connections(&self) -> bool {
422 self.accept_connections.unwrap_or(false)
423 }
424
425 pub fn discovery_scope(&self) -> Option<&str> {
427 self.discovery_scope.as_deref().filter(|s| !s.is_empty())
428 }
429
430 pub fn beacon_interval_secs(&self) -> u64 {
432 self.beacon_interval_secs
433 .unwrap_or(DEFAULT_BEACON_INTERVAL_SECS)
434 .max(MIN_BEACON_INTERVAL_SECS)
435 }
436}
437
438const DEFAULT_TCP_MTU: u16 = 1400;
444
445const DEFAULT_TCP_CONNECT_TIMEOUT_MS: u64 = 5000;
447
448const DEFAULT_TCP_KEEPALIVE_SECS: u64 = 30;
450
451const DEFAULT_TCP_RECV_BUF: usize = 2 * 1024 * 1024;
453
454const DEFAULT_TCP_SEND_BUF: usize = 2 * 1024 * 1024;
456
457const DEFAULT_TCP_MAX_INBOUND: usize = 256;
459
460#[derive(Debug, Clone, Default, Serialize, Deserialize)]
462#[serde(deny_unknown_fields)]
463pub struct TcpConfig {
464 #[serde(default, skip_serializing_if = "Option::is_none")]
466 pub bind_addr: Option<String>,
467
468 #[serde(default, skip_serializing_if = "Option::is_none")]
471 pub mtu: Option<u16>,
472
473 #[serde(default, skip_serializing_if = "Option::is_none")]
475 pub connect_timeout_ms: Option<u64>,
476
477 #[serde(default, skip_serializing_if = "Option::is_none")]
479 pub nodelay: Option<bool>,
480
481 #[serde(default, skip_serializing_if = "Option::is_none")]
483 pub keepalive_secs: Option<u64>,
484
485 #[serde(default, skip_serializing_if = "Option::is_none")]
487 pub recv_buf_size: Option<usize>,
488
489 #[serde(default, skip_serializing_if = "Option::is_none")]
491 pub send_buf_size: Option<usize>,
492
493 #[serde(default, skip_serializing_if = "Option::is_none")]
495 pub max_inbound_connections: Option<usize>,
496
497 #[serde(default, skip_serializing_if = "Option::is_none")]
500 pub advertise_on_nostr: Option<bool>,
501
502 #[serde(default, skip_serializing_if = "Option::is_none")]
510 pub external_addr: Option<String>,
511}
512
513impl TcpConfig {
514 pub fn mtu(&self) -> u16 {
516 self.mtu.unwrap_or(DEFAULT_TCP_MTU)
517 }
518
519 pub fn connect_timeout_ms(&self) -> u64 {
521 self.connect_timeout_ms
522 .unwrap_or(DEFAULT_TCP_CONNECT_TIMEOUT_MS)
523 }
524
525 pub fn nodelay(&self) -> bool {
527 self.nodelay.unwrap_or(true)
528 }
529
530 pub fn keepalive_secs(&self) -> u64 {
532 self.keepalive_secs.unwrap_or(DEFAULT_TCP_KEEPALIVE_SECS)
533 }
534
535 pub fn recv_buf_size(&self) -> usize {
537 self.recv_buf_size.unwrap_or(DEFAULT_TCP_RECV_BUF)
538 }
539
540 pub fn send_buf_size(&self) -> usize {
542 self.send_buf_size.unwrap_or(DEFAULT_TCP_SEND_BUF)
543 }
544
545 pub fn max_inbound_connections(&self) -> usize {
547 self.max_inbound_connections
548 .unwrap_or(DEFAULT_TCP_MAX_INBOUND)
549 }
550
551 pub fn advertise_on_nostr(&self) -> bool {
553 self.advertise_on_nostr.unwrap_or(false)
554 }
555
556 pub fn external_advert_addr(&self) -> Option<SocketAddr> {
561 let raw = self.external_addr.as_deref()?;
562 let bind_port = parse_bind_port(self.bind_addr.as_deref()?)?;
563 parse_external_advert_addr(raw, bind_port)
564 }
565}
566
567const DEFAULT_TOR_SOCKS5_ADDR: &str = "127.0.0.1:9050";
573
574const DEFAULT_TOR_CONTROL_ADDR: &str = "/run/tor/control";
576
577const DEFAULT_TOR_COOKIE_PATH: &str = "/var/run/tor/control.authcookie";
579
580const DEFAULT_TOR_CONNECT_TIMEOUT_MS: u64 = 120_000;
583
584const DEFAULT_TOR_MTU: u16 = 1400;
586
587const DEFAULT_TOR_MAX_INBOUND: usize = 64;
589
590const DEFAULT_HOSTNAME_FILE: &str = "/var/lib/tor/fips_onion_service/hostname";
592
593const DEFAULT_DIRECTORY_BIND_ADDR: &str = "127.0.0.1:8443";
595
596const DEFAULT_TOR_ADVERTISED_PORT: u16 = 443;
599
600#[derive(Debug, Clone, Default, Serialize, Deserialize)]
610#[serde(deny_unknown_fields)]
611pub struct TorConfig {
612 #[serde(default, skip_serializing_if = "Option::is_none")]
615 pub mode: Option<String>,
616
617 #[serde(default, skip_serializing_if = "Option::is_none")]
619 pub socks5_addr: Option<String>,
620
621 #[serde(default, skip_serializing_if = "Option::is_none")]
624 pub connect_timeout_ms: Option<u64>,
625
626 #[serde(default, skip_serializing_if = "Option::is_none")]
628 pub mtu: Option<u16>,
629
630 #[serde(default, skip_serializing_if = "Option::is_none")]
634 pub control_addr: Option<String>,
635
636 #[serde(default, skip_serializing_if = "Option::is_none")]
641 pub control_auth: Option<String>,
642
643 #[serde(default, skip_serializing_if = "Option::is_none")]
646 pub cookie_path: Option<String>,
647
648 #[serde(default, skip_serializing_if = "Option::is_none")]
650 pub max_inbound_connections: Option<usize>,
651
652 #[serde(default, skip_serializing_if = "Option::is_none")]
656 pub directory_service: Option<DirectoryServiceConfig>,
657
658 #[serde(default, skip_serializing_if = "Option::is_none")]
661 pub advertise_on_nostr: Option<bool>,
662
663 #[serde(default, skip_serializing_if = "Option::is_none")]
668 pub advertised_port: Option<u16>,
669}
670
671#[derive(Debug, Clone, Default, Serialize, Deserialize)]
678#[serde(deny_unknown_fields)]
679pub struct DirectoryServiceConfig {
680 #[serde(default, skip_serializing_if = "Option::is_none")]
683 pub hostname_file: Option<String>,
684
685 #[serde(default, skip_serializing_if = "Option::is_none")]
689 pub bind_addr: Option<String>,
690}
691
692impl DirectoryServiceConfig {
693 pub fn hostname_file(&self) -> &str {
695 self.hostname_file
696 .as_deref()
697 .unwrap_or(DEFAULT_HOSTNAME_FILE)
698 }
699
700 pub fn bind_addr(&self) -> &str {
702 self.bind_addr
703 .as_deref()
704 .unwrap_or(DEFAULT_DIRECTORY_BIND_ADDR)
705 }
706}
707
708impl TorConfig {
709 pub fn mode(&self) -> &str {
711 self.mode.as_deref().unwrap_or("socks5")
712 }
713
714 pub fn socks5_addr(&self) -> &str {
716 self.socks5_addr
717 .as_deref()
718 .unwrap_or(DEFAULT_TOR_SOCKS5_ADDR)
719 }
720
721 pub fn control_addr(&self) -> &str {
723 self.control_addr
724 .as_deref()
725 .unwrap_or(DEFAULT_TOR_CONTROL_ADDR)
726 }
727
728 pub fn control_auth(&self) -> &str {
730 self.control_auth.as_deref().unwrap_or("cookie")
731 }
732
733 pub fn cookie_path(&self) -> &str {
735 self.cookie_path
736 .as_deref()
737 .unwrap_or(DEFAULT_TOR_COOKIE_PATH)
738 }
739
740 pub fn connect_timeout_ms(&self) -> u64 {
742 self.connect_timeout_ms
743 .unwrap_or(DEFAULT_TOR_CONNECT_TIMEOUT_MS)
744 }
745
746 pub fn mtu(&self) -> u16 {
748 self.mtu.unwrap_or(DEFAULT_TOR_MTU)
749 }
750
751 pub fn max_inbound_connections(&self) -> usize {
753 self.max_inbound_connections
754 .unwrap_or(DEFAULT_TOR_MAX_INBOUND)
755 }
756
757 pub fn advertise_on_nostr(&self) -> bool {
759 self.advertise_on_nostr.unwrap_or(false)
760 }
761
762 pub fn advertised_port(&self) -> u16 {
765 self.advertised_port.unwrap_or(DEFAULT_TOR_ADVERTISED_PORT)
766 }
767}
768
769const DEFAULT_WEBRTC_MTU: u16 = 1200;
775
776const DEFAULT_WEBRTC_CONNECT_TIMEOUT_MS: u64 = 30_000;
778
779const DEFAULT_WEBRTC_ICE_GATHER_TIMEOUT_MS: u64 = 10_000;
781
782const DEFAULT_WEBRTC_MAX_CONNECTIONS: usize = 32;
784
785const DEFAULT_WEBRTC_DATA_CHANNEL_LABEL: &str = "fips";
787
788#[derive(Debug, Clone, Default, Serialize, Deserialize)]
793#[serde(deny_unknown_fields)]
794pub struct WebRtcConfig {
795 #[serde(default, skip_serializing_if = "Option::is_none")]
798 pub advertise_on_nostr: Option<bool>,
799
800 #[serde(default, skip_serializing_if = "Option::is_none")]
803 pub auto_connect: Option<bool>,
804
805 #[serde(default, skip_serializing_if = "Option::is_none")]
807 pub accept_connections: Option<bool>,
808
809 #[serde(default, skip_serializing_if = "Option::is_none")]
811 pub mtu: Option<u16>,
812
813 #[serde(default, skip_serializing_if = "Option::is_none")]
815 pub max_connections: Option<usize>,
816
817 #[serde(default, skip_serializing_if = "Option::is_none")]
819 pub connect_timeout_ms: Option<u64>,
820
821 #[serde(default, skip_serializing_if = "Option::is_none")]
823 pub ice_gather_timeout_ms: Option<u64>,
824
825 #[serde(default, skip_serializing_if = "Option::is_none")]
827 pub data_channel_label: Option<String>,
828
829 #[serde(default, skip_serializing_if = "Option::is_none")]
831 pub ordered: Option<bool>,
832
833 #[serde(default, skip_serializing_if = "Option::is_none")]
836 pub max_retransmits: Option<u16>,
837
838 #[serde(default, skip_serializing_if = "Option::is_none")]
841 pub signal_relays: Option<Vec<String>>,
842
843 #[serde(default, skip_serializing_if = "Option::is_none")]
846 pub stun_servers: Option<Vec<String>>,
847}
848
849impl WebRtcConfig {
850 pub fn advertise_on_nostr(&self) -> bool {
852 self.advertise_on_nostr.unwrap_or(false)
853 }
854
855 pub fn auto_connect(&self) -> bool {
857 self.auto_connect.unwrap_or(false)
858 }
859
860 pub fn accept_connections(&self) -> bool {
862 self.accept_connections.unwrap_or(true)
863 }
864
865 pub fn mtu(&self) -> u16 {
867 self.mtu.unwrap_or(DEFAULT_WEBRTC_MTU)
868 }
869
870 pub fn max_connections(&self) -> usize {
872 self.max_connections
873 .unwrap_or(DEFAULT_WEBRTC_MAX_CONNECTIONS)
874 }
875
876 pub fn connect_timeout_ms(&self) -> u64 {
878 self.connect_timeout_ms
879 .unwrap_or(DEFAULT_WEBRTC_CONNECT_TIMEOUT_MS)
880 }
881
882 pub fn ice_gather_timeout_ms(&self) -> u64 {
884 self.ice_gather_timeout_ms
885 .unwrap_or(DEFAULT_WEBRTC_ICE_GATHER_TIMEOUT_MS)
886 }
887
888 pub fn data_channel_label(&self) -> &str {
890 self.data_channel_label
891 .as_deref()
892 .unwrap_or(DEFAULT_WEBRTC_DATA_CHANNEL_LABEL)
893 }
894
895 pub fn ordered(&self) -> bool {
897 self.ordered.unwrap_or(false)
898 }
899
900 pub fn max_retransmits(&self) -> u16 {
902 self.max_retransmits.unwrap_or(0)
903 }
904
905 pub fn signal_relays<'a>(&'a self, fallback: &'a [String]) -> Vec<String> {
907 self.signal_relays
908 .as_ref()
909 .filter(|relays| !relays.is_empty())
910 .cloned()
911 .unwrap_or_else(|| fallback.to_vec())
912 }
913
914 pub fn stun_servers<'a>(&'a self, fallback: &'a [String]) -> Vec<String> {
916 self.stun_servers
917 .as_ref()
918 .filter(|servers| !servers.is_empty())
919 .cloned()
920 .unwrap_or_else(|| fallback.to_vec())
921 }
922}
923
924const DEFAULT_BLE_PSM: u16 = 0x0085;
930
931const DEFAULT_BLE_MTU: u16 = 2048;
933
934const DEFAULT_BLE_MAX_CONNECTIONS: usize = 7;
936
937const DEFAULT_BLE_CONNECT_TIMEOUT_MS: u64 = 10_000;
939
940const DEFAULT_BLE_PROBE_COOLDOWN_SECS: u64 = 30;
943
944#[derive(Debug, Clone, Default, Serialize, Deserialize)]
949#[serde(deny_unknown_fields)]
950pub struct BleConfig {
951 #[serde(default, skip_serializing_if = "Option::is_none")]
953 pub adapter: Option<String>,
954
955 #[serde(default, skip_serializing_if = "Option::is_none")]
957 pub psm: Option<u16>,
958
959 #[serde(default, skip_serializing_if = "Option::is_none")]
961 pub mtu: Option<u16>,
962
963 #[serde(default, skip_serializing_if = "Option::is_none")]
965 pub max_connections: Option<usize>,
966
967 #[serde(default, skip_serializing_if = "Option::is_none")]
969 pub connect_timeout_ms: Option<u64>,
970
971 #[serde(default, skip_serializing_if = "Option::is_none")]
973 pub advertise: Option<bool>,
974
975 #[serde(default, skip_serializing_if = "Option::is_none")]
977 pub scan: Option<bool>,
978
979 #[serde(default, skip_serializing_if = "Option::is_none")]
981 pub auto_connect: Option<bool>,
982
983 #[serde(default, skip_serializing_if = "Option::is_none")]
985 pub accept_connections: Option<bool>,
986
987 #[serde(default, skip_serializing_if = "Option::is_none")]
990 pub probe_cooldown_secs: Option<u64>,
991}
992
993impl BleConfig {
994 pub fn adapter(&self) -> &str {
996 self.adapter.as_deref().unwrap_or("hci0")
997 }
998
999 pub fn psm(&self) -> u16 {
1001 self.psm.unwrap_or(DEFAULT_BLE_PSM)
1002 }
1003
1004 pub fn mtu(&self) -> u16 {
1006 self.mtu.unwrap_or(DEFAULT_BLE_MTU)
1007 }
1008
1009 pub fn max_connections(&self) -> usize {
1011 self.max_connections.unwrap_or(DEFAULT_BLE_MAX_CONNECTIONS)
1012 }
1013
1014 pub fn connect_timeout_ms(&self) -> u64 {
1016 self.connect_timeout_ms
1017 .unwrap_or(DEFAULT_BLE_CONNECT_TIMEOUT_MS)
1018 }
1019
1020 pub fn advertise(&self) -> bool {
1022 self.advertise.unwrap_or(true)
1023 }
1024
1025 pub fn scan(&self) -> bool {
1027 self.scan.unwrap_or(true)
1028 }
1029
1030 pub fn auto_connect(&self) -> bool {
1032 self.auto_connect.unwrap_or(false)
1033 }
1034
1035 pub fn accept_connections(&self) -> bool {
1037 self.accept_connections.unwrap_or(true)
1038 }
1039
1040 pub fn probe_cooldown_secs(&self) -> u64 {
1042 self.probe_cooldown_secs
1043 .unwrap_or(DEFAULT_BLE_PROBE_COOLDOWN_SECS)
1044 }
1045}
1046
1047#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1056pub struct TransportsConfig {
1057 #[serde(default, skip_serializing_if = "is_transport_empty")]
1059 pub udp: TransportInstances<UdpConfig>,
1060
1061 #[cfg(feature = "sim-transport")]
1063 #[serde(default, skip_serializing_if = "is_transport_empty")]
1064 pub sim: TransportInstances<SimTransportConfig>,
1065
1066 #[serde(default, skip_serializing_if = "is_transport_empty")]
1068 pub ethernet: TransportInstances<EthernetConfig>,
1069
1070 #[serde(default, skip_serializing_if = "is_transport_empty")]
1072 pub tcp: TransportInstances<TcpConfig>,
1073
1074 #[serde(default, skip_serializing_if = "is_transport_empty")]
1076 pub tor: TransportInstances<TorConfig>,
1077
1078 #[serde(default, skip_serializing_if = "is_transport_empty")]
1080 pub webrtc: TransportInstances<WebRtcConfig>,
1081
1082 #[serde(default, skip_serializing_if = "is_transport_empty")]
1084 pub ble: TransportInstances<BleConfig>,
1085}
1086
1087fn is_transport_empty<T>(instances: &TransportInstances<T>) -> bool {
1089 instances.is_empty()
1090}
1091
1092impl TransportsConfig {
1093 pub fn is_empty(&self) -> bool {
1095 self.udp.is_empty()
1096 && {
1097 #[cfg(feature = "sim-transport")]
1098 {
1099 self.sim.is_empty()
1100 }
1101 #[cfg(not(feature = "sim-transport"))]
1102 {
1103 true
1104 }
1105 }
1106 && self.ethernet.is_empty()
1107 && self.tcp.is_empty()
1108 && self.tor.is_empty()
1109 && self.webrtc.is_empty()
1110 && self.ble.is_empty()
1111 }
1112
1113 pub fn merge(&mut self, other: TransportsConfig) {
1117 if !other.udp.is_empty() {
1118 self.udp = other.udp;
1119 }
1120 #[cfg(feature = "sim-transport")]
1121 if !other.sim.is_empty() {
1122 self.sim = other.sim;
1123 }
1124 if !other.ethernet.is_empty() {
1125 self.ethernet = other.ethernet;
1126 }
1127 if !other.tcp.is_empty() {
1128 self.tcp = other.tcp;
1129 }
1130 if !other.tor.is_empty() {
1131 self.tor = other.tor;
1132 }
1133 if !other.webrtc.is_empty() {
1134 self.webrtc = other.webrtc;
1135 }
1136 if !other.ble.is_empty() {
1137 self.ble = other.ble;
1138 }
1139 }
1140}
1141
1142#[cfg(test)]
1143mod tests {
1144 use super::*;
1145
1146 #[test]
1147 fn parse_external_addr_accepts_bare_ipv4_with_appended_bind_port() {
1148 let sa = parse_external_advert_addr("198.51.100.1", 2121).unwrap();
1149 assert_eq!(sa.to_string(), "198.51.100.1:2121");
1150 }
1151
1152 #[test]
1153 fn parse_external_addr_accepts_full_ipv4_socket_addr() {
1154 let sa = parse_external_advert_addr("198.51.100.1:443", 2121).unwrap();
1155 assert_eq!(sa.to_string(), "198.51.100.1:443");
1156 }
1158
1159 #[test]
1160 fn parse_external_addr_accepts_bare_ipv6_with_appended_bind_port() {
1161 let sa = parse_external_advert_addr("2001:db8::1", 443).unwrap();
1162 assert_eq!(sa.to_string(), "[2001:db8::1]:443");
1163 }
1164
1165 #[test]
1166 fn parse_external_addr_accepts_bracketed_ipv6_with_explicit_port() {
1167 let sa = parse_external_advert_addr("[2001:db8::1]:8443", 443).unwrap();
1168 assert_eq!(sa.to_string(), "[2001:db8::1]:8443");
1169 }
1170
1171 #[test]
1172 fn parse_external_addr_rejects_garbage() {
1173 assert!(parse_external_advert_addr("not-an-ip", 443).is_none());
1174 assert!(parse_external_advert_addr("", 443).is_none());
1175 }
1176
1177 #[test]
1178 fn udp_external_advert_addr_combines_with_bind_port_default() {
1179 let cfg = UdpConfig {
1180 external_addr: Some("198.51.100.1".to_string()),
1181 ..UdpConfig::default()
1182 };
1183 let sa = cfg.external_advert_addr().unwrap();
1185 assert_eq!(sa.to_string(), "198.51.100.1:2121");
1186 }
1187
1188 #[test]
1189 fn udp_external_advert_addr_with_explicit_full_socket_addr_overrides_bind_port() {
1190 let cfg = UdpConfig {
1191 bind_addr: Some("0.0.0.0:2121".to_string()),
1192 external_addr: Some("198.51.100.1:9999".to_string()),
1193 ..UdpConfig::default()
1194 };
1195 let sa = cfg.external_advert_addr().unwrap();
1196 assert_eq!(sa.to_string(), "198.51.100.1:9999");
1197 }
1198
1199 #[test]
1200 fn udp_external_advert_addr_returns_none_when_unset() {
1201 let cfg = UdpConfig::default();
1202 assert!(cfg.external_advert_addr().is_none());
1203 }
1204
1205 #[test]
1206 fn tcp_external_advert_addr_requires_bind_port() {
1207 let cfg = TcpConfig {
1208 external_addr: Some("198.51.100.1".to_string()),
1209 ..TcpConfig::default()
1210 };
1211 assert!(cfg.external_advert_addr().is_none());
1213
1214 let cfg = TcpConfig {
1215 bind_addr: Some("0.0.0.0:443".to_string()),
1216 external_addr: Some("198.51.100.1".to_string()),
1217 ..TcpConfig::default()
1218 };
1219 let sa = cfg.external_advert_addr().unwrap();
1220 assert_eq!(sa.to_string(), "198.51.100.1:443");
1221 }
1222
1223 #[test]
1224 fn tcp_external_advert_addr_with_full_socket_addr_independent_of_bind() {
1225 let cfg = TcpConfig {
1226 bind_addr: Some("0.0.0.0:443".to_string()),
1227 external_addr: Some("198.51.100.1:8443".to_string()),
1228 ..TcpConfig::default()
1229 };
1230 let sa = cfg.external_advert_addr().unwrap();
1231 assert_eq!(sa.to_string(), "198.51.100.1:8443");
1232 }
1233
1234 #[test]
1235 fn parse_bind_port_extracts_from_socket_addr_strings() {
1236 assert_eq!(parse_bind_port("0.0.0.0:2121"), Some(2121));
1237 assert_eq!(parse_bind_port("[::]:443"), Some(443));
1238 assert_eq!(parse_bind_port("not-a-socket-addr"), None);
1239 }
1240}