Skip to main content

sipx_transport/
endpoint.rs

1//! The endpoint: one event loop driving the sans-IO core.
2//!
3//! Everything mutable lives in this loop — the transaction layer, the timer queue, the
4//! sockets. No transaction is reachable from two tasks, so there are no locks in the
5//! signalling path and no way to observe a half-applied transition. Applications talk to the
6//! loop over channels.
7
8use std::collections::{HashMap, VecDeque};
9use std::net::SocketAddr;
10use std::sync::atomic::{AtomicBool, Ordering};
11use std::sync::{Arc, Mutex};
12
13use bytes::Bytes;
14use sipx_sip::build::RequestBuilder;
15use sipx_sip::transaction::{Dispatch, Output, Timer, TransactionKey, TransactionLayer, TuEvent};
16use sipx_sip::{
17    CSeq, Header, HeaderName, Limits, Message, Method, Reason, Request, Response, Timers,
18    parse_datagram,
19};
20use tokio::net::{TcpListener, UdpSocket};
21#[cfg(any(feature = "tls", feature = "ws"))]
22use tokio::sync::Semaphore;
23#[cfg(feature = "tls")]
24use tokio::sync::watch;
25use tokio::sync::{mpsc, oneshot};
26use tokio_util::sync::CancellationToken;
27use tokio_util::task::TaskTracker;
28
29use crate::capture::{Capture, CaptureConfig, Direction};
30use crate::counters::{Counters, Meters, ShedCounts};
31use crate::error::{Error, Result};
32use crate::nat::apply_received_and_rport;
33use crate::overload::{Controller as OverloadController, OverloadConfig};
34use crate::policy::{
35    ConnectionState, EndpointObservation, MessageDirection, MessageObservation, ObservationHub,
36    RequestPolicyDecision, RequestPolicyRef, SourceAdmission, SourcePrefix, TransactionClass,
37    connection_event, duplicate_policy_header, policy_header,
38};
39use crate::target::{ConnectionKey, Target, TransportKind, response_destination};
40use crate::tcp::{self, Pool, PoolConfig};
41use crate::timers::TimerQueue;
42
43/// Most ready UDP datagrams copied off the socket before the reader yields to its bounded queue.
44const UDP_RECEIVE_BATCH: usize = 512;
45
46/// RFC 3261 §18.1.1's request limit when no path MTU is known.
47const UNKNOWN_PATH_MTU_REQUEST_LIMIT: usize = 1_300;
48/// Headroom §18.1.1 reserves below a known path MTU.
49const PATH_MTU_HEADROOM: usize = 200;
50
51const fn unreliable_request_limit(path_mtu: Option<usize>) -> usize {
52    match path_mtu {
53        Some(path_mtu) => path_mtu.saturating_sub(PATH_MTU_HEADROOM),
54        None => UNKNOWN_PATH_MTU_REQUEST_LIMIT,
55    }
56}
57
58/// Which cleartext signalling listeners an endpoint exposes.
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
60#[non_exhaustive]
61pub enum CleartextTransports {
62    /// No cleartext listener. A TLS, WebSocket, secure-WebSocket, or QUIC server is required.
63    None,
64    /// UDP only.
65    Udp,
66    /// TCP only.
67    Tcp,
68    /// UDP and TCP on one address and port.
69    #[default]
70    UdpAndTcp,
71}
72
73impl CleartextTransports {
74    const fn udp(self) -> bool {
75        matches!(self, Self::Udp | Self::UdpAndTcp)
76    }
77
78    const fn tcp(self) -> bool {
79        matches!(self, Self::Tcp | Self::UdpAndTcp)
80    }
81}
82
83/// How an endpoint is configured.
84#[derive(Debug, Clone)]
85pub struct Config {
86    /// Where to bind.
87    pub bind: SocketAddr,
88    /// The host to put in `Via` sent-by.
89    ///
90    /// Deliberately separate from the bind address: behind a NAT or a load balancer the two
91    /// differ, and the socket's view is the wrong one to advertise.
92    pub sent_by: String,
93    /// The port to put in `Via` sent-by.
94    ///
95    /// `None` — and `Some(0)`, which means the same thing — is filled in with the port the
96    /// socket actually got. Binding to port 0 asks the OS to choose one, and advertising the
97    /// literal zero would tell peers to send responses to port 0.
98    pub sent_by_port: Option<u16>,
99    /// Transaction timer constants.
100    pub timers: Timers,
101    /// Parser limits.
102    pub limits: Limits,
103    /// How many events may queue for the application before new transactions are refused.
104    pub capacity: usize,
105    /// Most incomplete inbound TLS, WebSocket and secure-WebSocket handshakes at once.
106    pub handshake_limit: usize,
107    /// How long an inbound handshake may remain incomplete.
108    pub handshake_timeout: std::time::Duration,
109    /// The known path MTU for outbound SIP, if one is available.
110    ///
111    /// RFC 3261 §18.1.1 derives the unreliable-request limit as 200 bytes below this value.
112    /// `None` uses the RFC's 1300-byte unknown-path cutoff. This is a path property, not the
113    /// already-derived limit, so there is only one implementation of the subtraction.
114    pub path_mtu: Option<usize>,
115    /// Which cleartext signalling listeners to expose.
116    pub cleartext: CleartextTransports,
117    /// How sipx behaves as a TLS client, if TLS is to be used at all.
118    #[cfg(feature = "tls")]
119    pub tls_client: Option<crate::tls::ClientTls>,
120    /// The identity sipx presents as a TLS server, and the port to listen on.
121    ///
122    /// A separate port from the cleartext one, because RFC 3261 §19.1.2 gives `sips` its own
123    /// default (5061) and a peer connecting to 5060 does not expect a handshake.
124    #[cfg(feature = "tls")]
125    pub tls_server: Option<(crate::tls::ServerTls, u16)>,
126    /// How sipx verifies an outbound QUIC peer.
127    #[cfg(feature = "quic")]
128    pub quic_client: Option<crate::tls::ClientTls>,
129    /// The identity and UDP port for the experimental QUIC listener.
130    #[cfg(feature = "quic")]
131    pub quic_server: Option<(crate::tls::ServerTls, u16)>,
132    /// The port to listen for WebSocket connections on, if any.
133    ///
134    /// Its own port for the same reason TLS has one: a peer connecting to 5060 expects SIP on
135    /// the wire, not an HTTP upgrade request.
136    #[cfg(feature = "ws")]
137    pub ws_server: Option<u16>,
138    /// The identity sipx presents on the secure WebSocket port, and the port.
139    #[cfg(feature = "wss")]
140    pub wss_server: Option<(crate::tls::ServerTls, u16)>,
141    /// How often to ping an otherwise idle WebSocket.
142    ///
143    /// Well under the idle timeout of the intermediaries that sit in front of browsers — most
144    /// close a silent connection somewhere between 30 and 120 seconds, and a registration whose
145    /// connection died silently is a phone that rings nowhere.
146    #[cfg(feature = "ws")]
147    pub ws_keepalive: std::time::Duration,
148    /// How long a server transaction may receive no new application response before it is
149    /// abandoned.
150    ///
151    /// RFC 3261 §17.2 gives a server transaction in `Trying` or `Proceeding` no timer at all,
152    /// because its model is that the transaction user always responds. Real applications do
153    /// not, and a transaction nobody ever answers is held for the life of the process.
154    ///
155    /// Configurable because three minutes is not long for a telephone. Each successfully sent
156    /// provisional response starts a fresh interval; a final response removes the guard while the
157    /// RFC transaction completes its own absorption lifetime.
158    pub unanswered_limit: std::time::Duration,
159    /// How the connection pool behaves.
160    pub pool: PoolConfig,
161    /// Record the signalling this endpoint exchanges to a file (§13).
162    ///
163    /// `None` — the default — costs one `Option` check per message and opens nothing. **A capture
164    /// contains call content and identities even after redaction**; see [`CaptureConfig`].
165    pub capture: Option<CaptureConfig>,
166    /// Hop-by-hop overload feedback, client advertisement, rate tolerance, prioritization, and
167    /// randomness. Client advertisement is off by default; see [`OverloadConfig::advertise`].
168    pub overload: OverloadConfig,
169    /// Optional immutable pre-transaction request policy.
170    pub request_policy: Option<RequestPolicyRef>,
171    /// Maximum number of IP/CIDR entries in one live source-admission generation.
172    ///
173    /// Every admission check is a linear scan, so this is a work bound as well as a memory bound.
174    pub source_admission_limit: usize,
175}
176
177impl Config {
178    /// A configuration bound to an address, advertising that same address.
179    ///
180    /// If the bind address names port 0, the advertised port is the one the socket is
181    /// actually given. Note that binding to an unspecified address (`0.0.0.0`) leaves nothing
182    /// sensible to advertise; set [`Config::sent_by`] explicitly in that case.
183    #[must_use]
184    pub fn new(bind: SocketAddr) -> Self {
185        Self {
186            bind,
187            sent_by: bind.ip().to_string(),
188            sent_by_port: None,
189            timers: Timers::default(),
190            limits: Limits::datagram(),
191            capacity: 1024,
192            handshake_limit: 64,
193            handshake_timeout: std::time::Duration::from_secs(10),
194            path_mtu: None,
195            cleartext: CleartextTransports::default(),
196            #[cfg(feature = "tls")]
197            tls_client: None,
198            #[cfg(feature = "tls")]
199            tls_server: None,
200            #[cfg(feature = "quic")]
201            quic_client: None,
202            #[cfg(feature = "quic")]
203            quic_server: None,
204            #[cfg(feature = "ws")]
205            ws_server: None,
206            #[cfg(feature = "wss")]
207            wss_server: None,
208            capture: None,
209            overload: OverloadConfig::default(),
210            request_policy: None,
211            source_admission_limit: 1024,
212            #[cfg(feature = "ws")]
213            ws_keepalive: std::time::Duration::from_secs(25),
214            unanswered_limit: std::time::Duration::from_secs(180),
215            pool: PoolConfig::default(),
216        }
217    }
218
219    fn validate(&self) -> Result<()> {
220        let nonzero = |field| Error::InvalidConfig {
221            field,
222            reason: "must be non-zero",
223        };
224        if self.capacity == 0 {
225            return Err(nonzero("capacity"));
226        }
227        if self
228            .capture
229            .as_ref()
230            .is_some_and(|capture| capture.hep.is_some() && !capture.redact)
231        {
232            return Err(Error::InvalidConfig {
233                field: "capture.redact",
234                reason: "must be enabled when HEP export leaves the process",
235            });
236        }
237        if self.capacity > tokio::sync::Semaphore::MAX_PERMITS {
238            return Err(Error::InvalidConfig {
239                field: "capacity",
240                reason: "exceeds the runtime channel limit",
241            });
242        }
243        if self.pool.max_connections == 0 {
244            return Err(nonzero("pool.max_connections"));
245        }
246        if self.handshake_limit == 0 {
247            return Err(nonzero("handshake_limit"));
248        }
249        if self.handshake_timeout.is_zero() {
250            return Err(nonzero("handshake_timeout"));
251        }
252        if self.source_admission_limit == 0 {
253            return Err(nonzero("source_admission_limit"));
254        }
255        if self.overload.validity.is_zero() {
256            return Err(nonzero("overload.validity"));
257        }
258        if self.overload.validity.as_millis() == 0 {
259            return Err(Error::InvalidConfig {
260                field: "overload.validity",
261                reason: "must be at least one millisecond",
262            });
263        }
264        if self.overload.peer_limit == 0 {
265            return Err(nonzero("overload.peer_limit"));
266        }
267        if matches!(self.overload.feedback, crate::OverloadFeedback::Loss(value) if value > 100) {
268            return Err(Error::InvalidConfig {
269                field: "overload.feedback",
270                reason: "loss percentage must be between 0 and 100",
271            });
272        }
273        if self.overload.rate_tolerance_intervals >= self.overload.rate_priority_tolerance_intervals
274        {
275            return Err(Error::InvalidConfig {
276                field: "overload.rate_priority_tolerance_intervals",
277                reason: "must be greater than overload.rate_tolerance_intervals",
278            });
279        }
280        if self.cleartext == CleartextTransports::None && !self.has_other_signalling_listener() {
281            return Err(Error::InvalidConfig {
282                field: "cleartext",
283                reason: "at least one signalling listener must be configured",
284            });
285        }
286        #[cfg(feature = "ws")]
287        if self.ws_keepalive.is_zero() {
288            return Err(nonzero("ws_keepalive"));
289        }
290        Ok(())
291    }
292
293    fn has_other_signalling_listener(&self) -> bool {
294        #[allow(unused_mut)]
295        let mut configured = false;
296        #[cfg(feature = "tls")]
297        {
298            configured |= self.tls_server.is_some();
299        }
300        #[cfg(feature = "ws")]
301        {
302            configured |= self.ws_server.is_some();
303        }
304        #[cfg(feature = "wss")]
305        {
306            configured |= self.wss_server.is_some();
307        }
308        #[cfg(feature = "quic")]
309        {
310            configured |= self.quic_server.is_some();
311        }
312        configured
313    }
314}
315
316#[derive(Debug)]
317struct Background {
318    cancel: CancellationToken,
319    tasks: TaskTracker,
320    owns_lifetime: bool,
321}
322
323#[derive(Debug, Default)]
324struct ShutdownState {
325    complete: AtomicBool,
326    notify: tokio::sync::Notify,
327}
328
329impl ShutdownState {
330    async fn wait(&self) {
331        let notified = self.notify.notified();
332        tokio::pin!(notified);
333        notified.as_mut().enable();
334        if !self.complete.load(Ordering::SeqCst) {
335            notified.await;
336        }
337    }
338
339    fn complete(&self) {
340        self.complete.store(true, Ordering::SeqCst);
341        self.notify.notify_waiters();
342    }
343}
344
345impl Clone for Background {
346    fn clone(&self) -> Self {
347        Self {
348            cancel: self.cancel.clone(),
349            tasks: self.tasks.clone(),
350            owns_lifetime: false,
351        }
352    }
353}
354
355impl Background {
356    fn new() -> Self {
357        Self {
358            cancel: CancellationToken::new(),
359            tasks: TaskTracker::new(),
360            owns_lifetime: true,
361        }
362    }
363
364    fn spawn<F>(&self, future: F)
365    where
366        F: std::future::Future<Output = ()> + Send + 'static,
367    {
368        self.tasks.spawn(future);
369    }
370
371    async fn shutdown(&self) {
372        self.cancel.cancel();
373        self.tasks.close();
374        self.tasks.wait().await;
375    }
376}
377
378impl Drop for Background {
379    fn drop(&mut self) {
380        if self.owns_lifetime {
381            // This also covers a later bind failing after an earlier optional listener started.
382            // Cloned task handles do not own the lifetime and therefore cannot cancel siblings.
383            self.cancel.cancel();
384            self.tasks.close();
385        }
386    }
387}
388
389fn apply_network_source(message: Message, source: SocketAddr) -> Message {
390    match message {
391        Message::Request(mut request) => {
392            apply_received_and_rport(&mut request, source);
393            Message::Request(request)
394        }
395        response @ Message::Response(_) => response,
396    }
397}
398
399#[cfg(any(feature = "tls", feature = "ws"))]
400#[derive(Debug, Clone)]
401struct HandshakeRuntime {
402    deadline: std::time::Duration,
403    permits: Arc<Semaphore>,
404    owner: Background,
405    #[cfg(test)]
406    observations: Option<mpsc::UnboundedSender<HandshakeObservation>>,
407}
408
409/// The configured identity plus the endpoint-wide replacement selected by later handshakes.
410///
411/// Kept as one argument so TLS and WSS cannot accidentally read the publication channel and then
412/// construct an acceptor from a different configured policy.
413#[cfg(feature = "tls")]
414#[derive(Debug, Clone)]
415struct ServerHandshakePolicy {
416    configured: crate::tls::ServerTls,
417    replacement: watch::Receiver<Option<crate::tls::ServerTls>>,
418}
419
420#[cfg(feature = "tls")]
421impl ServerHandshakePolicy {
422    fn new(
423        configured: crate::tls::ServerTls,
424        replacement: watch::Receiver<Option<crate::tls::ServerTls>>,
425    ) -> Self {
426        Self {
427            configured,
428            replacement,
429        }
430    }
431
432    fn acceptor(&self) -> tokio_rustls::TlsAcceptor {
433        // One immutable configuration is selected by one watch-channel read. A concurrent reload
434        // may leave this handshake old or make it new, never split certificate chain from key.
435        self.replacement
436            .borrow()
437            .as_ref()
438            .unwrap_or(&self.configured)
439            .acceptor()
440    }
441}
442
443#[cfg(test)]
444#[derive(Debug, Clone, Copy, PartialEq, Eq)]
445enum HandshakeObservation {
446    Admitted,
447    Refused,
448}
449
450#[cfg(test)]
451fn observe_handshake(
452    observations: Option<&mpsc::UnboundedSender<HandshakeObservation>>,
453    observation: HandshakeObservation,
454) {
455    if let Some(observations) = observations {
456        // discard: observations exist only as a unit-test barrier and the test may already have
457        // ended while endpoint cleanup is still unwinding.
458        let _ = observations.send(observation);
459    }
460}
461
462/// A connection that finished its handshake and is ready to join the pool.
463///
464/// A closure rather than a stream: the pool lives on the driver's loop, and the three kinds of
465/// handshake produce three unrelated stream types the loop has no reason to distinguish.
466type Adopt = Box<dyn FnOnce(&mut Pool) + Send>;
467
468/// A request that arrived and created a server transaction.
469#[derive(Debug)]
470pub struct Incoming {
471    /// The transaction it belongs to; respond with [`Handle::respond`].
472    pub key: TransactionKey,
473    /// The request, with `received` and `rport` already applied to its topmost `Via`.
474    pub request: Request,
475    /// Where it came from.
476    pub source: SocketAddr,
477    /// How it arrived.
478    pub transport: TransportKind,
479    /// Exact stream generation which carried the request; absent for UDP.
480    pub connection_generation: Option<u64>,
481}
482
483/// Events from a client transaction: responses, then a terminal event.
484#[derive(Debug)]
485pub struct Responses {
486    rx: mpsc::Receiver<TuEvent>,
487    failures: mpsc::Receiver<Error>,
488    buffered: VecDeque<TuEvent>,
489    connection_generation: Option<u64>,
490    invitation: Option<Box<InviteCancellationState>>,
491}
492
493#[derive(Debug, Clone)]
494struct InviteCancellationContext {
495    request: Request,
496    target: Target,
497}
498
499#[derive(Debug, Clone, Copy)]
500struct TcpFallback {
501    size: usize,
502    limit: usize,
503}
504
505impl TcpFallback {
506    fn unavailable(self, source: Error) -> Error {
507        Error::TcpFallbackUnavailable {
508            size: self.size,
509            limit: self.limit,
510            source: Box::new(source),
511        }
512    }
513}
514
515#[derive(Debug, Clone)]
516struct InviteCancellationState {
517    key: TransactionKey,
518    context: InviteCancellationContext,
519    observation: InviteObservation,
520    cancel_created: bool,
521}
522
523#[derive(Debug, Clone)]
524enum InviteObservation {
525    Awaiting,
526    Provisional,
527    Final(Box<Response>),
528    Timeout,
529    TransportError,
530}
531
532/// The result of asking to cancel one exact outgoing INVITE transaction.
533#[derive(Debug)]
534#[non_exhaustive]
535pub enum CancelInviteOutcome {
536    /// The provisional-response precondition was met and one CANCEL transaction was created.
537    Sent(Box<InviteCancellation>),
538    /// A final INVITE response arrived before a CANCEL transaction was created.
539    FinalResponse {
540        /// The INVITE transaction that produced the response.
541        invite: TransactionKey,
542        /// The final response that won the race.
543        response: Response,
544    },
545    /// The INVITE timed out before a provisional response admitted CANCEL.
546    InviteTimeout {
547        /// The INVITE transaction that timed out.
548        invite: TransactionKey,
549    },
550    /// The INVITE transport failed before a provisional response admitted CANCEL.
551    InviteTransportError {
552        /// The INVITE transaction whose transport failed.
553        invite: TransactionKey,
554        /// Concrete driver cause when the transport recorded one.
555        error: Option<Error>,
556    },
557}
558
559/// One created CANCEL transaction, anchored to the INVITE it names.
560#[derive(Debug)]
561pub struct InviteCancellation {
562    invite: TransactionKey,
563    transaction: TransactionKey,
564    responses: Responses,
565}
566
567/// How a created CANCEL transaction terminated.
568#[derive(Debug)]
569#[non_exhaustive]
570pub enum CancelTransactionOutcome {
571    /// A final response arrived on the CANCEL transaction.
572    FinalResponse(Response),
573    /// The CANCEL transaction received no answer within its transaction timeout.
574    Timeout,
575    /// The selected transport failed.
576    TransportError {
577        /// Concrete driver cause when the transport recorded one.
578        error: Option<Error>,
579    },
580}
581
582impl InviteCancellation {
583    /// The INVITE transaction this CANCEL names.
584    #[must_use]
585    pub fn invite_key(&self) -> &TransactionKey {
586        &self.invite
587    }
588
589    /// The CANCEL transaction's own key.
590    #[must_use]
591    pub fn transaction_key(&self) -> &TransactionKey {
592        &self.transaction
593    }
594
595    /// Wait for the CANCEL transaction's terminal outcome.
596    pub async fn outcome(&mut self) -> CancelTransactionOutcome {
597        while let Some(event) = self.responses.next().await {
598            match event {
599                TuEvent::Response(response) if response.status.is_final() => {
600                    return CancelTransactionOutcome::FinalResponse(*response);
601                }
602                TuEvent::Timeout => return CancelTransactionOutcome::Timeout,
603                TuEvent::TransportError => {
604                    return CancelTransactionOutcome::TransportError {
605                        error: self.responses.take_transport_error(),
606                    };
607                }
608                _ => {}
609            }
610        }
611        CancelTransactionOutcome::TransportError {
612            error: Some(Error::EndpointClosed),
613        }
614    }
615}
616
617impl Responses {
618    /// The exact INVITE transaction these responses belong to, when they belong to an INVITE.
619    #[must_use]
620    pub fn transaction_key(&self) -> Option<&TransactionKey> {
621        self.invitation.as_ref().map(|state| &state.key)
622    }
623
624    /// Exact stream generation selected for the outbound request; absent for UDP.
625    #[must_use]
626    pub fn connection_generation(&self) -> Option<u64> {
627        self.connection_generation
628    }
629
630    /// The next event, or `None` once the transaction has finished.
631    pub async fn next(&mut self) -> Option<TuEvent> {
632        let event = match self.buffered.pop_front() {
633            Some(event) => Some(event),
634            None => self.rx.recv().await,
635        };
636        if let Some(event) = &event {
637            self.observe_invite(event);
638        }
639        event
640    }
641
642    /// Take the concrete driver failure associated with a `TransportError` event.
643    ///
644    /// The sans-I/O transaction layer carries only the fact that transport failed. The endpoint
645    /// queues the I/O-layer cause before feeding that fact into the core, which lets an application
646    /// preserve a TLS verification error instead of reporting an unanswered request.
647    pub fn take_transport_error(&mut self) -> Option<Error> {
648        self.failures.try_recv().ok()
649    }
650
651    /// Look at the next event without consuming it.
652    ///
653    /// Used to decide whether a resolved candidate is viable before handing the stream to the
654    /// caller, who must still see whatever was peeked at.
655    pub async fn peek(&mut self) -> Option<&TuEvent> {
656        if self.buffered.is_empty()
657            && let Some(event) = self.rx.recv().await
658        {
659            self.observe_invite(&event);
660            self.buffered.push_back(event);
661        }
662        self.buffered.front()
663    }
664
665    /// Wait for the first final response.
666    ///
667    /// Returns `None` if the transaction ended without one — a timeout or a transport error,
668    /// both of which arrive as events on [`Self::next`] if the caller wants to tell them
669    /// apart.
670    pub async fn final_response(&mut self) -> Option<Response> {
671        while let Some(event) = self.next().await {
672            if let TuEvent::Response(response) = event
673                && response.status.is_final()
674            {
675                return Some(*response);
676            }
677        }
678        None
679    }
680
681    fn observe_invite(&mut self, event: &TuEvent) {
682        let Some(invitation) = self.invitation.as_mut() else {
683            return;
684        };
685        invitation.observation = match event {
686            TuEvent::Response(response) if response.status.is_final() => {
687                InviteObservation::Final(Box::new((**response).clone()))
688            }
689            TuEvent::Response(_) => InviteObservation::Provisional,
690            TuEvent::Timeout => InviteObservation::Timeout,
691            TuEvent::TransportError => InviteObservation::TransportError,
692            TuEvent::Request(_) | TuEvent::Ack(_) => return,
693        };
694    }
695
696    async fn cancellation_precondition(&mut self) -> Result<InviteObservation> {
697        loop {
698            let observation = &self
699                .invitation
700                .as_ref()
701                .ok_or(Error::InvalidCancellation {
702                    reason: "the response stream does not belong to an INVITE",
703                })?
704                .observation;
705            match observation {
706                InviteObservation::Awaiting => {}
707                observed => return Ok(observed.clone()),
708            }
709            let Some(event) = self.rx.recv().await else {
710                return Err(Error::EndpointClosed);
711            };
712            self.observe_invite(&event);
713            self.buffered.push_back(event);
714        }
715    }
716}
717
718#[derive(Debug)]
719enum Command {
720    Request {
721        request: Box<Request>,
722        target: Target,
723        tcp_fallback: Option<TcpFallback>,
724        events: mpsc::Sender<TuEvent>,
725        failures: mpsc::Sender<Error>,
726        reply: oneshot::Sender<Result<(TransactionKey, Option<u64>)>>,
727    },
728    Respond {
729        key: TransactionKey,
730        response: Box<Response>,
731        /// Fired once the driver has performed the send, or with an error if there was no
732        /// transaction left to send it on.
733        sent: oneshot::Sender<Result<()>>,
734    },
735    /// A request handed straight to the transport, with no transaction behind it.
736    Direct {
737        request: Box<Request>,
738        target: Target,
739        tcp_fallback: Option<TcpFallback>,
740        /// Fired once the driver has actually performed the send.
741        sent: oneshot::Sender<Result<()>>,
742    },
743    /// A keep-alive on a flow (RFC 5626 §4.4): a STUN Binding Request over UDP, a CRLFCRLF ping
744    /// over anything connection-oriented.
745    Keepalive {
746        target: Target,
747        /// Fired when the answer arrives: the reflexive address for STUN, `None` for a CRLF pong
748        /// which carries no information beyond having arrived.
749        answered: oneshot::Sender<Result<Option<SocketAddr>>>,
750    },
751    /// Install a sink for responses that match no client transaction.
752    WatchUnmatched(mpsc::Sender<Unmatched>),
753    /// How much state the driver is holding, for a soak test to assert on.
754    Outstanding(oneshot::Sender<usize>),
755    /// Resolve when the transaction layer next has no client or server transaction.
756    Settled(oneshot::Sender<()>),
757    /// Stop the driver after every listener, handshake and pooled connection has terminated.
758    Shutdown,
759}
760
761#[derive(Debug)]
762struct ClientSink {
763    events: mpsc::Sender<TuEvent>,
764    failures: mpsc::Sender<Error>,
765}
766
767/// A response that matched no client transaction (RFC 3261 §16.7).
768///
769/// A user agent has nothing to do with one of these and is right to ignore it: it either answers a
770/// request this endpoint did not send, or it arrived after its transaction was already gone. A
771/// *forwarding element* is in the opposite position — §16.7 step 1 requires a stateful proxy that
772/// finds no response context to "forward the response statelessly", which it cannot do if the
773/// response never reaches it.
774///
775/// Delivered only to a caller that asked, through [`Handle::watch_unmatched`]. Nothing is allocated
776/// and nothing changes for an endpoint that never asks.
777#[derive(Debug, Clone)]
778pub struct Unmatched {
779    /// The response itself, unaltered.
780    pub response: Response,
781    /// Where it came from.
782    pub source: SocketAddr,
783    /// Which transport carried it.
784    pub transport: TransportKind,
785}
786
787/// A handle to a running endpoint.
788#[derive(Debug, Clone)]
789pub struct Handle {
790    commands: mpsc::Sender<Command>,
791    shutdown: Arc<ShutdownState>,
792    /// Monotonic outbound dialog-admission barrier shared by every handle clone.
793    draining: Arc<AtomicBool>,
794    local_addr: SocketAddr,
795    /// Every counter, shared with the driver so they can be read while the driver is busy —
796    /// which is the only time they are interesting (§12).
797    meters: Arc<Meters>,
798    admission: Arc<SourceAdmission>,
799    observations: Arc<ObservationHub>,
800    request_policy: Option<RequestPolicyRef>,
801    #[cfg(feature = "tls")]
802    tls_addr: Option<SocketAddr>,
803    /// Atomic publication point for the identity selected by later TLS and WSS handshakes.
804    ///
805    /// `None` when neither listener exists. QUIC deliberately does not subscribe: its live
806    /// configuration and connection lifetime are a separate contract (`sip-tls.md` §3.6).
807    #[cfg(feature = "tls")]
808    server_identity: Option<watch::Sender<Option<crate::tls::ServerTls>>>,
809    #[cfg(feature = "ws")]
810    ws_addr: Option<SocketAddr>,
811    #[cfg(feature = "wss")]
812    wss_addr: Option<SocketAddr>,
813    #[cfg(feature = "quic")]
814    quic_addr: Option<SocketAddr>,
815    /// The sent-by this endpoint uses on a WebSocket it dialled out (RFC 7118 §5.2).
816    ///
817    /// Invented once at bind time rather than per request: a `Via` that changed between a
818    /// request and its retransmission would be a different `Via`.
819    #[cfg(feature = "ws")]
820    ws_sent_by: Arc<str>,
821    advertise_overload: bool,
822    sent_by: Arc<String>,
823    sent_by_port: u16,
824    unreliable_request_limit: usize,
825}
826
827impl Handle {
828    /// Close admission for outbound requests which can establish a dialog.
829    ///
830    /// Existing transactions and requests carrying a `To` tag remain legal. The call dispatcher
831    /// supplies the inbound half of this barrier; [`Self::shutdown`] remains the final ownership
832    /// and task-join path.
833    pub fn begin_drain(&self) {
834        self.draining.store(true, Ordering::SeqCst);
835    }
836
837    /// Whether graceful drain has closed new-dialog admission.
838    #[must_use]
839    pub fn is_draining(&self) -> bool {
840        self.draining.load(Ordering::SeqCst)
841    }
842
843    /// Replace the complete live source-admission set and return its generation.
844    ///
845    /// An empty set refuses every new source. Use [`Self::clear_source_admission`] to allow all.
846    ///
847    /// # Errors
848    ///
849    /// Returns [`Error::SourceAdmissionCapacity`] without changing the active generation when
850    /// `prefixes` exceeds [`Config::source_admission_limit`].
851    pub fn replace_source_admission(&self, prefixes: Vec<SourcePrefix>) -> Result<u64> {
852        self.admission.replace(prefixes)
853    }
854
855    /// Clear source admission to allow all new sources and return the new generation.
856    pub fn clear_source_admission(&self) -> u64 {
857        self.admission.clear()
858    }
859
860    /// Replace the optional bounded endpoint observer.
861    ///
862    /// Producers never await this receiver. A full receiver drops and increments
863    /// [`Counters::observation_dropped`]; dropping it simply detaches observation.
864    #[must_use]
865    pub fn observe(&self, capacity: usize) -> mpsc::Receiver<EndpointObservation> {
866        self.observations.subscribe(capacity)
867    }
868
869    fn apply_request_policy(&self, request: &mut Request, target: &Target) -> Result<()> {
870        let Some(policy) = &self.request_policy else {
871            return Ok(());
872        };
873        match policy.decide(request, target) {
874            RequestPolicyDecision::Allow => Ok(()),
875            RequestPolicyDecision::Reject(reason) => Err(Error::PolicyRejected { reason }),
876            RequestPolicyDecision::AddHeaders(headers) => {
877                for header in headers {
878                    let (semantic, allowed) = policy_header(header.name());
879                    if !allowed || duplicate_policy_header(request, &semantic) {
880                        return Err(Error::ProtectedPolicyHeader {
881                            name: String::from_utf8_lossy(semantic.canonical()).into_owned(),
882                        });
883                    }
884                    request.headers.push(header);
885                }
886                Ok(())
887            }
888        }
889    }
890
891    /// The address the endpoint is bound to.
892    #[must_use]
893    pub fn local_addr(&self) -> SocketAddr {
894        self.local_addr
895    }
896
897    /// The address the TLS listener is bound to, if one was configured.
898    ///
899    /// Needed because the TLS port may be 0 — "any" — and the caller cannot put a port it does
900    /// not know into a `Contact`.
901    #[cfg(feature = "tls")]
902    #[must_use]
903    pub fn tls_addr(&self) -> Option<SocketAddr> {
904        self.tls_addr
905    }
906
907    /// Replace the identity selected by new TLS and WSS server handshakes (§3.6).
908    ///
909    /// Validation happens before publication: the complete certificate chain and private key are
910    /// first turned into one immutable [`crate::tls::ServerTls`] configuration. If they do not
911    /// belong together, this returns a typed TLS error and the active configuration is untouched.
912    ///
913    /// Existing connections are not renegotiated or closed. File watching and secret-store I/O
914    /// belong to the host, which supplies an already parsed [`crate::tls::Identity`] here.
915    #[cfg(feature = "tls")]
916    pub fn reload_server_identity(&self, identity: crate::tls::Identity) -> Result<()> {
917        let Some(publication) = &self.server_identity else {
918            return Err(Error::InvalidConfig {
919                field: "server_identity",
920                reason: "reload requires a configured TLS or WSS server listener",
921            });
922        };
923        let replacement = crate::tls::ServerTls::new(identity).map_err(|error| {
924            tracing::warn!(%error, "TLS server identity reload refused");
925            Error::Tls(error)
926        })?;
927        publication.send(Some(replacement)).map_err(|_| {
928            tracing::warn!("TLS server identity reload refused because no secure listener remains");
929            Error::InvalidConfig {
930                field: "server_identity",
931                reason: "no TLS or WSS server listener is running",
932            }
933        })?;
934        tracing::info!("TLS server identity reloaded for new TLS and WSS handshakes");
935        Ok(())
936    }
937
938    /// The address the WebSocket listener is bound to, if one was configured.
939    #[cfg(feature = "ws")]
940    #[must_use]
941    pub fn ws_addr(&self) -> Option<SocketAddr> {
942        self.ws_addr
943    }
944
945    /// The address the secure WebSocket listener is bound to, if one was configured.
946    #[cfg(feature = "wss")]
947    #[must_use]
948    pub fn wss_addr(&self) -> Option<SocketAddr> {
949        self.wss_addr
950    }
951
952    /// The host and port this endpoint tells peers to reach it on.
953    ///
954    /// Not the same as [`Self::local_addr`], and the difference matters wherever an address
955    /// goes into a message. An endpoint bound to `0.0.0.0` has a local address that means
956    /// "everywhere" to us and nothing to a peer; behind a NAT the local address is private.
957    /// `Contact` and `Via` must carry this.
958    #[must_use]
959    pub fn advertised(&self) -> String {
960        format!("{}:{}", self.sent_by, self.sent_by_port)
961    }
962
963    /// Send a request, creating a client transaction.
964    ///
965    /// A `Via` is added if the request has none — the transport owns that header, since only
966    /// it knows the branch and where responses should come back to.
967    pub async fn send(&self, mut request: Request, target: Target) -> Result<Responses> {
968        if self.is_draining() && starts_dialog(&request) {
969            return Err(Error::EndpointDraining);
970        }
971        let mut target = target;
972        self.apply_request_policy(&mut request, &target)?;
973        let generated_branch = if request.headers.get(&HeaderName::Via).is_none() {
974            let branch = new_branch();
975            let via = format!(
976                "SIP/2.0/{} {};rport;branch={}",
977                target.transport.as_str(),
978                self.sent_by_for(target.transport),
979                branch
980            );
981            let header = Header::build(HeaderName::Via, Bytes::from(via))?;
982            request.headers.push_front(header);
983            Some(branch)
984        } else {
985            None
986        };
987        if self.advertise_overload {
988            crate::overload::advertise(&mut request);
989        }
990        let tcp_fallback = self.select_tcp_for_oversized_request(
991            &mut request,
992            &mut target,
993            generated_branch.as_deref(),
994        )?;
995        let invitation = (request.method == Method::Invite).then(|| InviteCancellationContext {
996            request: request.clone(),
997            target: target.clone(),
998        });
999
1000        let (events_tx, events_rx) = mpsc::channel(32);
1001        let (failures_tx, failures_rx) = mpsc::channel(1);
1002        let (reply_tx, reply_rx) = oneshot::channel();
1003        self.commands
1004            .send(Command::Request {
1005                request: Box::new(request),
1006                target,
1007                tcp_fallback,
1008                events: events_tx,
1009                failures: failures_tx,
1010                reply: reply_tx,
1011            })
1012            .await
1013            .map_err(|_| Error::EndpointClosed)?;
1014        let (key, connection_generation) = reply_rx.await.map_err(|_| Error::EndpointClosed)??;
1015        let invitation = invitation.map(|context| {
1016            Box::new(InviteCancellationState {
1017                key,
1018                context,
1019                observation: InviteObservation::Awaiting,
1020                cancel_created: false,
1021            })
1022        });
1023        Ok(Responses {
1024            rx: events_rx,
1025            failures: failures_rx,
1026            buffered: VecDeque::new(),
1027            connection_generation,
1028            invitation,
1029        })
1030    }
1031
1032    /// Cancel the exact outgoing INVITE transaction represented by `invitation` (RFC 3261 §9.1).
1033    ///
1034    /// The operation waits for a provisional response before creating CANCEL. A final response,
1035    /// timeout or transport failure that wins that race is returned without sending a late CANCEL.
1036    /// Events observed while waiting remain available from `invitation`.
1037    ///
1038    /// # Errors
1039    ///
1040    /// Returns [`Error::InvalidCancellation`] when `invitation` belongs to another method, lacks
1041    /// mandatory CANCEL identity, or already created a CANCEL transaction. Other errors are the
1042    /// ordinary request-policy, endpoint and build failures from creating the CANCEL transaction.
1043    pub async fn cancel_invite(
1044        &self,
1045        invitation: &mut Responses,
1046        reason: Option<Reason>,
1047    ) -> Result<CancelInviteOutcome> {
1048        let state = invitation
1049            .invitation
1050            .as_ref()
1051            .ok_or(Error::InvalidCancellation {
1052                reason: "the response stream does not belong to an INVITE",
1053            })?;
1054        if state.cancel_created {
1055            return Err(Error::InvalidCancellation {
1056                reason: "a CANCEL transaction was already created for this INVITE",
1057            });
1058        }
1059        let context = state.context.clone();
1060
1061        let invite = state.key.clone();
1062        match invitation.cancellation_precondition().await? {
1063            InviteObservation::Provisional => {}
1064            InviteObservation::Final(response) => {
1065                return Ok(CancelInviteOutcome::FinalResponse {
1066                    invite,
1067                    response: *response,
1068                });
1069            }
1070            InviteObservation::Timeout => {
1071                return Ok(CancelInviteOutcome::InviteTimeout { invite });
1072            }
1073            InviteObservation::TransportError => {
1074                return Ok(CancelInviteOutcome::InviteTransportError {
1075                    invite,
1076                    error: invitation.take_transport_error(),
1077                });
1078            }
1079            InviteObservation::Awaiting => {
1080                return Err(Error::InvalidCancellation {
1081                    reason: "the INVITE cancellation precondition did not resolve",
1082                });
1083            }
1084        }
1085
1086        let request = cancel_request(&context.request, reason)?;
1087        let transaction = TransactionKey::from_sent_request(&request).ok_or(Error::NoVia)?;
1088        // Reserve the one permitted attempt before the first cancellation point in `send`.
1089        // Dropping this future may abandon the result, but it can never create a second CANCEL.
1090        if let Some(state) = invitation.invitation.as_mut() {
1091            state.cancel_created = true;
1092        }
1093        let responses = self.send(request, context.target).await?;
1094        Ok(CancelInviteOutcome::Sent(Box::new(InviteCancellation {
1095            invite,
1096            transaction,
1097            responses,
1098        })))
1099    }
1100
1101    /// Send a request straight to the transport, with no transaction behind it.
1102    ///
1103    /// For the one request that has no transaction of its own: the ACK to a 2xx. RFC 3261
1104    /// §13.2.2.4 has it "passed to the transport layer directly for transmission", and it is
1105    /// the UAC core — not a transaction — that resends it when a retransmitted 2xx arrives.
1106    /// Putting it in a transaction instead earns it Timer E retransmissions toward a response
1107    /// that will never come, and a timeout 32 seconds later for a call that is up and talking.
1108    ///
1109    /// The `Via` is the caller's business here: an ACK for a 2xx carries a *new* branch
1110    /// (§13.2.2.4 makes it a new transaction as far as any proxy is concerned), and only the
1111    /// caller knows the dialog it belongs to.
1112    ///
1113    /// Returns once the bytes have been handed to the socket.
1114    pub async fn send_directly(&self, mut request: Request, target: Target) -> Result<()> {
1115        if self.is_draining() && starts_dialog(&request) {
1116            return Err(Error::EndpointDraining);
1117        }
1118        let mut target = target;
1119        self.apply_request_policy(&mut request, &target)?;
1120        if self.advertise_overload {
1121            crate::overload::advertise(&mut request);
1122        }
1123        let tcp_fallback =
1124            self.select_tcp_for_oversized_request(&mut request, &mut target, None)?;
1125        let (sent_tx, sent_rx) = oneshot::channel();
1126        self.commands
1127            .send(Command::Direct {
1128                request: Box::new(request),
1129                target,
1130                tcp_fallback,
1131                sent: sent_tx,
1132            })
1133            .await
1134            .map_err(|_| Error::EndpointClosed)?;
1135        sent_rx.await.map_err(|_| Error::EndpointClosed)?
1136    }
1137
1138    fn select_tcp_for_oversized_request(
1139        &self,
1140        request: &mut Request,
1141        target: &mut Target,
1142        generated_branch: Option<&str>,
1143    ) -> Result<Option<TcpFallback>> {
1144        if target.transport != TransportKind::Udp {
1145            return Ok(None);
1146        }
1147        let size = Message::Request(request.clone()).to_bytes().len();
1148        if size <= self.unreliable_request_limit {
1149            return Ok(None);
1150        }
1151
1152        let fallback = TcpFallback {
1153            size,
1154            limit: self.unreliable_request_limit,
1155        };
1156        target.transport = TransportKind::Tcp;
1157        if let Some(branch) = generated_branch {
1158            let _owned_via = request.headers.remove_first(&HeaderName::Via);
1159            let via = format!(
1160                "SIP/2.0/TCP {};rport;branch={branch}",
1161                self.sent_by_for(TransportKind::Tcp)
1162            );
1163            request
1164                .headers
1165                .push_front(Header::build(HeaderName::Via, Bytes::from(via))?);
1166        }
1167        self.meters.oversized_request_tcp_fallback();
1168        tracing::info!(
1169            peer = %target.addr,
1170            size,
1171            limit = self.unreliable_request_limit,
1172            "oversized UDP request switched to TCP"
1173        );
1174        Ok(Some(fallback))
1175    }
1176
1177    /// Resolve a URI (RFC 3263) and send to the resulting candidates in order.
1178    ///
1179    /// A candidate that fails is not the request failing — the next one is tried, and only an
1180    /// exhausted list is an error. Each attempt is its own transaction with its own branch,
1181    /// which is what makes retrying legal: a transaction is bound to the destination it was
1182    /// created for.
1183    ///
1184    /// Note what "fails" costs on an unreliable transport. A dead TCP peer refuses the
1185    /// connection and is known bad in milliseconds; a dead UDP peer says nothing at all, and
1186    /// the only way to learn it is dead is to let the transaction time out — 64·T1, or 32
1187    /// seconds with the default constants. That is a property of UDP, not of this function,
1188    /// but it means a long candidate list over UDP is slow to exhaust. Callers that cannot
1189    /// afford it should use [`Handle::send`] with a candidate list they manage themselves.
1190    pub async fn send_to_uri<R: crate::resolve::Resolver + ?Sized>(
1191        &self,
1192        request: Request,
1193        uri: &sipx_sip::Uri,
1194        resolver: &R,
1195    ) -> Result<Responses> {
1196        let candidates = crate::resolve::resolve(uri, resolver, &mut crate::resolve::OsRng);
1197        if candidates.is_empty() {
1198            return Err(Error::Unresolvable(uri.to_bytes().to_vec()));
1199        }
1200
1201        let mut last = Err(Error::Unresolvable(uri.to_bytes().to_vec()));
1202        for target in candidates {
1203            let mut responses = self.send(request.clone(), target).await?;
1204            // Peek at the first event. A transport error here means this candidate is dead;
1205            // anything else means the exchange has begun and belongs to the caller.
1206            match responses.peek().await {
1207                // Both are "this candidate is dead". A transport error says so directly; a
1208                // timeout is how UDP says it, since a black hole sends nothing back.
1209                Some(TuEvent::TransportError) => last = Err(Error::EndpointClosed),
1210                Some(TuEvent::Timeout) => {
1211                    last = Err(Error::Unresolvable(uri.to_bytes().to_vec()));
1212                }
1213                _ => return Ok(responses),
1214            }
1215        }
1216        last
1217    }
1218
1219    /// The host and port this endpoint tells peers to reach it on over this transport.
1220    ///
1221    /// Almost always its real host and port, as [`Self::advertised`] gives them. The exception
1222    /// is a WebSocket sipx dialled out on: RFC 7118 §5.2 says such a client has no listening
1223    /// port and must invent an unresolvable name, and advertising a real address instead would
1224    /// send a proxy off to a port that is not listening while the connection it should have
1225    /// used sits open. An endpoint that *does* listen for WebSocket connections is not that
1226    /// client, and keeps its own name.
1227    ///
1228    /// Belongs in a `Contact` as much as in a `Via`, for the same reason: both are answers to
1229    /// "where do I reach you".
1230    #[must_use]
1231    pub fn sent_by_for(&self, transport: TransportKind) -> String {
1232        #[cfg(feature = "ws")]
1233        if matches!(transport, TransportKind::Ws | TransportKind::Wss) && !self.listens_for_ws() {
1234            return self.ws_sent_by.to_string();
1235        }
1236        // TLS is listened for on a port of its own (RFC 3261 §19.1.2), so a sent-by naming the
1237        // cleartext port would direct any response that cannot reuse the connection at a port
1238        // speaking a different protocol.
1239        #[cfg(feature = "tls")]
1240        if matches!(transport, TransportKind::Tls)
1241            && let Some(addr) = self.tls_addr
1242        {
1243            return format!("{}:{}", self.sent_by, addr.port());
1244        }
1245        #[cfg(feature = "quic")]
1246        if transport == TransportKind::Quic
1247            && let Some(addr) = self.quic_addr
1248        {
1249            return format!("{}:{}", self.sent_by, addr.port());
1250        }
1251        // discard: not a loss. The parameter is unused unless a transport feature is on, and
1252        // this is the suppressor rather than a discarded result.
1253        let _ = transport;
1254        format!("{}:{}", self.sent_by, self.sent_by_port)
1255    }
1256
1257    #[cfg(feature = "ws")]
1258    fn listens_for_ws(&self) -> bool {
1259        #[cfg(feature = "wss")]
1260        if self.wss_addr.is_some() {
1261            return true;
1262        }
1263        self.ws_addr.is_some()
1264    }
1265
1266    /// Send a response on a server transaction.
1267    ///
1268    /// Returns once the response has been handed to the socket, not merely queued. The
1269    /// difference is invisible until a process answers a call and exits — then the queued
1270    /// version loses the response to the exit, and the caller sees a timeout for a call that
1271    /// was in fact refused. Every caller already assumed this; now it is true.
1272    pub async fn respond(&self, key: &TransactionKey, response: Response) -> Result<()> {
1273        let (sent, delivered) = oneshot::channel();
1274        self.commands
1275            .send(Command::Respond {
1276                key: key.clone(),
1277                response: Box::new(response),
1278                sent,
1279            })
1280            .await
1281            .map_err(|_| Error::EndpointClosed)?;
1282        delivered.await.map_err(|_| Error::EndpointClosed)?
1283    }
1284
1285    /// Keep a flow alive, and wait for the answer (RFC 5626 §4.4).
1286    ///
1287    /// Over UDP this is a STUN Binding Request (§4.4.2) and the answer carries the reflexive
1288    /// address the far end saw — which is the reason to prefer STUN over a SIP request: §4.4.2 has
1289    /// a *changed* mapped address mean the flow has failed, so the keep-alive detects a NAT
1290    /// rebinding rather than only proving the socket still works. Over anything
1291    /// connection-oriented it is §4.4.1's CRLFCRLF ping, and the pong carries nothing but its own
1292    /// arrival, so the answer is `None`.
1293    ///
1294    /// `within` is how long to wait. §4.4.1 sets it at 10 seconds for the CRLF technique and
1295    /// requires a UA whose pong does not arrive to "treat the flow as failed"; the number is the
1296    /// caller's because it is RFC 5626 policy rather than a property of the transport.
1297    ///
1298    /// Sent over the same connection a request would take, which is the whole point: a ping on a
1299    /// second connection proves a flow nobody is using.
1300    pub async fn keepalive(
1301        &self,
1302        target: Target,
1303        within: std::time::Duration,
1304    ) -> Result<Option<SocketAddr>> {
1305        let (answered_tx, answered_rx) = oneshot::channel();
1306        self.commands
1307            .send(Command::Keepalive {
1308                target,
1309                answered: answered_tx,
1310            })
1311            .await
1312            .map_err(|_| Error::EndpointClosed)?;
1313        match tokio::time::timeout(within, answered_rx).await {
1314            Ok(Ok(result)) => result,
1315            // The driver dropped the waiter, which happens only on shutdown.
1316            Ok(Err(_)) => Err(Error::EndpointClosed),
1317            // §4.4.1: no answer in time is a failed flow, not a slow one.
1318            Err(_) => Err(Error::KeepaliveUnanswered),
1319        }
1320    }
1321
1322    /// Watch for responses that match no client transaction (RFC 3261 §16.7).
1323    ///
1324    /// Opt-in, and the reason it is opt-in is the whole design: a user agent has no answer for one
1325    /// of these — it either answers a request this endpoint did not send, or it arrived after its
1326    /// transaction was gone — and should not have to handle a case it cannot act on. A forwarding
1327    /// element is required to act on it, so it asks.
1328    ///
1329    /// Until someone calls this, unmatched responses are logged and dropped exactly as before, and
1330    /// no channel exists to allocate into.
1331    ///
1332    /// Calling it twice **replaces** the sink. Two watchers would each see some of the responses
1333    /// and neither would see all of them, which is a subtler failure than having none.
1334    pub async fn watch_unmatched(&self, capacity: usize) -> Result<mpsc::Receiver<Unmatched>> {
1335        let (tx, rx) = mpsc::channel(capacity.max(1));
1336        self.commands
1337            .send(Command::WatchUnmatched(tx))
1338            .await
1339            .map_err(|_| Error::EndpointClosed)?;
1340        Ok(rx)
1341    }
1342
1343    /// What this endpoint has dropped because the application was not keeping up.
1344    ///
1345    /// Read straight from a shared counter rather than by asking the event loop, because the loop
1346    /// is busy in precisely the situation this counts. A metric that is unavailable exactly when
1347    /// it is interesting is not a metric.
1348    ///
1349    /// Non-zero is not automatically a fault — shedding under load is a policy, and a `503` tells
1350    /// a peer something true. `ShedCounts::acks` is different: see its documentation.
1351    #[must_use]
1352    pub fn shed(&self) -> ShedCounts {
1353        self.meters.snapshot().shed
1354    }
1355
1356    /// Everything this endpoint will say about itself (§12).
1357    ///
1358    /// Synchronous, and deliberately so. [`Self::outstanding`] beside it is `async` and returns a
1359    /// `Result` because it asks the event loop; this reads shared atomics and cannot fail, because a
1360    /// snapshot that was unavailable while the loop was busy would be unavailable in exactly the
1361    /// situation an operator reaches for it.
1362    ///
1363    /// A snapshot is **not a consistent instant** — see [`Counters`] for what that does and does not
1364    /// allow you to conclude.
1365    #[must_use]
1366    pub fn counters(&self) -> Counters {
1367        self.meters.snapshot()
1368    }
1369
1370    /// Address of the experimental QUIC listener, when configured.
1371    #[cfg(feature = "quic")]
1372    #[must_use]
1373    pub fn quic_addr(&self) -> Option<SocketAddr> {
1374        self.quic_addr
1375    }
1376
1377    /// How many transactions and destinations the endpoint is still holding.
1378    ///
1379    /// Exposed for the soak test in `sipx-testkit`, and worth exposing: a transaction store
1380    /// that leaks is a slow, quiet outage — the stack goes on working for hours and then stops,
1381    /// and by then the cause is a long way behind. This is the cheapest way to notice.
1382    ///
1383    /// Note what a *non-zero* answer does not mean. RFC 3261 §17 keeps a completed transaction
1384    /// for Timer J, thirty-two seconds, so it can absorb a retransmission. Sampling before that
1385    /// has elapsed counts the specification.
1386    pub async fn outstanding(&self) -> Result<usize> {
1387        let (tx, rx) = oneshot::channel();
1388        self.commands
1389            .send(Command::Outstanding(tx))
1390            .await
1391            .map_err(|_| Error::EndpointClosed)?;
1392        rx.await.map_err(|_| Error::EndpointClosed)
1393    }
1394
1395    /// Wait until the endpoint transaction layer has no client or server transaction.
1396    ///
1397    /// This is a driver event, not a polling loop. The command is serialized with transaction
1398    /// creation and terminal outputs, so a caller can use it as the transaction half of a
1399    /// graceful-drain completion barrier.
1400    pub async fn settled(&self) -> Result<()> {
1401        let (tx, rx) = oneshot::channel();
1402        self.commands
1403            .send(Command::Settled(tx))
1404            .await
1405            .map_err(|_| Error::EndpointClosed)?;
1406        rx.await.map_err(|_| Error::EndpointClosed)
1407    }
1408
1409    /// Stop the endpoint.
1410    pub async fn shutdown(&self) {
1411        if !self.shutdown.complete.load(Ordering::SeqCst) {
1412            // discard: a closed command channel means shutdown has already begun. The shared
1413            // durable barrier below still waits for cleanup, including for callers arriving late.
1414            let _ = self.commands.send(Command::Shutdown).await;
1415            self.shutdown.wait().await;
1416        }
1417    }
1418}
1419
1420fn starts_dialog(request: &Request) -> bool {
1421    matches!(
1422        request.method,
1423        Method::Invite | Method::Subscribe | Method::Refer
1424    ) && request
1425        .headers
1426        .typed::<sipx_sip::headers::To>()
1427        .and_then(std::result::Result::ok)
1428        .and_then(|to| to.tag().map(<[u8]>::to_vec))
1429        .is_none()
1430}
1431
1432fn branch_with_rng<R>(rng: &mut R) -> String
1433where
1434    R: rand::CryptoRng + ?Sized,
1435{
1436    let value = rand::RngCore::next_u64(rng);
1437    format!("z9hG4bK{value:016x}")
1438}
1439
1440/// A `branch` token: the RFC's magic cookie plus 64 bits from a cryptographic RNG.
1441///
1442/// The width is ours, not the RFC's. A guessable branch lets an off-path attacker inject
1443/// responses into a transaction, so this is not a place for a counter.
1444#[must_use]
1445pub fn new_branch() -> String {
1446    branch_with_rng(&mut rand::rng())
1447}
1448
1449fn cancellation_header(invite: &Request, name: &HeaderName, reason: &'static str) -> Result<Bytes> {
1450    invite
1451        .headers
1452        .value(name)
1453        .map(|value| Bytes::from(value.into_owned()))
1454        .ok_or(Error::InvalidCancellation { reason })
1455}
1456
1457/// Derive CANCEL from the exact post-policy INVITE that created the transaction.
1458fn cancel_request(invite: &Request, reason: Option<Reason>) -> Result<Request> {
1459    if invite.method != Method::Invite {
1460        return Err(Error::InvalidCancellation {
1461            reason: "the stored request is not an INVITE",
1462        });
1463    }
1464
1465    let mut builder = RequestBuilder::new(Method::Cancel, invite.uri.clone()).header(
1466        HeaderName::Via,
1467        cancellation_header(invite, &HeaderName::Via, "the INVITE has no Via")?,
1468    )?;
1469    for route in invite.headers.get_all(&HeaderName::Route) {
1470        builder = builder.header(HeaderName::Route, Bytes::from(route.value().into_owned()))?;
1471    }
1472    for (name, missing) in [
1473        (HeaderName::To, "the INVITE has no To header"),
1474        (HeaderName::From, "the INVITE has no From header"),
1475        (HeaderName::CallId, "the INVITE has no Call-ID header"),
1476    ] {
1477        let value = cancellation_header(invite, &name, missing)?;
1478        builder = builder.header(name, value)?;
1479    }
1480    let sequence = invite
1481        .headers
1482        .typed::<CSeq>()
1483        .and_then(std::result::Result::ok)
1484        .filter(|cseq| cseq.method == Method::Invite)
1485        .map(|cseq| cseq.sequence)
1486        .ok_or(Error::InvalidCancellation {
1487            reason: "the INVITE has no valid INVITE CSeq",
1488        })?;
1489    builder = builder.cseq(sequence, &Method::Cancel)?.max_forwards(70);
1490    if let Some(reason) = reason {
1491        builder = builder.header(HeaderName::Reason, reason.to_bytes())?;
1492    }
1493    Ok(builder.build())
1494}
1495
1496/// Bind an endpoint and start its loop.
1497///
1498/// Returns a handle for sending, and a receiver of the requests that arrive.
1499#[allow(
1500    clippy::too_many_lines,
1501    reason = "one ordered assembly keeps validation, every bind and task ownership auditable"
1502)]
1503pub async fn bind(config: Config) -> Result<(Handle, mpsc::Receiver<Incoming>)> {
1504    config.validate()?;
1505    let CleartextBindings {
1506        udp: socket,
1507        tcp: listener,
1508        local_addr: cleartext_addr,
1509    } = bind_cleartext(&config).await?;
1510    let background = Background::new();
1511    let meters = Arc::new(Meters::default());
1512    let admission = Arc::new(SourceAdmission::new(config.source_admission_limit));
1513    let observations = Arc::new(ObservationHub::new(Arc::clone(&meters)));
1514    #[cfg(any(feature = "tls", feature = "ws"))]
1515    let handshakes = HandshakeRuntime {
1516        deadline: config.handshake_timeout,
1517        permits: Arc::new(Semaphore::new(config.handshake_limit)),
1518        owner: background.clone(),
1519        #[cfg(test)]
1520        observations: None,
1521    };
1522    // One channel for every handshaked connection, whatever kind it is. The driver owns the
1523    // pool, so adoption has to happen on its loop; what joins is a closure rather than a stream
1524    // because TCP-over-TLS, WebSocket and WebSocket-over-TLS are three unrelated types and the
1525    // loop has no reason to know which it is holding. One channel is also one `select!` branch,
1526    // which matters more than it looks: `tokio::select!` cannot compile a branch out behind a
1527    // feature flag, so a branch per optional transport does not build with that feature off.
1528    let (adopt_tx, adopt_rx) = mpsc::channel::<Adopt>(64);
1529
1530    // A single publication point feeds both secure stream listeners. Their configured identities
1531    // may differ before the first reload; afterwards both select the one complete replacement.
1532    // QUIC does not receive this channel (`sip-tls.md` §3.6).
1533    #[cfg(feature = "tls")]
1534    let (server_identity_tx, server_identity_rx) =
1535        watch::channel::<Option<crate::tls::ServerTls>>(None);
1536    #[cfg(feature = "tls")]
1537    let has_reloadable_server = config.tls_server.is_some() || {
1538        #[cfg(feature = "wss")]
1539        {
1540            config.wss_server.is_some()
1541        }
1542        #[cfg(not(feature = "wss"))]
1543        {
1544            false
1545        }
1546    };
1547
1548    #[cfg(feature = "tls")]
1549    let secure_addr = match config.tls_server.clone() {
1550        Some((server, port)) => Some(
1551            listen_tls(
1552                config.bind.ip(),
1553                port,
1554                ServerHandshakePolicy::new(server, server_identity_rx.clone()),
1555                &adopt_tx,
1556                &handshakes,
1557                Arc::clone(&admission),
1558                Arc::clone(&meters),
1559            )
1560            .await?,
1561        ),
1562        None => None,
1563    };
1564    #[cfg(feature = "ws")]
1565    let upgrade_addr = match config.ws_server {
1566        Some(port) => Some(
1567            listen_ws(
1568                config.bind.ip(),
1569                port,
1570                config.ws_keepalive,
1571                config.limits,
1572                &adopt_tx,
1573                &handshakes,
1574                Arc::clone(&admission),
1575                Arc::clone(&meters),
1576            )
1577            .await?,
1578        ),
1579        None => None,
1580    };
1581    #[cfg(feature = "wss")]
1582    let secure_upgrade_addr = match config.wss_server.clone() {
1583        Some((server, port)) => Some(
1584            listen_wss(
1585                config.bind.ip(),
1586                port,
1587                ServerHandshakePolicy::new(server, server_identity_rx.clone()),
1588                config.ws_keepalive,
1589                config.limits,
1590                &adopt_tx,
1591                &handshakes,
1592                Arc::clone(&admission),
1593                Arc::clone(&meters),
1594            )
1595            .await?,
1596        ),
1597        None => None,
1598    };
1599    #[cfg(feature = "quic")]
1600    let quic_endpoint = if config.quic_client.is_some() || config.quic_server.is_some() {
1601        let port = config.quic_server.as_ref().map_or(0, |(_, port)| *port);
1602        Some(crate::quic::endpoint(
1603            config.bind.ip(),
1604            port,
1605            config.quic_client.as_ref(),
1606            config.quic_server.as_ref().map(|(server, _)| server),
1607        )?)
1608    } else {
1609        None
1610    };
1611    #[cfg(feature = "quic")]
1612    let quic_addr = match (&quic_endpoint, &config.quic_server) {
1613        (Some(endpoint), Some(_)) => {
1614            let addr = endpoint.local_addr()?;
1615            listen_quic(
1616                endpoint.clone(),
1617                &adopt_tx,
1618                &handshakes,
1619                Arc::clone(&admission),
1620                Arc::clone(&meters),
1621            );
1622            Some(addr)
1623        }
1624        _ => None,
1625    };
1626
1627    #[allow(unused_mut)]
1628    let mut primary_addr = cleartext_addr;
1629    #[cfg(feature = "tls")]
1630    if primary_addr.is_none() {
1631        primary_addr = secure_addr;
1632    }
1633    #[cfg(feature = "ws")]
1634    if primary_addr.is_none() {
1635        primary_addr = upgrade_addr;
1636    }
1637    #[cfg(feature = "wss")]
1638    if primary_addr.is_none() {
1639        primary_addr = secure_upgrade_addr;
1640    }
1641    #[cfg(feature = "quic")]
1642    if primary_addr.is_none() {
1643        primary_addr = quic_addr;
1644    }
1645    let local_addr = primary_addr.ok_or(Error::InvalidConfig {
1646        field: "cleartext",
1647        reason: "at least one signalling listener must be configured",
1648    })?;
1649    // Port 0 in the configuration means the same as absent: it is a request for any port,
1650    // not an advertisement of port zero.
1651    let sent_by_port = match config.sent_by_port {
1652        Some(port) if port != 0 => port,
1653        _ => local_addr.port(),
1654    };
1655
1656    let (commands_tx, commands_rx) = mpsc::channel(config.capacity);
1657    let (incoming_tx, incoming_rx) = mpsc::channel(config.capacity);
1658    let shutdown = Arc::new(ShutdownState::default());
1659
1660    let handle = Handle {
1661        commands: commands_tx,
1662        shutdown: Arc::clone(&shutdown),
1663        draining: Arc::new(AtomicBool::new(false)),
1664        local_addr,
1665        meters: Arc::clone(&meters),
1666        admission: Arc::clone(&admission),
1667        observations: Arc::clone(&observations),
1668        request_policy: config.request_policy.clone(),
1669        #[cfg(feature = "tls")]
1670        tls_addr: secure_addr,
1671        #[cfg(feature = "tls")]
1672        server_identity: has_reloadable_server.then_some(server_identity_tx),
1673        #[cfg(feature = "ws")]
1674        ws_addr: upgrade_addr,
1675        #[cfg(feature = "wss")]
1676        wss_addr: secure_upgrade_addr,
1677        #[cfg(feature = "quic")]
1678        quic_addr,
1679        #[cfg(feature = "ws")]
1680        ws_sent_by: Arc::from(crate::ws::invented_sent_by()),
1681        advertise_overload: config.overload.advertise,
1682        sent_by: Arc::new(config.sent_by.clone()),
1683        sent_by_port,
1684        unreliable_request_limit: unreliable_request_limit(config.path_mtu),
1685    };
1686
1687    // Started before the driver, so a path that cannot be opened fails `bind` rather than leaving a
1688    // running endpoint that appears to be recording and writes nothing.
1689    let capture = match &config.capture {
1690        Some(wanted) => Some(
1691            Capture::start(wanted, Arc::clone(&meters)).map_err(|source| Error::Capture {
1692                path: wanted.path.display().to_string(),
1693                source,
1694            })?,
1695        ),
1696        None => None,
1697    };
1698
1699    let (net_tx, net_rx) = mpsc::channel(config.capacity);
1700    let (udp_tx, udp_rx) = mpsc::channel(config.capacity);
1701    let socket = socket.map(Arc::new);
1702    if let Some(socket) = &socket {
1703        background.spawn(receive_udp_until(
1704            Arc::clone(socket),
1705            udp_tx,
1706            background.cancel.clone(),
1707        ));
1708    }
1709    let (accept_tx, accept_rx) = mpsc::channel(64);
1710    if let Some(listener) = listener {
1711        let cancel = background.cancel.clone();
1712        background.spawn(accept_tcp_until(
1713            listener,
1714            accept_tx,
1715            cancel,
1716            Arc::clone(&admission),
1717            Arc::clone(&meters),
1718        ));
1719    }
1720
1721    let driver = Driver {
1722        socket,
1723        udp: udp_rx,
1724        layer: TransactionLayer::new(config.timers),
1725        timers: TimerQueue::new(),
1726        destinations: HashMap::new(),
1727        transaction_generations: HashMap::new(),
1728        unanswered_since: HashMap::new(),
1729        reconnect: HashMap::new(),
1730        tcp_fallbacks: HashMap::new(),
1731        unanswered_limit: config.unanswered_limit,
1732        overload: OverloadController::new(
1733            config.overload.rate_tolerance_intervals,
1734            config.overload.rate_priority_tolerance_intervals,
1735            config.overload.peer_limit,
1736        ),
1737        overload_config: config.overload.clone(),
1738        overload_epoch: tokio::time::Instant::now(),
1739        overload_sequence: 0,
1740        server_overloaded_until: None,
1741        clients: HashMap::new(),
1742        incoming: incoming_tx,
1743        commands: commands_rx,
1744        net: net_rx,
1745        accepts: accept_rx,
1746        adopts: adopt_rx,
1747        _adopt: adopt_tx,
1748        #[cfg(feature = "tls")]
1749        tls_client: config.tls_client.clone(),
1750        #[cfg(feature = "ws")]
1751        ws_keepalive: config.ws_keepalive,
1752        #[cfg(feature = "quic")]
1753        quic_client: config.quic_client.clone(),
1754        #[cfg(feature = "quic")]
1755        quic_endpoint,
1756        pool: Pool::new_observed(
1757            config.pool,
1758            config.limits,
1759            net_tx,
1760            Arc::clone(&observations),
1761        ),
1762        limits: config.limits,
1763        unreliable_request_limit: unreliable_request_limit(config.path_mtu),
1764        meters,
1765        admission,
1766        observations,
1767        capture,
1768        local_addr,
1769        unmatched: None,
1770        stun_waiters: HashMap::new(),
1771        pong_waiters: HashMap::new(),
1772        #[cfg(feature = "quic")]
1773        quic_replies: HashMap::new(),
1774        background,
1775        shutdown,
1776        settled: Vec::new(),
1777    };
1778    tokio::spawn(driver.run());
1779
1780    Ok((handle, incoming_rx))
1781}
1782
1783/// One side of the hidden in-process construction seam.
1784#[doc(hidden)]
1785pub type InProcessEndpoint = (Handle, mpsc::Receiver<Incoming>);
1786
1787/// The two sides returned by the hidden in-process construction seam.
1788#[doc(hidden)]
1789pub type InProcessPair = (InProcessEndpoint, InProcessEndpoint);
1790
1791/// Build two endpoints joined by a bounded in-process signalling path.
1792///
1793/// This is a construction seam for `sipx-testkit`, not a second production transport. It drives
1794/// the same public [`Handle`] contract as [`bind`] — including client response streams, server
1795/// [`Incoming`] values, and direct 2xx ACK delivery — while opening no signalling socket. Media
1796/// remains owned by the call layer and is deliberately outside this seam.
1797///
1798/// Hidden from the rendered API because downstream tests should use the higher-level testkit
1799/// harness, whose call-scoped ownership prevents one exchange from observing another's events.
1800/// Construction returns a typed error unless called inside an entered Tokio runtime.
1801#[doc(hidden)]
1802pub fn in_process_pair(capacity: usize) -> Result<InProcessPair> {
1803    let runtime = tokio::runtime::Handle::try_current().map_err(|_| Error::RuntimeUnavailable)?;
1804    let capacity = capacity.max(1);
1805    let routes = Arc::new(Mutex::new(HashMap::<
1806        (InProcessSide, TransactionKey),
1807        ClientSink,
1808    >::new()));
1809    let left_addr = SocketAddr::from(([127, 0, 0, 1], 50_600));
1810    let right_addr = SocketAddr::from(([127, 0, 0, 1], 50_601));
1811    let (left, left_commands, left_incoming_tx, left_incoming_rx) =
1812        in_process_handle(left_addr, capacity);
1813    let (right, right_commands, right_incoming_tx, right_incoming_rx) =
1814        in_process_handle(right_addr, capacity);
1815
1816    runtime.spawn(run_in_process(
1817        InProcessSide::Left,
1818        left_addr,
1819        capacity,
1820        left_commands,
1821        right_incoming_tx,
1822        Arc::clone(&routes),
1823        Arc::clone(&left.shutdown),
1824    ));
1825    runtime.spawn(run_in_process(
1826        InProcessSide::Right,
1827        right_addr,
1828        capacity,
1829        right_commands,
1830        left_incoming_tx,
1831        routes,
1832        Arc::clone(&right.shutdown),
1833    ));
1834
1835    Ok(((left, left_incoming_rx), (right, right_incoming_rx)))
1836}
1837
1838#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1839enum InProcessSide {
1840    Left,
1841    Right,
1842}
1843
1844impl InProcessSide {
1845    const fn peer(self) -> Self {
1846        match self {
1847            Self::Left => Self::Right,
1848            Self::Right => Self::Left,
1849        }
1850    }
1851}
1852
1853type InProcessRoutes = Arc<Mutex<HashMap<(InProcessSide, TransactionKey), ClientSink>>>;
1854
1855fn insert_in_process_route(
1856    routes: &InProcessRoutes,
1857    capacity: usize,
1858    owner: InProcessSide,
1859    key: TransactionKey,
1860    sink: ClientSink,
1861    peer: SocketAddr,
1862) -> Result<()> {
1863    let mut routes = routes
1864        .lock()
1865        .unwrap_or_else(std::sync::PoisonError::into_inner);
1866    routes.retain(|_, client| !client.events.is_closed());
1867    if routes.len() >= capacity {
1868        return Err(Error::Overloaded { peer });
1869    }
1870    routes.insert((owner, key), sink);
1871    Ok(())
1872}
1873
1874fn in_process_response_events(
1875    routes: &InProcessRoutes,
1876    owner: InProcessSide,
1877    key: TransactionKey,
1878    final_response: bool,
1879) -> Option<mpsc::Sender<TuEvent>> {
1880    let mut routes = routes
1881        .lock()
1882        .unwrap_or_else(std::sync::PoisonError::into_inner);
1883    if final_response {
1884        routes.remove(&(owner, key)).map(|client| client.events)
1885    } else {
1886        routes
1887            .get(&(owner, key))
1888            .map(|client| client.events.clone())
1889    }
1890}
1891
1892fn clear_in_process_routes(routes: &InProcessRoutes) {
1893    routes
1894        .lock()
1895        .unwrap_or_else(std::sync::PoisonError::into_inner)
1896        .clear();
1897}
1898
1899fn wake_in_process_settled(
1900    routes: &InProcessRoutes,
1901    side: InProcessSide,
1902    settled: &mut Vec<oneshot::Sender<()>>,
1903) {
1904    let has_transaction = routes
1905        .lock()
1906        .unwrap_or_else(std::sync::PoisonError::into_inner)
1907        .keys()
1908        .any(|(owner, _)| *owner == side);
1909    if !has_transaction {
1910        for answered in settled.drain(..) {
1911            let _ = answered.send(());
1912        }
1913    }
1914}
1915
1916fn in_process_outstanding(routes: &InProcessRoutes, side: InProcessSide) -> usize {
1917    routes
1918        .lock()
1919        .unwrap_or_else(std::sync::PoisonError::into_inner)
1920        .keys()
1921        .filter(|(owner, _)| *owner == side)
1922        .count()
1923}
1924
1925fn in_process_handle(
1926    local_addr: SocketAddr,
1927    capacity: usize,
1928) -> (
1929    Handle,
1930    mpsc::Receiver<Command>,
1931    mpsc::Sender<Incoming>,
1932    mpsc::Receiver<Incoming>,
1933) {
1934    let (commands, command_rx) = mpsc::channel(capacity);
1935    let incoming = mpsc::channel(capacity);
1936    let shutdown = Arc::new(ShutdownState::default());
1937    let sent_by = Arc::new(local_addr.ip().to_string());
1938    let meters = Arc::new(Meters::default());
1939    let handle = Handle {
1940        commands,
1941        shutdown,
1942        draining: Arc::new(AtomicBool::new(false)),
1943        local_addr,
1944        meters: Arc::clone(&meters),
1945        admission: Arc::new(SourceAdmission::default()),
1946        observations: Arc::new(ObservationHub::new(meters)),
1947        request_policy: None,
1948        #[cfg(feature = "tls")]
1949        tls_addr: None,
1950        #[cfg(feature = "tls")]
1951        server_identity: None,
1952        #[cfg(feature = "ws")]
1953        ws_addr: None,
1954        #[cfg(feature = "wss")]
1955        wss_addr: None,
1956        #[cfg(feature = "quic")]
1957        quic_addr: None,
1958        #[cfg(feature = "ws")]
1959        ws_sent_by: Arc::from(format!("in-process-{}", local_addr.port())),
1960        advertise_overload: false,
1961        sent_by,
1962        sent_by_port: local_addr.port(),
1963        unreliable_request_limit: UNKNOWN_PATH_MTU_REQUEST_LIMIT,
1964    };
1965    (handle, command_rx, incoming.0, incoming.1)
1966}
1967
1968async fn run_in_process(
1969    side: InProcessSide,
1970    local_addr: SocketAddr,
1971    capacity: usize,
1972    mut commands: mpsc::Receiver<Command>,
1973    peer_incoming: mpsc::Sender<Incoming>,
1974    routes: InProcessRoutes,
1975    shutdown: Arc<ShutdownState>,
1976) {
1977    let mut settled = Vec::<oneshot::Sender<()>>::new();
1978    while let Some(command) = commands.recv().await {
1979        match command {
1980            Command::Request {
1981                request,
1982                target,
1983                events,
1984                failures,
1985                reply,
1986                ..
1987            } => {
1988                let Some(client_key) = TransactionKey::from_sent_request(&request) else {
1989                    let _ = reply.send(Err(Error::NoVia));
1990                    continue;
1991                };
1992                let Some(server_key) = TransactionKey::from_request(&request) else {
1993                    let _ = reply.send(Err(Error::NoVia));
1994                    continue;
1995                };
1996                if let Err(error) = insert_in_process_route(
1997                    &routes,
1998                    capacity,
1999                    side.peer(),
2000                    server_key.clone(),
2001                    ClientSink { events, failures },
2002                    target.addr,
2003                ) {
2004                    let _ = reply.send(Err(error));
2005                    continue;
2006                }
2007                let _ = reply.send(Ok((client_key, None)));
2008                if peer_incoming
2009                    .send(Incoming {
2010                        key: server_key,
2011                        request: *request,
2012                        source: local_addr,
2013                        transport: target.transport,
2014                        connection_generation: None,
2015                    })
2016                    .await
2017                    .is_err()
2018                {
2019                    break;
2020                }
2021            }
2022            Command::Respond {
2023                key,
2024                response,
2025                sent,
2026            } => {
2027                let events =
2028                    in_process_response_events(&routes, side, key, response.status.is_final());
2029                let result = if let Some(events) = events {
2030                    events
2031                        .send(TuEvent::Response(response))
2032                        .await
2033                        .map_err(|_| Error::EndpointClosed)
2034                } else {
2035                    Err(Error::EndpointClosed)
2036                };
2037                let _ = sent.send(result);
2038            }
2039            Command::Direct {
2040                request,
2041                target,
2042                sent,
2043                ..
2044            } => {
2045                let result =
2046                    send_in_process_direct(local_addr, &peer_incoming, request, target).await;
2047                let _ = sent.send(result);
2048            }
2049            Command::Keepalive { answered, .. } => {
2050                let _ = answered.send(Ok(None));
2051            }
2052            Command::WatchUnmatched(_) => {}
2053            Command::Outstanding(answered) => {
2054                let _ = answered.send(in_process_outstanding(&routes, side));
2055            }
2056            Command::Settled(answered) => settled.push(answered),
2057            Command::Shutdown => break,
2058        }
2059        wake_in_process_settled(&routes, side, &mut settled);
2060    }
2061    clear_in_process_routes(&routes);
2062    shutdown.complete();
2063}
2064
2065async fn send_in_process_direct(
2066    local_addr: SocketAddr,
2067    peer_incoming: &mpsc::Sender<Incoming>,
2068    request: Box<Request>,
2069    target: Target,
2070) -> Result<()> {
2071    let Some(key) = TransactionKey::from_request(&request) else {
2072        return Err(Error::NoVia);
2073    };
2074    peer_incoming
2075        .send(Incoming {
2076            key,
2077            request: *request,
2078            source: local_addr,
2079            transport: target.transport,
2080            connection_generation: None,
2081        })
2082        .await
2083        .map_err(|_| Error::EndpointClosed)
2084}
2085
2086/// Listen for TLS connections, handshaking each off the accept path.
2087///
2088/// Off the accept path so one slow or hostile peer cannot hold up every other connection
2089/// waiting behind it. The listener's own address is returned because the caller may have asked
2090/// for port 0 and cannot put a port it does not know into a `Contact`.
2091#[cfg(feature = "tls")]
2092async fn listen_tls(
2093    ip: std::net::IpAddr,
2094    port: u16,
2095    server: ServerHandshakePolicy,
2096    adopt: &mpsc::Sender<Adopt>,
2097    runtime: &HandshakeRuntime,
2098    admission: Arc<SourceAdmission>,
2099    meters: Arc<Meters>,
2100) -> Result<SocketAddr> {
2101    let listener = TcpListener::bind(SocketAddr::new(ip, port)).await?;
2102    let addr = listener.local_addr()?;
2103    let adopt = adopt.clone();
2104    let owner = runtime.owner.clone();
2105    let cancel = owner.cancel.clone();
2106    let permits = Arc::clone(&runtime.permits);
2107    let deadline = runtime.deadline;
2108    #[cfg(test)]
2109    let observations = runtime.observations.clone();
2110    runtime.owner.spawn(async move {
2111        loop {
2112            let accepted = tokio::select! {
2113                biased;
2114                () = cancel.cancelled() => break,
2115                accepted = listener.accept() => accepted,
2116            };
2117            let (stream, peer) = match accepted {
2118                Ok(accepted) => accepted,
2119                Err(error) => {
2120                    tracing::warn!(%error, "TLS accept failed");
2121                    break;
2122                }
2123            };
2124            let Some(admission_generation) = admission.admit(peer.ip()) else {
2125                meters.source_refusal(TransportKind::Tls);
2126                tracing::debug!(%peer, "refused inbound TLS source before handshake");
2127                continue;
2128            };
2129            let permit = Arc::clone(&permits).try_acquire_owned();
2130            #[cfg(test)]
2131            observe_handshake(
2132                observations.as_ref(),
2133                if permit.is_ok() {
2134                    HandshakeObservation::Admitted
2135                } else {
2136                    HandshakeObservation::Refused
2137                },
2138            );
2139            let Ok(permit) = permit else {
2140                // discard: the configured no-queue admission policy closes excess unauthenticated
2141                // sockets immediately; retaining one here would defeat the handshake bound.
2142                tracing::debug!(%peer, "refused inbound TLS handshake at capacity");
2143                continue;
2144            };
2145            let acceptor = server.acceptor();
2146            let adopt = adopt.clone();
2147            let cancel = cancel.clone();
2148            owner.spawn(async move {
2149                let outcome = tokio::select! {
2150                    biased;
2151                    () = cancel.cancelled() => None,
2152                    result = tokio::time::timeout(deadline, acceptor.accept(stream)) => Some(result),
2153                };
2154                match outcome {
2155                    Some(Ok(Ok(tls))) => {
2156                        // Discarded deliberately, with the reason §12.1 asks for rather than a
2157                        // counter: a send on this channel fails only when the driver has already
2158                        // stopped, so the connection has nothing left to be adopted *into*. The
2159                        // socket closes as it drops, which is the correct outcome and not a loss —
2160                        // and this runs in a task spawned before the driver exists, so there is no
2161                        // counter in scope to reach for anyway.
2162                        // discard: see the reason below.
2163                        tokio::select! {
2164                            biased;
2165                            () = cancel.cancelled() => {}
2166                            result = adopt.send(Box::new(move |pool: &mut Pool| pool.accept_tls_admitted(tls, peer, admission_generation))) => {
2167                                let _ = result;
2168                            }
2169                        }
2170                    }
2171                    Some(Ok(Err(error))) => {
2172                        tracing::debug!(%error, %peer, "inbound TLS handshake failed");
2173                    }
2174                    Some(Err(_)) => tracing::debug!(%peer, "inbound TLS handshake timed out"),
2175                    None => {}
2176                }
2177                drop(permit);
2178            });
2179        }
2180    });
2181    Ok(addr)
2182}
2183
2184/// Accept QUIC handshakes off the driver loop and adopt established connections through the
2185/// same bounded channel as every other optional transport.
2186#[cfg(feature = "quic")]
2187fn listen_quic(
2188    endpoint: quinn::Endpoint,
2189    adopt: &mpsc::Sender<Adopt>,
2190    runtime: &HandshakeRuntime,
2191    admission: Arc<SourceAdmission>,
2192    meters: Arc<Meters>,
2193) {
2194    let adopt = adopt.clone();
2195    let owner = runtime.owner.clone();
2196    let cancel = owner.cancel.clone();
2197    let permits = Arc::clone(&runtime.permits);
2198    let deadline = runtime.deadline;
2199    runtime.owner.spawn(async move {
2200        loop {
2201            let incoming = tokio::select! {
2202                biased;
2203                () = cancel.cancelled() => break,
2204                incoming = endpoint.accept() => incoming,
2205            };
2206            let Some(incoming) = incoming else {
2207                break;
2208            };
2209            let peer = incoming.remote_address();
2210            let Some(admission_generation) = admission.admit(peer.ip()) else {
2211                incoming.refuse();
2212                meters.source_refusal(TransportKind::Quic);
2213                tracing::debug!(%peer, "refused inbound QUIC source before handshake");
2214                continue;
2215            };
2216            let Ok(permit) = Arc::clone(&permits).try_acquire_owned() else {
2217                incoming.refuse();
2218                tracing::debug!(%peer, "refused inbound QUIC handshake at capacity");
2219                continue;
2220            };
2221            let adopt = adopt.clone();
2222            let cancel = cancel.clone();
2223            owner.spawn(async move {
2224                let connected = tokio::select! {
2225                    biased;
2226                    () = cancel.cancelled() => None,
2227                    result = tokio::time::timeout(deadline, incoming) => Some(result),
2228                };
2229                match connected {
2230                    Some(Ok(Ok(connection))) => {
2231                        let result = adopt
2232                            .send(Box::new(move |pool: &mut Pool| {
2233                                pool.accept_quic_admitted(connection, peer, admission_generation);
2234                            }))
2235                            .await;
2236                        if result.is_err() {
2237                            tracing::debug!(%peer, "QUIC connection lost its endpoint before adoption");
2238                        }
2239                    }
2240                    Some(Ok(Err(error))) => {
2241                        tracing::debug!(%error, %peer, "inbound QUIC handshake failed");
2242                    }
2243                    Some(Err(_)) => tracing::debug!(%peer, "inbound QUIC handshake timed out"),
2244                    None => {}
2245                }
2246                drop(permit);
2247            });
2248        }
2249    });
2250}
2251
2252/// Listen for WebSocket connections, upgrading each off the accept path.
2253#[cfg(feature = "ws")]
2254#[allow(clippy::too_many_arguments)]
2255async fn listen_ws(
2256    ip: std::net::IpAddr,
2257    port: u16,
2258    keepalive: std::time::Duration,
2259    limits: Limits,
2260    adopt: &mpsc::Sender<Adopt>,
2261    runtime: &HandshakeRuntime,
2262    admission: Arc<SourceAdmission>,
2263    meters: Arc<Meters>,
2264) -> Result<SocketAddr> {
2265    let listener = TcpListener::bind(SocketAddr::new(ip, port)).await?;
2266    let addr = listener.local_addr()?;
2267    let adopt = adopt.clone();
2268    let owner = runtime.owner.clone();
2269    let cancel = owner.cancel.clone();
2270    let permits = Arc::clone(&runtime.permits);
2271    let deadline = runtime.deadline;
2272    #[cfg(test)]
2273    let observations = runtime.observations.clone();
2274    runtime.owner.spawn(async move {
2275        loop {
2276            let accepted = tokio::select! {
2277                biased;
2278                () = cancel.cancelled() => break,
2279                accepted = listener.accept() => accepted,
2280            };
2281            let (stream, peer) = match accepted {
2282                Ok(accepted) => accepted,
2283                Err(error) => {
2284                    tracing::warn!(%error, "WebSocket accept failed");
2285                    break;
2286                }
2287            };
2288            let Some(admission_generation) = admission.admit(peer.ip()) else {
2289                meters.source_refusal(TransportKind::Ws);
2290                tracing::debug!(%peer, "refused inbound WebSocket source before handshake");
2291                continue;
2292            };
2293            let permit = Arc::clone(&permits).try_acquire_owned();
2294            #[cfg(test)]
2295            observe_handshake(
2296                observations.as_ref(),
2297                if permit.is_ok() {
2298                    HandshakeObservation::Admitted
2299                } else {
2300                    HandshakeObservation::Refused
2301                },
2302            );
2303            let Ok(permit) = permit else {
2304                // discard: the configured no-queue admission policy closes excess unauthenticated
2305                // sockets immediately; retaining one here would defeat the handshake bound.
2306                tracing::debug!(%peer, "refused inbound WebSocket handshake at capacity");
2307                continue;
2308            };
2309            let adopt = adopt.clone();
2310            let cancel = cancel.clone();
2311            owner.spawn(async move {
2312                let upgraded = tokio::select! {
2313                    biased;
2314                    () = cancel.cancelled() => None,
2315                    result = tokio::time::timeout(
2316                        deadline,
2317                        crate::ws::accept_with_limits(stream, peer, &limits),
2318                    ) => Some(result),
2319                };
2320                match upgraded {
2321                    Some(Ok(result)) => {
2322                        adopt_upgraded(
2323                            result,
2324                            peer,
2325                            TransportKind::Ws,
2326                            keepalive,
2327                            admission_generation,
2328                            &adopt,
2329                            &cancel,
2330                        )
2331                        .await;
2332                    }
2333                    Some(Err(_)) => tracing::debug!(%peer, "inbound WebSocket handshake timed out"),
2334                    None => {}
2335                }
2336                drop(permit);
2337            });
2338        }
2339    });
2340    Ok(addr)
2341}
2342
2343/// Listen for secure WebSocket connections: TLS, then the upgrade.
2344///
2345/// The certificate policy is `T-7`'s because this is `T-7`'s code — the same acceptor, built
2346/// from the same [`crate::tls::ServerTls`]. A second implementation of a security check is how
2347/// one of the two ends up weaker.
2348#[cfg(feature = "wss")]
2349#[allow(clippy::too_many_arguments)]
2350async fn listen_wss(
2351    ip: std::net::IpAddr,
2352    port: u16,
2353    server: ServerHandshakePolicy,
2354    keepalive: std::time::Duration,
2355    limits: Limits,
2356    adopt: &mpsc::Sender<Adopt>,
2357    runtime: &HandshakeRuntime,
2358    admission: Arc<SourceAdmission>,
2359    meters: Arc<Meters>,
2360) -> Result<SocketAddr> {
2361    let listener = TcpListener::bind(SocketAddr::new(ip, port)).await?;
2362    let addr = listener.local_addr()?;
2363    let adopt = adopt.clone();
2364    let owner = runtime.owner.clone();
2365    let cancel = owner.cancel.clone();
2366    let permits = Arc::clone(&runtime.permits);
2367    let deadline = runtime.deadline;
2368    #[cfg(test)]
2369    let observations = runtime.observations.clone();
2370    runtime.owner.spawn(async move {
2371        loop {
2372            let accepted = tokio::select! {
2373                biased;
2374                () = cancel.cancelled() => break,
2375                accepted = listener.accept() => accepted,
2376            };
2377            let (stream, peer) = match accepted {
2378                Ok(accepted) => accepted,
2379                Err(error) => {
2380                    tracing::warn!(%error, "WSS accept failed");
2381                    break;
2382                }
2383            };
2384            let Some(admission_generation) = admission.admit(peer.ip()) else {
2385                meters.source_refusal(TransportKind::Wss);
2386                tracing::debug!(%peer, "refused inbound WSS source before handshake");
2387                continue;
2388            };
2389            let permit = Arc::clone(&permits).try_acquire_owned();
2390            #[cfg(test)]
2391            observe_handshake(
2392                observations.as_ref(),
2393                if permit.is_ok() {
2394                    HandshakeObservation::Admitted
2395                } else {
2396                    HandshakeObservation::Refused
2397                },
2398            );
2399            let Ok(permit) = permit else {
2400                // discard: the configured no-queue admission policy closes excess unauthenticated
2401                // sockets immediately; retaining one here would defeat the handshake bound.
2402                tracing::debug!(%peer, "refused inbound WSS handshake at capacity");
2403                continue;
2404            };
2405            let acceptor = server.acceptor();
2406            let adopt = adopt.clone();
2407            let cancel = cancel.clone();
2408            owner.spawn(async move {
2409                let upgraded = tokio::select! {
2410                    biased;
2411                    () = cancel.cancelled() => None,
2412                    result = tokio::time::timeout(deadline, async move {
2413                        let tls = acceptor.accept(stream).await.map_err(|error| error.to_string())?;
2414                        crate::ws::accept_with_limits(tls, peer, &limits)
2415                            .await
2416                            .map_err(|error| error.to_string())
2417                    }) => Some(result),
2418                };
2419                match upgraded {
2420                    Some(Ok(Ok(socket))) => {
2421                        adopt_upgraded(
2422                            Ok(socket),
2423                            peer,
2424                            TransportKind::Wss,
2425                            keepalive,
2426                            admission_generation,
2427                            &adopt,
2428                            &cancel,
2429                        )
2430                        .await;
2431                    }
2432                    Some(Ok(Err(error))) => {
2433                        tracing::debug!(%error, %peer, "inbound WSS handshake failed");
2434                    }
2435                    Some(Err(_)) => tracing::debug!(%peer, "inbound WSS handshake timed out"),
2436                    None => {}
2437                }
2438                drop(permit);
2439            });
2440        }
2441    });
2442    Ok(addr)
2443}
2444
2445/// Hand a completed WebSocket upgrade to the driver, or report why there was none.
2446#[cfg(feature = "ws")]
2447async fn adopt_upgraded<S>(
2448    upgraded: std::result::Result<crate::ws::Socket<S>, crate::ws::WsError>,
2449    peer: SocketAddr,
2450    transport: TransportKind,
2451    keepalive: std::time::Duration,
2452    admission_generation: u64,
2453    adopt: &mpsc::Sender<Adopt>,
2454    cancel: &CancellationToken,
2455) where
2456    S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static,
2457{
2458    match upgraded {
2459        Ok(socket) => {
2460            let key = ConnectionKey::new(peer, transport);
2461            // Discarded deliberately; see the matching site in `listen_tls` for the reason. A failed
2462            // send here means the driver has stopped, and a connection with no driver to be adopted
2463            // into is closed by dropping it.
2464            // discard: see the reason below.
2465            tokio::select! {
2466                biased;
2467                () = cancel.cancelled() => {}
2468                result = adopt.send(Box::new(move |pool: &mut Pool| {
2469                        pool.accept_ws_admitted(socket, key, keepalive, admission_generation);
2470                    })) => {
2471                    let _ = result;
2472                }
2473            }
2474        }
2475        Err(error) => tracing::debug!(%error, %peer, "inbound websocket handshake failed"),
2476    }
2477}
2478
2479/// Accept clear TCP only from the current source-admission generation.
2480async fn accept_tcp_until(
2481    listener: TcpListener,
2482    incoming: mpsc::Sender<(tokio::net::TcpStream, SocketAddr, u64)>,
2483    cancel: CancellationToken,
2484    admission: Arc<SourceAdmission>,
2485    meters: Arc<Meters>,
2486) {
2487    loop {
2488        let accepted = tokio::select! {
2489            biased;
2490            () = cancel.cancelled() => return,
2491            accepted = listener.accept() => accepted,
2492        };
2493        let (stream, peer) = match accepted {
2494            Ok(accepted) => accepted,
2495            Err(error) => {
2496                tracing::warn!(%error, "accept failed");
2497                return;
2498            }
2499        };
2500        let Some(generation) = admission.admit(peer.ip()) else {
2501            meters.source_refusal(TransportKind::Tcp);
2502            tracing::debug!(%peer, "refused inbound TCP source before stream parsing");
2503            continue;
2504        };
2505        tokio::select! {
2506            biased;
2507            () = cancel.cancelled() => return,
2508            result = incoming.send((stream, peer, generation)) => {
2509                if result.is_err() {
2510                    return;
2511                }
2512            }
2513        }
2514    }
2515}
2516
2517struct CleartextBindings {
2518    udp: Option<UdpSocket>,
2519    tcp: Option<TcpListener>,
2520    local_addr: Option<SocketAddr>,
2521}
2522
2523/// Bind exactly the selected cleartext listeners.
2524///
2525/// When both are selected, peers assume they share one port: a `Via` naming
2526/// `SIP/2.0/TCP host:port` and one naming UDP refer to one port number.
2527///
2528/// The awkward part is that UDP and TCP have independent port spaces, so a port the OS hands
2529/// out for UDP may already be held by someone else for TCP. When the caller asked for port 0 —
2530/// "any port" — that is not an error, it is a port to not use: try again. When the caller named
2531/// a port, it is a real conflict and is reported as one.
2532async fn bind_cleartext(config: &Config) -> Result<CleartextBindings> {
2533    const ATTEMPTS: usize = 16;
2534
2535    if !config.cleartext.udp() {
2536        if config.cleartext.tcp() {
2537            let listener = TcpListener::bind(config.bind).await?;
2538            let local_addr = listener.local_addr()?;
2539            return Ok(CleartextBindings {
2540                udp: None,
2541                tcp: Some(listener),
2542                local_addr: Some(local_addr),
2543            });
2544        }
2545        return Ok(CleartextBindings {
2546            udp: None,
2547            tcp: None,
2548            local_addr: None,
2549        });
2550    }
2551
2552    let wants_any_port = config.bind.port() == 0;
2553    let mut last_error = None;
2554
2555    for _ in 0..ATTEMPTS {
2556        let socket = UdpSocket::bind(config.bind).await?;
2557        let local_addr = socket.local_addr()?;
2558
2559        if !config.cleartext.tcp() {
2560            return Ok(CleartextBindings {
2561                udp: Some(socket),
2562                tcp: None,
2563                local_addr: Some(local_addr),
2564            });
2565        }
2566
2567        match TcpListener::bind(local_addr).await {
2568            Ok(listener) => {
2569                return Ok(CleartextBindings {
2570                    udp: Some(socket),
2571                    tcp: Some(listener),
2572                    local_addr: Some(local_addr),
2573                });
2574            }
2575            Err(error) if wants_any_port && error.kind() == std::io::ErrorKind::AddrInUse => {
2576                // Someone else holds this port for TCP. Drop the UDP socket so the OS may
2577                // hand the port out again, and ask for another.
2578                drop(socket);
2579                last_error = Some(error);
2580            }
2581            Err(error) => return Err(error.into()),
2582        }
2583    }
2584
2585    Err(last_error
2586        .unwrap_or_else(|| {
2587            std::io::Error::new(
2588                std::io::ErrorKind::AddrInUse,
2589                "no port was free for both UDP and TCP",
2590            )
2591        })
2592        .into())
2593}
2594
2595struct Driver {
2596    socket: Option<Arc<UdpSocket>>,
2597    /// Ordered datagrams copied off the socket by the bounded, state-free reader task.
2598    udp: mpsc::Receiver<(Bytes, SocketAddr)>,
2599    layer: TransactionLayer,
2600    timers: TimerQueue<(TransactionKey, Timer)>,
2601    destinations: HashMap<TransactionKey, Target>,
2602    /// Exact stream incarnation carrying each transaction; UDP transactions have no entry.
2603    transaction_generations: HashMap<TransactionKey, ConnectionGeneration>,
2604    /// When each server transaction was handed over or last received application progress, so
2605    /// silence remains bounded without imposing an absolute deadline on a live transaction.
2606    unanswered_since: HashMap<TransactionKey, tokio::time::Instant>,
2607    /// Where a response goes if the connection its request arrived on has closed.
2608    ///
2609    /// RFC 3261 §18.2.2: the address from `received` at the `sent-by` port, which is a port the
2610    /// peer listens on — unlike the source port, which is the ephemeral one it dialled out
2611    /// from. Held only for server transactions on a connection-oriented transport, because it
2612    /// is the only case where the question arises.
2613    reconnect: HashMap<TransactionKey, Target>,
2614    /// Requests whose UDP target was changed to TCP under RFC 3261 §18.1.1.
2615    tcp_fallbacks: HashMap<TransactionKey, TcpFallback>,
2616    /// How long a server transaction may receive no new application response before abandonment.
2617    unanswered_limit: std::time::Duration,
2618    /// Per-next-hop RFC 7339/RFC 7415 state, serialized with sends and responses on this loop.
2619    overload: OverloadController,
2620    overload_config: OverloadConfig,
2621    overload_epoch: tokio::time::Instant,
2622    overload_sequence: u64,
2623    /// Queue-full detector state advertised on responses until its stated validity expires.
2624    server_overloaded_until: Option<tokio::time::Instant>,
2625    clients: HashMap<TransactionKey, ClientSink>,
2626    incoming: mpsc::Sender<Incoming>,
2627    commands: mpsc::Receiver<Command>,
2628    net: mpsc::Receiver<tcp::Event>,
2629    accepts: mpsc::Receiver<(tokio::net::TcpStream, SocketAddr, u64)>,
2630    adopts: mpsc::Receiver<Adopt>,
2631    /// Held only to keep the adoption channel open when no optional listener is configured. A
2632    /// closed channel would leave that `select!` branch resolving instantly on every pass.
2633    _adopt: mpsc::Sender<Adopt>,
2634    #[cfg(feature = "tls")]
2635    tls_client: Option<crate::tls::ClientTls>,
2636    #[cfg(feature = "ws")]
2637    ws_keepalive: std::time::Duration,
2638    #[cfg(feature = "quic")]
2639    quic_client: Option<crate::tls::ClientTls>,
2640    #[cfg(feature = "quic")]
2641    quic_endpoint: Option<quinn::Endpoint>,
2642    pool: Pool,
2643    limits: Limits,
2644    unreliable_request_limit: usize,
2645    /// Every counter, shared with every [`Handle`]; see [`Counters`].
2646    meters: Arc<Meters>,
2647    admission: Arc<SourceAdmission>,
2648    observations: Arc<ObservationHub>,
2649    /// The running capture, if one was configured (§13). `None` is the ordinary case.
2650    capture: Option<Capture>,
2651    /// The address this endpoint is bound to.
2652    ///
2653    /// Stored rather than asked of the socket. It cannot change after `bind`, and
2654    /// `UdpSocket::local_addr` is a `getsockname(2)` — which a previous version of this called once
2655    /// per observed message, capture on or off.
2656    local_addr: SocketAddr,
2657    /// Where to send responses that match no client transaction, if anyone asked for them.
2658    ///
2659    /// `None` is the ordinary case and costs nothing: no channel exists, and the response is
2660    /// logged and dropped exactly as before.
2661    unmatched: Option<mpsc::Sender<Unmatched>>,
2662    stun_waiters: HashMap<crate::stun::TransactionId, oneshot::Sender<Result<Option<SocketAddr>>>>,
2663    /// Keep-alives sent over a connection, waiting for a CRLF pong.
2664    ///
2665    /// A queue per connection rather than one slot: nothing stops a caller pinging twice, and
2666    /// pongs are indistinguishable from each other, so the only honest match is first-in-first-out.
2667    pong_waiters: HashMap<
2668        ConnectionGeneration,
2669        std::collections::VecDeque<oneshot::Sender<Result<Option<SocketAddr>>>>,
2670    >,
2671    /// Exact response route for each server transaction received on a QUIC stream.
2672    #[cfg(feature = "quic")]
2673    quic_replies: HashMap<TransactionKey, crate::quic::Reply>,
2674    /// Listener and pre-pool handshake tasks owned by this endpoint.
2675    background: Background,
2676    /// Durable completion barrier shared with callers that arrive after command closure.
2677    shutdown: Arc<ShutdownState>,
2678    /// Transaction-terminal waiters registered by [`Handle::settled`].
2679    settled: Vec<oneshot::Sender<()>>,
2680}
2681
2682fn forget_transaction_timers(
2683    timers: &mut TimerQueue<(TransactionKey, Timer)>,
2684    key: &TransactionKey,
2685) {
2686    for timer in Timer::ALL {
2687        timers.forget(&(key.clone(), timer));
2688    }
2689}
2690
2691#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2692struct ConnectionGeneration {
2693    key: ConnectionKey,
2694    id: u64,
2695}
2696
2697/// Proof that [`Endpoint::perform`] ran to completion.
2698///
2699/// It exists so that "the datagram is on the wire before the caller is told so" is a property of
2700/// the *types* rather than of the order two statements happen to be written in. `respond` reports
2701/// success by consuming this value, so moving the report above the send is a compile error rather
2702/// than a silent regression.
2703///
2704/// `X-36` is why. The test named `respond_returns_only_once_the_response_has_been_sent` could not
2705/// detect the reversal: on a `current_thread` runtime, sending on the oneshot does not yield, so
2706/// `perform` completed before the waiting task was ever polled — the datagram was always out by
2707/// the time anyone could look, whichever order the two lines were in. A test cannot observe the
2708/// difference, so the guarantee is made structural instead.
2709struct Performed {
2710    /// At least one transaction output reached its configured transport boundary.
2711    sent_message: bool,
2712}
2713
2714impl Performed {
2715    /// Whether a message output reached its configured transport boundary.
2716    #[must_use]
2717    fn sent_message(&self) -> bool {
2718        self.sent_message
2719    }
2720
2721    /// The success `respond` reports, obtainable only from proof that the send happened.
2722    ///
2723    /// Clippy objects to both halves of this signature, and both are the point. `unused_self`: taking
2724    /// `self` by value is the entire mechanism — it is what makes the `Ok` unobtainable without the
2725    /// send. `unnecessary_wraps`: the `Result` is what goes over the oneshot, whose other arm really
2726    /// can be `Err(Error::NoTransaction)`, so the wrap is the caller's type and not decoration.
2727    #[allow(
2728        clippy::unused_self,
2729        clippy::unnecessary_wraps,
2730        reason = "consuming self is the guarantee; the Result is the channel's type"
2731    )]
2732    fn into_result(self) -> Result<()> {
2733        Ok(())
2734    }
2735}
2736
2737impl Driver {
2738    async fn run(mut self) {
2739        // Idle connections are swept periodically rather than given a timer each; the pool is
2740        // small and the sweep is cheap.
2741        let mut idle_sweep = tokio::time::interval(std::time::Duration::from_secs(30));
2742        idle_sweep.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
2743        loop {
2744            let deadline = self.timers.next_deadline();
2745            let receives_udp = self.socket.is_some();
2746            tokio::select! {
2747                Some((datagram, source)) = self.udp.recv(), if receives_udp => {
2748                    self.on_datagram(datagram, source).await;
2749                }
2750                () = sleep_until(deadline), if deadline.is_some() => {
2751                    self.on_timers().await;
2752                }
2753                command = self.commands.recv() => match command {
2754                    Some(Command::Shutdown) | None => break,
2755                    Some(command) => self.on_command(command).await,
2756                },
2757                Some(event) = self.net.recv() => self.on_net_event(event).await,
2758                Some((stream, peer, generation)) = self.accepts.recv() => {
2759                    self.pool.accept_admitted(stream, peer, generation);
2760                },
2761                Some(adopt) = self.adopts.recv() => adopt(&mut self.pool),
2762                _ = idle_sweep.tick() => {
2763                    for closed in self.pool.evict_idle() {
2764                        tracing::debug!(peer = %closed.peer, "closed an idle connection");
2765                    }
2766                    self.abandon_unanswered();
2767                }
2768            }
2769            self.wake_settled();
2770        }
2771        self.commands.close();
2772        self.background.shutdown().await;
2773        self.pool.shutdown().await;
2774        // The acknowledgement must be the driver's final observable action: dropping `self`
2775        // first releases the UDP socket, command receiver and every remaining channel owner.
2776        let shutdown = Arc::clone(&self.shutdown);
2777        drop(self);
2778        shutdown.complete();
2779    }
2780
2781    async fn on_datagram(&mut self, datagram: Bytes, source: SocketAddr) {
2782        if self.admission.admit(source.ip()).is_none() {
2783            self.meters.source_refusal(TransportKind::Udp);
2784            tracing::debug!(%source, "refused inbound UDP source before parsing");
2785            return;
2786        }
2787        // RFC 5389 §7.3's test, before the SIP parser sees it: a STUN response is not a SIP
2788        // message and would be dropped as malformed, taking the keep-alive with it.
2789        if crate::stun::is_stun(&datagram) {
2790            self.on_stun(&datagram, source);
2791            return;
2792        }
2793        // Captured before parsing, so a malformed datagram is captured malformed: the bytes a
2794        // peer actually sent are the whole point of the exercise (§13.2).
2795        self.observe(source, TransportKind::Udp, Direction::In, || {
2796            datagram.clone()
2797        });
2798
2799        match parse_datagram(datagram, &self.limits) {
2800            Ok(message) => {
2801                self.on_message(
2802                    message,
2803                    source,
2804                    TransportKind::Udp,
2805                    None,
2806                    #[cfg(feature = "quic")]
2807                    None,
2808                )
2809                .await;
2810            }
2811            Err(error) => {
2812                // One malformed packet must not disturb the socket. The alternative is a
2813                // trivial denial of service.
2814                //
2815                // Counted as a parse failure and deliberately not as a request or a response:
2816                // which it would have been is exactly what could not be determined (§12.2).
2817                self.meters.parse_failure(TransportKind::Udp);
2818                tracing::debug!(%error, %source, "dropping malformed datagram");
2819            }
2820        }
2821    }
2822
2823    fn wake_settled(&mut self) {
2824        if self.layer.len() == (0, 0) {
2825            for answered in self.settled.drain(..) {
2826                let _ = answered.send(());
2827            }
2828        }
2829    }
2830
2831    /// Send one keep-alive and remember who is waiting for the answer (RFC 5626 §4.4).
2832    async fn on_keepalive(
2833        &mut self,
2834        target: Target,
2835        answered: oneshot::Sender<Result<Option<SocketAddr>>>,
2836    ) {
2837        // Waiters whose caller has given up. Swept here rather than on a timer: the only thing
2838        // that creates them is this method, so this is the only place the map can grow.
2839        self.stun_waiters.retain(|_, waiter| !waiter.is_closed());
2840        self.pong_waiters.retain(|_, queue| {
2841            queue.retain(|waiter| !waiter.is_closed());
2842            !queue.is_empty()
2843        });
2844
2845        if target.transport == TransportKind::Udp {
2846            // §4.4.2: STUN for UDP flows. The transaction ID is what ties the response back, and
2847            // §6 of RFC 5389 wants it unguessable — a forged response naming a different mapped
2848            // address would have a UA declare a working flow dead.
2849            let id = crate::stun::new_transaction_id();
2850            let request = Bytes::from(crate::stun::binding_request(&id));
2851            match self.transmit_raw(request, &target).await {
2852                Ok(_) => {
2853                    self.stun_waiters.insert(id, answered);
2854                }
2855                Err(error) => {
2856                    // discard: the caller stopped waiting. A dropped receiver means nobody is listening
2857                    // for this answer, so nothing is lost and there is nothing worth counting.
2858                    let _ = answered.send(Err(error));
2859                }
2860            }
2861            return;
2862        }
2863
2864        // §4.4.1: CRLFCRLF is the ping, and the pong is a lone CRLF the peer's parser is
2865        // otherwise told to ignore.
2866        match self
2867            .transmit_raw(Bytes::from_static(b"\r\n\r\n"), &target)
2868            .await
2869        {
2870            Ok(Some(generation)) => {
2871                self.pong_waiters
2872                    .entry(generation)
2873                    .or_default()
2874                    .push_back(answered);
2875            }
2876            Ok(None) => {
2877                // A connection-oriented target always reports its pool generation.
2878                let _ = answered.send(Err(Error::ConnectionClosed));
2879            }
2880            Err(error) => {
2881                // discard: the caller stopped waiting. A dropped receiver means nobody is listening
2882                // for this answer, so nothing is lost and there is nothing worth counting.
2883                let _ = answered.send(Err(error));
2884            }
2885        }
2886    }
2887
2888    /// Answer the waiter a STUN reply belongs to (RFC 5626 §4.4.2).
2889    fn on_stun(&mut self, datagram: &[u8], source: SocketAddr) {
2890        let Some(reply) = crate::stun::parse_reply(datagram) else {
2891            // A Binding *Request*: something on the network is treating this socket as a STUN
2892            // server. Not ours to answer, and not an error worth raising.
2893            self.meters.discard_stun_unmatched();
2894            tracing::debug!(%source, "ignoring a STUN message that is not a reply");
2895            return;
2896        };
2897        let Some(waiter) = self.stun_waiters.remove(&reply.id()) else {
2898            // An unsolicited or late reply. Dropping it is right: matching it to a *different*
2899            // keep-alive would report one flow's liveness as another's.
2900            self.meters.discard_stun_unmatched();
2901            tracing::debug!(%source, "a STUN reply matched no keep-alive");
2902            return;
2903        };
2904        let answer = match reply {
2905            crate::stun::Reply::Bound { mapped, .. } => Ok(mapped),
2906            // §4.4.2: "If a STUN Binding Error Response is received ... the UA considers the flow
2907            // failed."
2908            crate::stun::Reply::Failed { .. } => Err(Error::KeepaliveRefused),
2909        };
2910        // discard: the caller stopped waiting. A dropped receiver means nobody is listening
2911        // for this answer, so nothing is lost and there is nothing worth counting.
2912        let _ = waiter.send(answer);
2913    }
2914
2915    #[allow(
2916        clippy::too_many_lines,
2917        reason = "one exhaustive transport-event dispatch keeps ordering and loss accounting visible"
2918    )]
2919    async fn on_net_event(&mut self, event: tcp::Event) {
2920        match event {
2921            tcp::Event::Message {
2922                message,
2923                source,
2924                transport,
2925                id,
2926                #[cfg(feature = "quic")]
2927                quic_reply,
2928            } => {
2929                // Re-serialised rather than raw: framing happened in the connection's task and the
2930                // stream bytes are not retained, so §13.2 records that a stream capture is not
2931                // byte-exact and does not pretend to be.
2932                // `to_bytes` re-serialises and allocates, so it is inside the closure: with no
2933                // capture configured it never runs.
2934                self.observe(source, transport, Direction::In, || message.to_bytes());
2935                self.on_message(
2936                    *message,
2937                    source,
2938                    transport,
2939                    Some(id),
2940                    #[cfg(feature = "quic")]
2941                    quic_reply,
2942                )
2943                .await;
2944            }
2945            tcp::Event::FramingFailed { key } => {
2946                if let Some((id, admission_generation)) = self.pool.observation_generation(&key) {
2947                    self.observations.emit(connection_event(
2948                        key.clone(),
2949                        id,
2950                        admission_generation,
2951                        ConnectionState::Failed,
2952                    ));
2953                }
2954                // The stream half of a parse failure, counted against the transport that carried it
2955                // (§12). `Closed` follows and fails the transactions bound to the connection; this
2956                // is the *loss* — everything in flight on a stream whose framing is gone — which
2957                // until now was a `tracing::debug!` and nothing else.
2958                self.meters.parse_failure(key.transport);
2959            }
2960            tcp::Event::Pong { key, id } => {
2961                // First waiter for this connection, or nobody — a peer is entitled to send a
2962                // CRLF we did not ask for, and RFC 3261 §7.5 says to ignore it.
2963                let generation = ConnectionGeneration { key, id };
2964                if let Some(queue) = self.pong_waiters.get_mut(&generation)
2965                    && let Some(waiter) = queue.pop_front()
2966                {
2967                    // discard: the caller stopped waiting. A dropped receiver means nobody is listening
2968                    // for this answer, so nothing is lost and there is nothing worth counting.
2969                    let _ = waiter.send(Ok(None));
2970                }
2971            }
2972            tcp::Event::ConnectFailed {
2973                key,
2974                id,
2975                kind,
2976                detail,
2977            } => {
2978                // Remove this generation now. The task wrapper's following `Closed` is then
2979                // stale and cannot count or fail the same transactions twice.
2980                if !self.pool.remove(&key, id) {
2981                    return;
2982                }
2983                let generation = ConnectionGeneration { key, id };
2984                self.fail_transactions_on(&generation, None, Some((kind, detail)))
2985                    .await;
2986            }
2987            #[cfg(feature = "tls")]
2988            tcp::Event::HandshakeFailed { key, id, detail } => {
2989                let admission_generation = self
2990                    .pool
2991                    .observation_generation(&key)
2992                    .filter(|(current, _)| *current == id)
2993                    .and_then(|(_, admission_generation)| admission_generation);
2994                self.observations.emit(connection_event(
2995                    key.clone(),
2996                    id,
2997                    admission_generation,
2998                    ConnectionState::Failed,
2999                ));
3000                // Authentication failure is terminal for this generation. Remove it now and fail
3001                // its transactions with the typed cause; the `Closed` emitted by the task wrapper
3002                // then becomes a stale close and has no second effect.
3003                if !self.pool.remove(&key, id) {
3004                    return;
3005                }
3006                let generation = ConnectionGeneration {
3007                    key: key.clone(),
3008                    id,
3009                };
3010                self.fail_transactions_on(&generation, Some(detail), None)
3011                    .await;
3012            }
3013            #[cfg(feature = "quic")]
3014            tcp::Event::QuicClosed { key, id, detail } => {
3015                if !self.pool.remove(&key, id) {
3016                    return;
3017                }
3018                let generation = ConnectionGeneration {
3019                    key: key.clone(),
3020                    id,
3021                };
3022                for (transaction, bound) in &self.transaction_generations {
3023                    if bound == &generation
3024                        && let Some(client) = self.clients.get(transaction)
3025                    {
3026                        let failure = Error::Quic(crate::quic::QuicError::ConnectionClosed {
3027                            peer: key.peer.to_string(),
3028                            detail: detail.clone(),
3029                        });
3030                        let _ = client.failures.try_send(failure);
3031                    }
3032                }
3033                self.fail_transactions_on(&generation, None, None).await;
3034            }
3035            tcp::Event::Closed { key, id } => {
3036                // A retiring generation can report after a replacement with the same key has
3037                // already joined. Every side effect below belongs to the generation that closed,
3038                // so a stale report must not fail the replacement's transactions or keep-alives.
3039                if !self.pool.remove(&key, id) {
3040                    return;
3041                }
3042                let generation = ConnectionGeneration {
3043                    key: key.clone(),
3044                    id,
3045                };
3046                // A flow whose connection has gone is a failed flow, and saying so now beats
3047                // making the caller wait out its own timeout for something already known.
3048                if let Some(queue) = self.pong_waiters.remove(&generation) {
3049                    for waiter in queue {
3050                        // discard: the caller stopped waiting. A dropped receiver means nobody is listening
3051                        // for this answer, so nothing is lost and there is nothing worth counting.
3052                        let _ = waiter.send(Err(Error::ConnectionClosed));
3053                    }
3054                }
3055                self.fail_transactions_on(&generation, None, None).await;
3056            }
3057        }
3058    }
3059
3060    /// Fail every transaction bound to a connection that has gone.
3061    ///
3062    /// The alternative is letting them time out, which means waiting up to 32 seconds to
3063    /// discover something already known — a bad experience and a resource leak.
3064    async fn fail_transactions_on(
3065        &mut self,
3066        closed: &ConnectionGeneration,
3067        tls_detail: Option<String>,
3068        connect_failure: Option<(std::io::ErrorKind, String)>,
3069    ) {
3070        let affected: Vec<TransactionKey> = self
3071            .transaction_generations
3072            .iter()
3073            .filter(|(_, generation)| *generation == closed)
3074            // A server transaction that knows where the peer listens is not failed by the loss
3075            // of the connection its request arrived on: RFC 3261 §18.2.2 has it open a new one
3076            // to the advertised port, and the response is still deliverable.
3077            .filter(|(key, _)| !self.reconnect.contains_key(*key))
3078            .map(|(key, _)| key.clone())
3079            .collect();
3080        for key in affected {
3081            if connect_failure.is_some() || tls_detail.is_some() {
3082                self.meters.discard_send_failure();
3083                if let Some(request) = self.layer.client_request(&key) {
3084                    self.meters.unsent(&request.method);
3085                }
3086            }
3087            if let Some(fallback) = self.tcp_fallbacks.get(&key).copied()
3088                && let Some(client) = self.clients.get(&key)
3089            {
3090                // Connection establishment is asynchronous: the pool accepts the generation,
3091                // then `Closed` reports that the selected TCP path could not become usable.
3092                // Preserve that this connection existed only because the UDP request was too
3093                // large, rather than exposing an unqualified close to the transaction user.
3094                let source = connect_failure
3095                    .as_ref()
3096                    .map_or(Error::ConnectionClosed, |failure| {
3097                        Error::Io(std::io::Error::new(failure.0, failure.1.clone()))
3098                    });
3099                let failure = fallback.unavailable(source);
3100                let _ = client.failures.try_send(failure);
3101            }
3102            #[cfg(feature = "tls")]
3103            if let Some(detail) = &tls_detail
3104                && let Some(client) = self.clients.get(&key)
3105            {
3106                #[cfg(feature = "quic")]
3107                let failure = if closed.key.transport == TransportKind::Quic {
3108                    Error::Quic(crate::quic::QuicError::handshake(
3109                        closed.key.peer.to_string(),
3110                        detail.clone(),
3111                    ))
3112                } else {
3113                    Error::Tls(crate::tls::TlsError::Handshake {
3114                        peer: closed.key.peer.to_string(),
3115                        detail: detail.clone(),
3116                    })
3117                };
3118                #[cfg(not(feature = "quic"))]
3119                let failure = Error::Tls(crate::tls::TlsError::Handshake {
3120                    peer: closed.key.peer.to_string(),
3121                    detail: detail.clone(),
3122                });
3123                let _ = client.failures.try_send(failure);
3124            }
3125            #[cfg(not(feature = "tls"))]
3126            let _ = &tls_detail;
3127            let outputs = self.layer.on_transport_error(&key);
3128            self.perform(&key, outputs, None).await;
3129        }
3130    }
3131
3132    async fn on_message(
3133        &mut self,
3134        message: Message,
3135        source: SocketAddr,
3136        transport: TransportKind,
3137        generation: Option<u64>,
3138        #[cfg(feature = "quic")] quic_reply: Option<crate::quic::Reply>,
3139    ) {
3140        let overload_response = match &message {
3141            Message::Response(response) => Some(response.clone()),
3142            Message::Request(_) => None,
3143        };
3144        // Datagram and stream messages both funnel here, the one inbound counter site (§12).
3145        self.meters
3146            .message_in(transport, matches!(message, Message::Response(_)));
3147        let message = apply_network_source(message, source);
3148        let observed_message = message.clone();
3149
3150        // A server transaction's responses go wherever its topmost Via says, which is why the
3151        // destination is computed now, from the request as amended above.
3152        // RFC 5923: on a connection-oriented transport the response goes back over the
3153        // connection the request arrived on, before §18.2.2 is consulted at all. Opening a new
3154        // connection to a NATed client's `Via` cannot work.
3155        let advertised = match &message {
3156            Message::Request(request) => request
3157                .headers
3158                .typed::<sipx_sip::headers::Via>()
3159                .and_then(std::result::Result::ok)
3160                .map(|via| response_destination(&via, source, transport)),
3161            Message::Response(_) => None,
3162        };
3163        let reply_to = match &message {
3164            Message::Request(_) if transport == TransportKind::Udp => advertised
3165                .clone()
3166                .unwrap_or_else(|| Target::new(source, transport)),
3167            _ => Target::new(source, transport),
3168        };
3169        match self.layer.receive(message, transport.reliability()) {
3170            Dispatch::Created { key, outputs } => {
3171                self.observe_inbound(
3172                    observed_message,
3173                    source,
3174                    transport,
3175                    TransactionClass::ServerCreated,
3176                );
3177                self.destinations.insert(key.clone(), reply_to);
3178                if let Some(id) = generation {
3179                    self.transaction_generations.insert(
3180                        key.clone(),
3181                        ConnectionGeneration {
3182                            key: ConnectionKey::new(source, transport),
3183                            id,
3184                        },
3185                    );
3186                }
3187                #[cfg(feature = "quic")]
3188                self.remember_quic_reply(&key, quic_reply);
3189                self.unanswered_since
3190                    .insert(key.clone(), tokio::time::Instant::now());
3191                // §18.2.2's fallback only arises on a transport that has a connection to lose.
3192                if transport.reliability().is_reliable()
3193                    && transport != TransportKind::Quic
3194                    && let Some(advertised) = advertised
3195                {
3196                    self.reconnect.insert(key.clone(), advertised);
3197                }
3198                self.perform(&key, outputs, Some((source, transport))).await;
3199            }
3200            Dispatch::Matched { key, outputs } => {
3201                self.observe_inbound(
3202                    observed_message,
3203                    source,
3204                    transport,
3205                    TransactionClass::Matched,
3206                );
3207                self.observe_overload_response(source, overload_response.as_ref());
3208                self.perform(&key, outputs, Some((source, transport))).await;
3209            }
3210            Dispatch::Unmatched(message) => {
3211                self.observe_inbound(
3212                    observed_message,
3213                    source,
3214                    transport,
3215                    TransactionClass::Unmatched,
3216                );
3217                self.on_unmatched(message, source, transport, generation);
3218            }
3219        }
3220    }
3221
3222    fn on_unmatched(
3223        &mut self,
3224        message: Box<Message>,
3225        source: SocketAddr,
3226        transport: TransportKind,
3227        connection_generation: Option<u64>,
3228    ) {
3229        tracing::debug!(%source, "message matched no transaction");
3230        // Counted before the question of whether anyone is watching: §16.7 makes an unmatched
3231        // response a forwarding element's business and a user agent's non-problem, and the rate
3232        // is worth knowing to either of them.
3233        if let Message::Response(response) = &*message {
3234            self.meters.unmatched_response();
3235            if let Some(sink) = &self.unmatched
3236                && sink
3237                    .try_send(Unmatched {
3238                        response: response.clone(),
3239                        source,
3240                        transport,
3241                    })
3242                    .is_err()
3243            {
3244                // A full watcher must not stop every endpoint timer while it catches up.
3245                self.meters.shed.unmatched.fetch_add(1, Ordering::Relaxed);
3246                tracing::warn!(
3247                    %source,
3248                    "unmatched-response watcher is not keeping up; dropped one"
3249                );
3250            }
3251            return;
3252        }
3253
3254        // An unmatched ACK belongs to the application; anything else is noise it can still
3255        // choose to look at.
3256        if let Message::Request(request) = *message {
3257            let Some(key) = TransactionKey::from_request(&request) else {
3258                return;
3259            };
3260            let method = request.method.clone();
3261            if self
3262                .incoming
3263                .try_send(Self::incoming_request(
3264                    key,
3265                    request,
3266                    source,
3267                    transport,
3268                    connection_generation,
3269                ))
3270                .is_err()
3271            {
3272                // There is no transaction here to answer with a 503, so count the loss and name it.
3273                self.meters.shed.unmatched.fetch_add(1, Ordering::Relaxed);
3274                tracing::warn!(
3275                    %source,
3276                    method = %method,
3277                    "application queue full; an unmatched request was dropped"
3278                );
3279            }
3280        }
3281    }
3282
3283    fn incoming_request(
3284        key: TransactionKey,
3285        request: Request,
3286        source: SocketAddr,
3287        transport: TransportKind,
3288        connection_generation: Option<u64>,
3289    ) -> Incoming {
3290        Incoming {
3291            key,
3292            request,
3293            source,
3294            transport,
3295            connection_generation,
3296        }
3297    }
3298
3299    /// Drop server transactions whose application owner stopped making progress.
3300    ///
3301    /// RFC 3261 §17.2 gives a server transaction in `Trying` no timer at all, because its model
3302    /// is that the transaction user always responds. Real applications do not: one that ignores
3303    /// a method it does not implement, or that panics in a handler, leaves the transaction
3304    /// there — and nothing ever collects it, so the store grows for as long as traffic arrives.
3305    /// A soak run found exactly this: 300 of them for 300 calls, still present two minutes on.
3306    ///
3307    /// The bound is generous on purpose and refreshes after every performed provisional response.
3308    /// A long-ringing call can therefore remain live while an application that wedges after one
3309    /// response is still collected. This is a backstop against silence, not an absolute deadline.
3310    fn abandon_unanswered(&mut self) {
3311        let now = tokio::time::Instant::now();
3312        let stale: Vec<TransactionKey> = self
3313            .unanswered_since
3314            .iter()
3315            .filter(|(_, at)| now.saturating_duration_since(**at) > self.unanswered_limit)
3316            .map(|(key, _)| key.clone())
3317            .collect();
3318
3319        for key in stale {
3320            self.unanswered_since.remove(&key);
3321
3322            // What is being abandoned, named. A warning that blames the application and then
3323            // says nothing about which request, which method or which peer leaves an operator
3324            // with N identical lines and nowhere to start.
3325            let described = self.layer.server_request(&key).map(|request| {
3326                (
3327                    request.method.clone(),
3328                    request
3329                        .headers
3330                        .value(&HeaderName::CallId)
3331                        .map(|id| String::from_utf8_lossy(&id).into_owned())
3332                        .unwrap_or_default(),
3333                )
3334            });
3335
3336            if !self.layer.abandon(&key) {
3337                continue;
3338            }
3339            if let Some((method, call_id)) = described {
3340                tracing::warn!(
3341                    ?method,
3342                    %call_id,
3343                    limit = ?self.unanswered_limit,
3344                    "abandoning a transaction the application never answered; that is an \
3345                     application bug rather than a network one"
3346                );
3347                self.meters.discard_unanswered();
3348            }
3349
3350            // `clients` is never touched, and `destinations` only when nothing else claims the
3351            // key. A `TransactionKey` carries no client/server role, so an endpoint that sends
3352            // a request to itself — a proxy, a B2BUA, a loopback test — can have a live *client*
3353            // transaction under the same key. Cleaning the shared maps then closes that
3354            // client's response stream and strands its retransmissions, which is a worse fault
3355            // than the leak being fixed.
3356            if self.clients.contains_key(&key) {
3357                continue;
3358            }
3359            forget_transaction_timers(&mut self.timers, &key);
3360            self.destinations.remove(&key);
3361            self.transaction_generations.remove(&key);
3362            #[cfg(feature = "quic")]
3363            self.quic_replies.remove(&key);
3364            // `reconnect` too. It is removed nowhere else but `Output::Terminated`, which an
3365            // abandoned transaction never reaches — so leaving it here would trade one
3366            // unbounded map for another.
3367            self.reconnect.remove(&key);
3368            self.tcp_fallbacks.remove(&key);
3369        }
3370    }
3371
3372    async fn on_timers(&mut self) {
3373        let due = self.timers.take_due(tokio::time::Instant::now());
3374        for (key, timer) in due {
3375            // Counted here, where the timer fires, rather than after the socket call. A
3376            // retransmission the socket then refuses is still a retransmission this endpoint
3377            // decided to send; counting it later would mean a peer that stopped hearing us
3378            // produced a *falling* count (§12.2).
3379            self.meters.on_timer(timer);
3380            let outputs = self.layer.on_timer(&key, timer);
3381            self.perform(&key, outputs, None).await;
3382        }
3383    }
3384
3385    async fn on_command(&mut self, command: Command) {
3386        match command {
3387            Command::Request {
3388                request,
3389                target,
3390                tcp_fallback,
3391                events,
3392                failures,
3393                reply,
3394            } => {
3395                let now =
3396                    tokio::time::Instant::now().saturating_duration_since(self.overload_epoch);
3397                let category = (self.overload_config.categorize)(&request);
3398                if !self.overload.admit(target.addr, category, now) {
3399                    self.meters.overload_rejection();
3400                    // discard: the caller dropped its wait; the rejection is already counted and
3401                    // no network request was lost.
3402                    let _ = reply.send(Err(Error::Overloaded { peer: target.addr }));
3403                    return;
3404                }
3405                let Some((key, outputs)) = self
3406                    .layer
3407                    .send_request(*request, target.transport.reliability())
3408                else {
3409                    // discard: the caller stopped waiting. A dropped receiver means nobody is listening
3410                    // for this answer, so nothing is lost and there is nothing worth counting.
3411                    let _ = reply.send(Err(Error::NoVia));
3412                    return;
3413                };
3414                self.destinations.insert(key.clone(), target);
3415                if let Some(fallback) = tcp_fallback {
3416                    self.tcp_fallbacks.insert(key.clone(), fallback);
3417                }
3418                self.clients
3419                    .insert(key.clone(), ClientSink { events, failures });
3420                // discard: the caller stopped waiting. A dropped receiver means nobody is listening
3421                // for this answer, so nothing is lost and there is nothing worth counting.
3422                self.perform(&key, outputs, None).await;
3423                let generation = self.transaction_generations.get(&key).map(|value| value.id);
3424                let _ = reply.send(Ok((key, generation)));
3425            }
3426            Command::Respond {
3427                key,
3428                response,
3429                sent,
3430            } => self.on_respond_command(key, response, sent).await,
3431            Command::Direct {
3432                request,
3433                target,
3434                tcp_fallback,
3435                sent,
3436            } => {
3437                self.on_direct_command(request, target, tcp_fallback, sent)
3438                    .await;
3439            }
3440            Command::WatchUnmatched(sink) => {
3441                // Replaces rather than fans out. Two watchers would each see some of the
3442                // responses and neither would see all of them, which is worse than one watcher
3443                // and much worse than an error.
3444                self.unmatched = Some(sink);
3445            }
3446            Command::Keepalive { target, answered } => {
3447                self.on_keepalive(target, answered).await;
3448            }
3449            Command::Outstanding(reply) => {
3450                let (clients, servers) = self.layer.len();
3451                // Every per-transaction map, not just the transactions. An entry that outlives
3452                // its transaction is exactly the leak a count of transactions alone would miss,
3453                // and a map left out here is a map a soak run is structurally blind to.
3454                // discard: the caller stopped waiting. A dropped receiver means nobody is listening
3455                // for this answer, so nothing is lost and there is nothing worth counting.
3456                let _ = reply.send(
3457                    clients
3458                        + servers
3459                        + self.destinations.len()
3460                        + self.transaction_generations.len()
3461                        + self.tcp_fallbacks.len()
3462                        + {
3463                            #[cfg(feature = "quic")]
3464                            {
3465                                self.quic_replies.len()
3466                            }
3467                            #[cfg(not(feature = "quic"))]
3468                            {
3469                                0
3470                            }
3471                        }
3472                        + self.reconnect.len()
3473                        + self.unanswered_since.len(),
3474                );
3475            }
3476            Command::Settled(reply) => {
3477                self.settled.push(reply);
3478            }
3479            Command::Shutdown => {}
3480        }
3481    }
3482
3483    async fn on_direct_command(
3484        &mut self,
3485        request: Box<Request>,
3486        target: Target,
3487        tcp_fallback: Option<TcpFallback>,
3488        sent: oneshot::Sender<Result<()>>,
3489    ) {
3490        let now = tokio::time::Instant::now().saturating_duration_since(self.overload_epoch);
3491        let category = (self.overload_config.categorize)(&request);
3492        if !self.overload.admit(target.addr, category, now) {
3493            self.meters.overload_rejection();
3494            // discard: the caller dropped its wait; the rejection is already counted and no
3495            // network request was lost.
3496            let _ = sent.send(Err(Error::Overloaded { peer: target.addr }));
3497            return;
3498        }
3499        let method = request.method.clone();
3500        let message = Message::Request(*request);
3501        self.observe_message(
3502            message.clone(),
3503            target.addr,
3504            target.transport,
3505            MessageDirection::Outbound,
3506            TransactionClass::Direct,
3507        );
3508        let bytes = message.to_bytes();
3509        self.observe_out(&bytes, &target, false);
3510        let result = self
3511            .transmit(bytes, target, false, None)
3512            .await
3513            .map(|_| ())
3514            .map_err(|error| match tcp_fallback {
3515                Some(fallback) => fallback.unavailable(error),
3516                None => error,
3517            });
3518        if result.is_err() {
3519            // The same fact as the transaction path's site above, on the one request that has no
3520            // transaction (§12.3). Deliberately not also `discard_send_failure`: that field is the
3521            // transaction path's aggregate, and an ACK for a 2xx never had a transaction to fail.
3522            self.meters.unsent(&method);
3523        }
3524        // discard: the caller stopped waiting. A dropped receiver means nobody is listening for
3525        // this answer, so nothing is lost and there is nothing worth counting.
3526        let _ = sent.send(result);
3527    }
3528
3529    async fn on_respond_command(
3530        &mut self,
3531        key: TransactionKey,
3532        response: Box<Response>,
3533        sent: oneshot::Sender<Result<()>>,
3534    ) {
3535        if self.layer.server_request(&key).is_none() {
3536            // No transaction to answer on. Reporting success here would tell an application its
3537            // 200 OK went out while the caller heard nothing.
3538            // discard: the caller stopped waiting, so nothing is lost or worth counting.
3539            let _ = sent.send(Err(Error::NoTransaction));
3540            return;
3541        }
3542        let provisional = response.status.is_provisional();
3543        let outputs = self.layer.send_response(&key, *response);
3544        let sent_response = outputs.iter().any(|output| {
3545            matches!(
3546                output,
3547                Output::Send(message) if matches!(message.as_ref(), Message::Response(_))
3548            )
3549        });
3550        // The success reported here is produced by the send: consuming `Performed` is the only
3551        // way to obtain the `Ok`, so reversing these statements does not compile (`X-36`).
3552        let performed = self.perform(&key, outputs, None).await;
3553        if sent_response && performed.sent_message() {
3554            if provisional && self.layer.server_request(&key).is_some() {
3555                if let Some(since) = self.unanswered_since.get_mut(&key) {
3556                    *since = tokio::time::Instant::now();
3557                }
3558            } else if !provisional {
3559                self.unanswered_since.remove(&key);
3560            }
3561        }
3562        // discard: the caller stopped waiting, so nothing is lost or worth counting.
3563        let _ = sent.send(performed.into_result());
3564    }
3565
3566    /// Perform a transaction's outputs, in order.
3567    async fn perform(
3568        &mut self,
3569        key: &TransactionKey,
3570        outputs: Vec<Output>,
3571        origin: Option<(SocketAddr, TransportKind)>,
3572    ) -> Performed {
3573        let mut sent_message = false;
3574        for output in outputs {
3575            match output {
3576                Output::Send(message) => {
3577                    let mut message = *message;
3578                    if let Message::Response(response) = &mut message
3579                        && let Some(request) = self.layer.server_request(key).cloned()
3580                    {
3581                        self.decorate_overload_response(response, &request);
3582                    }
3583                    let target =
3584                        self.destinations.get(key).cloned().or_else(|| {
3585                            origin.map(|(addr, transport)| Target::new(addr, transport))
3586                        });
3587                    let Some(target) = target else {
3588                        self.meters.discard_no_destination();
3589                        tracing::warn!("no destination for a message the transaction wants sent");
3590                        continue;
3591                    };
3592                    // Kept before `to_bytes` consumes the message: a failed transmit is counted by
3593                    // method (§12.3), and after this line the method is no longer reachable.
3594                    let method = match &message {
3595                        Message::Request(request) => Some(request.method.clone()),
3596                        Message::Response(_) => None,
3597                    };
3598                    let is_response = method.is_none();
3599                    self.observe_message(
3600                        message.clone(),
3601                        target.addr,
3602                        target.transport,
3603                        MessageDirection::Outbound,
3604                        if is_response {
3605                            TransactionClass::Matched
3606                        } else {
3607                            TransactionClass::ClientCreated
3608                        },
3609                    );
3610                    let bytes = message.to_bytes();
3611                    let addr = target.addr;
3612                    self.observe_out(&bytes, &target, is_response);
3613                    let fallback = self.reconnect.get(key).cloned();
3614                    #[cfg(feature = "quic")]
3615                    let transmitted = if is_response && target.transport == TransportKind::Quic {
3616                        match self.quic_replies.get(key).cloned() {
3617                            Some(reply) => reply
3618                                .send(bytes)
3619                                .await
3620                                .map(|()| self.transaction_generations.get(key).cloned())
3621                                .map_err(|_| Error::ConnectionClosed),
3622                            None => Err(Error::ConnectionClosed),
3623                        }
3624                    } else {
3625                        self.transmit(bytes, target, is_response, fallback).await
3626                    };
3627                    #[cfg(not(feature = "quic"))]
3628                    let transmitted = self.transmit(bytes, target, is_response, fallback).await;
3629                    match transmitted {
3630                        Ok(Some(generation)) => {
3631                            self.transaction_generations.insert(key.clone(), generation);
3632                            sent_message = true;
3633                        }
3634                        Ok(None) => {
3635                            self.transaction_generations.remove(key);
3636                            sent_message = true;
3637                        }
3638                        Err(error) => {
3639                            let error = match self.tcp_fallbacks.get(key).copied() {
3640                                Some(fallback) => fallback.unavailable(error),
3641                                None => error,
3642                            };
3643                            self.meters.discard_send_failure();
3644                            // And by method, when it was a request (§12.3). This is where the
3645                            // wire is actually missed. Counting before this hand-off would miss
3646                            // every refused connection, unreachable peer and over-MTU datagram —
3647                            // which is the whole of "why did that call linger".
3648                            if let Some(method) = &method {
3649                                self.meters.unsent(method);
3650                            }
3651                            tracing::warn!(%error, %addr, "send failed");
3652                            if let Some(client) = self.clients.get(key) {
3653                                // One transport failure terminates this transaction, so one
3654                                // bounded slot is sufficient. A full/closed slot means the caller
3655                                // has already stopped listening.
3656                                let _ = client.failures.try_send(error);
3657                            }
3658                            let outputs = self.layer.on_transport_error(key);
3659                            let remainder = Box::pin(self.perform(key, outputs, origin)).await;
3660                            return Performed {
3661                                sent_message: sent_message || remainder.sent_message,
3662                            };
3663                        }
3664                    }
3665                }
3666                // The clock is read *here*, by the driver, and handed to the queue. That is what
3667                // lets any other driver — one on virtual time, say — use the same queue.
3668                Output::SetTimer { timer, after } => {
3669                    self.timers
3670                        .set((key.clone(), timer), tokio::time::Instant::now(), after);
3671                }
3672                Output::ClearTimer(timer) => self.timers.clear(&(key.clone(), timer)),
3673                Output::ToTu(event) => self.deliver(key, *event, origin).await,
3674                Output::Terminated(_) => self.finish_transaction(key),
3675            }
3676        }
3677        Performed { sent_message }
3678    }
3679
3680    fn finish_transaction(&mut self, key: &TransactionKey) {
3681        forget_transaction_timers(&mut self.timers, key);
3682        self.destinations.remove(key);
3683        self.transaction_generations.remove(key);
3684        #[cfg(feature = "quic")]
3685        self.quic_replies.remove(key);
3686        self.unanswered_since.remove(key);
3687        self.reconnect.remove(key);
3688        self.tcp_fallbacks.remove(key);
3689        // Dropping the sender closes the application's response stream, which is how it learns
3690        // the transaction is over.
3691        self.clients.remove(key);
3692    }
3693
3694    /// Hand one observed message to the capture, if one is running (§13).
3695    ///
3696    /// Called from the driver loop, which is what makes the sequence number the capture stamps
3697    /// meaningful: the *order* is decided here, at the point the bytes crossed the boundary, and the
3698    /// write happens elsewhere. Costs one `Option` check when no capture is configured.
3699    fn observe(
3700        &mut self,
3701        peer: SocketAddr,
3702        transport: TransportKind,
3703        direction: Direction,
3704        bytes: impl FnOnce() -> Bytes,
3705    ) {
3706        // `bytes` is a closure so that an endpoint with no capture pays nothing: see
3707        // `Capture::observe_if_capturing`, which is where the guard and its test live.
3708        Capture::observe_if_capturing(
3709            self.capture.as_mut(),
3710            &self.meters,
3711            self.local_addr,
3712            peer,
3713            transport,
3714            direction,
3715            bytes,
3716        );
3717    }
3718
3719    fn observe_message(
3720        &self,
3721        message: Message,
3722        peer: SocketAddr,
3723        transport: TransportKind,
3724        direction: MessageDirection,
3725        transaction: TransactionClass,
3726    ) {
3727        self.observations
3728            .emit(EndpointObservation::Message(Box::new(MessageObservation {
3729                message,
3730                local: self.local_addr,
3731                peer,
3732                transport,
3733                direction,
3734                transaction,
3735            })));
3736    }
3737
3738    fn observe_inbound(
3739        &self,
3740        message: Message,
3741        peer: SocketAddr,
3742        transport: TransportKind,
3743        transaction: TransactionClass,
3744    ) {
3745        self.observe_message(
3746            message,
3747            peer,
3748            transport,
3749            MessageDirection::Inbound,
3750            transaction,
3751        );
3752    }
3753
3754    /// Count and capture a SIP message on its way out.
3755    ///
3756    /// The one site outbound messages are counted, so §12.2's "exactly one increment site per
3757    /// counter" holds. Deliberately *not* inside [`Driver::transmit`]: that also carries keep-alives,
3758    /// which are not SIP messages and must not be counted as requests.
3759    fn observe_out(&mut self, bytes: &Bytes, target: &Target, is_response: bool) {
3760        self.meters.message_out(target.transport, is_response);
3761        // Already serialised — the send needs these bytes either way — so the clone is a refcount.
3762        self.observe(target.addr, target.transport, Direction::Out, || {
3763            bytes.clone()
3764        });
3765    }
3766
3767    /// Put bytes on the wire that are not a SIP message.
3768    ///
3769    /// A keep-alive is not a request and must not be treated as one: no MTU refusal (a STUN
3770    /// header is 20 bytes), no transaction, no `Via`. It reuses [`Driver::transmit`] so a flow's
3771    /// ping travels over the *same connection* its requests do — which is the whole of RFC 5626
3772    /// §4.4, since a ping on a second connection tests a flow nobody is using.
3773    async fn transmit_raw(
3774        &mut self,
3775        bytes: Bytes,
3776        target: &Target,
3777    ) -> Result<Option<ConnectionGeneration>> {
3778        self.transmit(bytes, target.clone(), true, None).await
3779    }
3780
3781    #[cfg(feature = "quic")]
3782    fn remember_quic_reply(&mut self, key: &TransactionKey, reply: Option<crate::quic::Reply>) {
3783        if let Some(reply) = reply {
3784            self.quic_replies.insert(key.clone(), reply);
3785        }
3786    }
3787
3788    #[cfg(feature = "quic")]
3789    async fn transmit_quic(
3790        &mut self,
3791        bytes: Bytes,
3792        target: &Target,
3793        is_response: bool,
3794    ) -> Result<Option<ConnectionGeneration>> {
3795        if is_response {
3796            return Err(Error::ConnectionClosed);
3797        }
3798        let Some(client) = self.quic_client.clone() else {
3799            return Err(Error::UnsupportedTransport(
3800                "QUIC (no client configuration, so no outbound connection can be verified)",
3801            ));
3802        };
3803        let Some(endpoint) = self.quic_endpoint.clone() else {
3804            return Err(Error::UnsupportedTransport("QUIC (no local endpoint)"));
3805        };
3806        let key = target.connection();
3807        let name = target
3808            .verify_as
3809            .as_deref()
3810            .map_or_else(|| target.addr.ip().to_string(), str::to_owned);
3811        let id = self
3812            .pool
3813            .send_quic_generation(&key, &name, &client, &endpoint, bytes)
3814            .await?;
3815        Ok(Some(ConnectionGeneration { key, id }))
3816    }
3817
3818    /// Put bytes on the wire, opening a connection if the transport needs one.
3819    ///
3820    /// `is_response` decides whether an inbound connection may be used. A response goes back
3821    /// over the connection its request arrived on — RFC 5923, and the only thing that works
3822    /// when the peer is behind a NAT. An outbound *request* is different: reusing an inbound
3823    /// connection for one is how a peer that connected to you gets your traffic routed
3824    /// through it, so that is off unless configured.
3825    async fn transmit(
3826        &mut self,
3827        bytes: Bytes,
3828        target: Target,
3829        is_response: bool,
3830        fallback: Option<Target>,
3831    ) -> Result<Option<ConnectionGeneration>> {
3832        match target.transport {
3833            TransportKind::Udp => {
3834                // RFC 3261 §18.1.1. Public request entry points switch to TCP before creating
3835                // the transaction. This refusal remains as the final invariant: an internal path
3836                // must not emit an oversized datagram if it bypasses that selection.
3837                //
3838                // Requests only. §18.1.1 offers a sender the alternative of switching to a
3839                // congestion-controlled transport; §18.2.2 offers a *responder* nothing — the
3840                // response goes back per the topmost `Via`, over the transport the request
3841                // came in on. Refusing it here would answer a 200 with silence, leaving the
3842                // caller to time out while the callee believes the call is up.
3843                if !is_response && bytes.len() > self.unreliable_request_limit {
3844                    return Err(Error::TooLarge {
3845                        size: bytes.len(),
3846                        limit: self.unreliable_request_limit,
3847                    });
3848                }
3849                let Some(socket) = &self.socket else {
3850                    return Err(Error::TransportNotConfigured { transport: "UDP" });
3851                };
3852                socket.send_to(&bytes, target.addr).await?;
3853                Ok(None)
3854            }
3855            TransportKind::Tcp => {
3856                let key = target.connection();
3857                if is_response
3858                    && let Some(id) = self
3859                        .pool
3860                        .send_on_existing_generation(&key, bytes.clone())
3861                        .await
3862                {
3863                    return Ok(Some(ConnectionGeneration { key, id }));
3864                }
3865                // The connection is gone. RFC 3261 §18.2.2 sends the response to the address
3866                // the request came from at the port the sender said it listens on — not back
3867                // at the ephemeral port it dialled out from, where nothing is accepting.
3868                let key = match (is_response, &fallback) {
3869                    (true, Some(advertised)) => advertised.connection(),
3870                    _ => key,
3871                };
3872                let id = self.pool.send_generation(&key, bytes).await?;
3873                Ok(Some(ConnectionGeneration { key, id }))
3874            }
3875            #[cfg(feature = "tls")]
3876            TransportKind::Tls => {
3877                // Answering on the connection the request arrived over comes first, and needs
3878                // no client configuration at all — a pure TLS server has no reason to hold
3879                // one, and requiring it would leave such a server unable to reply.
3880                let key = target.connection();
3881                if is_response
3882                    && let Some(id) = self
3883                        .pool
3884                        .send_on_existing_generation(&key, bytes.clone())
3885                        .await
3886                {
3887                    return Ok(Some(ConnectionGeneration { key, id }));
3888                }
3889                // Only opening a *new* connection needs somewhere to verify against.
3890                let Some(client) = self.tls_client.clone() else {
3891                    return Err(Error::UnsupportedTransport(
3892                        "TLS (no client configuration, so no outbound connection can be verified)",
3893                    ));
3894                };
3895                // The name a certificate is checked against is the host from the URI, carried
3896                // on the target rather than derived from the address it resolved to.
3897                let name = target
3898                    .verify_as
3899                    .as_deref()
3900                    .map_or_else(|| target.addr.ip().to_string(), str::to_owned);
3901                let id = self
3902                    .pool
3903                    .send_tls_generation(&key, &name, &client, bytes)
3904                    .await?;
3905                Ok(Some(ConnectionGeneration { key, id }))
3906            }
3907            #[cfg(feature = "ws")]
3908            TransportKind::Ws | TransportKind::Wss => {
3909                let key = target.connection();
3910                // Unconditionally, and not only for responses. A WebSocket peer has no
3911                // listening port (RFC 7118 §5.2), so an existing connection is not merely the
3912                // preferred way to reach it — it is the only one. The pool's "do not carry
3913                // outbound requests over an inbound connection" rule protects against traffic
3914                // being routed through a peer that connected to us; here the peer *is* the
3915                // destination, so there is nothing to route through and nothing to protect.
3916                if let Some(id) = self
3917                    .pool
3918                    .send_on_existing_generation(&key, bytes.clone())
3919                    .await
3920                {
3921                    return Ok(Some(ConnectionGeneration { key, id }));
3922                }
3923                let authority = target.verify_as.as_deref().map_or_else(
3924                    || target.addr.to_string(),
3925                    |name| format!("{name}:{}", target.addr.port()),
3926                );
3927                let id = self
3928                    .pool
3929                    .send_ws_generation(
3930                        &key,
3931                        &authority,
3932                        self.ws_keepalive,
3933                        #[cfg(feature = "wss")]
3934                        self.tls_client.as_ref(),
3935                        bytes,
3936                    )
3937                    .await?;
3938                Ok(Some(ConnectionGeneration { key, id }))
3939            }
3940            #[cfg(feature = "quic")]
3941            TransportKind::Quic => self.transmit_quic(bytes, &target, is_response).await,
3942            #[allow(unreachable_patterns)]
3943            other => Err(Error::UnsupportedTransport(other.as_str())),
3944        }
3945    }
3946
3947    async fn deliver(
3948        &mut self,
3949        key: &TransactionKey,
3950        event: TuEvent,
3951        origin: Option<(SocketAddr, TransportKind)>,
3952    ) {
3953        // A client transaction's events go to whoever sent the request.
3954        if let Some(client) = self.clients.get(key) {
3955            // The receiver is gone: the application dropped its `Responses` before the transaction
3956            // finished. Legitimate — a caller that stopped caring is allowed to — but it means an
3957            // outcome went nowhere, and nothing retransmits an event, so it is counted rather than
3958            // discarded in silence (§12.1).
3959            if client.events.send(event).await.is_err() {
3960                self.meters.discard_transaction_event();
3961                tracing::debug!(
3962                    "a transaction event had no receiver; the caller stopped listening"
3963                );
3964            }
3965            return;
3966        }
3967
3968        let (source, transport) = origin.unwrap_or((self.local_addr(), TransportKind::Udp));
3969        match event {
3970            TuEvent::Request(request) | TuEvent::Ack(request) => {
3971                let is_ack = request.method == sipx_sip::Method::Ack;
3972                if self
3973                    .incoming
3974                    .try_send(Incoming {
3975                        key: key.clone(),
3976                        request: *request,
3977                        source,
3978                        transport,
3979                        connection_generation: self
3980                            .transaction_generations
3981                            .get(key)
3982                            .map(|value| value.id),
3983                    })
3984                    .is_err()
3985                {
3986                    // The application is not keeping up. Blocking the loop would stop timers,
3987                    // which turns a slow application into a stack that drops established
3988                    // calls; dropping the event silently loses a request.
3989                    if is_ack {
3990                        // An ACK cannot be refused. SIP has no response to an ACK, and an ACK
3991                        // for a 2xx is a transaction of its own (RFC 3261 §17.1.1.3) with
3992                        // nothing to answer — so there is no 503 to send, nothing will
3993                        // retransmit it once Timer H expires, and both ends are left in a
3994                        // dialog no timer reaps unless RFC 4028 session timers happen to be
3995                        // running. This is the one that leaks calls, which is why it is
3996                        // counted apart and logged at error rather than warn.
3997                        self.meters.shed.acks.fetch_add(1, Ordering::Relaxed);
3998                        tracing::error!(
3999                            %source,
4000                            "application queue full; an ACK was dropped and cannot be refused — \
4001                             the dialog it would have completed will not be reaped"
4002                        );
4003                    } else {
4004                        self.meters.shed.requests.fetch_add(1, Ordering::Relaxed);
4005                        tracing::warn!(%source, "application queue full; refusing the transaction");
4006                        self.refuse(key).await;
4007                    }
4008                }
4009            }
4010            _ => {}
4011        }
4012    }
4013
4014    async fn refuse(&mut self, key: &TransactionKey) {
4015        let Some(status) = sipx_sip::StatusCode::new(503) else {
4016            return;
4017        };
4018        let Some(request) = self.layer.server_request(key).cloned() else {
4019            return;
4020        };
4021        let Ok(builder) =
4022            sipx_sip::build::ResponseBuilder::to_request(&request, status, "Service Unavailable")
4023        else {
4024            return;
4025        };
4026        let Ok(builder) = builder.header(HeaderName::RetryAfter, Bytes::from_static(b"5")) else {
4027            return;
4028        };
4029        self.server_overloaded_until =
4030            Some(tokio::time::Instant::now() + self.overload_config.validity);
4031        let outputs = self.layer.send_response(key, builder.build());
4032        Box::pin(self.perform(key, outputs, None)).await;
4033    }
4034
4035    /// Accept feedback only after the transaction layer has authenticated it by matching a live
4036    /// client transaction. An unmatched response is application data, not controller input.
4037    fn observe_overload_response(&mut self, source: SocketAddr, response: Option<&Response>) {
4038        if !self.overload_config.advertise {
4039            return;
4040        }
4041        if let Some(response) = response {
4042            let now = tokio::time::Instant::now().saturating_duration_since(self.overload_epoch);
4043            self.overload.observe(source, response, now);
4044        }
4045    }
4046
4047    /// Decorate every server response with the queue detector's current state.
4048    fn decorate_overload_response(&mut self, response: &mut Response, request: &Request) {
4049        let now = tokio::time::Instant::now();
4050        let active_for = self
4051            .server_overloaded_until
4052            .and_then(|until| until.checked_duration_since(now));
4053        let (feedback, validity) = match active_for {
4054            Some(remaining) if !remaining.is_zero() => {
4055                let millis = u64::try_from(remaining.as_millis().max(1)).unwrap_or(u64::MAX);
4056                (
4057                    self.overload_config.feedback,
4058                    std::time::Duration::from_millis(millis),
4059                )
4060            }
4061            _ => {
4062                self.server_overloaded_until = None;
4063                let stopped = match self.overload_config.feedback {
4064                    crate::OverloadFeedback::Loss(_) => crate::OverloadFeedback::Loss(0),
4065                    crate::OverloadFeedback::Rate(_) => crate::OverloadFeedback::Rate(0),
4066                };
4067                (stopped, std::time::Duration::ZERO)
4068            }
4069        };
4070        self.overload_sequence = if self.overload_sequence >= 999_999_999_999 {
4071            1
4072        } else {
4073            self.overload_sequence.saturating_add(1)
4074        };
4075        if let Some(sequence) =
4076            sipx_sip::headers::OverloadSequence::from_integer(self.overload_sequence)
4077        {
4078            crate::overload::add_feedback(response, request, feedback, validity, sequence);
4079        }
4080    }
4081
4082    fn local_addr(&self) -> SocketAddr {
4083        self.local_addr
4084    }
4085}
4086
4087async fn receive_udp_until(
4088    socket: Arc<UdpSocket>,
4089    datagrams: mpsc::Sender<(Bytes, SocketAddr)>,
4090    cancel: CancellationToken,
4091) {
4092    let mut buf = vec![0u8; 65_536];
4093    loop {
4094        let received = tokio::select! {
4095            biased;
4096            () = cancel.cancelled() => return,
4097            received = socket.recv_from(&mut buf) => received,
4098        };
4099        let (len, source) = match received {
4100            Ok(received) => received,
4101            Err(error) => {
4102                tracing::warn!(%error, "UDP receive task stopped");
4103                return;
4104            }
4105        };
4106        let mut ready = Vec::with_capacity(UDP_RECEIVE_BATCH);
4107        ready.push((
4108            Bytes::copy_from_slice(buf.get(..len).unwrap_or(&[])),
4109            source,
4110        ));
4111        while ready.len() < UDP_RECEIVE_BATCH {
4112            match socket.try_recv_from(&mut buf) {
4113                Ok((len, source)) => {
4114                    ready.push((
4115                        Bytes::copy_from_slice(buf.get(..len).unwrap_or(&[])),
4116                        source,
4117                    ));
4118                }
4119                Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => break,
4120                Err(error) => {
4121                    tracing::warn!(%error, "UDP receive task stopped");
4122                    return;
4123                }
4124            }
4125        }
4126        for datagram in ready {
4127            tokio::select! {
4128                biased;
4129                () = cancel.cancelled() => return,
4130                sent = datagrams.send(datagram) => {
4131                    if sent.is_err() {
4132                        return;
4133                    }
4134                }
4135            }
4136        }
4137    }
4138}
4139
4140async fn sleep_until(deadline: Option<tokio::time::Instant>) {
4141    match deadline {
4142        Some(deadline) => tokio::time::sleep_until(deadline).await,
4143        // Never resolves; the `if` guard in `select!` keeps this branch disabled anyway.
4144        None => std::future::pending().await,
4145    }
4146}
4147
4148#[cfg(test)]
4149#[allow(
4150    clippy::unwrap_used,
4151    clippy::expect_used,
4152    clippy::panic,
4153    clippy::indexing_slicing
4154)]
4155mod tests {
4156    use std::sync::Arc;
4157    use std::time::Duration;
4158
4159    use bytes::Bytes;
4160    use sipx_sip::build::{RequestBuilder, ResponseBuilder};
4161    use sipx_sip::{HeaderName, Host, HostName, Method, StatusCode, Uri};
4162    use tokio::net::TcpStream;
4163    #[cfg(any(feature = "tls", feature = "ws"))]
4164    use tokio::sync::Semaphore;
4165    use tokio::sync::mpsc;
4166
4167    #[cfg(any(feature = "tls", feature = "ws"))]
4168    use super::{Adopt, HandshakeObservation, HandshakeRuntime};
4169    use super::{
4170        Background, Driver, Message, ShutdownState, Target, TransportKind, unreliable_request_limit,
4171    };
4172
4173    const IDENTIFIER_SAMPLE_SIZE: u64 = 4096;
4174
4175    #[test]
4176    fn unreliable_request_limit_is_derived_once_from_path_mtu() {
4177        assert_eq!(unreliable_request_limit(None), 1_300);
4178        assert_eq!(unreliable_request_limit(Some(1_500)), 1_300);
4179        assert_eq!(unreliable_request_limit(Some(1_200)), 1_000);
4180        assert_eq!(unreliable_request_limit(Some(100)), 0);
4181    }
4182
4183    fn in_process_request(call_id: &'static [u8]) -> sipx_sip::Request {
4184        let uri = Uri::sip(Host::Name(
4185            HostName::new("callee.example").expect("valid host"),
4186        ));
4187        RequestBuilder::new(Method::Options, uri)
4188            .header(HeaderName::To, Bytes::from_static(b"<sip:callee.example>"))
4189            .expect("valid To")
4190            .header(
4191                HeaderName::From,
4192                Bytes::from_static(b"<sip:caller.example>;tag=caller"),
4193            )
4194            .expect("valid From")
4195            .header(HeaderName::CallId, Bytes::from_static(call_id))
4196            .expect("valid Call-ID")
4197            .cseq(1, &Method::Options)
4198            .expect("valid CSeq")
4199            .max_forwards(70)
4200            .build()
4201    }
4202
4203    #[tokio::test]
4204    async fn in_process_routes_are_bounded_and_closed_consumers_release_capacity() {
4205        let ((originating, _), (answering, mut incoming)) =
4206            super::in_process_pair(1).expect("runtime is entered");
4207        let target = Target::new(answering.local_addr(), TransportKind::Udp);
4208        let first = originating
4209            .send(in_process_request(b"first@example"), target.clone())
4210            .await
4211            .expect("first route is admitted");
4212        let _ = incoming.recv().await.expect("first request arrives");
4213
4214        let refused = originating
4215            .send(in_process_request(b"second@example"), target.clone())
4216            .await
4217            .expect_err("the one-slot route table is full");
4218        assert!(matches!(refused, crate::Error::Overloaded { .. }));
4219
4220        drop(first);
4221        originating
4222            .send(in_process_request(b"third@example"), target)
4223            .await
4224            .expect("a closed response stream releases its route");
4225    }
4226
4227    #[tokio::test]
4228    async fn a_final_in_process_response_releases_its_route() {
4229        let ((originating, _), (answering, mut incoming)) =
4230            super::in_process_pair(1).expect("runtime is entered");
4231        let target = Target::new(answering.local_addr(), TransportKind::Udp);
4232        let mut responses = originating
4233            .send(in_process_request(b"final@example"), target)
4234            .await
4235            .expect("route is admitted");
4236        let invitation = incoming.recv().await.expect("request arrives");
4237        assert_eq!(answering.outstanding().await.expect("route count"), 1);
4238
4239        let status = StatusCode::new(200).expect("valid final status");
4240        let response = ResponseBuilder::to_request(&invitation.request, status, "OK")
4241            .expect("response headers")
4242            .build();
4243        answering
4244            .respond(&invitation.key, response)
4245            .await
4246            .expect("final response is delivered");
4247        assert!(responses.next().await.is_some());
4248        assert_eq!(answering.outstanding().await.expect("route count"), 0);
4249    }
4250
4251    fn bit_counts(values: impl IntoIterator<Item = u64>) -> [usize; 64] {
4252        let mut counts = [0; 64];
4253        for value in values {
4254            for (bit, count) in counts.iter_mut().enumerate() {
4255                *count += usize::from(value & (1_u64 << bit) != 0);
4256            }
4257        }
4258        counts
4259    }
4260
4261    fn assert_full_width(counts: &[usize; 64], subject: &str) {
4262        for (bit, ones) in counts.iter().copied().enumerate() {
4263            assert!(
4264                (1664..=2432).contains(&ones), // 128 positions * 2 * exp(-2 * 384^2 / 4096) < 1.4e-29.
4265                "{subject} bit {bit} had {ones} ones in {IDENTIFIER_SAMPLE_SIZE} samples"
4266            );
4267        }
4268    }
4269
4270    #[tokio::test]
4271    async fn stream_generation_is_reported_on_both_transaction_boundaries() {
4272        let mut server_config = crate::Config::new("127.0.0.1:0".parse().expect("address"));
4273        server_config.cleartext = crate::CleartextTransports::UdpAndTcp;
4274        let (server, mut incoming) = super::bind(server_config).await.expect("server");
4275        let mut client_config = crate::Config::new("127.0.0.1:0".parse().expect("address"));
4276        client_config.cleartext = crate::CleartextTransports::UdpAndTcp;
4277        let (client, _) = super::bind(client_config).await.expect("client");
4278        let uri = Uri::parse(Bytes::from(format!("sip:{}", server.local_addr()))).expect("URI");
4279        let request = RequestBuilder::new(Method::Options, uri)
4280            .header(HeaderName::To, "<sip:server@example.test>")
4281            .expect("To")
4282            .header(HeaderName::From, "<sip:client@example.test>;tag=a")
4283            .expect("From")
4284            .header(HeaderName::CallId, "generation@example.test")
4285            .expect("Call-ID")
4286            .cseq(1, &Method::Options)
4287            .expect("CSeq")
4288            .max_forwards(70)
4289            .build();
4290        let responses = client
4291            .send(
4292                request,
4293                Target::new(server.local_addr(), TransportKind::Tcp),
4294            )
4295            .await
4296            .expect("transaction starts");
4297        assert!(responses.connection_generation().is_some());
4298        let received = tokio::time::timeout(Duration::from_secs(2), incoming.recv())
4299            .await
4300            .expect("request is bounded")
4301            .expect("server stays open");
4302        assert!(received.connection_generation.is_some());
4303        client.shutdown().await;
4304        server.shutdown().await;
4305    }
4306
4307    /// RFC 3261 §8.1.1.7 requires the magic cookie. The remaining sixteen hexadecimal digits
4308    /// are the 64 random bits promised by `sip-transport.md` §7; checking every bit's balance
4309    /// catches a truncated value and a counter whose high bits never change.
4310    #[test]
4311    fn via_branch_keeps_the_cookie_and_all_sixty_four_random_bits() {
4312        let values = (0..IDENTIFIER_SAMPLE_SIZE).map(|_| {
4313            let branch = super::new_branch();
4314            let random = branch
4315                .strip_prefix("z9hG4bK")
4316                .expect("the RFC 3261 magic cookie");
4317            assert_eq!(random.len(), 16, "exactly 64 bits in hexadecimal");
4318            assert!(
4319                random
4320                    .bytes()
4321                    .all(|byte| byte.is_ascii_hexdigit() && !byte.is_ascii_uppercase()),
4322                "the random portion is canonical lowercase hexadecimal: {random}"
4323            );
4324            u64::from_str_radix(random, 16).expect("the generator wrote hexadecimal")
4325        });
4326        assert_full_width(&bit_counts(values), "Via branch");
4327    }
4328
4329    /// The bound on `branch_with_rng` is the non-statistical assertion: a generator that only
4330    /// implements `RngCore` cannot be used here, however plausible its sample looks.
4331    #[test]
4332    fn via_branch_requires_a_cryptographic_rng_by_construction() {
4333        fn draw<R: rand::CryptoRng + ?Sized>(rng: &mut R) -> String {
4334            super::branch_with_rng(rng)
4335        }
4336
4337        let branch = draw(&mut rand::rng());
4338        assert!(branch.starts_with("z9hG4bK"));
4339    }
4340
4341    /// The statistical guard is not the cryptographic proof; this shows that it detects the
4342    /// cheaper counter substitution which the compiler's `CryptoRng` bound independently refuses.
4343    #[test]
4344    fn the_width_guard_rejects_a_counter() {
4345        let counts = bit_counts(0..IDENTIFIER_SAMPLE_SIZE);
4346        assert!(
4347            counts.iter().any(|ones| !(1664..=2432).contains(ones)),
4348            "a 12-bit counter must not look like a 64-bit generator"
4349        );
4350    }
4351
4352    async fn driver_with_pool(
4353        pool: crate::tcp::Pool,
4354        net: mpsc::Receiver<crate::tcp::Event>,
4355    ) -> Driver {
4356        let socket = Arc::new(
4357            tokio::net::UdpSocket::bind("127.0.0.1:0")
4358                .await
4359                .expect("UDP binds"),
4360        );
4361        let local_addr = socket.local_addr().expect("local address");
4362        let (_commands_tx, commands) = mpsc::channel(8);
4363        let (_udp_tx, udp) = mpsc::channel(8);
4364        let (incoming, _incoming_rx) = mpsc::channel(8);
4365        let (_accepts_tx, accepts) = mpsc::channel(8);
4366        let (adopt, adopts) = mpsc::channel(8);
4367        let meters = Arc::new(crate::counters::Meters::default());
4368        let admission = Arc::new(crate::policy::SourceAdmission::default());
4369        let observations = Arc::new(crate::policy::ObservationHub::new(Arc::clone(&meters)));
4370        Driver {
4371            socket: Some(socket),
4372            udp,
4373            layer: sipx_sip::transaction::TransactionLayer::new(sipx_sip::Timers::default()),
4374            timers: crate::timers::TimerQueue::new(),
4375            destinations: std::collections::HashMap::new(),
4376            transaction_generations: std::collections::HashMap::new(),
4377            unanswered_since: std::collections::HashMap::new(),
4378            reconnect: std::collections::HashMap::new(),
4379            tcp_fallbacks: std::collections::HashMap::new(),
4380            unanswered_limit: Duration::from_secs(60),
4381            overload: crate::overload::Controller::new(5, 10, 1024),
4382            overload_config: crate::OverloadConfig::default(),
4383            overload_epoch: tokio::time::Instant::now(),
4384            overload_sequence: 0,
4385            server_overloaded_until: None,
4386            clients: std::collections::HashMap::new(),
4387            incoming,
4388            commands,
4389            net,
4390            accepts,
4391            adopts,
4392            _adopt: adopt,
4393            #[cfg(feature = "tls")]
4394            tls_client: None,
4395            #[cfg(feature = "ws")]
4396            ws_keepalive: Duration::from_secs(60),
4397            #[cfg(feature = "quic")]
4398            quic_client: None,
4399            #[cfg(feature = "quic")]
4400            quic_endpoint: None,
4401            pool,
4402            limits: sipx_sip::Limits::stream(),
4403            unreliable_request_limit: unreliable_request_limit(None),
4404            meters,
4405            admission,
4406            observations,
4407            capture: None,
4408            local_addr,
4409            unmatched: None,
4410            stun_waiters: std::collections::HashMap::new(),
4411            pong_waiters: std::collections::HashMap::new(),
4412            #[cfg(feature = "quic")]
4413            quic_replies: std::collections::HashMap::new(),
4414            background: Background::new(),
4415            shutdown: Arc::new(ShutdownState::default()),
4416            settled: Vec::new(),
4417        }
4418    }
4419
4420    #[tokio::test(start_paused = true)]
4421    async fn a_response_with_no_destination_does_not_refresh_application_liveness() {
4422        let (events, net_rx) = mpsc::channel(8);
4423        let pool = crate::tcp::Pool::new(
4424            crate::tcp::PoolConfig::default(),
4425            sipx_sip::Limits::stream(),
4426            events,
4427        );
4428        let mut driver = driver_with_pool(pool, net_rx).await;
4429        let parsed = sipx_sip::parse_datagram(
4430            Bytes::from_static(
4431                b"OPTIONS sip:a@example.com SIP/2.0\r\n\
4432                  Via: SIP/2.0/UDP 127.0.0.1:5060;branch=z9hG4bKno-destination\r\n\
4433                  To: <sip:a@example.com>\r\n\
4434                  From: <sip:b@example.net>;tag=1\r\n\
4435                  Call-ID: no-destination@example.net\r\n\
4436                  CSeq: 1 OPTIONS\r\n\
4437                  Max-Forwards: 70\r\n\
4438                  Content-Length: 0\r\n\r\n",
4439            ),
4440            &sipx_sip::Limits::datagram(),
4441        )
4442        .expect("request parses");
4443        let Message::Request(request) = parsed else {
4444            panic!("expected a request");
4445        };
4446        let response =
4447            ResponseBuilder::to_request(&request, StatusCode::new(180).expect("valid"), "Ringing")
4448                .expect("response builds")
4449                .build();
4450        let sipx_sip::transaction::Dispatch::Created { key, .. } = driver
4451            .layer
4452            .receive(Message::Request(request), sipx_sip::Reliability::Unreliable)
4453        else {
4454            panic!("server transaction is created");
4455        };
4456        let handed_over = tokio::time::Instant::now();
4457        driver.unanswered_since.insert(key.clone(), handed_over);
4458
4459        tokio::time::advance(Duration::from_secs(20)).await;
4460        let (sent, result) = tokio::sync::oneshot::channel();
4461        driver
4462            .on_respond_command(key.clone(), Box::new(response), sent)
4463            .await;
4464
4465        assert!(matches!(result.await, Ok(Ok(()))));
4466        assert_eq!(driver.unanswered_since.get(&key), Some(&handed_over));
4467        assert_eq!(driver.meters.snapshot().discards.no_destination, 1);
4468        driver.pool.shutdown().await;
4469    }
4470
4471    #[tokio::test]
4472    async fn stale_close_does_not_fail_a_transaction_on_the_live_generation() {
4473        use sipx_sip::transaction::Reliability;
4474
4475        let listener = tokio::net::TcpListener::bind("127.0.0.1:0")
4476            .await
4477            .expect("TCP binds");
4478        let address = listener.local_addr().expect("listener address");
4479        let peer_socket = TcpStream::connect(address).await.expect("peer connects");
4480        let (server_socket, peer) = listener.accept().await.expect("connection accepts");
4481        let key = crate::ConnectionKey::new(peer, TransportKind::Tcp);
4482        let (net_tx, net_rx) = mpsc::channel(8);
4483        let mut pool = crate::tcp::Pool::new(
4484            crate::tcp::PoolConfig::default(),
4485            sipx_sip::Limits::stream(),
4486            net_tx,
4487        );
4488        pool.accept(server_socket, peer);
4489        assert!(pool.holds(&key), "the live generation is installed");
4490
4491        let mut driver = driver_with_pool(pool, net_rx).await;
4492        let parsed = sipx_sip::parse_datagram(
4493            bytes::Bytes::from_static(
4494                b"OPTIONS sip:a@example.com SIP/2.0\r\n\
4495                  Via: SIP/2.0/TCP 127.0.0.1:5555;branch=z9hG4bKstale\r\n\
4496                  To: <sip:a@example.com>\r\n\
4497                  From: <sip:b@example.net>;tag=1\r\n\
4498                  Call-ID: stale-close@example.net\r\n\
4499                  CSeq: 1 OPTIONS\r\n\
4500                  Max-Forwards: 70\r\n\
4501                  Content-Length: 0\r\n\r\n",
4502            ),
4503            &sipx_sip::Limits::datagram(),
4504        )
4505        .expect("request parses");
4506        let Message::Request(request) = parsed else {
4507            panic!("expected a request");
4508        };
4509        let (transaction, _outputs) = driver
4510            .layer
4511            .send_request(request, Reliability::Reliable)
4512            .expect("transaction starts");
4513        driver
4514            .destinations
4515            .insert(transaction.clone(), Target::new(peer, TransportKind::Tcp));
4516        let live_id = driver.pool.generation(&key).expect("live generation");
4517        driver.transaction_generations.insert(
4518            transaction.clone(),
4519            super::ConnectionGeneration {
4520                key: key.clone(),
4521                id: live_id,
4522            },
4523        );
4524        let (client_events, mut received) = mpsc::channel(8);
4525        let (failures, _failure_rx) = mpsc::channel(1);
4526        driver.clients.insert(
4527            transaction.clone(),
4528            super::ClientSink {
4529                events: client_events,
4530                failures,
4531            },
4532        );
4533
4534        // Generation zero predates every real pool entry (IDs begin at one), modelling an old
4535        // task's delayed close after the current generation and transaction were installed.
4536        driver
4537            .on_net_event(crate::tcp::Event::Closed {
4538                key: key.clone(),
4539                id: 0,
4540            })
4541            .await;
4542
4543        assert!(driver.pool.holds(&key), "the live connection survives");
4544        assert_eq!(driver.layer.len(), (1, 0), "the transaction stays live");
4545        assert!(driver.destinations.contains_key(&transaction));
4546        assert!(driver.clients.contains_key(&transaction));
4547        assert!(
4548            matches!(received.try_recv(), Err(mpsc::error::TryRecvError::Empty)),
4549            "the client receives no stale transport error"
4550        );
4551        driver.pool.shutdown().await;
4552        drop(peer_socket);
4553    }
4554
4555    #[tokio::test]
4556    async fn retiring_current_generation_fails_its_transaction_and_pong_waiter_once() {
4557        use sipx_sip::transaction::Reliability;
4558
4559        let listener = tokio::net::TcpListener::bind("127.0.0.1:0")
4560            .await
4561            .expect("TCP binds");
4562        let address = listener.local_addr().expect("listener address");
4563        let peer_socket = TcpStream::connect(address).await.expect("peer connects");
4564        let (server_socket, peer) = listener.accept().await.expect("connection accepts");
4565        let key = crate::ConnectionKey::new(peer, TransportKind::Tcp);
4566        let (net_tx, net_rx) = mpsc::channel(8);
4567        let mut pool = crate::tcp::Pool::new(
4568            crate::tcp::PoolConfig {
4569                idle_timeout: Duration::ZERO,
4570                ..crate::tcp::PoolConfig::default()
4571            },
4572            sipx_sip::Limits::stream(),
4573            net_tx,
4574        );
4575        pool.accept(server_socket, peer);
4576        let id = pool.generation(&key).expect("generation");
4577        let mut driver = driver_with_pool(pool, net_rx).await;
4578        let parsed = sipx_sip::parse_datagram(
4579            bytes::Bytes::from_static(
4580                b"OPTIONS sip:a@example.com SIP/2.0\r\n\
4581                  Via: SIP/2.0/TCP 127.0.0.1:5555;branch=z9hG4bKretire\r\n\
4582                  To: <sip:a@example.com>\r\n\
4583                  From: <sip:b@example.net>;tag=1\r\n\
4584                  Call-ID: retire@example.net\r\n\
4585                  CSeq: 1 OPTIONS\r\n\
4586                  Max-Forwards: 70\r\n\
4587                  Content-Length: 0\r\n\r\n",
4588            ),
4589            &sipx_sip::Limits::datagram(),
4590        )
4591        .expect("request parses");
4592        let Message::Request(request) = parsed else {
4593            panic!("expected request");
4594        };
4595        let (transaction, _outputs) = driver
4596            .layer
4597            .send_request(request, Reliability::Reliable)
4598            .expect("transaction starts");
4599        driver
4600            .destinations
4601            .insert(transaction.clone(), Target::new(peer, TransportKind::Tcp));
4602        let generation = super::ConnectionGeneration {
4603            key: key.clone(),
4604            id,
4605        };
4606        driver
4607            .transaction_generations
4608            .insert(transaction.clone(), generation.clone());
4609        let (client_events, mut received) = mpsc::channel(8);
4610        let (failures, _failure_rx) = mpsc::channel(1);
4611        driver.clients.insert(
4612            transaction,
4613            super::ClientSink {
4614                events: client_events,
4615                failures,
4616            },
4617        );
4618        let (pong, pong_result) = tokio::sync::oneshot::channel();
4619        driver
4620            .pong_waiters
4621            .entry(generation)
4622            .or_default()
4623            .push_back(pong);
4624
4625        assert_eq!(driver.pool.evict_idle(), vec![key.clone()]);
4626        driver
4627            .on_net_event(crate::tcp::Event::Closed {
4628                key: key.clone(),
4629                id,
4630            })
4631            .await;
4632        assert!(matches!(
4633            received.recv().await,
4634            Some(sipx_sip::transaction::TuEvent::TransportError)
4635        ));
4636        assert!(matches!(
4637            pong_result.await,
4638            Ok(Err(crate::Error::ConnectionClosed))
4639        ));
4640        assert!(!driver.pool.holds(&key));
4641
4642        // A duplicated close is stale after the first acknowledgement and has no second effect.
4643        driver
4644            .on_net_event(crate::tcp::Event::Closed { key, id })
4645            .await;
4646        driver.pool.shutdown().await;
4647        drop(peer_socket);
4648    }
4649
4650    #[tokio::test]
4651    async fn queued_old_pong_cannot_answer_the_replacement_generation_waiter() {
4652        let (events, net_rx) = mpsc::channel(8);
4653        let pool = crate::tcp::Pool::new(
4654            crate::tcp::PoolConfig::default(),
4655            sipx_sip::Limits::stream(),
4656            events,
4657        );
4658        let mut driver = driver_with_pool(pool, net_rx).await;
4659        let key = crate::ConnectionKey::new(
4660            "127.0.0.1:59999".parse().expect("address"),
4661            TransportKind::Tcp,
4662        );
4663        let replacement_id = 2;
4664        let (answered, mut answer) = tokio::sync::oneshot::channel();
4665        driver
4666            .pong_waiters
4667            .entry(super::ConnectionGeneration {
4668                key: key.clone(),
4669                id: replacement_id,
4670            })
4671            .or_default()
4672            .push_back(answered);
4673
4674        driver
4675            .on_net_event(crate::tcp::Event::Pong {
4676                key: key.clone(),
4677                id: 1,
4678            })
4679            .await;
4680        assert!(matches!(
4681            answer.try_recv(),
4682            Err(tokio::sync::oneshot::error::TryRecvError::Empty)
4683        ));
4684
4685        driver
4686            .on_net_event(crate::tcp::Event::Pong {
4687                key,
4688                id: replacement_id,
4689            })
4690            .await;
4691        assert!(matches!(answer.await, Ok(Ok(None))));
4692        driver.pool.shutdown().await;
4693    }
4694
4695    fn handle_with_shutdown_barrier(
4696        commands: mpsc::Sender<super::Command>,
4697        shutdown: Arc<ShutdownState>,
4698    ) -> super::Handle {
4699        let meters = Arc::new(crate::counters::Meters::default());
4700        super::Handle {
4701            commands,
4702            shutdown,
4703            draining: Arc::new(std::sync::atomic::AtomicBool::new(false)),
4704            local_addr: "127.0.0.1:5060".parse().expect("address"),
4705            meters: Arc::clone(&meters),
4706            admission: Arc::new(crate::policy::SourceAdmission::default()),
4707            observations: Arc::new(crate::policy::ObservationHub::new(meters)),
4708            request_policy: None,
4709            #[cfg(feature = "tls")]
4710            tls_addr: None,
4711            #[cfg(feature = "tls")]
4712            server_identity: None,
4713            #[cfg(feature = "ws")]
4714            ws_addr: None,
4715            #[cfg(feature = "wss")]
4716            wss_addr: None,
4717            #[cfg(feature = "quic")]
4718            quic_addr: None,
4719            #[cfg(feature = "ws")]
4720            ws_sent_by: Arc::from("shutdown.invalid"),
4721            advertise_overload: false,
4722            sent_by: Arc::new("127.0.0.1".to_owned()),
4723            sent_by_port: 5060,
4724            unreliable_request_limit: unreliable_request_limit(None),
4725        }
4726    }
4727
4728    #[tokio::test]
4729    async fn caller_arriving_after_command_closure_still_waits_for_cleanup_completion() {
4730        let (commands, mut received) = mpsc::channel(8);
4731        let shutdown = Arc::new(ShutdownState::default());
4732        let handle = handle_with_shutdown_barrier(commands, Arc::clone(&shutdown));
4733        let (receiver_closed, closed) = tokio::sync::oneshot::channel();
4734        let (release_cleanup, cleanup_released) = tokio::sync::oneshot::channel();
4735        let driver = tokio::spawn(async move {
4736            assert!(matches!(
4737                received.recv().await,
4738                Some(super::Command::Shutdown)
4739            ));
4740            received.close();
4741            receiver_closed.send(()).expect("test remains present");
4742            cleanup_released.await.expect("cleanup is released");
4743            shutdown.complete();
4744        });
4745
4746        let first = {
4747            let handle = handle.clone();
4748            tokio::spawn(async move { handle.shutdown().await })
4749        };
4750        closed.await.expect("driver closed command receiver");
4751        let late = {
4752            let handle = handle.clone();
4753            tokio::spawn(async move { handle.shutdown().await })
4754        };
4755        tokio::task::yield_now().await;
4756        assert!(
4757            !late.is_finished(),
4758            "late caller waits on the durable barrier after send fails"
4759        );
4760
4761        release_cleanup.send(()).expect("driver remains present");
4762        first.await.expect("first shutdown returns after cleanup");
4763        late.await.expect("late shutdown returns after cleanup");
4764        driver.await.expect("driver completes");
4765    }
4766
4767    #[cfg(any(feature = "tls", feature = "ws"))]
4768    const DEADLINE: Duration = Duration::from_millis(150);
4769
4770    #[cfg(any(feature = "tls", feature = "ws"))]
4771    fn handshake_runtime(
4772        limit: usize,
4773    ) -> (
4774        Background,
4775        HandshakeRuntime,
4776        mpsc::UnboundedReceiver<HandshakeObservation>,
4777    ) {
4778        let owner = Background::new();
4779        let (observations, observed) = mpsc::unbounded_channel();
4780        let runtime = HandshakeRuntime {
4781            deadline: DEADLINE,
4782            permits: Arc::new(Semaphore::new(limit)),
4783            owner: owner.clone(),
4784            observations: Some(observations),
4785        };
4786        (owner, runtime, observed)
4787    }
4788
4789    async fn wait_for_observation(
4790        observed: &mut mpsc::UnboundedReceiver<HandshakeObservation>,
4791        expected: HandshakeObservation,
4792    ) {
4793        assert_eq!(
4794            observed.recv().await.expect("listener remains alive"),
4795            expected
4796        );
4797    }
4798
4799    #[cfg(any(feature = "tls", feature = "ws"))]
4800    async fn wait_for_available(runtime: &HandshakeRuntime, expected: usize) {
4801        for _ in 0..512 {
4802            if runtime.permits.available_permits() == expected {
4803                return;
4804            }
4805            tokio::task::yield_now().await;
4806        }
4807        assert_eq!(runtime.permits.available_permits(), expected);
4808    }
4809
4810    #[cfg(any(feature = "tls", feature = "ws"))]
4811    async fn wait_for_eof(stream: &TcpStream) {
4812        tokio::time::timeout(Duration::from_secs(2), async {
4813            let mut byte = [0u8; 1];
4814            loop {
4815                stream.readable().await.expect("socket remains readable");
4816                match stream.try_read(&mut byte) {
4817                    Ok(0) => return,
4818                    Ok(_) => panic!("a refused incomplete handshake produced bytes"),
4819                    Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => {}
4820                    Err(error)
4821                        if matches!(
4822                            error.kind(),
4823                            std::io::ErrorKind::ConnectionReset
4824                                | std::io::ErrorKind::ConnectionAborted
4825                                | std::io::ErrorKind::BrokenPipe
4826                        ) =>
4827                    {
4828                        return;
4829                    }
4830                    Err(error) => panic!("unexpected read error: {error}"),
4831                }
4832            }
4833        })
4834        .await
4835        .expect("peer closes within the configured handshake deadline");
4836    }
4837
4838    #[cfg(any(feature = "tls", feature = "ws"))]
4839    fn open_source_policy() -> (
4840        Arc<crate::policy::SourceAdmission>,
4841        Arc<crate::counters::Meters>,
4842    ) {
4843        (
4844            Arc::new(crate::policy::SourceAdmission::default()),
4845            Arc::new(crate::counters::Meters::default()),
4846        )
4847    }
4848
4849    /// X18: incomplete upgrades have one endpoint-wide budget and an observed admission barrier.
4850    #[cfg(feature = "ws")]
4851    #[tokio::test]
4852    async fn websocket_handshake_budget_has_deterministic_admission_and_reclamation() {
4853        let (owner, runtime, mut observed) = handshake_runtime(2);
4854        let (admission, meters) = open_source_policy();
4855        let (adopt, mut adopted) = mpsc::channel::<Adopt>(8);
4856        let address = super::listen_ws(
4857            "127.0.0.1".parse().expect("loopback"),
4858            0,
4859            Duration::from_secs(60),
4860            sipx_sip::Limits::stream(),
4861            &adopt,
4862            &runtime,
4863            admission,
4864            meters,
4865        )
4866        .await
4867        .expect("listener binds");
4868
4869        let first = TcpStream::connect(address).await.expect("first connects");
4870        wait_for_observation(&mut observed, HandshakeObservation::Admitted).await;
4871        wait_for_available(&runtime, 1).await;
4872        let second = TcpStream::connect(address).await.expect("second connects");
4873        wait_for_observation(&mut observed, HandshakeObservation::Admitted).await;
4874        wait_for_available(&runtime, 0).await;
4875
4876        for _ in 0..16 {
4877            let refused = TcpStream::connect(address).await.expect("excess connects");
4878            wait_for_observation(&mut observed, HandshakeObservation::Refused).await;
4879            wait_for_eof(&refused).await;
4880        }
4881
4882        wait_for_eof(&first).await;
4883        wait_for_eof(&second).await;
4884        wait_for_available(&runtime, 2).await;
4885
4886        let stream = TcpStream::connect(address)
4887            .await
4888            .expect("connects after deadline");
4889        let socket = crate::ws::connect(stream, &address.to_string(), "/", false)
4890            .await
4891            .expect("released permit admits an upgrade");
4892        let adoption = adopted.recv().await.expect("upgraded socket is adopted");
4893        drop(adoption);
4894        drop(socket);
4895        owner.shutdown().await;
4896    }
4897
4898    /// X18: TLS and WebSocket listeners draw from the same directly observed permit.
4899    #[cfg(all(feature = "tls", feature = "ws"))]
4900    #[tokio::test]
4901    async fn tls_and_websocket_share_one_deterministic_handshake_budget() {
4902        use sipx_testkit::certs::Ca;
4903
4904        use crate::tls::{Identity, ServerTls};
4905
4906        let ca = Ca::new();
4907        let (certificate, key) = ca.issue_for("localhost");
4908        let identity =
4909            Identity::from_pem(certificate.as_bytes(), key.as_bytes()).expect("an identity");
4910        let (owner, runtime, mut observed) = handshake_runtime(1);
4911        let (admission, meters) = open_source_policy();
4912        let (adopt, mut adopted) = mpsc::channel::<Adopt>(8);
4913        let (_identity_tx, identity_rx) = tokio::sync::watch::channel(None);
4914        let tls_address = super::listen_tls(
4915            "127.0.0.1".parse().expect("loopback"),
4916            0,
4917            super::ServerHandshakePolicy::new(
4918                ServerTls::new(identity).expect("a server"),
4919                identity_rx,
4920            ),
4921            &adopt,
4922            &runtime,
4923            Arc::clone(&admission),
4924            Arc::clone(&meters),
4925        )
4926        .await
4927        .expect("TLS listener binds");
4928        let ws_address = super::listen_ws(
4929            "127.0.0.1".parse().expect("loopback"),
4930            0,
4931            Duration::from_secs(60),
4932            sipx_sip::Limits::stream(),
4933            &adopt,
4934            &runtime,
4935            admission,
4936            meters,
4937        )
4938        .await
4939        .expect("WebSocket listener binds");
4940
4941        let partial_tls = TcpStream::connect(tls_address).await.expect("TLS connects");
4942        wait_for_observation(&mut observed, HandshakeObservation::Admitted).await;
4943        wait_for_available(&runtime, 0).await;
4944        let refused_ws = TcpStream::connect(ws_address)
4945            .await
4946            .expect("WebSocket TCP connects");
4947        wait_for_observation(&mut observed, HandshakeObservation::Refused).await;
4948        wait_for_eof(&refused_ws).await;
4949
4950        wait_for_eof(&partial_tls).await;
4951        wait_for_available(&runtime, 1).await;
4952
4953        let stream = TcpStream::connect(ws_address)
4954            .await
4955            .expect("connects after deadline");
4956        let socket = crate::ws::connect(stream, &ws_address.to_string(), "/", false)
4957            .await
4958            .expect("released shared permit admits WebSocket");
4959        let adoption = adopted.recv().await.expect("upgraded socket is adopted");
4960        drop(adoption);
4961        drop(socket);
4962        owner.shutdown().await;
4963    }
4964
4965    /// X18: WSS keeps its single permit across both TLS and HTTP upgrade phases.
4966    #[cfg(feature = "wss")]
4967    #[tokio::test]
4968    async fn wss_handshake_budget_has_deterministic_admission_and_reclamation() {
4969        use sipx_testkit::certs::Ca;
4970
4971        use crate::tls::{Identity, ServerTls};
4972
4973        let ca = Ca::new();
4974        let (certificate, key) = ca.issue_for("localhost");
4975        let identity =
4976            Identity::from_pem(certificate.as_bytes(), key.as_bytes()).expect("an identity");
4977        let (owner, runtime, mut observed) = handshake_runtime(1);
4978        let (admission, meters) = open_source_policy();
4979        let (adopt, _adopted) = mpsc::channel::<Adopt>(8);
4980        let (_identity_tx, identity_rx) = tokio::sync::watch::channel(None);
4981        let address = super::listen_wss(
4982            "127.0.0.1".parse().expect("loopback"),
4983            0,
4984            super::ServerHandshakePolicy::new(
4985                ServerTls::new(identity).expect("a server"),
4986                identity_rx,
4987            ),
4988            Duration::from_secs(60),
4989            sipx_sip::Limits::stream(),
4990            &adopt,
4991            &runtime,
4992            admission,
4993            meters,
4994        )
4995        .await
4996        .expect("WSS listener binds");
4997
4998        let first = TcpStream::connect(address).await.expect("first connects");
4999        wait_for_observation(&mut observed, HandshakeObservation::Admitted).await;
5000        wait_for_available(&runtime, 0).await;
5001        let refused = TcpStream::connect(address).await.expect("second connects");
5002        wait_for_observation(&mut observed, HandshakeObservation::Refused).await;
5003        wait_for_eof(&refused).await;
5004
5005        wait_for_eof(&first).await;
5006        wait_for_available(&runtime, 1).await;
5007
5008        let admitted = TcpStream::connect(address).await.expect("third connects");
5009        wait_for_observation(&mut observed, HandshakeObservation::Admitted).await;
5010        wait_for_available(&runtime, 0).await;
5011        owner.shutdown().await;
5012        wait_for_eof(&admitted).await;
5013    }
5014}