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 max_concurrent_attempts: usize,
98
99 pub prefer_rfc_nat_traversal: bool,
101}
102
103impl Default for NatConfig {
104 fn default() -> Self {
105 Self {
106 max_candidates: 10,
107 enable_symmetric_nat: true,
108 enable_relay_fallback: true,
109 max_concurrent_attempts: 3,
110 prefer_rfc_nat_traversal: true,
111 }
112 }
113}
114
115#[derive(Debug, Clone)]
125pub struct MtuConfig {
126 pub initial_mtu: u16,
131
132 pub min_mtu: u16,
137
138 pub discovery_enabled: bool,
143
144 pub max_mtu: u16,
149
150 pub auto_pqc_adjustment: bool,
155}
156
157impl Default for MtuConfig {
158 fn default() -> Self {
159 Self {
160 initial_mtu: 1200,
161 min_mtu: 1200,
162 discovery_enabled: true,
163 max_mtu: 1452, auto_pqc_adjustment: true,
165 }
166 }
167}
168
169impl MtuConfig {
170 pub fn pqc_optimized() -> Self {
172 Self {
173 initial_mtu: 1500,
174 min_mtu: 1200,
175 discovery_enabled: true,
176 max_mtu: 4096, auto_pqc_adjustment: true,
178 }
179 }
180
181 pub fn constrained() -> Self {
183 Self {
184 initial_mtu: 1200,
185 min_mtu: 1200,
186 discovery_enabled: false,
187 max_mtu: 1200,
188 auto_pqc_adjustment: false,
189 }
190 }
191
192 pub fn jumbo_frames() -> Self {
194 Self {
195 initial_mtu: 1500,
196 min_mtu: 1200,
197 discovery_enabled: true,
198 max_mtu: 9000, auto_pqc_adjustment: true,
200 }
201 }
202}
203
204impl Default for P2pConfig {
205 fn default() -> Self {
206 Self {
207 bind_addr: None,
208 known_peers: Vec::new(),
209 max_connections: 256,
210 nat: NatConfig::default(),
212 timeouts: TimeoutConfig::default(),
213 pqc: PqcConfig::default(),
214 mtu: MtuConfig::default(),
215 stats_interval: Duration::from_secs(30),
216 keypair: None,
217 }
218 }
219}
220
221impl P2pConfig {
222 pub fn builder() -> P2pConfigBuilder {
224 P2pConfigBuilder::default()
225 }
226
227 pub fn to_nat_config(&self) -> crate::nat_traversal_api::NatTraversalConfig {
229 crate::nat_traversal_api::NatTraversalConfig {
230 known_peers: self.known_peers.clone(),
231 max_candidates: self.nat.max_candidates,
232 coordination_timeout: self.timeouts.nat_traversal.coordination_timeout,
233 enable_symmetric_nat: self.nat.enable_symmetric_nat,
234 enable_relay_fallback: self.nat.enable_relay_fallback,
235 max_concurrent_attempts: self.nat.max_concurrent_attempts,
236 bind_addr: self.bind_addr,
237 prefer_rfc_nat_traversal: self.nat.prefer_rfc_nat_traversal,
238 pqc: Some(self.pqc.clone()),
239 timeouts: self.timeouts.clone(),
240 identity_key: None,
241 }
242 }
243
244 pub fn to_nat_config_with_key(
249 &self,
250 public_key: MlDsaPublicKey,
251 secret_key: MlDsaSecretKey,
252 ) -> crate::nat_traversal_api::NatTraversalConfig {
253 let mut config = self.to_nat_config();
254 config.identity_key = Some((public_key, secret_key));
255 config
256 }
257}
258
259#[derive(Debug, Clone, Default)]
261pub struct P2pConfigBuilder {
262 bind_addr: Option<SocketAddr>,
263 known_peers: Vec<SocketAddr>,
264 max_connections: Option<usize>,
265 nat: Option<NatConfig>,
267 timeouts: Option<TimeoutConfig>,
268 pqc: Option<PqcConfig>,
269 mtu: Option<MtuConfig>,
270 stats_interval: Option<Duration>,
271 keypair: Option<(MlDsaPublicKey, MlDsaSecretKey)>,
272}
273
274#[derive(Debug, Clone, thiserror::Error)]
276pub enum ConfigError {
277 #[error("max_connections must be at least 1")]
279 InvalidMaxConnections,
280
281 #[error("Invalid timeout: {0}")]
283 InvalidTimeout(String),
284
285 #[error("PQC configuration error: {0}")]
287 PqcError(String),
288
289 #[error("Invalid MTU configuration: {0}")]
291 InvalidMtu(String),
292}
293
294impl P2pConfigBuilder {
295 pub fn bind_addr(mut self, addr: SocketAddr) -> Self {
297 self.bind_addr = Some(addr);
298 self
299 }
300
301 pub fn known_peer(mut self, addr: SocketAddr) -> Self {
304 self.known_peers.push(addr);
305 self
306 }
307
308 pub fn known_peers(mut self, addrs: impl IntoIterator<Item = SocketAddr>) -> Self {
310 self.known_peers.extend(addrs);
311 self
312 }
313
314 #[doc(hidden)]
316 pub fn bootstrap(mut self, addr: SocketAddr) -> Self {
317 self.known_peers.push(addr);
318 self
319 }
320
321 pub fn max_connections(mut self, max: usize) -> Self {
323 self.max_connections = Some(max);
324 self
325 }
326
327 pub fn nat(mut self, nat: NatConfig) -> Self {
331 self.nat = Some(nat);
332 self
333 }
334
335 pub fn timeouts(mut self, timeouts: TimeoutConfig) -> Self {
337 self.timeouts = Some(timeouts);
338 self
339 }
340
341 pub fn fast_timeouts(mut self) -> Self {
343 self.timeouts = Some(TimeoutConfig::fast());
344 self
345 }
346
347 pub fn conservative_timeouts(mut self) -> Self {
349 self.timeouts = Some(TimeoutConfig::conservative());
350 self
351 }
352
353 pub fn pqc(mut self, pqc: PqcConfig) -> Self {
355 self.pqc = Some(pqc);
356 self
357 }
358
359 pub fn mtu(mut self, mtu: MtuConfig) -> Self {
361 self.mtu = Some(mtu);
362 self
363 }
364
365 pub fn pqc_optimized_mtu(mut self) -> Self {
369 self.mtu = Some(MtuConfig::pqc_optimized());
370 self
371 }
372
373 pub fn constrained_mtu(mut self) -> Self {
377 self.mtu = Some(MtuConfig::constrained());
378 self
379 }
380
381 pub fn jumbo_mtu(mut self) -> Self {
385 self.mtu = Some(MtuConfig::jumbo_frames());
386 self
387 }
388
389 pub fn stats_interval(mut self, interval: Duration) -> Self {
391 self.stats_interval = Some(interval);
392 self
393 }
394
395 pub fn keypair(mut self, public_key: MlDsaPublicKey, secret_key: MlDsaSecretKey) -> Self {
400 self.keypair = Some((public_key, secret_key));
401 self
402 }
403
404 pub fn build(self) -> Result<P2pConfig, ConfigError> {
406 let max_connections = self.max_connections.unwrap_or(256);
408 if max_connections == 0 {
409 return Err(ConfigError::InvalidMaxConnections);
410 }
411
412 Ok(P2pConfig {
416 bind_addr: self.bind_addr,
417 known_peers: self.known_peers,
418 max_connections,
419 nat: self.nat.unwrap_or_default(),
421 timeouts: self.timeouts.unwrap_or_default(),
422 pqc: self.pqc.unwrap_or_default(),
423 mtu: self.mtu.unwrap_or_default(),
424 stats_interval: self.stats_interval.unwrap_or(Duration::from_secs(30)),
425 keypair: self.keypair,
426 })
427 }
428}
429
430#[cfg(test)]
431mod tests {
432 use super::*;
433
434 #[test]
435 fn test_default_config() {
436 let config = P2pConfig::default();
437 assert!(config.bind_addr.is_none());
439 assert!(config.known_peers.is_empty());
440 assert_eq!(config.max_connections, 256);
441 }
442
443 #[test]
444 fn test_builder_basic() {
445 let config = P2pConfig::builder()
446 .max_connections(100)
447 .build()
448 .expect("Failed to build config");
449
450 assert_eq!(config.max_connections, 100);
452 }
453
454 #[test]
455 fn test_builder_with_known_peers() {
456 let addr1: SocketAddr = "127.0.0.1:9000".parse().expect("valid addr");
457 let addr2: SocketAddr = "127.0.0.1:9001".parse().expect("valid addr");
458
459 let config = P2pConfig::builder()
460 .known_peer(addr1)
461 .known_peer(addr2)
462 .build()
463 .expect("Failed to build config");
464
465 assert_eq!(config.known_peers.len(), 2);
466 }
467
468 #[test]
469 fn test_invalid_max_connections() {
470 let result = P2pConfig::builder().max_connections(0).build();
471
472 assert!(matches!(result, Err(ConfigError::InvalidMaxConnections)));
473 }
474
475 #[test]
476 fn test_to_nat_config() {
477 let config = P2pConfig::builder()
478 .known_peer("127.0.0.1:9000".parse().expect("valid addr"))
479 .nat(NatConfig {
480 max_candidates: 20,
481 enable_symmetric_nat: false,
482 ..Default::default()
483 })
484 .build()
485 .expect("Failed to build config");
486
487 let nat_config = config.to_nat_config();
488 assert_eq!(nat_config.max_candidates, 20);
489 assert!(!nat_config.enable_symmetric_nat);
490 }
491
492 #[test]
493 fn test_nat_config_default() {
494 let nat = NatConfig::default();
495 assert_eq!(nat.max_candidates, 10);
496 assert!(nat.enable_symmetric_nat);
497 assert!(nat.enable_relay_fallback);
498 assert_eq!(nat.max_concurrent_attempts, 3);
499 assert!(nat.prefer_rfc_nat_traversal);
500 }
501
502 #[test]
503 fn test_mtu_config_default() {
504 let mtu = MtuConfig::default();
505 assert_eq!(mtu.initial_mtu, 1200);
506 assert_eq!(mtu.min_mtu, 1200);
507 assert!(mtu.discovery_enabled);
508 assert_eq!(mtu.max_mtu, 1452);
509 assert!(mtu.auto_pqc_adjustment);
510 }
511
512 #[test]
513 fn test_mtu_config_pqc_optimized() {
514 let mtu = MtuConfig::pqc_optimized();
515 assert_eq!(mtu.initial_mtu, 1500);
516 assert_eq!(mtu.min_mtu, 1200);
517 assert!(mtu.discovery_enabled);
518 assert_eq!(mtu.max_mtu, 4096);
519 assert!(mtu.auto_pqc_adjustment);
520 }
521
522 #[test]
523 fn test_mtu_config_constrained() {
524 let mtu = MtuConfig::constrained();
525 assert_eq!(mtu.initial_mtu, 1200);
526 assert_eq!(mtu.min_mtu, 1200);
527 assert!(!mtu.discovery_enabled);
528 assert_eq!(mtu.max_mtu, 1200);
529 assert!(!mtu.auto_pqc_adjustment);
530 }
531
532 #[test]
533 fn test_mtu_config_jumbo_frames() {
534 let mtu = MtuConfig::jumbo_frames();
535 assert_eq!(mtu.initial_mtu, 1500);
536 assert_eq!(mtu.min_mtu, 1200);
537 assert!(mtu.discovery_enabled);
538 assert_eq!(mtu.max_mtu, 9000);
539 assert!(mtu.auto_pqc_adjustment);
540 }
541
542 #[test]
543 fn test_builder_with_mtu_config() {
544 let config = P2pConfig::builder()
546 .mtu(MtuConfig::pqc_optimized())
547 .build()
548 .expect("Failed to build config");
549
550 assert_eq!(config.mtu.initial_mtu, 1500);
551 assert_eq!(config.mtu.max_mtu, 4096);
552 }
553
554 #[test]
555 fn test_builder_pqc_optimized_mtu() {
556 let config = P2pConfig::builder()
558 .pqc_optimized_mtu()
559 .build()
560 .expect("Failed to build config");
561
562 assert_eq!(config.mtu.initial_mtu, 1500);
563 assert_eq!(config.mtu.max_mtu, 4096);
564 }
565
566 #[test]
567 fn test_builder_constrained_mtu() {
568 let config = P2pConfig::builder()
570 .constrained_mtu()
571 .build()
572 .expect("Failed to build config");
573
574 assert!(!config.mtu.discovery_enabled);
575 assert_eq!(config.mtu.max_mtu, 1200);
576 }
577
578 #[test]
579 fn test_builder_jumbo_mtu() {
580 let config = P2pConfig::builder()
582 .jumbo_mtu()
583 .build()
584 .expect("Failed to build config");
585
586 assert_eq!(config.mtu.max_mtu, 9000);
587 }
588
589 #[test]
590 fn test_default_config_has_mtu() {
591 let config = P2pConfig::default();
592 assert_eq!(config.mtu.initial_mtu, 1200);
593 assert!(config.mtu.discovery_enabled);
594 }
595}