1use std::net::SocketAddr;
27use std::time::Duration;
28
29use crate::config::nat_timeouts::TimeoutConfig;
31use crate::crypto::pqc::PqcConfig;
32use crate::crypto::pqc::types::{MlDsaPublicKey, MlDsaSecretKey};
33
34#[derive(Debug, Clone)]
46pub struct P2pConfig {
47 pub bind_addr: Option<SocketAddr>,
50
51 pub known_peers: Vec<SocketAddr>,
54
55 pub max_connections: usize,
57
58 pub nat: NatConfig,
61
62 pub timeouts: TimeoutConfig,
64
65 pub pqc: PqcConfig,
67
68 pub mtu: MtuConfig,
70
71 pub stats_interval: Duration,
73
74 pub keypair: Option<(MlDsaPublicKey, MlDsaSecretKey)>,
78}
79#[derive(Debug, Clone)]
86pub struct NatConfig {
87 pub max_candidates: usize,
89
90 pub enable_symmetric_nat: bool,
92
93 pub enable_relay_fallback: bool,
95
96 pub relay_nodes: Vec<std::net::SocketAddr>,
98
99 pub max_concurrent_attempts: usize,
101
102 pub prefer_rfc_nat_traversal: bool,
104}
105
106impl Default for NatConfig {
107 fn default() -> Self {
108 Self {
109 max_candidates: 10,
110 enable_symmetric_nat: true,
111 enable_relay_fallback: true,
112 relay_nodes: Vec::new(),
113 max_concurrent_attempts: 3,
114 prefer_rfc_nat_traversal: true,
115 }
116 }
117}
118
119#[derive(Debug, Clone)]
129pub struct MtuConfig {
130 pub initial_mtu: u16,
135
136 pub min_mtu: u16,
141
142 pub discovery_enabled: bool,
147
148 pub max_mtu: u16,
153
154 pub auto_pqc_adjustment: bool,
159}
160
161impl Default for MtuConfig {
162 fn default() -> Self {
163 Self {
164 initial_mtu: 1200,
165 min_mtu: 1200,
166 discovery_enabled: true,
167 max_mtu: 1452, auto_pqc_adjustment: true,
169 }
170 }
171}
172
173impl MtuConfig {
174 pub fn pqc_optimized() -> Self {
176 Self {
177 initial_mtu: 1500,
178 min_mtu: 1200,
179 discovery_enabled: true,
180 max_mtu: 4096, auto_pqc_adjustment: true,
182 }
183 }
184
185 pub fn constrained() -> Self {
187 Self {
188 initial_mtu: 1200,
189 min_mtu: 1200,
190 discovery_enabled: false,
191 max_mtu: 1200,
192 auto_pqc_adjustment: false,
193 }
194 }
195
196 pub fn jumbo_frames() -> Self {
198 Self {
199 initial_mtu: 1500,
200 min_mtu: 1200,
201 discovery_enabled: true,
202 max_mtu: 9000, auto_pqc_adjustment: true,
204 }
205 }
206}
207
208impl Default for P2pConfig {
209 fn default() -> Self {
210 Self {
211 bind_addr: None,
212 known_peers: Vec::new(),
213 max_connections: 256,
214 nat: NatConfig::default(),
216 timeouts: TimeoutConfig::default(),
217 pqc: PqcConfig::default(),
218 mtu: MtuConfig::default(),
219 stats_interval: Duration::from_secs(30),
220 keypair: None,
221 }
222 }
223}
224
225impl P2pConfig {
226 pub fn builder() -> P2pConfigBuilder {
228 P2pConfigBuilder::default()
229 }
230
231 pub fn to_nat_config(&self) -> crate::nat_traversal_api::NatTraversalConfig {
233 crate::nat_traversal_api::NatTraversalConfig {
234 known_peers: self.known_peers.clone(),
235 max_candidates: self.nat.max_candidates,
236 coordination_timeout: self.timeouts.nat_traversal.coordination_timeout,
237 enable_symmetric_nat: self.nat.enable_symmetric_nat,
238 enable_relay_fallback: self.nat.enable_relay_fallback,
239 relay_nodes: self.nat.relay_nodes.clone(),
240 max_concurrent_attempts: self.nat.max_concurrent_attempts,
241 bind_addr: self.bind_addr,
242 prefer_rfc_nat_traversal: self.nat.prefer_rfc_nat_traversal,
243 pqc: Some(self.pqc.clone()),
244 timeouts: self.timeouts.clone(),
245 identity_key: None,
246 }
247 }
248
249 pub fn to_nat_config_with_key(
254 &self,
255 public_key: MlDsaPublicKey,
256 secret_key: MlDsaSecretKey,
257 ) -> crate::nat_traversal_api::NatTraversalConfig {
258 let mut config = self.to_nat_config();
259 config.identity_key = Some((public_key, secret_key));
260 config
261 }
262}
263
264#[derive(Debug, Clone, Default)]
266pub struct P2pConfigBuilder {
267 bind_addr: Option<SocketAddr>,
268 known_peers: Vec<SocketAddr>,
269 max_connections: Option<usize>,
270 nat: Option<NatConfig>,
272 timeouts: Option<TimeoutConfig>,
273 pqc: Option<PqcConfig>,
274 mtu: Option<MtuConfig>,
275 stats_interval: Option<Duration>,
276 keypair: Option<(MlDsaPublicKey, MlDsaSecretKey)>,
277}
278
279#[derive(Debug, Clone, thiserror::Error)]
281pub enum ConfigError {
282 #[error("max_connections must be at least 1")]
284 InvalidMaxConnections,
285
286 #[error("Invalid timeout: {0}")]
288 InvalidTimeout(String),
289
290 #[error("PQC configuration error: {0}")]
292 PqcError(String),
293
294 #[error("Invalid MTU configuration: {0}")]
296 InvalidMtu(String),
297}
298
299impl P2pConfigBuilder {
300 pub fn bind_addr(mut self, addr: SocketAddr) -> Self {
302 self.bind_addr = Some(addr);
303 self
304 }
305
306 pub fn known_peer(mut self, addr: SocketAddr) -> Self {
309 self.known_peers.push(addr);
310 self
311 }
312
313 pub fn known_peers(mut self, addrs: impl IntoIterator<Item = SocketAddr>) -> Self {
315 self.known_peers.extend(addrs);
316 self
317 }
318
319 #[doc(hidden)]
321 pub fn bootstrap(mut self, addr: SocketAddr) -> Self {
322 self.known_peers.push(addr);
323 self
324 }
325
326 pub fn max_connections(mut self, max: usize) -> Self {
328 self.max_connections = Some(max);
329 self
330 }
331
332 pub fn nat(mut self, nat: NatConfig) -> Self {
336 self.nat = Some(nat);
337 self
338 }
339
340 pub fn timeouts(mut self, timeouts: TimeoutConfig) -> Self {
342 self.timeouts = Some(timeouts);
343 self
344 }
345
346 pub fn fast_timeouts(mut self) -> Self {
348 self.timeouts = Some(TimeoutConfig::fast());
349 self
350 }
351
352 pub fn conservative_timeouts(mut self) -> Self {
354 self.timeouts = Some(TimeoutConfig::conservative());
355 self
356 }
357
358 pub fn pqc(mut self, pqc: PqcConfig) -> Self {
360 self.pqc = Some(pqc);
361 self
362 }
363
364 pub fn mtu(mut self, mtu: MtuConfig) -> Self {
366 self.mtu = Some(mtu);
367 self
368 }
369
370 pub fn pqc_optimized_mtu(mut self) -> Self {
374 self.mtu = Some(MtuConfig::pqc_optimized());
375 self
376 }
377
378 pub fn constrained_mtu(mut self) -> Self {
382 self.mtu = Some(MtuConfig::constrained());
383 self
384 }
385
386 pub fn jumbo_mtu(mut self) -> Self {
390 self.mtu = Some(MtuConfig::jumbo_frames());
391 self
392 }
393
394 pub fn stats_interval(mut self, interval: Duration) -> Self {
396 self.stats_interval = Some(interval);
397 self
398 }
399
400 pub fn keypair(mut self, public_key: MlDsaPublicKey, secret_key: MlDsaSecretKey) -> Self {
405 self.keypair = Some((public_key, secret_key));
406 self
407 }
408
409 pub fn build(self) -> Result<P2pConfig, ConfigError> {
411 let max_connections = self.max_connections.unwrap_or(256);
413 if max_connections == 0 {
414 return Err(ConfigError::InvalidMaxConnections);
415 }
416
417 Ok(P2pConfig {
421 bind_addr: self.bind_addr,
422 known_peers: self.known_peers,
423 max_connections,
424 nat: self.nat.unwrap_or_default(),
426 timeouts: self.timeouts.unwrap_or_default(),
427 pqc: self.pqc.unwrap_or_default(),
428 mtu: self.mtu.unwrap_or_default(),
429 stats_interval: self.stats_interval.unwrap_or(Duration::from_secs(30)),
430 keypair: self.keypair,
431 })
432 }
433}
434
435#[cfg(test)]
436mod tests {
437 use super::*;
438
439 #[test]
440 fn test_default_config() {
441 let config = P2pConfig::default();
442 assert!(config.bind_addr.is_none());
444 assert!(config.known_peers.is_empty());
445 assert_eq!(config.max_connections, 256);
446 }
447
448 #[test]
449 fn test_builder_basic() {
450 let config = P2pConfig::builder()
451 .max_connections(100)
452 .build()
453 .expect("Failed to build config");
454
455 assert_eq!(config.max_connections, 100);
457 }
458
459 #[test]
460 fn test_builder_with_known_peers() {
461 let addr1: SocketAddr = "127.0.0.1:9000".parse().expect("valid addr");
462 let addr2: SocketAddr = "127.0.0.1:9001".parse().expect("valid addr");
463
464 let config = P2pConfig::builder()
465 .known_peer(addr1)
466 .known_peer(addr2)
467 .build()
468 .expect("Failed to build config");
469
470 assert_eq!(config.known_peers.len(), 2);
471 }
472
473 #[test]
474 fn test_invalid_max_connections() {
475 let result = P2pConfig::builder().max_connections(0).build();
476
477 assert!(matches!(result, Err(ConfigError::InvalidMaxConnections)));
478 }
479
480 #[test]
481 fn test_to_nat_config() {
482 let config = P2pConfig::builder()
483 .known_peer("127.0.0.1:9000".parse().expect("valid addr"))
484 .nat(NatConfig {
485 max_candidates: 20,
486 enable_symmetric_nat: false,
487 ..Default::default()
488 })
489 .build()
490 .expect("Failed to build config");
491
492 let nat_config = config.to_nat_config();
493 assert_eq!(nat_config.max_candidates, 20);
494 assert!(!nat_config.enable_symmetric_nat);
495 }
496
497 #[test]
498 fn test_nat_config_default() {
499 let nat = NatConfig::default();
500 assert_eq!(nat.max_candidates, 10);
501 assert!(nat.enable_symmetric_nat);
502 assert!(nat.enable_relay_fallback);
503 assert_eq!(nat.max_concurrent_attempts, 3);
504 assert!(nat.prefer_rfc_nat_traversal);
505 }
506
507 #[test]
508 fn test_mtu_config_default() {
509 let mtu = MtuConfig::default();
510 assert_eq!(mtu.initial_mtu, 1200);
511 assert_eq!(mtu.min_mtu, 1200);
512 assert!(mtu.discovery_enabled);
513 assert_eq!(mtu.max_mtu, 1452);
514 assert!(mtu.auto_pqc_adjustment);
515 }
516
517 #[test]
518 fn test_mtu_config_pqc_optimized() {
519 let mtu = MtuConfig::pqc_optimized();
520 assert_eq!(mtu.initial_mtu, 1500);
521 assert_eq!(mtu.min_mtu, 1200);
522 assert!(mtu.discovery_enabled);
523 assert_eq!(mtu.max_mtu, 4096);
524 assert!(mtu.auto_pqc_adjustment);
525 }
526
527 #[test]
528 fn test_mtu_config_constrained() {
529 let mtu = MtuConfig::constrained();
530 assert_eq!(mtu.initial_mtu, 1200);
531 assert_eq!(mtu.min_mtu, 1200);
532 assert!(!mtu.discovery_enabled);
533 assert_eq!(mtu.max_mtu, 1200);
534 assert!(!mtu.auto_pqc_adjustment);
535 }
536
537 #[test]
538 fn test_mtu_config_jumbo_frames() {
539 let mtu = MtuConfig::jumbo_frames();
540 assert_eq!(mtu.initial_mtu, 1500);
541 assert_eq!(mtu.min_mtu, 1200);
542 assert!(mtu.discovery_enabled);
543 assert_eq!(mtu.max_mtu, 9000);
544 assert!(mtu.auto_pqc_adjustment);
545 }
546
547 #[test]
548 fn test_builder_with_mtu_config() {
549 let config = P2pConfig::builder()
551 .mtu(MtuConfig::pqc_optimized())
552 .build()
553 .expect("Failed to build config");
554
555 assert_eq!(config.mtu.initial_mtu, 1500);
556 assert_eq!(config.mtu.max_mtu, 4096);
557 }
558
559 #[test]
560 fn test_builder_pqc_optimized_mtu() {
561 let config = P2pConfig::builder()
563 .pqc_optimized_mtu()
564 .build()
565 .expect("Failed to build config");
566
567 assert_eq!(config.mtu.initial_mtu, 1500);
568 assert_eq!(config.mtu.max_mtu, 4096);
569 }
570
571 #[test]
572 fn test_builder_constrained_mtu() {
573 let config = P2pConfig::builder()
575 .constrained_mtu()
576 .build()
577 .expect("Failed to build config");
578
579 assert!(!config.mtu.discovery_enabled);
580 assert_eq!(config.mtu.max_mtu, 1200);
581 }
582
583 #[test]
584 fn test_builder_jumbo_mtu() {
585 let config = P2pConfig::builder()
587 .jumbo_mtu()
588 .build()
589 .expect("Failed to build config");
590
591 assert_eq!(config.mtu.max_mtu, 9000);
592 }
593
594 #[test]
595 fn test_default_config_has_mtu() {
596 let config = P2pConfig::default();
597 assert_eq!(config.mtu.initial_mtu, 1200);
598 assert!(config.mtu.discovery_enabled);
599 }
600}