1use std::{
2 collections::HashMap,
3 fmt,
4 net::SocketAddr,
5 time::{Duration, Instant},
6};
7
8use bitfold_core::{config::Config, packet_pool::PacketAllocator};
9use bitfold_protocol::{command::ProtocolCommand, AcknowledgmentHandler, SentPacket};
10
11use super::{
12 bandwidth_throttle::BandwidthThrottle,
13 channel_state::ChannelState,
14 command_queue::CommandQueue,
15 flow_control::FlowControl,
16 fragment_buffer::{cleanup_stale_fragments, CommandFragmentBuffer},
17 peer_state::PeerState,
18 pmtu_discovery::PmtuDiscovery,
19 statistics::PeerStatistics,
20 unsequenced::UnsequencedState,
21};
22
23mod command_processor;
24mod encoder;
25mod fragmenter;
26
27pub struct Peer {
30 pub last_heard: Instant,
32 pub last_sent: Instant,
34 pub remote_address: SocketAddr,
36
37 state: PeerState,
39
40 peer_id: u16,
43 incoming_session_id: u16,
45 outgoing_session_id: u16,
47 connect_id: u32,
49
50 #[allow(dead_code)]
52 outgoing_reliable_sequence: u16,
53 #[allow(dead_code)]
55 outgoing_unreliable_sequence: u16,
56 #[allow(dead_code)]
58 incoming_reliable_sequence: u16,
59 #[allow(dead_code)]
61 incoming_unreliable_sequence: u16,
62 next_unreliable_sequence: u16,
64
65 unsequenced_state: UnsequencedState,
67
68 acknowledge_handler: AcknowledgmentHandler,
70
71 config: Config,
73
74 command_queue: CommandQueue,
76 total_waiting_data: usize,
78 command_fragments: HashMap<u16, CommandFragmentBuffer>,
80 channel_states: HashMap<u8, ChannelState>,
82
83 flow_control: FlowControl,
86
87 bandwidth_throttle: BandwidthThrottle,
90
91 statistics: PeerStatistics,
94
95 tx_pool: PacketAllocator,
97 compression_pool: bitfold_core::packet_pool::CompressionBufferPool,
99
100 pmtu: PmtuDiscovery,
102}
103
104impl Peer {
105 pub fn new(addr: SocketAddr, config: &Config, time: Instant) -> Peer {
107 use rand::Rng;
108 let mut rng = rand::rng();
109
110 Peer {
111 last_heard: time,
112 last_sent: time,
113 remote_address: addr,
114 state: PeerState::Idle,
115 peer_id: 0, incoming_session_id: 0,
117 outgoing_session_id: rng.random(), connect_id: rng.random(), outgoing_reliable_sequence: 0,
120 outgoing_unreliable_sequence: 0,
121 incoming_reliable_sequence: 0,
122 incoming_unreliable_sequence: 0,
123 next_unreliable_sequence: 0,
124 unsequenced_state: UnsequencedState::new(),
125 acknowledge_handler: {
126 let mut handler = AcknowledgmentHandler::new();
127 if config.use_advanced_throttling {
129 handler.congestion_mut().enable_advanced_throttling(
130 config.throttle_scale,
131 config.throttle_acceleration,
132 config.throttle_deceleration,
133 config.throttle_interval,
134 );
135 }
136 handler
137 },
138 config: config.to_owned(),
139 command_queue: CommandQueue::default(),
140 total_waiting_data: 0,
141 command_fragments: HashMap::new(),
142 channel_states: HashMap::new(),
143 flow_control: FlowControl::new(config),
144 bandwidth_throttle: BandwidthThrottle::new(
145 config.outgoing_bandwidth_limit,
146 config.incoming_bandwidth_limit,
147 time,
148 ),
149 statistics: PeerStatistics::default(),
150 tx_pool: PacketAllocator::new(config.max_packet_size, 256),
151 compression_pool: bitfold_core::packet_pool::CompressionBufferPool::default(),
152 pmtu: PmtuDiscovery::new(config, time),
153 }
154 }
155
156 pub fn record_send(&mut self) -> bool {
159 let was_est = self.is_established();
160
161 match self.state {
163 PeerState::Idle => {
164 if self.config.use_connection_handshake {
165 self.initiate_connect();
167 } else {
168 self.state = PeerState::Connecting;
170 }
171 }
172 PeerState::ConnectionSucceeded => {
173 self.state = PeerState::Connected;
175 }
176 _ => {}
177 }
178
179 !was_est && self.is_established()
180 }
181
182 pub fn record_recv(&mut self) -> bool {
185 let was_est = self.is_established();
186
187 match self.state {
189 PeerState::Idle => {
190 if !self.config.use_connection_handshake {
191 self.state = PeerState::Connected;
194 }
195 }
197 PeerState::Connecting => {
198 if !self.config.use_connection_handshake {
199 self.state = PeerState::Connected;
201 }
202 }
204 PeerState::AcknowledgingConnect => {
205 self.state = PeerState::Connected;
207 }
208 _ => {}
209 }
210
211 !was_est && self.is_established()
212 }
213
214 pub fn is_established(&self) -> bool {
216 self.state.is_established()
217 }
218
219 pub fn state(&self) -> PeerState {
221 self.state
222 }
223
224 pub fn disconnect(&mut self) {
226 if !self.state.is_disconnecting() {
227 self.state = PeerState::Disconnecting;
228 self.command_queue.enqueue(ProtocolCommand::Disconnect { reason: 0 });
229 }
230 }
231
232 pub fn initiate_connect(&mut self) {
237 if self.state == PeerState::Idle {
238 self.state = PeerState::Connecting;
239 let connect_command = ProtocolCommand::Connect {
240 channels: self.config.channel_count,
241 mtu: 1400, protocol_version: 1, outgoing_session_id: self.outgoing_session_id,
244 connect_id: self.connect_id,
245 };
246 self.command_queue.enqueue(connect_command);
247 }
248 }
249
250 pub fn packets_in_flight(&self) -> u16 {
252 self.acknowledge_handler.packets_in_flight()
253 }
254
255 pub fn last_heard(&self, time: Instant) -> Duration {
257 time.duration_since(self.last_heard)
258 }
259
260 pub fn last_sent(&self, time: Instant) -> Duration {
262 time.duration_since(self.last_sent)
263 }
264
265 pub fn rtt(&self) -> Duration {
267 self.acknowledge_handler.rtt()
268 }
269
270 pub fn rto(&self) -> Duration {
272 self.acknowledge_handler.rto()
273 }
274
275 pub fn loss_rate(&self) -> f32 {
277 self.acknowledge_handler.loss_rate()
278 }
279
280 pub fn throttle(&self) -> f32 {
282 self.acknowledge_handler.throttle()
283 }
284
285 pub fn update_throttle(&mut self, time: Instant) -> bool {
287 self.acknowledge_handler.update_throttle(time)
288 }
289
290 pub fn config(&self) -> &Config {
292 &self.config
293 }
294
295 pub fn gather_dropped_packets(&mut self) -> Vec<SentPacket> {
297 let dropped = self.acknowledge_handler.dropped_packets();
298
299 for _ in &dropped {
301 self.record_packet_lost();
302 }
303
304 dropped
305 }
306
307 pub fn statistics(&self) -> &PeerStatistics {
311 &self.statistics
312 }
313
314 pub fn statistics_mut(&mut self) -> &mut PeerStatistics {
316 &mut self.statistics
317 }
318
319 fn record_packet_sent(&mut self) {
321 self.statistics.packets_sent += 1;
322 }
323
324 fn record_packet_received(&mut self) {
326 self.statistics.packets_received += 1;
327 }
328
329 fn record_packet_lost(&mut self) {
331 self.statistics.packets_lost += 1;
332 }
333
334 fn record_data_sent(&mut self, bytes: usize) {
336 self.statistics.bytes_sent += bytes as u64;
337 }
338
339 fn record_data_received(&mut self, bytes: usize) {
341 self.statistics.bytes_received += bytes as u64;
342 }
343
344 pub fn current_fragment_size(&self) -> u16 {
346 self.pmtu.current_fragment_size()
347 }
348
349 pub fn handle_pmtu(&mut self, time: Instant) {
351 let rto = self.rto();
352 if let Some(probe_cmd) = self.pmtu.handle_pmtu(time, rto) {
353 self.enqueue_command(probe_cmd);
354 }
355 }
356
357 pub fn window_size(&self) -> u32 {
361 self.flow_control.window_size()
362 }
363
364 pub fn reliable_data_in_transit(&self) -> u32 {
366 self.flow_control.reliable_data_in_transit()
367 }
368
369 pub fn set_window_size(&mut self, window_size: u32) {
371 self.flow_control.set_window_size(&self.config, window_size);
372 }
373
374 pub fn record_reliable_data_sent(&mut self, data_size: u32) {
376 self.flow_control.record_reliable_data_sent(data_size);
377 }
378
379 pub fn record_reliable_data_acked(&mut self, data_size: u32) {
381 self.flow_control.record_reliable_data_acked(data_size);
382 }
383
384 pub fn can_send_reliable(&self) -> bool {
387 self.flow_control.can_send_reliable(&self.config, self.packets_in_flight())
388 }
389
390 pub fn adjust_window_size(&mut self) {
393 let loss_rate = self.loss_rate();
394 let rtt_ms = self.rtt().as_millis() as u32;
395 self.flow_control.adjust_window_size(&self.config, loss_rate, rtt_ms);
396 }
397
398 pub fn update_bandwidth_window(&mut self, time: Instant) -> bool {
403 self.bandwidth_throttle.update_bandwidth_window(time)
404 }
405
406 pub fn record_bytes_sent(&mut self, bytes: u32) {
408 self.bandwidth_throttle.record_bytes_sent(bytes);
409 }
410
411 pub fn record_bytes_received(&mut self, bytes: u32) {
413 self.bandwidth_throttle.record_bytes_received(bytes);
414 }
415
416 pub fn can_send_within_bandwidth(&self) -> bool {
419 self.bandwidth_throttle.can_send_within_bandwidth()
420 }
421
422 pub fn bandwidth_utilization(&self) -> f32 {
425 self.bandwidth_throttle.bandwidth_utilization()
426 }
427
428 pub fn can_receive_within_bandwidth(&self) -> bool {
431 self.bandwidth_throttle.can_receive_within_bandwidth()
432 }
433
434 pub fn incoming_bandwidth_utilization(&self) -> f32 {
437 self.bandwidth_throttle.incoming_bandwidth_utilization()
438 }
439
440 pub fn next_unsequenced_group(&mut self) -> u16 {
444 self.unsequenced_state.next_outgoing_group()
445 }
446
447 pub fn is_unsequenced_duplicate(&self, group: u16) -> bool {
450 self.unsequenced_state.is_duplicate(group)
451 }
452
453 pub fn mark_unsequenced_received(&mut self, group: u16) {
456 self.unsequenced_state.mark_received(group);
457 }
458
459 pub fn cleanup_stale_fragments(&mut self, time: Instant) {
465 cleanup_stale_fragments(&mut self.command_fragments, time);
466 }
467
468 fn command_data_size(command: &ProtocolCommand) -> usize {
473 match command {
474 ProtocolCommand::SendReliable { data, .. }
475 | ProtocolCommand::SendUnreliable { data, .. }
476 | ProtocolCommand::SendUnreliableSequenced { data, .. }
477 | ProtocolCommand::SendUnsequenced { data, .. }
478 | ProtocolCommand::SendFragment { data, .. }
479 | ProtocolCommand::SendUnreliableFragment { data, .. } => data.len(),
480 _ => 0, }
482 }
483
484 pub fn enqueue_command(&mut self, command: ProtocolCommand) -> bool {
488 let data_size = Self::command_data_size(&command);
489
490 if self.config.max_waiting_data > 0 {
492 let new_total = self.total_waiting_data + data_size;
493 if new_total > self.config.max_waiting_data {
494 tracing::warn!(
496 "Dropping command: would exceed max_waiting_data limit ({} + {} > {})",
497 self.total_waiting_data,
498 data_size,
499 self.config.max_waiting_data
500 );
501 return false;
502 }
503 }
504
505 self.total_waiting_data += data_size;
506 self.command_queue.enqueue(command)
507 }
508
509 pub fn enqueue_ack_command(&mut self, sent_time: Option<u32>) {
512 let ack_command = ProtocolCommand::Acknowledge {
513 sequence: self.acknowledge_handler.remote_sequence_num(),
514 received_mask: self.acknowledge_handler.ack_bitfield(),
515 sent_time,
516 };
517 self.enqueue_command(ack_command);
518 }
519
520 pub fn enqueue_ping_command(&mut self, timestamp: u32) {
522 self.enqueue_command(ProtocolCommand::Ping { timestamp });
523 }
524
525 pub fn enqueue_pong_command(&mut self, timestamp: u32) {
527 self.enqueue_command(ProtocolCommand::Pong { timestamp });
528 }
529
530 pub fn drain_commands(&mut self) -> impl Iterator<Item = ProtocolCommand> + '_ {
533 self.total_waiting_data = 0; self.command_queue.drain()
535 }
536
537 pub fn queued_commands_count(&self) -> usize {
539 self.command_queue.len()
540 }
541
542 pub fn has_queued_commands(&self) -> bool {
544 !self.command_queue.is_empty()
545 }
546}
547
548impl fmt::Debug for Peer {
549 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
550 write!(f, "{}:{}", self.remote_address.ip(), self.remote_address.port())
551 }
552}
553
554#[cfg(test)]
555mod tests {
556 use std::time::Instant;
557
558 use bitfold_core::config::Config;
559
560 use super::Peer;
561 use crate::peer_state::PeerState;
562
563 fn get_fake_addr() -> std::net::SocketAddr {
564 "127.0.0.1:0".parse().unwrap()
565 }
566
567 #[test]
571 fn test_window_adjustment_decreases_on_poor_conditions() {
572 let mut config = Config::default();
573 config.use_window_flow_control = true;
574 config.initial_window_size = 200;
575 config.min_window_size = 64;
576 let mut peer = Peer::new(get_fake_addr(), &config, Instant::now());
577
578 let initial_window = peer.window_size();
579
580 for _ in 0..100 {
583 peer.acknowledge_handler.congestion_mut().record_sent();
584 }
585 for _ in 0..10 {
586 peer.acknowledge_handler.congestion_mut().record_loss();
587 } peer.adjust_window_size();
590
591 assert!(peer.window_size() < initial_window);
593 }
594
595 #[test]
596 fn test_window_flow_control_respects_min_max() {
597 let mut config = Config::default();
598 config.use_window_flow_control = true;
599 config.initial_window_size = 100;
600 config.min_window_size = 64;
601 config.max_window_size = 128;
602 let mut peer = Peer::new(get_fake_addr(), &config, Instant::now());
603
604 for _ in 0..50 {
606 peer.adjust_window_size();
607 }
608
609 assert!(peer.window_size() <= 128);
611
612 for _round in 0..50 {
614 for _ in 0..100 {
615 peer.acknowledge_handler.congestion_mut().record_sent();
616 }
617 for _ in 0..10 {
618 peer.acknowledge_handler.congestion_mut().record_loss();
619 }
620 peer.adjust_window_size();
621 }
622
623 assert!(peer.window_size() >= 64);
625 }
626
627 #[test]
628 fn test_pmtu_discovery_probe_reply() {
629 let mut config = Config::default();
630 config.use_pmtu_discovery = true;
631 config.pmtu_min = 576;
632 config.pmtu_max = 1400;
633 config.pmtu_interval_ms = 100; let start_time = Instant::now();
636 let mut peer = Peer::new(get_fake_addr(), &config, start_time);
637
638 assert_eq!(peer.current_fragment_size(), config.fragment_size);
640
641 let time = start_time + std::time::Duration::from_millis(150);
643 peer.handle_pmtu(time);
644
645 assert!(peer.has_queued_commands());
647
648 let encoded = peer.encode_queued_commands().unwrap();
650 assert!(!encoded.is_empty());
651
652 assert!(peer.pmtu.has_outstanding_probe());
654
655 if let Some((size, token, _)) = peer.pmtu.outstanding_probe() {
657 let reply = bitfold_protocol::command::ProtocolCommand::PMTUReply { size, token };
658 let _ = peer.process_command(&reply, time).unwrap();
659
660 assert_eq!(peer.current_fragment_size(), size);
662 }
663 }
664
665 #[test]
666 fn test_pmtu_discovery_timeout() {
667 let mut config = Config::default();
668 config.use_pmtu_discovery = true;
669 config.pmtu_min = 576;
670 config.pmtu_max = 1400;
671 config.pmtu_interval_ms = 100;
672
673 let start_time = Instant::now();
674 let mut peer = Peer::new(get_fake_addr(), &config, start_time);
675
676 let mut time = start_time + std::time::Duration::from_millis(150);
678 peer.handle_pmtu(time);
679 assert!(peer.has_queued_commands());
680 let _ = peer.encode_queued_commands().unwrap();
681
682 let high_before = peer.pmtu.high_bound();
683
684 time = time + std::time::Duration::from_secs(2);
686
687 peer.handle_pmtu(time);
689
690 assert!(!peer.pmtu.has_outstanding_probe());
692 assert!(peer.pmtu.high_bound() < high_before);
693 }
694
695 #[test]
696 fn test_pmtu_discovery_enabled_by_default() {
697 let config = Config::default();
698 assert!(config.use_pmtu_discovery);
699
700 let creation_time = Instant::now();
701 let mut peer = Peer::new(get_fake_addr(), &config, creation_time);
702 peer.state = PeerState::Connected;
704
705 let probe_time =
707 creation_time + std::time::Duration::from_millis(config.pmtu_interval_ms as u64 + 100);
708
709 peer.handle_pmtu(probe_time);
711 assert!(peer.has_queued_commands()); }
713}