1use std::collections::VecDeque;
8
9use crate::crypto::Encryptor;
10use crate::packet::{Ack, Control, ControlPacket, DataPacket, Position};
11use crate::rtt::Rtt;
12use crate::seq::Seq;
13
14#[derive(Debug, Clone)]
17pub struct SendConfig {
18 pub max_packets: usize,
21 pub max_bytes: usize,
23 pub max_age_us: u64,
25 pub max_payload: usize,
27 pub bandwidth: u64,
29 pub max_retransmits: u32,
31}
32
33impl Default for SendConfig {
34 fn default() -> Self {
35 Self {
36 max_packets: 4096,
37 max_bytes: 4 * 1024 * 1024,
38 max_age_us: 3_000_000,
39 max_payload: 1316,
40 bandwidth: 1_250_000,
41 max_retransmits: 32,
42 }
43 }
44}
45
46impl SendConfig {
47 pub(crate) fn valid(&self) -> bool {
48 (1..=65_536).contains(&self.max_packets)
49 && (1..=64 * 1024 * 1024).contains(&self.max_bytes)
50 && (1..=60_000_000).contains(&self.max_age_us)
51 && (1..=1456).contains(&self.max_payload)
52 && (1..=1_000_000_000).contains(&self.bandwidth)
53 && (1..=1024).contains(&self.max_retransmits)
54 }
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub enum SendError {
60 NotConnected,
63 Empty,
65 PayloadTooLarge,
67 QueueFull,
69}
70
71impl std::fmt::Display for SendError {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 f.write_str(match self {
74 Self::NotConnected => "SRT sender is not connected",
75 Self::Empty => "empty live message",
76 Self::PayloadTooLarge => "live message exceeds negotiated payload size",
77 Self::QueueFull => "SRT packet or byte budget exhausted",
78 })
79 }
80}
81impl std::error::Error for SendError {}
82
83#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
86pub struct SendStats {
87 pub accepted_packets: u64,
89 pub accepted_bytes: u64,
91 pub sent_packets: u64,
93 pub sent_bytes: u64,
95 pub retransmitted_packets: u64,
97 pub retransmitted_bytes: u64,
99 pub acknowledged_packets: u64,
101 pub acknowledged_bytes: u64,
103 pub rejected_packets: u64,
105 pub abandoned_packets: u64,
107 pub abandoned_bytes: u64,
109 pub buffered_packets: usize,
111 pub buffered_bytes: usize,
114 pub peak_buffered_packets: usize,
116 pub peak_buffered_bytes: usize,
118 pub nak_packets: u64,
120 pub invalid_controls: u64,
122 pub timeout_retransmissions: u64,
125 pub rtt_us: u64,
127 pub encrypted_packets: u64,
130 pub km_requests: u64,
132 pub km_responses: u64,
134}
135
136#[derive(Debug, Clone, Copy, PartialEq, Eq)]
137pub(crate) enum Failure {
138 MediaExpired,
139 Crypto,
140 RetryLimit,
141 PeerClosed,
142 PeerError(u32),
143}
144
145struct Queued {
146 payload: Vec<u8>,
147 born: i64,
148}
149
150struct Flight {
151 data: Queued,
152 seq: Seq,
153 message: u32,
154 last_sent: i64,
155 retries: u32,
156 requested: bool,
157 key: u8,
158}
159
160pub(crate) struct Sender {
161 config: SendConfig,
162 pending: VecDeque<Queued>,
163 flight: VecDeque<Flight>,
164 retries: VecDeque<Seq>,
165 next_seq: Seq,
166 next_message: u32,
167 acked: Seq,
168 peer_socket: u32,
169 flow_window: usize,
170 peer_space: usize,
171 next_send: i64,
172 last_send: i64,
173 last_receive: i64,
174 next_rto: Option<i64>,
175 rto_count: u32,
176 rtt: Rtt,
177 peer_variance: i64,
178 ack_ack: Option<u32>,
179 stats: SendStats,
180 failure: Option<Failure>,
181 crypto: Option<Encryptor>,
182 key_counts: [usize; 2],
183}
184
185impl Sender {
186 pub(crate) fn new(
187 config: SendConfig,
188 now: i64,
189 peer_socket: u32,
190 initial: Seq,
191 window: usize,
192 ) -> Self {
193 Self {
194 config,
195 pending: VecDeque::new(),
196 flight: VecDeque::new(),
197 retries: VecDeque::new(),
198 next_seq: initial,
199 next_message: 1,
200 acked: initial,
201 peer_socket,
202 flow_window: window,
203 peer_space: window,
204 next_send: now,
205 last_send: now,
206 last_receive: now,
207 next_rto: None,
208 rto_count: 0,
209 rtt: Rtt::new(),
210 peer_variance: 50_000,
211 ack_ack: None,
212 stats: SendStats::default(),
213 failure: None,
214 crypto: None,
215 key_counts: [0; 2],
216 }
217 }
218
219 pub(crate) fn set_crypto(&mut self, crypto: Option<Encryptor>) {
220 self.crypto = crypto;
221 }
222
223 pub(crate) fn stats(&self) -> SendStats {
224 let mut s = self.stats;
225 s.rtt_us = self.rtt.rtt() as u64;
226 s
227 }
228
229 pub(crate) fn peer_socket(&self) -> u32 {
230 self.peer_socket
231 }
232 pub(crate) fn last_receive(&self) -> i64 {
233 self.last_receive
234 }
235 pub(crate) fn failure(&self) -> Option<Failure> {
236 self.failure
237 }
238 pub(crate) fn max_payload(&self) -> usize {
239 self.config.max_payload
240 }
241
242 pub(crate) fn try_enqueue(
243 &mut self,
244 now: i64,
245 payload: Vec<u8>,
246 ) -> Result<(), (SendError, Vec<u8>)> {
247 let error = if self.failure.is_some() {
248 Some(SendError::NotConnected)
249 } else if payload.is_empty() {
250 Some(SendError::Empty)
251 } else if payload.len() > self.config.max_payload {
252 Some(SendError::PayloadTooLarge)
253 } else if self.stats.buffered_packets >= self.config.max_packets
254 || payload.capacity()
255 > self
256 .config
257 .max_bytes
258 .saturating_sub(self.stats.buffered_bytes)
259 {
260 Some(SendError::QueueFull)
261 } else {
262 None
263 };
264 if let Some(error) = error {
265 self.stats.rejected_packets += 1;
266 return Err((error, payload));
267 }
268 self.stats.accepted_packets += 1;
269 self.stats.accepted_bytes += payload.len() as u64;
270 self.stats.buffered_packets += 1;
271 self.stats.buffered_bytes += payload.capacity();
272 self.stats.peak_buffered_packets = self
273 .stats
274 .peak_buffered_packets
275 .max(self.stats.buffered_packets);
276 self.stats.peak_buffered_bytes = self
277 .stats
278 .peak_buffered_bytes
279 .max(self.stats.buffered_bytes);
280 self.pending.push_back(Queued { payload, born: now });
281 Ok(())
282 }
283
284 pub(crate) fn clear(&mut self) {
285 self.stats.abandoned_packets += self.stats.buffered_packets as u64;
286 self.stats.abandoned_bytes += self
287 .pending
288 .iter()
289 .map(|p| p.payload.len() as u64)
290 .chain(self.flight.iter().map(|f| f.data.payload.len() as u64))
291 .sum::<u64>();
292 self.crypto = None;
293 self.key_counts = [0; 2];
294 self.stats.buffered_packets = 0;
295 self.stats.buffered_bytes = 0;
296 self.pending = VecDeque::new();
297 self.flight = VecDeque::new();
298 self.retries = VecDeque::new();
299 self.ack_ack = None;
300 self.next_rto = None;
301 }
302
303 fn rto(&self) -> i64 {
304 self.rtt
305 .retry()
306 .max(self.rtt.rtt() + 4 * self.peer_variance)
307 + 20_000
308 }
309
310 pub(crate) fn on_control(&mut self, now: i64, control: &Control) {
311 if self.failure.is_some() {
312 return;
313 }
314 let valid = match control {
315 Control::Ack(ack) => self.on_ack(now, ack),
316 Control::Nak(ranges) => self.on_nak(now, ranges),
317 Control::Other {
318 control_type: 0x7fff,
319 subtype: 4,
320 info: 0,
321 cif,
322 } => {
323 let confirmed = self
324 .crypto
325 .as_mut()
326 .is_some_and(|crypto| crypto.confirm(cif));
327 if confirmed {
328 self.stats.km_responses += 1;
329 }
330 confirmed
331 }
332 Control::KeepAlive => true,
333 Control::Shutdown => {
334 self.failure = Some(Failure::PeerClosed);
335 true
336 }
337 Control::PeerError { code } => {
338 self.failure = Some(Failure::PeerError(*code));
339 true
340 }
341 _ => false,
343 };
344 if valid {
345 self.last_receive = now;
346 } else {
347 self.stats.invalid_controls += 1;
348 }
349 }
350
351 fn on_ack(&mut self, now: i64, ack: &Ack) -> bool {
352 let advance = self.acked.distance_to(ack.ack);
353 if advance < 0 || ack.ack.distance_to(self.next_seq) < 0 {
354 return false;
355 }
356 if ack.number != 0 && ack.stats.is_some() {
357 self.ack_ack = Some(ack.number);
358 }
359 if let Some(stats) = ack.stats {
360 self.peer_space = (stats.buffer as usize).min(self.flow_window);
361 self.rtt.sample(i64::from(stats.rtt));
362 self.peer_variance = i64::from(stats.rtt_var).min(60_000_000);
363 }
364 while self
365 .flight
366 .front()
367 .is_some_and(|f| f.seq.distance_to(ack.ack) > 0)
368 {
369 if let Some(f) = self.flight.pop_front() {
370 if let Some(count) = f
371 .key
372 .checked_sub(1)
373 .and_then(|k| self.key_counts.get_mut(k as usize))
374 {
375 *count = count.saturating_sub(1);
376 }
377 self.stats.acknowledged_packets += 1;
378 self.stats.acknowledged_bytes += f.data.payload.len() as u64;
379 self.stats.buffered_packets -= 1;
380 self.stats.buffered_bytes -= f.data.payload.capacity();
381 }
382 }
383 self.acked = ack.ack;
384 self.retries.retain(|seq| seq.distance_to(ack.ack) <= 0);
385 if advance > 0 {
386 self.rto_count = 0;
387 self.next_rto = (!self.flight.is_empty()).then(|| now.saturating_add(self.rto()));
388 }
389 true
390 }
391
392 fn on_nak(&mut self, now: i64, ranges: &[(Seq, Seq)]) -> bool {
393 if ranges.is_empty()
396 || ranges
397 .iter()
398 .any(|(a, b)| a.distance_to(*b) < 0 || b.distance_to(self.next_seq) <= 0)
399 {
400 return false;
401 }
402 self.stats.nak_packets += 1;
403 let Some(first) = self.flight.front().map(|f| f.seq) else {
404 return true;
405 };
406 let mut work_left = self.config.max_packets;
407 for (a, b) in ranges {
408 let start = first.distance_to(*a).max(0) as usize;
409 let end = first.distance_to(*b);
410 if end < 0 {
411 continue;
412 }
413 let end = (end as usize).min(self.flight.len().saturating_sub(1));
414 for index in start..=end {
415 if work_left == 0 {
416 return true;
417 }
418 work_left -= 1;
419 if let Some(f) = self.flight.get_mut(index) {
420 if !f.requested
423 && (f.retries == 0
424 || now.saturating_sub(f.last_sent) >= self.rtt.rtt().max(1000))
425 {
426 f.requested = true;
427 self.retries.push_back(f.seq);
428 }
429 }
430 }
431 }
432 true
433 }
434
435 pub(crate) fn on_timer(&mut self, now: i64) {
436 if self.failure.is_some() {
437 return;
438 }
439 if self
440 .oldest()
441 .is_some_and(|born| now.saturating_sub(born) >= self.config.max_age_us as i64)
442 {
443 self.failure = Some(Failure::MediaExpired);
444 return;
445 }
446 if self.next_rto.is_some_and(|deadline| now >= deadline) {
447 self.rto_count = self.rto_count.saturating_add(1);
448 for f in &mut self.flight {
449 if !f.requested {
450 f.requested = true;
451 self.retries.push_back(f.seq);
452 self.stats.timeout_retransmissions += 1;
453 }
454 }
455 self.next_rto =
456 Some(now.saturating_add(self.rto().saturating_mul(i64::from(self.rto_count + 1))));
457 }
458 }
459
460 fn oldest(&self) -> Option<i64> {
461 self.flight
462 .front()
463 .map(|f| f.data.born)
464 .into_iter()
465 .chain(self.pending.front().map(|p| p.born))
466 .min()
467 }
468
469 pub(crate) fn next_timer(&self) -> i64 {
470 let mut next = self.last_send.saturating_add(1_000_000);
471 if self.ack_ack.is_some() {
472 next = next.min(self.last_receive);
473 }
474 if !self.retries.is_empty()
475 || (!self.pending.is_empty()
476 && self.flight.len() < self.flow_window
477 && self.peer_space > 0)
478 {
479 next = next.min(self.next_send);
480 }
481 if let Some(born) = self.oldest() {
482 next = next.min(born.saturating_add(self.config.max_age_us as i64));
483 }
484 if let Some(at) = self.crypto.as_ref().and_then(Encryptor::deadline) {
485 next = next.min(at);
486 }
487 if let Some(rto) = self.next_rto {
488 next = next.min(rto);
489 }
490 next
491 }
492
493 pub(crate) fn poll_transmit(&mut self, now: i64) -> Option<Vec<u8>> {
494 self.on_timer(now);
495 if self.failure.is_some() {
496 return None;
497 }
498 if let Some(km) = self.crypto.as_mut().and_then(|c| c.poll_km(now)) {
499 self.stats.km_requests += 1;
500 return Some(self.control(
501 now,
502 Control::Other {
503 control_type: 0x7fff,
504 subtype: 3,
505 info: 0,
506 cif: km,
507 },
508 ));
509 }
510 if let Some(number) = self.ack_ack.take() {
511 return Some(self.control(now, Control::AckAck { number }));
512 }
513 if now >= self.next_send {
514 while let Some(seq) = self.retries.pop_front() {
515 let first = self.flight.front()?.seq;
516 let index = first.distance_to(seq);
517 if index < 0 {
518 continue;
519 }
520 let Some(f) = self.flight.get_mut(index as usize) else {
521 continue;
522 };
523 f.requested = false;
524 if f.retries >= self.config.max_retransmits {
525 self.failure = Some(Failure::RetryLimit);
526 return None;
527 }
528 f.retries += 1;
529 f.last_sent = now;
530 let len = f.data.payload.len();
531 let out = encode_data(f, self.peer_socket, true);
532 self.stats.retransmitted_packets += 1;
533 self.stats.retransmitted_bytes += len as u64;
534 self.sent(now, len);
535 return Some(out);
536 }
537 if self.flight.len() < self.flow_window
538 && self.peer_space > 0
539 && let Some(mut data) = self.pending.pop_front()
540 {
541 let retained = self
542 .key_counts
543 .iter()
544 .enumerate()
545 .fold(0, |bits, (i, count)| {
546 bits | if *count > 0 { 1 << i } else { 0 }
547 });
548 let key = if let Some(crypto) = &mut self.crypto {
549 match crypto.encrypt(self.next_seq, &mut data.payload, retained) {
550 Ok(key) => key,
551 Err(_) => {
552 self.pending.push_front(data);
553 self.failure = Some(Failure::Crypto);
554 return None;
555 }
556 }
557 } else {
558 0
559 };
560 if let Some(count) = key
561 .checked_sub(1)
562 .and_then(|k| self.key_counts.get_mut(k as usize))
563 {
564 *count += 1;
565 }
566 if key != 0 {
567 self.stats.encrypted_packets += 1;
568 }
569 let f = Flight {
570 key,
571 data,
572 seq: self.next_seq,
573 message: self.next_message,
574 last_sent: now,
575 retries: 0,
576 requested: false,
577 };
578 self.next_seq = self.next_seq.next();
579 self.next_message = (self.next_message + 1) & 0x03ff_ffff;
580 if self.next_message == 0 {
581 self.next_message = 1;
582 }
583 let len = f.data.payload.len();
584 let out = encode_data(&f, self.peer_socket, false);
585 self.flight.push_back(f);
586 self.peer_space -= 1;
587 if self.next_rto.is_none() {
588 self.next_rto = Some(now.saturating_add(self.rto()));
589 }
590 self.sent(now, len);
591 return Some(out);
592 }
593 }
594 if now >= self.last_send.saturating_add(1_000_000) {
595 return Some(self.control(now, Control::KeepAlive));
596 }
597 None
598 }
599
600 fn sent(&mut self, now: i64, len: usize) {
601 self.stats.sent_packets += 1;
602 self.stats.sent_bytes += len as u64;
603 self.last_send = now;
604 let period = ((len as u64 + 16) * 1_000_000).div_ceil(self.config.bandwidth);
607 self.next_send = now.saturating_add(period.max(1) as i64);
608 }
609
610 fn control(&mut self, now: i64, body: Control) -> Vec<u8> {
611 let mut bytes = Vec::with_capacity(16);
612 ControlPacket::new(now as u32, self.peer_socket, body).encode(&mut bytes);
613 self.last_send = now;
614 bytes
615 }
616}
617
618fn encode_data(f: &Flight, dest: u32, retransmitted: bool) -> Vec<u8> {
619 let mut bytes = Vec::with_capacity(16 + f.data.payload.len());
620 DataPacket {
621 seq: f.seq,
622 position: Position::Only,
623 in_order: false,
624 key: f.key,
625 retransmitted,
626 message: f.message,
627 timestamp: f.data.born as u32,
628 dest,
629 payload: &f.data.payload,
630 }
631 .encode(&mut bytes);
632 bytes
633}