Skip to main content

sozu_lib/
socket.rs

1//! Socket I/O wrappers and TCP option helpers.
2//!
3//! Hosts the `SocketHandler` trait, the `FrontRustls` wrapper that drives
4//! a rustls `ServerConnection` over a `TcpStream`, plus the ancillary
5//! `getsockopt(TCP_INFO)` / TCP-keepalive helpers. The
6//! `FrontRustls::socket_write` / `socket_write_vectored` pair is a known
7//! truncation hot spot — keep the two paths structurally symmetric (see
8//! the per-method `///` invariants).
9
10use std::{
11    io::{ErrorKind, Read, Write},
12    net::SocketAddr,
13};
14
15use mio::net::{TcpListener, TcpStream, UdpSocket};
16use rustls::{ProtocolVersion, ServerConnection};
17use rusty_ulid::Ulid;
18use socket2::{Domain, Protocol, Socket, Type};
19use sozu_command::{config::MAX_LOOP_ITERATIONS, logging::ansi_palette, ready::Ready};
20
21use crate::metrics::names;
22
23#[derive(thiserror::Error, Debug)]
24pub enum ServerBindError {
25    #[error("could not set bind to socket: {0}")]
26    BindError(std::io::Error),
27    #[error("could not listen on socket: {0}")]
28    Listen(std::io::Error),
29    #[error("could not set socket to nonblocking: {0}")]
30    SetNonBlocking(std::io::Error),
31    #[error("could not set reuse address: {0}")]
32    SetReuseAddress(std::io::Error),
33    #[error("could not set reuse address: {0}")]
34    SetReusePort(std::io::Error),
35    #[error("Could not create socket: {0}")]
36    SocketCreationError(std::io::Error),
37    #[error("Invalid socket address '{address}': {error}")]
38    InvalidSocketAddress { address: String, error: String },
39    #[error(
40        "could not bind the listener {address} to the network interface '{interface}' \
41         (SO_BINDTODEVICE): {error}. The interface must exist when the listener is activated, \
42         and on Linux kernels before 5.7 binding a socket to an interface requires the \
43         CAP_NET_RAW capability"
44    )]
45    BindToDevice {
46        address: SocketAddr,
47        interface: String,
48        error: std::io::Error,
49    },
50    #[error(
51        "the listener {address} names the network interface '{interface}', but binding a \
52         socket to an interface (SO_BINDTODEVICE) is only supported on Linux"
53    )]
54    BindToDeviceUnsupported {
55        address: SocketAddr,
56        interface: String,
57    },
58}
59
60#[derive(Debug, PartialEq, Eq, Copy, Clone)]
61pub enum SocketResult {
62    Continue,
63    Closed,
64    WouldBlock,
65    Error,
66}
67
68#[derive(Debug, PartialEq, Eq, Copy, Clone)]
69pub enum TransportProtocol {
70    Tcp,
71    Ssl2,
72    Ssl3,
73    Tls1_0,
74    Tls1_1,
75    Tls1_2,
76    Tls1_3,
77}
78
79pub trait SocketHandler {
80    fn socket_read(&mut self, buf: &mut [u8]) -> (usize, SocketResult);
81    fn socket_write(&mut self, buf: &[u8]) -> (usize, SocketResult);
82    fn socket_write_vectored(&mut self, _buf: &[std::io::IoSlice]) -> (usize, SocketResult);
83    fn socket_wants_write(&self) -> bool {
84        false
85    }
86    fn socket_close(&mut self) {}
87    /// Write `buf`, then begin the close [`Self::socket_close`] begins, and
88    /// report what [`Self::socket_write`] would for `buf`.
89    ///
90    /// The close is begun only when the whole of `buf` was accepted, so a
91    /// caller that gets back less resumes with the rest and the close still
92    /// follows its last byte. A handler without a close of its own does
93    /// exactly the two calls; [`FrontRustls`] puts the plaintext and its
94    /// `close_notify` behind one flush, so the last application bytes and
95    /// the alert leave in one `writev(2)` instead of two.
96    fn socket_write_then_close(&mut self, buf: &[u8]) -> (usize, SocketResult) {
97        let (size, status) = self.socket_write(buf);
98        if size == buf.len() {
99            self.socket_close();
100        }
101        (size, status)
102    }
103    fn socket_ref(&self) -> &TcpStream;
104    fn socket_mut(&mut self) -> &mut TcpStream;
105    /// Peer address of this connection, preferring a snapshot taken when the
106    /// handler was built over a live `getpeername(2)`.
107    ///
108    /// `getpeername(2)` fails with `ENOTCONN` the moment the peer resets, so a
109    /// live lookup renders `peer=None` on exactly the error lines an operator
110    /// reads during an incident. It also reports the transport peer, which on a
111    /// PROXY-protocol frontend is the load balancer rather than the client the
112    /// rest of the session is logged against.
113    ///
114    /// Implementations that cache an address ([`SessionTcpStream`],
115    /// [`FrontRustls`]) return it and fall back to the live lookup only when
116    /// they have none; the raw [`TcpStream`] impl carries no context and has
117    /// nothing but the live lookup. Deliberately has no default body: a new
118    /// handler must state which of the two it is.
119    fn peer_addr(&self) -> Option<SocketAddr>;
120    fn protocol(&self) -> TransportProtocol;
121    fn read_error(&self);
122    fn write_error(&self);
123    /// Returns the owning connection's session ULID when known. Used by
124    /// `log_socket_context!` to render the `[<session_ulid> - - -]` segment
125    /// of the socket-layer log prefix, matching the format used by the
126    /// rest of the mux stack. Returns `None` for contextless implementations
127    /// (e.g. raw `mio::TcpStream`); the macro renders `-` in the ULID slot.
128    fn session_ulid(&self) -> Option<Ulid> {
129        None
130    }
131}
132
133/// Format the socket-layer log prefix `[<session_ulid_or_->]\tSOCKET\tSession(
134/// peer=..., local=..., rtt=..., state=..., protocol=...)\t >>>` for a
135/// [`SocketHandler`] impl that has `self` in scope. When `$self.session_ulid()`
136/// returns `None` (e.g. the raw [`TcpStream`] impl that carries no session
137/// context) the ULID slot is rendered as `-` so the column layout stays
138/// stable across sessionless plumbing. The `[ulid - - -]` context comes first
139/// to stay aligned with `MUX-*`, `PIPE` and `RUSTLS` log lines. Colour scheme
140/// comes from [`sozu_command::logging::ansi_palette`] — single source of
141/// truth for every `log_*_context!` macro in the proxy.
142///
143/// `peer` is [`SocketHandler::peer_addr`] — the address the handler cached,
144/// falling back to a live `getpeername(2)` only where it has none. Same
145/// preference order, and now the same single source, as
146/// [`log_socket_module_prefix`] and the `MUX-*` contexts, so every rendering
147/// of one connection names one host.
148///
149/// Spelled as a fully-qualified trait call to foreclose a latent hazard, not
150/// to fix a present one: `$self.peer_addr()` compiles clean today and passes
151/// every test, because no current expansion sits on a raw [`TcpStream`] — all
152/// of them are in `impl SocketHandler for FrontRustls`, which has no inherent
153/// `peer_addr` for method resolution to prefer. Add one on a bare `mio`
154/// [`TcpStream`] and the unqualified form silently picks mio's inherent
155/// method instead of this trait's: measured, that slot renders
156/// `peer=Ok(127.0.0.1:33587)` beside `local=Some(..)` — an `io::Result` where
157/// every other expansion renders an `Option`. The qualification makes that
158/// impossible rather than merely unlikely.
159///
160/// `local`, `rtt`, `state` render per [`log_socket_module_prefix`]'s
161/// description; `local` stays a live `getsockname(2)`, which survives what
162/// `getpeername(2)` does not.
163macro_rules! log_socket_context {
164    ($self:expr) => {{
165        let (open, reset, grey, gray, white) = ansi_palette();
166        let ulid = match $self.session_ulid() {
167            Some(ulid) => ulid.to_string(),
168            None => "-".to_string(),
169        };
170        let snapshot = crate::socket::stats::socket_snapshot($self.socket_ref());
171        let rtt = snapshot.as_ref().map(|s| s.rtt);
172        let state = snapshot.as_ref().map(|s| s.state);
173        format!(
174            "[{ulid} - - -]\t{open}SOCKET{reset}\t{grey}Session{reset}({gray}peer{reset}={white}{peer:?}{reset}, {gray}local{reset}={white}{local:?}{reset}, {gray}rtt{reset}={white}{rtt:?}{reset}, {gray}state{reset}={white}{state:?}{reset}, {gray}protocol{reset}={white}{protocol:?}{reset})\t >>>",
175            open = open,
176            reset = reset,
177            grey = grey,
178            gray = gray,
179            white = white,
180            ulid = ulid,
181            peer = crate::socket::SocketHandler::peer_addr($self),
182            local = $self.socket_ref().local_addr().ok(),
183            rtt = rtt,
184            state = state,
185            protocol = $self.protocol(),
186        )
187    }};
188}
189
190/// Module-level socket log prefix used from free functions (e.g. the shared
191/// `tcp_socket_*` helpers) where `self` is not in scope but the caller can
192/// still thread a session `Ulid`, a cached peer address, and the underlying
193/// [`TcpStream`] through as parameters. Renders the same
194/// `[<ulid> - - -]\tSOCKET\tSession(peer=..., local=..., rtt=..., state=..., protocol=Tcp)\t >>>`
195/// prefix as [`log_socket_context!`]; colour scheme via
196/// [`sozu_command::logging::ansi_palette`].
197///
198/// Per-slot semantics:
199///
200/// - `peer` — prefers the caller-supplied `configured_peer` (cached at
201///   [`SessionTcpStream`] construction, immune to ENOTCONN on a socket that
202///   failed an asynchronous `connect()`) and falls back to a live
203///   `getpeername(2)` lookup when no cache was provided.
204/// - `local` — `getsockname(2)`, stays valid across failed connects.
205/// - `rtt` / `state` — a single `getsockopt(TCP_INFO)` call via
206///   [`stats::socket_snapshot`]; both render as `None` on an FSM state
207///   where the kernel rejects the call. `state="SYN_SENT"` is the
208///   clearest signal for a failed outbound `connect()`.
209/// - `protocol` — hardcoded to `Tcp` (raw-TCP helpers only).
210fn log_socket_module_prefix(
211    stream: &TcpStream,
212    session_ulid: Option<Ulid>,
213    configured_peer: Option<SocketAddr>,
214) -> String {
215    let (open, reset, grey, gray, white) = ansi_palette();
216    let ulid = match session_ulid {
217        Some(ulid) => ulid.to_string(),
218        None => "-".to_string(),
219    };
220    let snapshot = crate::socket::stats::socket_snapshot(stream);
221    let rtt = snapshot.as_ref().map(|s| s.rtt);
222    let state = snapshot.as_ref().map(|s| s.state);
223    format!(
224        "[{ulid} - - -]\t{open}SOCKET{reset}\t{grey}Session{reset}({gray}peer{reset}={white}{peer:?}{reset}, {gray}local{reset}={white}{local:?}{reset}, {gray}rtt{reset}={white}{rtt:?}{reset}, {gray}state{reset}={white}{state:?}{reset}, {gray}protocol{reset}={white}Tcp{reset})\t >>>",
225        peer = configured_peer.or_else(|| stream.peer_addr().ok()),
226        local = stream.local_addr().ok(),
227    )
228}
229
230/// Body of [`tcp_socket_read`], generic over the transport so tests can count
231/// every read a call issues against it.
232///
233/// One `read` per call. A stream socket that answers fewer bytes than it was
234/// offered has emptied its receive queue: `man 7 epoll` (man-pages 6.13, the
235/// EPOLLET question) — "if you call read(2) by asking to read a certain
236/// amount of data and read(2) returns a lower number of bytes, you can be sure
237/// of having exhausted the read I/O space for the file descriptor". A second
238/// `recv(2)` could only answer EAGAIN, so the call stops there, as HAProxy
239/// (`src/raw_sock.c`, `fd_cant_recv` when `ret < try`) and tokio
240/// (`tokio/src/io/poll_evented.rs`, `clear_readiness` when `0 < n < len`) do.
241///
242/// One exception to that guarantee: TCP urgent data. `recv` stops before an
243/// urgent (out-of-band) mark even when bytes are queued behind it, so a short
244/// read does NOT prove the queue empty while such a mark is pending. Measured
245/// on a loopback socket: `AAAA`, `send(B, MSG_OOB)`, `CCCC` raise one edge,
246/// this read answers `(4, WouldBlock)` with `AAAA`, no further event comes,
247/// and `CCCC` stays in the kernel until the peer sends again. A stream that
248/// carries OOB data (telnet, rlogin, FTP `ABOR`) can therefore stall until the
249/// peer's next send. HAProxy and tokio behave the same, and sozu never read
250/// out-of-band data before either.
251///
252/// Readiness contract:
253///
254/// - a short read answers `(n, WouldBlock)`, exactly what the previous loop
255///   answered one EAGAIN later; the caller drops READABLE, and mio registers
256///   every socket edge-triggered (`mio/src/sys/unix/selector/epoll.rs`,
257///   `EPOLLET`), where "an event will be generated upon each receipt of a
258///   chunk of data" (`man 7 epoll`), so bytes arriving after this `recv`
259///   raise the next event;
260/// - a read that fills `buf` is not a short read: it answers `(n, Continue)`
261///   and READABLE stays, because more may be queued;
262/// - EOF behind the data is left for the next call. A FIN that was already
263///   signalled comes with no further edge, so a caller that saw HUP must keep
264///   READABLE to read it: `update_readiness_after_read` in the mux does.
265///
266/// A read the kernel interrupted (`EINTR`) is retried at once, as
267/// [`flush_tls`] does for writes: it says nothing about the socket.
268///
269/// The returned error, when there is one, is a transport failure the caller
270/// logs with its socket context; the result is then [`SocketResult::Error`].
271fn plain_socket_read<R: Read>(
272    stream: &mut R,
273    buf: &mut [u8],
274) -> (usize, SocketResult, Option<std::io::Error>) {
275    // An empty slice reads nothing and says nothing about the socket; callers
276    // guard against it, and `(0, Continue)` is what they expect back.
277    if buf.is_empty() {
278        return (0, SocketResult::Continue, None);
279    }
280    let read = loop {
281        match stream.read(buf) {
282            Err(e) if e.kind() == ErrorKind::Interrupted => continue,
283            read => break read,
284        }
285    };
286    match read {
287        Ok(0) => (0, SocketResult::Closed, None),
288        Ok(sz) => {
289            // `read` cannot report more bytes than the slice it was given.
290            debug_assert!(
291                sz <= buf.len(),
292                "read reported {sz} bytes into a {}-byte slice",
293                buf.len()
294            );
295            if sz == buf.len() {
296                (sz, SocketResult::Continue, None)
297            } else {
298                (sz, SocketResult::WouldBlock, None)
299            }
300        }
301        Err(e) => match e.kind() {
302            ErrorKind::WouldBlock => (0, SocketResult::WouldBlock, None),
303            // Treat `ConnectionRefused` as a closed socket, mirroring the
304            // write path. On Linux a failed asynchronous `connect()`
305            // surfaces as `ECONNREFUSED` on the first read; it is
306            // operationally identical to any other benign peer-initiated
307            // close and does not warrant a log line on every backend
308            // that happens to be down.
309            //
310            // A reset is still a close, but it is counted: clients that abort
311            // instead of finishing cleanly are an operational signal, not an
312            // error (sozu-proxy/sozu#434). The kernel reports `ECONNRESET` to
313            // the first syscall after the RST only; later reads see EOF and
314            // later writes `EPIPE`, so each reset is counted once.
315            ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted => {
316                incr!(names::tcp::READ_RESET);
317                (0, SocketResult::Closed, None)
318            }
319            ErrorKind::BrokenPipe | ErrorKind::ConnectionRefused => (0, SocketResult::Closed, None),
320            _ => (0, SocketResult::Error, Some(e)),
321        },
322    }
323}
324
325/// Shared read/write/vectored-write logic used by both
326/// [`impl SocketHandler for TcpStream`] and
327/// [`impl SocketHandler for SessionTcpStream`]. Free-function entry point:
328/// `self` is out of scope here, so error logs use [`log_socket_module_prefix`]
329/// which renders the same `Session(peer, rtt, protocol)` context as
330/// [`log_socket_context!`] by reading from the `stream` + `session_ulid`
331/// parameters threaded through each helper. The read itself is
332/// [`plain_socket_read`].
333fn tcp_socket_read(
334    stream: &mut TcpStream,
335    buf: &mut [u8],
336    session_ulid: Option<Ulid>,
337    configured_peer: Option<SocketAddr>,
338) -> (usize, SocketResult) {
339    let (size, result, fault) = plain_socket_read(stream, buf);
340    if let Some(e) = fault {
341        match e.kind() {
342            // Noisy-expected transport failures: backend unreachable,
343            // TCP_USER_TIMEOUT expiry, post-close reads. Keep a log line
344            // so operators can still trend the rate, but `warn!` — this
345            // is reality-at-scale, not a sozu invariant break.
346            ErrorKind::HostUnreachable
347            | ErrorKind::NetworkUnreachable
348            | ErrorKind::TimedOut
349            | ErrorKind::NotConnected => warn!(
350                "{} socket_read error={:?}",
351                log_socket_module_prefix(stream, session_ulid, configured_peer),
352                e
353            ),
354            // Genuinely loud variants (`PermissionDenied`, `AddrNotAvailable`,
355            // `InvalidInput`/`Data`, …) and the unknown catch-all stay at
356            // `error!` so operators keep paging on real misconfig.
357            _ => error!(
358                "{} socket_read error={:?}",
359                log_socket_module_prefix(stream, session_ulid, configured_peer),
360                e
361            ),
362        }
363    }
364    (size, result)
365}
366
367/// A failure [`plain_socket_write`] or [`plain_socket_write_vectored`] hit,
368/// handed back rather than logged so [`tcp_socket_write`] and
369/// [`tcp_socket_write_vectored`] render it with their socket context, as
370/// [`tcp_socket_read`] does for [`plain_socket_read`]. Its counters are
371/// already bumped.
372#[derive(Debug)]
373enum PlainWriteFault {
374    /// The write loop ran [`MAX_LOOP_ITERATIONS`] times without settling.
375    LoopLimit,
376    /// The socket failed with something other than `WouldBlock`, a reset, a
377    /// broken pipe, a refused connection or an interruption.
378    Io(std::io::Error),
379}
380
381/// Map a failed plain TCP write to its result, bumping its counters. A peer
382/// reset (see [`plain_socket_read`]) keeps counting under `tcp.write.error`
383/// as well, as it did before `tcp.write.reset`.
384fn plain_write_error(e: std::io::Error) -> (SocketResult, Option<PlainWriteFault>) {
385    match e.kind() {
386        ErrorKind::WouldBlock => (SocketResult::WouldBlock, None),
387        ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted => {
388            incr!(names::tcp::WRITE_RESET);
389            incr!(names::tcp::WRITE_ERROR);
390            (SocketResult::Closed, None)
391        }
392        ErrorKind::BrokenPipe | ErrorKind::ConnectionRefused => {
393            incr!(names::tcp::WRITE_ERROR);
394            (SocketResult::Closed, None)
395        }
396        _ => {
397            incr!(names::tcp::WRITE_ERROR);
398            (SocketResult::Error, Some(PlainWriteFault::Io(e)))
399        }
400    }
401}
402
403/// Body of [`tcp_socket_write`], generic over the transport so tests can
404/// script what each write answers.
405///
406/// A write the kernel interrupted (`EINTR`) is retried at once, as
407/// [`flush_tls`] and std's `write_all` do: it says nothing about the socket,
408/// so it must neither end the write as `WouldBlock`, which no edge would
409/// follow, nor as `Error`, which closes the session. The retry counts against
410/// [`MAX_LOOP_ITERATIONS`] like every other pass of the loop.
411fn plain_socket_write<W: Write>(
412    stream: &mut W,
413    buf: &[u8],
414) -> (usize, SocketResult, Option<PlainWriteFault>) {
415    let mut size = 0usize;
416    let mut counter = 0;
417    loop {
418        counter += 1;
419        if counter > MAX_LOOP_ITERATIONS {
420            incr!(names::socket::WRITE_INFINITE_LOOP_ERROR);
421            return (size, SocketResult::Error, Some(PlainWriteFault::LoopLimit));
422        }
423        // Loop invariant: the cursor never overshoots the buffer, so the
424        // `&buf[size..]` slice below can never panic on a bad offset.
425        debug_assert!(
426            size <= buf.len(),
427            "write cursor {size} overran buffer len {} (would slice out of bounds)",
428            buf.len()
429        );
430        if size == buf.len() {
431            return (size, SocketResult::Continue, None);
432        }
433        match stream.write(&buf[size..]) {
434            Ok(0) => return (size, SocketResult::Continue, None),
435            Ok(sz) => {
436                // `write` cannot report more bytes than the slice it was given.
437                debug_assert!(
438                    sz <= buf.len() - size,
439                    "write reported {sz} bytes from a {}-byte remaining slice",
440                    buf.len() - size
441                );
442                size += sz;
443            }
444            Err(e) if e.kind() == ErrorKind::Interrupted => {}
445            Err(e) => {
446                let (result, fault) = plain_write_error(e);
447                return (size, result, fault);
448            }
449        }
450    }
451}
452
453/// Body of [`tcp_socket_write_vectored`], generic over the transport so tests
454/// can script what each write answers. One `writev(2)`, retried at once when
455/// the kernel interrupts it (`EINTR`), as [`plain_socket_write`] retries.
456fn plain_socket_write_vectored<W: Write>(
457    stream: &mut W,
458    bufs: &[std::io::IoSlice],
459) -> (usize, SocketResult, Option<PlainWriteFault>) {
460    let written = loop {
461        match stream.write_vectored(bufs) {
462            Err(e) if e.kind() == ErrorKind::Interrupted => continue,
463            written => break written,
464        }
465    };
466    match written {
467        Ok(sz) => {
468            // `write_vectored` cannot report more bytes than the slices held.
469            debug_assert!(
470                sz <= bufs.iter().map(|b| b.len()).sum::<usize>(),
471                "write_vectored reported {sz} bytes from {}-byte slices",
472                bufs.iter().map(|b| b.len()).sum::<usize>()
473            );
474            (sz, SocketResult::Continue, None)
475        }
476        Err(e) => {
477            let (result, fault) = plain_write_error(e);
478            (0, result, fault)
479        }
480    }
481}
482
483/// Log a [`PlainWriteFault`] with the socket context of [`tcp_socket_read`].
484fn log_plain_write_fault(
485    stream: &TcpStream,
486    session_ulid: Option<Ulid>,
487    configured_peer: Option<SocketAddr>,
488    fault: PlainWriteFault,
489) {
490    match fault {
491        PlainWriteFault::LoopLimit => error!(
492            "{} MAX_LOOP_ITERATION reached in TcpStream::socket_write",
493            log_socket_module_prefix(stream, session_ulid, configured_peer)
494        ),
495        PlainWriteFault::Io(e) => match e.kind() {
496            // Noisy-expected transport failures (see `tcp_socket_read` for
497            // rationale): `warn!`, the `tcp.write.error` counter still bumped
498            // so rate-based dashboards stay accurate.
499            ErrorKind::HostUnreachable
500            | ErrorKind::NetworkUnreachable
501            | ErrorKind::TimedOut
502            | ErrorKind::NotConnected => warn!(
503                "{} socket_write error={:?}",
504                log_socket_module_prefix(stream, session_ulid, configured_peer),
505                e
506            ),
507            //FIXME: timeout and other common errors should be sent up
508            _ => error!(
509                "{} socket_write error={:?}",
510                log_socket_module_prefix(stream, session_ulid, configured_peer),
511                e
512            ),
513        },
514    }
515}
516
517fn tcp_socket_write(
518    stream: &mut TcpStream,
519    buf: &[u8],
520    session_ulid: Option<Ulid>,
521    configured_peer: Option<SocketAddr>,
522) -> (usize, SocketResult) {
523    let (size, result, fault) = plain_socket_write(stream, buf);
524    if let Some(fault) = fault {
525        log_plain_write_fault(stream, session_ulid, configured_peer, fault);
526    }
527    (size, result)
528}
529
530fn tcp_socket_write_vectored(
531    stream: &mut TcpStream,
532    bufs: &[std::io::IoSlice],
533    session_ulid: Option<Ulid>,
534    configured_peer: Option<SocketAddr>,
535) -> (usize, SocketResult) {
536    let (size, result, fault) = plain_socket_write_vectored(stream, bufs);
537    if let Some(fault) = fault {
538        log_plain_write_fault(stream, session_ulid, configured_peer, fault);
539    }
540    (size, result)
541}
542
543impl SocketHandler for TcpStream {
544    fn socket_read(&mut self, buf: &mut [u8]) -> (usize, SocketResult) {
545        tcp_socket_read(self, buf, None, None)
546    }
547
548    fn socket_write(&mut self, buf: &[u8]) -> (usize, SocketResult) {
549        tcp_socket_write(self, buf, None, None)
550    }
551
552    fn socket_write_vectored(&mut self, bufs: &[std::io::IoSlice]) -> (usize, SocketResult) {
553        tcp_socket_write_vectored(self, bufs, None, None)
554    }
555
556    fn socket_ref(&self) -> &TcpStream {
557        self
558    }
559
560    fn socket_mut(&mut self) -> &mut TcpStream {
561        self
562    }
563
564    /// No context to cache: a bare stream is all there is, so this is the live
565    /// lookup and renders `None` once the peer has reset. Call sites that need
566    /// a surviving address use [`SessionTcpStream`] or [`FrontRustls`].
567    /// Fully-qualified so it reads as the inherent `mio` method, not a
568    /// recursive call into the trait method being defined.
569    fn peer_addr(&self) -> Option<SocketAddr> {
570        TcpStream::peer_addr(self).ok()
571    }
572
573    fn protocol(&self) -> TransportProtocol {
574        TransportProtocol::Tcp
575    }
576
577    fn read_error(&self) {
578        incr!(names::tcp::READ_ERROR);
579    }
580
581    fn write_error(&self) {
582        incr!(names::tcp::WRITE_ERROR);
583    }
584}
585
586/// [`TcpStream`] wrapped with the owning session's ULID. Exists so plain-TCP
587/// frontends and backends inside the mux stack can prefix SOCKET-layer error
588/// logs with `[<session_ulid> - - -]`, matching what TLS-wrapped frontends
589/// already do via [`FrontRustls::session_ulid`].
590///
591/// The inner [`TcpStream`] is exposed directly so mio registration sites can
592/// borrow it as-is; the outer type only participates in the [`SocketHandler`]
593/// trait dispatch.
594#[derive(Debug)]
595pub struct SessionTcpStream {
596    pub stream: TcpStream,
597    pub session_ulid: Ulid,
598    /// Peer address cached at construction. For backend-facing sockets
599    /// (created from a nonblocking `connect()` in `Mux::dial_backend`) this is
600    /// the cluster-configured backend address — reliable across ENOTCONN
601    /// after a failed handshake, which is the sharp case that motivates the
602    /// cache. For frontend-facing sockets constructed from an accepted
603    /// `TcpStream`, this is the client's peer address — identical to what a
604    /// live `getpeername(2)` would return, but threaded through the same
605    /// plumbing for uniformity. Used as the preferred source of truth for
606    /// the `peer=` slot in `log_socket_module_prefix`, falling back to a
607    /// live lookup when `None`.
608    pub configured_peer: Option<SocketAddr>,
609}
610
611impl SessionTcpStream {
612    pub fn new(stream: TcpStream, session_ulid: Ulid, configured_peer: Option<SocketAddr>) -> Self {
613        Self {
614            stream,
615            session_ulid,
616            configured_peer,
617        }
618    }
619}
620
621impl SocketHandler for SessionTcpStream {
622    fn socket_read(&mut self, buf: &mut [u8]) -> (usize, SocketResult) {
623        tcp_socket_read(
624            &mut self.stream,
625            buf,
626            Some(self.session_ulid),
627            self.configured_peer,
628        )
629    }
630
631    fn socket_write(&mut self, buf: &[u8]) -> (usize, SocketResult) {
632        tcp_socket_write(
633            &mut self.stream,
634            buf,
635            Some(self.session_ulid),
636            self.configured_peer,
637        )
638    }
639
640    fn socket_write_vectored(&mut self, bufs: &[std::io::IoSlice]) -> (usize, SocketResult) {
641        tcp_socket_write_vectored(
642            &mut self.stream,
643            bufs,
644            Some(self.session_ulid),
645            self.configured_peer,
646        )
647    }
648
649    fn socket_ref(&self) -> &TcpStream {
650        &self.stream
651    }
652
653    fn socket_mut(&mut self) -> &mut TcpStream {
654        &mut self.stream
655    }
656
657    /// Same preference order as `log_socket_module_prefix` (private, so not
658    /// linked), which this type's
659    /// I/O helpers already feed `configured_peer` into — one address for both
660    /// the `SOCKET` and `MUX-*` renderings of the same connection.
661    fn peer_addr(&self) -> Option<SocketAddr> {
662        self.configured_peer
663            .or_else(|| self.stream.peer_addr().ok())
664    }
665
666    fn protocol(&self) -> TransportProtocol {
667        TransportProtocol::Tcp
668    }
669
670    fn read_error(&self) {
671        incr!(names::tcp::READ_ERROR);
672    }
673
674    fn write_error(&self) {
675        incr!(names::tcp::WRITE_ERROR);
676    }
677
678    fn session_ulid(&self) -> Option<Ulid> {
679        Some(self.session_ulid)
680    }
681}
682
683pub struct FrontRustls {
684    pub stream: TcpStream,
685    pub session: ServerConnection,
686    /// Peer sent a graceful FIN on the read side (`read()` returned `Ok(0)`).
687    /// We can no longer receive plaintext, but may still have rustls-buffered
688    /// records to flush on the write side — do NOT abort pending writes.
689    pub peer_disconnected: bool,
690    /// The TCP channel is dead: the peer reset the connection
691    /// (RST/ConnectionAborted/BrokenPipe), or a write answered
692    /// [`SocketResult::Error`] — a socket error other than `WouldBlock`
693    /// (an `Interrupted` write is retried in `flush_tls` and never gets
694    /// here), a rustls writer failure, or the write loop's budget. Further
695    /// writes are pointless and short-circuit, and
696    /// [`SocketHandler::socket_wants_write`] stops reporting the records
697    /// rustls still holds: no write can deliver them, so they must neither
698    /// keep the session open nor wait for a WRITABLE edge that will not come.
699    pub peer_reset: bool,
700    /// `process_new_packets` failed on this connection: a corrupt record, a
701    /// fatal alert, a protocol violation. rustls keeps that error for good,
702    /// so from then on [`SocketHandler::socket_read`] answers `(0, Error)`
703    /// at once, without serving plaintext rustls decrypted before the
704    /// failure. See `rustls_socket_read`.
705    pub tls_fatal: bool,
706    /// Connection/session ULID propagated from the enclosing mux session.
707    /// Rendered into SOCKET-layer error logs via [`Self::session_ulid`].
708    pub session_ulid: Ulid,
709    /// Peer address snapshot, same role as [`SessionTcpStream::configured_peer`]
710    /// and same name so the two handlers read alike. Seeded from
711    /// `HttpsSession::peer_address`, which is the PROXY-advertised source on an
712    /// expect-proxy frontend and the accepted socket's peer otherwise — NOT
713    /// from `stream.peer_addr()`, which would be the load balancer in the first
714    /// case and would die with `ENOTCONN` in both. Read through
715    /// [`SocketHandler::peer_addr`].
716    pub configured_peer: Option<SocketAddr>,
717    /// What the read path may assume about `stream`'s receive queue from one
718    /// [`SocketHandler::socket_read`] call to the next. See [`RecvMemory`].
719    pub recv_memory: RecvMemory,
720}
721
722impl FrontRustls {
723    /// Record that the event loop delivered `events` for `stream`: whatever a
724    /// `recv` proved before, bytes may have arrived since. The HTTPS session
725    /// calls it for every event on its frontend token, whatever its state
726    /// (`HttpsSession::update_readiness`, `lib/src/https.rs`), which is the
727    /// only way events reach a session (`Server::ready`, `lib/src/server.rs`).
728    pub fn readiness_delivered(&mut self, events: Ready) {
729        self.recv_memory.event_delivered(events);
730    }
731}
732
733/// What `rustls_socket_read` may assume about the receive queue between two
734/// calls.
735///
736/// The H2 read path makes one call per frame header and one per payload
737/// (`lib/src/protocol/mux/h2.rs`, `readable_inner`), so the frames of one
738/// record are served by several calls: the first one's `recv` is short, the
739/// rest come from rustls's plaintext buffer. Without a memory, the call that
740/// finds that buffer empty issued one more `recv`, which could only answer
741/// EAGAIN — once per request on a multiplexed connection (#1609).
742///
743/// `drained` carries the proof across calls, and is safe for as long as no
744/// readiness event has been delivered since it was set. mio registers every
745/// socket edge-triggered (`mio/src/sys/unix/selector/epoll.rs`, `EPOLLET`),
746/// and "an event will be generated upon each receipt of a chunk of data"
747/// (`man 7 epoll`), so a byte that arrives after the proof either raises an
748/// event still pending in epoll — the next `epoll_wait` delivers it and
749/// re-arms READABLE — or one already delivered, which cleared `drained`. A
750/// delivery that lands while the mux still holds READABLE changes nothing the
751/// mux can see, which is why the memory is cleared at delivery rather than
752/// inferred from READABLE.
753///
754/// `hup_seen` turns the memory off for good once HUP or ERROR is delivered.
755/// A FIN that arrived with the data raised its edge already, and no later
756/// event will announce the EOF behind a short read; the mux keeps READABLE
757/// for it (`update_readiness_after_read`), and the next call must read it.
758///
759/// The TCP urgent data reserve of `plain_socket_read` applies unchanged: a
760/// `recv` stopped short by an urgent mark proves nothing, and the stream
761/// stalls until the peer's next send, as it does within a call since #1606.
762#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
763pub struct RecvMemory {
764    /// A `recv` answered short or EAGAIN, and no event has been delivered
765    /// since.
766    drained: bool,
767    /// HUP or ERROR has been delivered.
768    hup_seen: bool,
769}
770
771impl RecvMemory {
772    /// The memory a session starts with once its handshake is over. `drained`
773    /// is what the handshake proved: a `recv` that answered short or EAGAIN
774    /// dropped READABLE from its event, and only a delivered event with
775    /// READABLE put it back (`handshake_read`, `lib/src/protocol/rustls.rs`).
776    /// A handshake closes on HUP or ERROR, so none was seen.
777    pub fn after_handshake(drained: bool) -> Self {
778        RecvMemory {
779            drained,
780            hup_seen: false,
781        }
782    }
783
784    fn event_delivered(&mut self, events: Ready) {
785        self.drained = false;
786        if events.is_hup() || events.is_error() {
787            self.hup_seen = true;
788        }
789    }
790}
791
792/// One `write_tls` of `session` into `stream`: at most one `writev(2)`, and
793/// none when rustls holds no record (`ChunkVecBuffer::write_to` returns
794/// `Ok(0)` before touching the socket, `rustls-0.23.45/src/vecbuf.rs`).
795///
796/// Every `FrontRustls` write goes through here so tests can count the writes
797/// that reach the socket ([`tls_writes`]).
798///
799/// It is also the one place a TLS frontend's write can observe a peer reset,
800/// so `rustls.write.reset` is counted here rather than at each caller's
801/// error arm (sozu-proxy/sozu#434); the callers' `peer_reset` then stops
802/// every later write before it reaches the socket, so a reset counts once.
803/// The callers still count it under `rustls.write.error` as well.
804///
805/// A write the kernel interrupted (`EINTR`) is retried at once, as the
806/// relay (`lib/src/protocol/proxy_protocol/relay.rs`), the UDP path
807/// (`lib/src/udp.rs`) and the plain TCP paths ([`plain_socket_read`],
808/// [`plain_socket_write`], [`plain_socket_write_vectored`]) do: it says
809/// nothing about the socket, so it must
810/// neither end the write as `WouldBlock`, which no edge would follow, nor
811/// as `Error`, which marks the channel dead.
812fn flush_tls(
813    session: &mut ServerConnection,
814    stream: &mut impl std::io::Write,
815) -> std::io::Result<usize> {
816    #[cfg(test)]
817    if session.wants_write() {
818        TLS_WRITES.with(|writes| writes.set(writes.get() + 1));
819    }
820    let written = loop {
821        match session.write_tls(stream) {
822            Err(e) if e.kind() == ErrorKind::Interrupted => continue,
823            written => break written,
824        }
825    };
826    if let Err(e) = &written
827        && matches!(
828            e.kind(),
829            ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted
830        )
831    {
832        incr!(names::rustls::WRITE_RESET);
833    }
834    written
835}
836
837#[cfg(test)]
838thread_local! {
839    static TLS_WRITES: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
840}
841
842/// How many `write_tls` calls holding at least one record the calling thread
843/// has issued through [`flush_tls`] so far.
844#[cfg(test)]
845pub(crate) fn tls_writes() -> usize {
846    TLS_WRITES.with(std::cell::Cell::get)
847}
848
849impl std::fmt::Debug for FrontRustls {
850    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
851        f.debug_struct("FrontRustls")
852            .field("stream", &self.stream)
853            .finish_non_exhaustive()
854    }
855}
856
857/// A failure [`rustls_socket_read`] hit, handed back rather than logged so the
858/// caller can render it with its full socket context: the helper borrows the
859/// stream mutably for the whole pass, which is exactly what
860/// `log_socket_context!` needs to read.
861#[derive(Debug)]
862enum RustlsReadFault {
863    /// The pass ran [`MAX_LOOP_ITERATIONS`] times without settling.
864    LoopLimit,
865    /// `read_tls` failed with something other than `WouldBlock`, a reset, an
866    /// interruption (retried), or rustls's own "plaintext buffer full".
867    ReadTls(std::io::Error),
868    /// `process_new_packets` rejected what `read_tls` delivered.
869    ProcessPackets(rustls::Error),
870    /// The plaintext reader failed with something other than `WouldBlock` or
871    /// a reset.
872    Plaintext(std::io::Error),
873}
874
875/// A [`Read`] adapter that records whether its last read returned fewer bytes
876/// than it was offered.
877///
878/// `ServerConnection::read_tls` issues exactly one `read` into its deframer
879/// buffer (`rustls-0.23.45/src/msgs/deframer/buffers.rs:208`) and returns only
880/// the byte count, not the length it offered, so a short read is invisible
881/// from its return value. An `Ok(0)` is EOF, not a short read, and an error is
882/// neither.
883///
884/// Two callers wrap `read_tls` in it: [`rustls_socket_read`] once the session
885/// is established, and `handshake_read` (`lib/src/protocol/rustls.rs`) while
886/// the handshake runs.
887pub(crate) struct ShortReadProbe<'a, R> {
888    inner: &'a mut R,
889    short: bool,
890}
891
892impl<'a, R> ShortReadProbe<'a, R> {
893    pub(crate) fn new(inner: &'a mut R) -> Self {
894        ShortReadProbe {
895            inner,
896            short: false,
897        }
898    }
899
900    /// Whether the last read answered fewer bytes than it was offered, which
901    /// on a stream socket proves its receive queue empty (see
902    /// [`plain_socket_read`] for the one exception, TCP urgent data).
903    pub(crate) fn was_short(&self) -> bool {
904        self.short
905    }
906}
907
908impl<R: Read> Read for ShortReadProbe<'_, R> {
909    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
910        let read = self.inner.read(buf)?;
911        self.short = 0 < read && read < buf.len();
912        Ok(read)
913    }
914}
915
916/// Body of [`FrontRustls::socket_read`], generic over the transport so tests
917/// can count every read the pass issues against it.
918///
919/// Each pass drains the plaintext rustls already decrypted, and only then —
920/// if the caller's buffer is still not full — calls `read_tls` (one `recv(2)`)
921/// and `process_new_packets`. That order is what tokio-rustls follows
922/// (`tokio-rustls-0.26.4/src/common/mod.rs:198-212`: `read_tls` only while
923/// `wants_read()`, then the plaintext), and what OpenSSL gives HAProxy for
924/// free: `SSL_read` serves an already-decrypted record without touching the
925/// socket.
926///
927/// Readiness contract, unchanged by that order:
928///
929/// - every `recv` that answers EAGAIN ends the call with
930///   [`SocketResult::WouldBlock`], because the drain ran first and so the
931///   buffer is not full; the mux then drops READABLE until the next mio
932///   event (`update_readiness`), which is the edge-triggered re-arm;
933/// - so does a `read_tls` whose `recv` answered fewer bytes than rustls
934///   offered (4096, `rustls-0.23.45/src/msgs/deframer/buffers.rs:220`): the
935///   receive queue is empty, as for [`plain_socket_read`], so the pass makes
936///   no second `recv` that could only answer EAGAIN. It still processes what
937///   arrived and drains the plaintext, and answers `WouldBlock` only when
938///   the buffer is still not full, and `Closed` when that arrival carried
939///   `close_notify`. [`ShortReadProbe`] sees the offered length, which
940///   `read_tls` does not return;
941/// - [`SocketResult::Continue`] with a full buffer means "more may be
942///   buffered", so READABLE stays and the next call drains before it reads;
943/// - a `read_tls` that fills what rustls offered but completes no record
944///   produces no plaintext, so the pass loops and reads again until a short
945///   read, EAGAIN, EOF or a full buffer;
946/// - one record can hold several H2 frames: the later calls are served from
947///   the plaintext buffer without a `recv`, and the call that empties that
948///   buffer makes no `recv` either when an earlier call's `recv` answered
949///   short or EAGAIN and no readiness event was delivered since: `memory`
950///   carries that proof ([`RecvMemory`]), so the call answers `WouldBlock`
951///   without touching the socket. Once HUP or ERROR has been delivered the
952///   memory is off, and a call that finds the plaintext empty reads.
953///
954/// [`SocketResult::Error`] from `process_new_packets` is sticky: the failing
955/// pass still reports the plaintext it had already copied into `buf` before
956/// reaching `read_tls` (a `(n, Error)` return), but it sets `tls_fatal`, and
957/// every later pass answers `(0, Error)` without draining anything rustls
958/// decrypted before the failure.
959///
960/// EOF and `close_notify` are reported as [`SocketResult::Closed`] by the
961/// first call that finds no plaintext left to deliver, never behind it: a
962/// peer's last frames are handed over before the close. A call the buffered
963/// plaintext can satisfy completely returns `Continue` without looking at
964/// the socket, so a FIN that is already queued is seen one call later than
965/// when every call began with `read_tls`. A TCP FIN queued behind a short
966/// read is likewise seen by the next call, which the mux makes once it has
967/// seen HUP (`update_readiness_after_read`), and which reads because that HUP
968/// turned the memory off.
969fn rustls_socket_read<R: Read>(
970    session: &mut ServerConnection,
971    stream: &mut R,
972    buf: &mut [u8],
973    peer_disconnected: &mut bool,
974    peer_reset: &mut bool,
975    tls_fatal: &mut bool,
976    memory: &mut RecvMemory,
977) -> (usize, SocketResult, Option<RustlsReadFault>) {
978    // `Error` is sticky. Once `process_new_packets` has failed, plaintext it
979    // appended from records that preceded the bad one may still sit in the
980    // reader; serving it would hand the mux frames from a session that is
981    // already dead, and the mux only drops READABLE on `Error`, so the next
982    // peer bytes would be parsed. The failure was logged on the pass that
983    // hit it; later passes answer silently.
984    if *tls_fatal {
985        return (0, SocketResult::Error, None);
986    }
987    let mut size = 0usize;
988    let mut can_read = true;
989    // Seeded from the memory: a `recv` in an earlier call may already have
990    // proved the queue empty, with no event delivered since.
991    let mut drained = memory.drained && !memory.hup_seen;
992    let mut is_error = false;
993    let mut is_closed = false;
994    let mut fault = None;
995
996    let mut counter = 0;
997    loop {
998        counter += 1;
999        if counter > MAX_LOOP_ITERATIONS {
1000            fault = Some(RustlsReadFault::LoopLimit);
1001            is_error = true;
1002            break;
1003        }
1004
1005        // Plaintext first: rustls may already hold decrypted bytes from a
1006        // record an earlier call read — under H2, which asks for one 9-byte
1007        // frame header and then one payload at a time, the rest of that
1008        // record's frames. Serving them before `read_tls` is what keeps a
1009        // call the buffer can satisfy from issuing a `recv(2)` that can only
1010        // answer EAGAIN. `wants_read()` is false exactly while plaintext is
1011        // pending or `close_notify` has been received
1012        // (rustls-0.23.45/src/common_state.rs:674-684); in the second case the
1013        // reader answers `Ok(0)` and the `read_tls` below reports it.
1014        while !session.wants_read() {
1015            match session.reader().read(&mut buf[size..]) {
1016                Ok(0) => break,
1017                Ok(sz) => {
1018                    // The rustls reader cannot return more plaintext than
1019                    // the remaining slice it was handed.
1020                    debug_assert!(
1021                        sz <= buf.len() - size,
1022                        "rustls reader returned {sz} bytes into a {}-byte remaining slice",
1023                        buf.len() - size
1024                    );
1025                    size += sz;
1026                }
1027                Err(e) => match e.kind() {
1028                    ErrorKind::WouldBlock => {
1029                        break;
1030                    }
1031                    ErrorKind::ConnectionReset
1032                    | ErrorKind::ConnectionAborted
1033                    | ErrorKind::BrokenPipe => {
1034                        is_closed = true;
1035                        break;
1036                    }
1037                    _ => {
1038                        fault = Some(RustlsReadFault::Plaintext(e));
1039                        is_error = true;
1040                        break;
1041                    }
1042                },
1043            }
1044        }
1045
1046        // Loop invariant: the plaintext cursor never overshoots the caller's
1047        // buffer, so the next pass's `&mut buf[size..]` is a valid slice.
1048        debug_assert!(
1049            size <= buf.len(),
1050            "rustls read cursor {size} overran buffer len {} (would slice out of bounds)",
1051            buf.len()
1052        );
1053        if size == buf.len() {
1054            break;
1055        }
1056
1057        if !can_read | is_error | is_closed {
1058            break;
1059        }
1060
1061        // A short or EAGAIN `recv` earlier in this pass — or in an earlier
1062        // call, with no event delivered since (`RecvMemory`) — emptied the
1063        // receive queue, so a `read_tls` that would `recv` again can only
1064        // answer EAGAIN. One that
1065        // would not — `close_notify` received, which is exactly when
1066        // `wants_read()` is false with the plaintext drained — still runs:
1067        // it answers `Ok(0)` without touching the socket
1068        // (rustls-0.23.45/src/conn.rs:768-770) and reports the close.
1069        if drained && session.wants_read() {
1070            can_read = false;
1071            break;
1072        }
1073
1074        // rustls hands an interrupted `recv` (`EINTR`) back from `read_tls`
1075        // (only its `complete_io` retries it), and it says nothing about the
1076        // socket, so it is retried at once, as [`plain_socket_read`] does. The
1077        // probe only records a successful read, so the retry leaves
1078        // `was_short` exact.
1079        let mut probe = ShortReadProbe::new(&mut *stream);
1080        let read = loop {
1081            match session.read_tls(&mut probe) {
1082                Err(e) if e.kind() == ErrorKind::Interrupted => continue,
1083                read => break read,
1084            }
1085        };
1086        drained |= probe.was_short();
1087        match read {
1088            Ok(0) => {
1089                // Graceful FIN on the read side: peer closed its write
1090                // half. Keep `peer_reset` unset so outbound writes can
1091                // still flush rustls's buffered records (half-close).
1092                can_read = false;
1093                is_closed = true;
1094                *peer_disconnected = true;
1095            }
1096            Ok(_sz) => {}
1097            Err(e) => match e.kind() {
1098                ErrorKind::WouldBlock => {
1099                    can_read = false;
1100                    drained = true;
1101                }
1102                ErrorKind::ConnectionReset
1103                | ErrorKind::ConnectionAborted
1104                | ErrorKind::BrokenPipe => {
1105                    // Full RST/abort: the TCP channel is dead. Mark
1106                    // `peer_reset` so writes short-circuit (nothing can
1107                    // reach the peer anymore) but still set
1108                    // `peer_disconnected` for back-compatible read-side
1109                    // logic.
1110                    //
1111                    // The reset is counted here, the only arm that reads the
1112                    // socket, and once: `peer_reset` stops every later write
1113                    // before it reaches the socket (sozu-proxy/sozu#434).
1114                    // `EPIPE` is not a reset this `recv` observed.
1115                    if e.kind() != ErrorKind::BrokenPipe {
1116                        incr!(names::rustls::READ_RESET);
1117                    }
1118                    is_closed = true;
1119                    *peer_disconnected = true;
1120                    *peer_reset = true;
1121                }
1122                // rustls-0.23.45/src/conn.rs:761-766: rustls's 16 KB
1123                // received_plaintext buffer is full. The drain above empties
1124                // it before every `read_tls` unless the caller's buffer
1125                // filled first, which breaks out before reaching here, so
1126                // this arm is defensive; the next pass drains again.
1127                ErrorKind::Other => {}
1128                _ => {
1129                    fault = Some(RustlsReadFault::ReadTls(e));
1130                    is_error = true;
1131                    break;
1132                }
1133            },
1134        }
1135
1136        if let Err(e) = session.process_new_packets() {
1137            fault = Some(RustlsReadFault::ProcessPackets(e));
1138            *tls_fatal = true;
1139            is_error = true;
1140            break;
1141        }
1142    }
1143
1144    // Post-condition: we never report more plaintext than the caller asked
1145    // for, and Error/Closed are mutually exclusive (the loop `break`s on the
1146    // first one set, so both can never be true on the same pass).
1147    debug_assert!(
1148        size <= buf.len(),
1149        "rustls socket_read returned {size} bytes for a {}-byte buffer",
1150        buf.len()
1151    );
1152    debug_assert!(
1153        !(is_error && is_closed),
1154        "rustls socket_read cannot be both Error and Closed"
1155    );
1156    // Carried to the next call; `FrontRustls::readiness_delivered` clears it.
1157    memory.drained = drained;
1158    let result = if is_error {
1159        SocketResult::Error
1160    } else if is_closed {
1161        SocketResult::Closed
1162    } else if size == buf.len() {
1163        // The full requested amount was read (possibly from the rustls
1164        // plaintext buffer). Report Continue so the caller keeps
1165        // READABLE in the readiness set — there may be more decrypted
1166        // data available without a new mio event.
1167        SocketResult::Continue
1168    } else if !can_read {
1169        SocketResult::WouldBlock
1170    } else {
1171        SocketResult::Continue
1172    };
1173    (size, result, fault)
1174}
1175
1176impl SocketHandler for FrontRustls {
1177    fn socket_read(&mut self, buf: &mut [u8]) -> (usize, SocketResult) {
1178        let (size, result, fault) = rustls_socket_read(
1179            &mut self.session,
1180            &mut self.stream,
1181            buf,
1182            &mut self.peer_disconnected,
1183            &mut self.peer_reset,
1184            &mut self.tls_fatal,
1185            &mut self.recv_memory,
1186        );
1187        match fault {
1188            None => {}
1189            Some(RustlsReadFault::LoopLimit) => {
1190                error!(
1191                    "{} MAX_LOOP_ITERATION reached in FrontRustls::socket_read",
1192                    log_socket_context!(self)
1193                );
1194                incr!(names::rustls::READ_INFINITE_LOOP_ERROR);
1195            }
1196            Some(RustlsReadFault::ReadTls(e)) => error!(
1197                "{} could not read TLS stream from socket: {:?}",
1198                log_socket_context!(self),
1199                e
1200            ),
1201            Some(RustlsReadFault::ProcessPackets(e)) => error!(
1202                "{} could not process read TLS packets: {:?}",
1203                log_socket_context!(self),
1204                e
1205            ),
1206            Some(RustlsReadFault::Plaintext(e)) => error!(
1207                "{} could not read data from TLS stream: {:?}",
1208                log_socket_context!(self),
1209                e
1210            ),
1211        }
1212        (size, result)
1213    }
1214
1215    /// Keep these two functions structurally symmetric — a divergence
1216    /// caused the 4.5 MB H2 truncation bug. Tests
1217    /// `e2e::tests::h2_correctness_tests::*` and
1218    /// `e2e::tests::h2_tests::test_h2_large_*` are the regression guard.
1219    fn socket_write(&mut self, buf: &[u8]) -> (usize, SocketResult) {
1220        // Abort only on a true RST — a FIN on the read side still permits
1221        // flushing rustls's plaintext buffer (TLS half-close).
1222        if self.peer_reset {
1223            return (0, SocketResult::Closed);
1224        }
1225
1226        let mut buffered_size = 0usize;
1227        let mut can_write = true;
1228        let mut is_error = false;
1229        let mut is_closed = false;
1230
1231        let mut counter = 0;
1232        loop {
1233            counter += 1;
1234            if counter > MAX_LOOP_ITERATIONS {
1235                error!(
1236                    "{} MAX_LOOP_ITERATION reached in FrontRustls::socket_write",
1237                    log_socket_context!(self)
1238                );
1239                incr!(names::rustls::WRITE_INFINITE_LOOP_ERROR);
1240                is_error = true;
1241                break;
1242            }
1243            // Loop invariant: the absorbed-plaintext cursor never overshoots the
1244            // caller's buffer, so `&buf[buffered_size..]` is always a valid slice.
1245            debug_assert!(
1246                buffered_size <= buf.len(),
1247                "rustls write cursor {buffered_size} overran buffer len {} (would slice out of bounds)",
1248                buf.len()
1249            );
1250            if buffered_size == buf.len() {
1251                break;
1252            }
1253
1254            if !can_write | is_error | is_closed {
1255                break;
1256            }
1257
1258            match self.session.writer().write(&buf[buffered_size..]) {
1259                Ok(0) => {} // zero byte written means that the Rustls buffers are full, we will try to write on the socket and try again
1260                Ok(sz) => {
1261                    // rustls cannot absorb more plaintext than the remaining slice.
1262                    debug_assert!(
1263                        sz <= buf.len() - buffered_size,
1264                        "rustls writer absorbed {sz} bytes from a {}-byte remaining slice",
1265                        buf.len() - buffered_size
1266                    );
1267                    buffered_size += sz;
1268                }
1269                Err(e) => match e.kind() {
1270                    ErrorKind::WouldBlock => {
1271                        // we don't need to do anything, the session will return false in wants_write?
1272                        //error!("rustls socket_write wouldblock");
1273                    }
1274                    ErrorKind::ConnectionReset
1275                    | ErrorKind::ConnectionAborted
1276                    | ErrorKind::BrokenPipe => {
1277                        //FIXME: this should probably not happen here
1278                        incr!(names::rustls::WRITE_ERROR);
1279                        is_closed = true;
1280                        self.peer_reset = true;
1281                        break;
1282                    }
1283                    _ => {
1284                        error!(
1285                            "{} could not write data to TLS stream: {:?}",
1286                            log_socket_context!(self),
1287                            e
1288                        );
1289                        incr!(names::rustls::WRITE_ERROR);
1290                        is_error = true;
1291                        break;
1292                    }
1293                },
1294            }
1295
1296            loop {
1297                match flush_tls(&mut self.session, &mut self.stream) {
1298                    Ok(0) => {
1299                        //can_write = false;
1300                        break;
1301                    }
1302                    Ok(_sz) => {}
1303                    Err(e) => match e.kind() {
1304                        ErrorKind::WouldBlock => {
1305                            can_write = false;
1306                            break;
1307                        }
1308                        ErrorKind::ConnectionReset
1309                        | ErrorKind::ConnectionAborted
1310                        | ErrorKind::BrokenPipe => {
1311                            incr!(names::rustls::WRITE_ERROR);
1312                            is_closed = true;
1313                            self.peer_reset = true;
1314                            break;
1315                        }
1316                        _ => {
1317                            error!(
1318                                "{} could not write TLS stream to socket: {:?}",
1319                                log_socket_context!(self),
1320                                e
1321                            );
1322                            incr!(names::rustls::WRITE_ERROR);
1323                            is_error = true;
1324                            break;
1325                        }
1326                    },
1327                }
1328            }
1329        }
1330
1331        // Flush any pending TLS records even if no application data was written.
1332        // This handles the case where h2.rs calls socket_write(&[]) to flush
1333        // buffered TLS data (e.g. NewSessionTicket, key updates). Without this,
1334        // the main loop above exits immediately for empty buffers and write_tls
1335        // is never called.
1336        if !is_error && !is_closed && can_write && self.session.wants_write() {
1337            loop {
1338                match flush_tls(&mut self.session, &mut self.stream) {
1339                    Ok(0) => break,
1340                    Ok(_) => {}
1341                    Err(e) => match e.kind() {
1342                        ErrorKind::WouldBlock => {
1343                            can_write = false;
1344                            break;
1345                        }
1346                        ErrorKind::ConnectionReset
1347                        | ErrorKind::ConnectionAborted
1348                        | ErrorKind::BrokenPipe => {
1349                            incr!(names::rustls::WRITE_ERROR);
1350                            is_closed = true;
1351                            self.peer_reset = true;
1352                            break;
1353                        }
1354                        _ => {
1355                            error!(
1356                                "{} could not flush TLS stream to socket: {:?}",
1357                                log_socket_context!(self),
1358                                e
1359                            );
1360                            incr!(names::rustls::WRITE_ERROR);
1361                            is_error = true;
1362                            break;
1363                        }
1364                    },
1365                }
1366            }
1367        }
1368
1369        // Post-condition: we never report absorbing more plaintext than the
1370        // caller handed us — over-reporting is exactly the truncation-class bug
1371        // these two symmetric paths exist to avoid.
1372        debug_assert!(
1373            buffered_size <= buf.len(),
1374            "rustls socket_write reported {buffered_size} bytes for a {}-byte buffer",
1375            buf.len()
1376        );
1377        debug_assert!(
1378            !(is_error && is_closed),
1379            "rustls socket_write cannot be both Error and Closed"
1380        );
1381        if is_error {
1382            // Whatever failed — the socket, rustls, or the loop budget — no
1383            // later write can deliver what rustls holds: see `peer_reset`.
1384            self.peer_reset = true;
1385            (buffered_size, SocketResult::Error)
1386        } else if is_closed {
1387            (buffered_size, SocketResult::Closed)
1388        } else if !can_write {
1389            (buffered_size, SocketResult::WouldBlock)
1390        } else {
1391            (buffered_size, SocketResult::Continue)
1392        }
1393    }
1394
1395    /// Write a list of plaintext slices through the rustls session.
1396    ///
1397    /// Empty-buffer invariant: callers may legitimately pass `bufs.is_empty()`
1398    /// or an all-empty slice to request a pure flush pass. In that case
1399    /// `total_len == 0`, the top-of-loop `buffered_size == total_len` guard
1400    /// fires immediately after `write_tls` drains any pending TLS records the
1401    /// session still has buffered (e.g. the remainder of a record split by
1402    /// the previous call, or `close_notify` output). This mirrors
1403    /// [`Self::socket_write`]: both entry points must stay structurally
1404    /// symmetric so that a zero-byte flush never early-returns without giving
1405    /// rustls a chance to emit bytes.
1406    ///
1407    /// Keep these two functions structurally symmetric — a divergence
1408    /// caused the 4.5 MB H2 truncation bug. Tests
1409    /// `e2e::tests::h2_correctness_tests::*` and
1410    /// `e2e::tests::h2_tests::test_h2_large_*` are the regression guard.
1411    fn socket_write_vectored(&mut self, bufs: &[std::io::IoSlice]) -> (usize, SocketResult) {
1412        if self.peer_reset {
1413            return (0, SocketResult::Closed);
1414        }
1415
1416        let total_len: usize = bufs.iter().map(|b| b.len()).sum();
1417        let mut buffered_size = 0usize;
1418        let mut can_write = true;
1419        let mut is_error = false;
1420        let mut is_closed = false;
1421
1422        let mut counter = 0;
1423        loop {
1424            counter += 1;
1425            if counter > MAX_LOOP_ITERATIONS {
1426                error!(
1427                    "{} MAX_LOOP_ITERATION reached in FrontRustls::socket_write_vectored",
1428                    log_socket_context!(self)
1429                );
1430                incr!(names::rustls::WRITE_INFINITE_LOOP_ERROR);
1431                is_error = true;
1432                break;
1433            }
1434            // Loop invariant: the absorbed-plaintext cursor never overshoots the
1435            // summed slice length we computed up front (mirrors the scalar path).
1436            debug_assert!(
1437                buffered_size <= total_len,
1438                "rustls vectored write cursor {buffered_size} overran total slice len {total_len}"
1439            );
1440            if buffered_size == total_len {
1441                break;
1442            }
1443
1444            if !can_write | is_error | is_closed {
1445                break;
1446            }
1447
1448            // rustls's Writer does not expose a "write from offset across slices"
1449            // helper, so we push plaintext once and then drain via write_tls.
1450            // If rustls only partially absorbs the slices, we break and return
1451            // the partial count so the caller can advance its buffers and retry.
1452            if buffered_size == 0 {
1453                match self.session.writer().write_vectored(bufs) {
1454                    Ok(0) => {}
1455                    Ok(sz) => {
1456                        // rustls cannot absorb more plaintext than the slices held.
1457                        debug_assert!(
1458                            sz <= total_len,
1459                            "rustls writer absorbed {sz} bytes from {total_len}-byte slices"
1460                        );
1461                        buffered_size += sz;
1462                    }
1463                    Err(e) => match e.kind() {
1464                        ErrorKind::WouldBlock => {}
1465                        ErrorKind::ConnectionReset
1466                        | ErrorKind::ConnectionAborted
1467                        | ErrorKind::BrokenPipe => {
1468                            incr!(names::rustls::WRITE_ERROR);
1469                            is_closed = true;
1470                            self.peer_reset = true;
1471                            break;
1472                        }
1473                        _ => {
1474                            error!(
1475                                "{} could not write data to TLS stream: {:?}",
1476                                log_socket_context!(self),
1477                                e
1478                            );
1479                            incr!(names::rustls::WRITE_ERROR);
1480                            is_error = true;
1481                            break;
1482                        }
1483                    },
1484                }
1485            }
1486
1487            // Plaintext was partially absorbed — we cannot re-call write_vectored
1488            // because the IoSlice pointers have not been advanced. Drain whatever
1489            // rustls buffered to the socket, then return the partial count so the
1490            // caller can consume and retry with adjusted slices.
1491            if buffered_size > 0 && buffered_size < total_len {
1492                loop {
1493                    match flush_tls(&mut self.session, &mut self.stream) {
1494                        Ok(0) => break,
1495                        Ok(_) => {}
1496                        Err(e) => match e.kind() {
1497                            ErrorKind::WouldBlock => {
1498                                can_write = false;
1499                                break;
1500                            }
1501                            ErrorKind::ConnectionReset
1502                            | ErrorKind::ConnectionAborted
1503                            | ErrorKind::BrokenPipe => {
1504                                incr!(names::rustls::WRITE_ERROR);
1505                                is_closed = true;
1506                                self.peer_reset = true;
1507                                break;
1508                            }
1509                            _ => {
1510                                error!(
1511                                    "{} could not write TLS stream to socket: {:?}",
1512                                    log_socket_context!(self),
1513                                    e
1514                                );
1515                                incr!(names::rustls::WRITE_ERROR);
1516                                is_error = true;
1517                                break;
1518                            }
1519                        },
1520                    }
1521                }
1522                break;
1523            }
1524
1525            loop {
1526                match flush_tls(&mut self.session, &mut self.stream) {
1527                    Ok(0) => {
1528                        break;
1529                    }
1530                    Ok(_sz) => {}
1531                    Err(e) => match e.kind() {
1532                        ErrorKind::WouldBlock => {
1533                            can_write = false;
1534                            break;
1535                        }
1536                        ErrorKind::ConnectionReset
1537                        | ErrorKind::ConnectionAborted
1538                        | ErrorKind::BrokenPipe => {
1539                            incr!(names::rustls::WRITE_ERROR);
1540                            is_closed = true;
1541                            self.peer_reset = true;
1542                            break;
1543                        }
1544                        _ => {
1545                            error!(
1546                                "{} could not write TLS stream to socket: {:?}",
1547                                log_socket_context!(self),
1548                                e
1549                            );
1550                            incr!(names::rustls::WRITE_ERROR);
1551                            is_error = true;
1552                            break;
1553                        }
1554                    },
1555                }
1556            }
1557        }
1558
1559        if !is_error && !is_closed && can_write && self.session.wants_write() {
1560            loop {
1561                match flush_tls(&mut self.session, &mut self.stream) {
1562                    Ok(0) => break,
1563                    Ok(_) => {}
1564                    Err(e) => match e.kind() {
1565                        ErrorKind::WouldBlock => {
1566                            can_write = false;
1567                            break;
1568                        }
1569                        ErrorKind::ConnectionReset
1570                        | ErrorKind::ConnectionAborted
1571                        | ErrorKind::BrokenPipe => {
1572                            incr!(names::rustls::WRITE_ERROR);
1573                            is_closed = true;
1574                            self.peer_reset = true;
1575                            break;
1576                        }
1577                        _ => {
1578                            error!(
1579                                "{} could not flush TLS stream to socket: {:?}",
1580                                log_socket_context!(self),
1581                                e
1582                            );
1583                            incr!(names::rustls::WRITE_ERROR);
1584                            is_error = true;
1585                            break;
1586                        }
1587                    },
1588                }
1589            }
1590        }
1591
1592        // Post-condition: report no more than the summed slice length, and keep
1593        // Error/Closed mutually exclusive — must stay structurally symmetric with
1594        // `socket_write` (divergence here is the 4.5 MB truncation-class bug).
1595        debug_assert!(
1596            buffered_size <= total_len,
1597            "rustls socket_write_vectored reported {buffered_size} bytes for {total_len}-byte slices"
1598        );
1599        debug_assert!(
1600            !(is_error && is_closed),
1601            "rustls socket_write_vectored cannot be both Error and Closed"
1602        );
1603        if is_error {
1604            // Same as `socket_write`: an `Error` always marks the channel dead.
1605            self.peer_reset = true;
1606            (buffered_size, SocketResult::Error)
1607        } else if is_closed {
1608            (buffered_size, SocketResult::Closed)
1609        } else if !can_write {
1610            (buffered_size, SocketResult::WouldBlock)
1611        } else {
1612            (buffered_size, SocketResult::Continue)
1613        }
1614    }
1615
1616    fn socket_close(&mut self) {
1617        self.session.send_close_notify();
1618    }
1619
1620    /// Queue `buf` and the `close_notify` behind it, then flush both with one
1621    /// `write_tls`, which hands every pending record to one `write_vectored`
1622    /// (`rustls-0.23.45/src/vecbuf.rs`, `ChunkVecBuffer::write_to`).
1623    ///
1624    /// The plaintext must be queued first: rustls encrypts it into the send
1625    /// buffer at once (the handshake is over on every connection the mux
1626    /// drives), and the alert queued after it is the next record on the wire,
1627    /// so the peer reads the bytes and then the close. The other order would
1628    /// end the peer's reading before the bytes.
1629    ///
1630    /// When rustls does not take all of `buf` (its send buffer is full) the
1631    /// alert is not queued, as the trait requires, and the caller's next call
1632    /// carries the rest. A write error falls back to [`Self::socket_write`],
1633    /// which reports it with the socket context.
1634    fn socket_write_then_close(&mut self, buf: &[u8]) -> (usize, SocketResult) {
1635        if self.peer_reset {
1636            return (0, SocketResult::Closed);
1637        }
1638        match self.session.writer().write(buf) {
1639            Ok(absorbed) => {
1640                if absorbed == buf.len() {
1641                    self.session.send_close_notify();
1642                }
1643                let (_flushed, status) = self.socket_write(&[]);
1644                (absorbed, status)
1645            }
1646            Err(_) => self.socket_write(buf),
1647        }
1648    }
1649
1650    fn socket_wants_write(&self) -> bool {
1651        // Only a dead channel (a RST, or a failed socket write) stops us
1652        // wanting to write — a peer FIN still allows flushing TLS plaintext
1653        // buffered in rustls (half-close).
1654        !self.peer_reset && self.session.wants_write()
1655    }
1656
1657    fn socket_ref(&self) -> &TcpStream {
1658        &self.stream
1659    }
1660
1661    fn socket_mut(&mut self) -> &mut TcpStream {
1662        &mut self.stream
1663    }
1664
1665    /// No production route reaches the fallback any more. The expect-proxy
1666    /// route gets there only through `upgrade_expect`, which returns `None`
1667    /// unless both PROXY addresses parse, so `peer_address` is `Some` by the
1668    /// time a handshake exists; the direct route seeds it in
1669    /// `HttpsSession::new` (`https.rs`) with the address `accept(2)` returned
1670    /// with the socket, which cannot fail the way `getpeername(2)` can. The
1671    /// arm stays as defence in depth: a handler built without a peer would
1672    /// otherwise blank the `peer=` slot of a healthy connection. Do not
1673    /// delete it — `https::tests::front_rustls_peer_addr_falls_back_to_the_live_lookup`
1674    /// builds such a handler by hand and fails without it.
1675    fn peer_addr(&self) -> Option<SocketAddr> {
1676        self.configured_peer
1677            .or_else(|| self.stream.peer_addr().ok())
1678    }
1679
1680    fn protocol(&self) -> TransportProtocol {
1681        self.session
1682            .protocol_version()
1683            .map(|version| match version {
1684                ProtocolVersion::SSLv2 => TransportProtocol::Ssl2,
1685                ProtocolVersion::SSLv3 => TransportProtocol::Ssl3,
1686                ProtocolVersion::TLSv1_0 => TransportProtocol::Tls1_0,
1687                ProtocolVersion::TLSv1_1 => TransportProtocol::Tls1_1,
1688                ProtocolVersion::TLSv1_2 => TransportProtocol::Tls1_2,
1689                ProtocolVersion::TLSv1_3 => TransportProtocol::Tls1_3,
1690                _ => TransportProtocol::Tls1_3,
1691            })
1692            .unwrap_or(TransportProtocol::Tcp)
1693    }
1694
1695    fn read_error(&self) {
1696        incr!(names::rustls::READ_ERROR);
1697    }
1698
1699    fn write_error(&self) {
1700        incr!(names::rustls::WRITE_ERROR);
1701    }
1702
1703    fn session_ulid(&self) -> Option<Ulid> {
1704        Some(self.session_ulid)
1705    }
1706}
1707
1708/// Bind `sock`, the listening socket for `addr`, to the network `interface`
1709/// (`SO_BINDTODEVICE`), before `bind(2)`: the listener then accepts only what
1710/// arrives through that interface, whatever address it holds, which is what
1711/// lets a listener follow an interface whose address is not known ahead (a
1712/// WireGuard `wg0`). `None` leaves the socket unbound, as before interfaces
1713/// existed.
1714///
1715/// The option is set before `bind(2)` so that two listeners on the same
1716/// address, bound to different interfaces, can both bind under
1717/// `SO_REUSEADDR`/`SO_REUSEPORT`. It survives the SCM hand-off of an upgrade:
1718/// it is a property of the socket, not of the process.
1719fn bind_to_device(
1720    sock: &Socket,
1721    addr: SocketAddr,
1722    interface: Option<&str>,
1723) -> Result<(), ServerBindError> {
1724    let Some(interface) = interface else {
1725        return Ok(());
1726    };
1727    #[cfg(target_os = "linux")]
1728    {
1729        sock.bind_device(Some(interface.as_bytes()))
1730            .map_err(|error| ServerBindError::BindToDevice {
1731                address: addr,
1732                interface: interface.to_owned(),
1733                error,
1734            })?;
1735        debug_assert!(
1736            sock.device().map_or(true, |device| device.as_deref()
1737                == Some(interface.as_bytes())),
1738            "a socket bound to an interface must report that interface"
1739        );
1740        Ok(())
1741    }
1742    #[cfg(not(target_os = "linux"))]
1743    {
1744        let _ = sock;
1745        Err(ServerBindError::BindToDeviceUnsupported {
1746            address: addr,
1747            interface: interface.to_owned(),
1748        })
1749    }
1750}
1751
1752pub fn server_bind(
1753    addr: SocketAddr,
1754    interface: Option<&str>,
1755) -> Result<TcpListener, ServerBindError> {
1756    let sock = Socket::new(Domain::for_address(addr), Type::STREAM, Some(Protocol::TCP))
1757        .map_err(ServerBindError::SocketCreationError)?;
1758
1759    bind_to_device(&sock, addr, interface)?;
1760
1761    // set so_reuseaddr, but only on unix (mirrors what libstd does)
1762    if cfg!(unix) {
1763        sock.set_reuse_address(true)
1764            .map_err(ServerBindError::SetReuseAddress)?;
1765    }
1766
1767    sock.set_reuse_port(true)
1768        .map_err(ServerBindError::SetReusePort)?;
1769
1770    sock.bind(&addr.into())
1771        .map_err(ServerBindError::BindError)?;
1772
1773    sock.set_nonblocking(true)
1774        .map_err(ServerBindError::SetNonBlocking)?;
1775
1776    // listen
1777    // FIXME: make the backlog configurable?
1778    sock.listen(1024).map_err(ServerBindError::Listen)?;
1779
1780    // Post-conditions (invariant violations only — every fallible syscall above
1781    // already returns an error; these `debug_assert!`s catch a flag we *set*
1782    // silently not sticking, which would be our own logic bug, not a syscall
1783    // failure on network input). The getters return `io::Result`; we only
1784    // assert when the kernel answers, degrading to a no-op on the rare query
1785    // failure so we never panic on a dying fd.
1786    if let Ok(nonblocking) = sock.nonblocking() {
1787        debug_assert!(
1788            nonblocking,
1789            "server_bind must return a non-blocking socket (the worker event loop is edge-triggered)"
1790        );
1791    }
1792    // `SO_REUSEPORT` is set on every platform; assert it stuck so a SCM hand-off
1793    // across a hot-upgrade can re-bind the same address.
1794    #[cfg(unix)]
1795    if let Ok(reuse_port) = sock.reuse_port() {
1796        debug_assert!(
1797            reuse_port,
1798            "server_bind must set SO_REUSEPORT so the listener survives a hot-upgrade re-bind"
1799        );
1800    }
1801    // `SO_REUSEADDR` is unix-only here (mirrors libstd).
1802    #[cfg(unix)]
1803    if let Ok(reuse_address) = sock.reuse_address() {
1804        debug_assert!(
1805            reuse_address,
1806            "server_bind must set SO_REUSEADDR on unix (mirrors libstd)"
1807        );
1808    }
1809    // A bound STREAM socket carries a local address in the requested family.
1810    if let Ok(local) = sock.local_addr() {
1811        debug_assert_eq!(
1812            local.is_ipv4(),
1813            addr.is_ipv4(),
1814            "bound socket family must match the requested address family"
1815        );
1816        debug_assert_eq!(
1817            local.is_ipv6(),
1818            addr.is_ipv6(),
1819            "bound socket family must match the requested address family"
1820        );
1821    }
1822
1823    Ok(TcpListener::from_std(sock.into()))
1824}
1825
1826/// Bind a non-blocking UDP listener socket on `addr`.
1827///
1828/// Mirrors [`server_bind`] but for DGRAM: `SO_REUSEADDR` (unix) + `SO_REUSEPORT`
1829/// so the socket can be SCM-passed and re-bound across a hot-upgrade, then
1830/// `bind` + non-blocking. Unlike TCP there is **no `listen()`** — a UDP socket
1831/// receives datagrams directly. The returned `mio::net::UdpSocket` is the one
1832/// listener socket the UDP datapath demuxes many flows over (one-socket-many-
1833/// flows; per-flow return sockets are created by [`udp_connect`]).
1834pub fn udp_bind(addr: SocketAddr, interface: Option<&str>) -> Result<UdpSocket, ServerBindError> {
1835    let sock = Socket::new(Domain::for_address(addr), Type::DGRAM, Some(Protocol::UDP))
1836        .map_err(ServerBindError::SocketCreationError)?;
1837
1838    bind_to_device(&sock, addr, interface)?;
1839
1840    // set so_reuseaddr, but only on unix (mirrors what libstd does)
1841    if cfg!(unix) {
1842        sock.set_reuse_address(true)
1843            .map_err(ServerBindError::SetReuseAddress)?;
1844    }
1845
1846    sock.set_reuse_port(true)
1847        .map_err(ServerBindError::SetReusePort)?;
1848
1849    sock.bind(&addr.into())
1850        .map_err(ServerBindError::BindError)?;
1851
1852    sock.set_nonblocking(true)
1853        .map_err(ServerBindError::SetNonBlocking)?;
1854
1855    // No `listen()` for DGRAM sockets.
1856
1857    // Post-conditions — same rationale as `server_bind`: assert the flags we set
1858    // stuck (logic bug if not), degrading to a no-op when the kernel refuses the
1859    // query so a dying fd never panics. There is deliberately no `listen()`
1860    // check here: DGRAM sockets are never listened on.
1861    if let Ok(nonblocking) = sock.nonblocking() {
1862        debug_assert!(
1863            nonblocking,
1864            "udp_bind must return a non-blocking socket (the worker event loop is edge-triggered)"
1865        );
1866    }
1867    #[cfg(unix)]
1868    if let Ok(reuse_port) = sock.reuse_port() {
1869        debug_assert!(
1870            reuse_port,
1871            "udp_bind must set SO_REUSEPORT so the listener survives a hot-upgrade re-bind"
1872        );
1873    }
1874    #[cfg(unix)]
1875    if let Ok(reuse_address) = sock.reuse_address() {
1876        debug_assert!(
1877            reuse_address,
1878            "udp_bind must set SO_REUSEADDR on unix (mirrors libstd / server_bind)"
1879        );
1880    }
1881    if let Ok(local) = sock.local_addr() {
1882        debug_assert_eq!(
1883            local.is_ipv4(),
1884            addr.is_ipv4(),
1885            "bound UDP socket family must match the requested address family"
1886        );
1887        debug_assert_eq!(
1888            local.is_ipv6(),
1889            addr.is_ipv6(),
1890            "bound UDP socket family must match the requested address family"
1891        );
1892    }
1893
1894    Ok(UdpSocket::from_std(sock.into()))
1895}
1896
1897/// Create a non-blocking **connected** per-flow upstream UDP socket toward
1898/// `backend`.
1899///
1900/// The socket is bound to an ephemeral local port (family matched to the
1901/// backend) and `connect`-ed to the backend address. A connected UDP socket
1902/// "only receives from the connected address" (`connect(2)`), so its fd is the
1903/// symmetric-NAT return-demux key for one flow: the shell registers
1904/// `upstream_token -> FlowId` and feeds anything that arrives on it back into
1905/// the manager as a `BackendDatagram`. `send` (not `send_to`) is then used for
1906/// the forward path. Errors (`EMFILE`/`ENFILE`/connect refusal) bubble up so
1907/// the caller can shed the flow rather than panic.
1908///
1909/// On Linux the socket is created non-blocking and close-on-exec in the one
1910/// `socket(2)` call (`SOCK_NONBLOCK | SOCK_CLOEXEC`; `Socket::new` adds the
1911/// latter), so a new flow costs `socket`, `bind`, `connect` and no `fcntl(2)`.
1912/// Other platforms keep the `set_nonblocking` round trip. The post-condition
1913/// queries (`fcntl(F_GETFL)`, `getsockname(2)`, `getpeername(2)`) only feed
1914/// `debug_assert!`s, so they are compiled out of release builds.
1915pub fn udp_connect(backend: SocketAddr) -> Result<UdpSocket, ServerBindError> {
1916    let unspecified: SocketAddr = match backend {
1917        SocketAddr::V4(_) => (std::net::Ipv4Addr::UNSPECIFIED, 0).into(),
1918        SocketAddr::V6(_) => (std::net::Ipv6Addr::UNSPECIFIED, 0).into(),
1919    };
1920    // The ephemeral bind address must be in the backend's family with port 0,
1921    // or the subsequent `connect` would mix families / pin a wrong local port.
1922    debug_assert_eq!(
1923        unspecified.is_ipv4(),
1924        backend.is_ipv4(),
1925        "ephemeral bind family must match the backend family"
1926    );
1927    debug_assert_eq!(
1928        unspecified.port(),
1929        0,
1930        "ephemeral bind must use port 0 so the kernel picks the source port"
1931    );
1932    // Linux takes `O_NONBLOCK` at creation, which saves the `F_GETFL`/`F_SETFL`
1933    // pair of `set_nonblocking` on every new flow.
1934    #[cfg(target_os = "linux")]
1935    let ty = Type::DGRAM.nonblocking();
1936    #[cfg(not(target_os = "linux"))]
1937    let ty = Type::DGRAM;
1938    let sock = Socket::new(Domain::for_address(backend), ty, Some(Protocol::UDP))
1939        .map_err(ServerBindError::SocketCreationError)?;
1940
1941    sock.bind(&unspecified.into())
1942        .map_err(ServerBindError::BindError)?;
1943    #[cfg(not(target_os = "linux"))]
1944    sock.set_nonblocking(true)
1945        .map_err(ServerBindError::SetNonBlocking)?;
1946    // `connect` on a DGRAM socket pins the return 4-tuple; a non-blocking
1947    // connect on UDP completes immediately (no handshake).
1948    sock.connect(&backend.into())
1949        .map_err(ServerBindError::BindError)?;
1950
1951    // Post-conditions — assert the flag/connect state stuck (logic bug if not),
1952    // degrading to a no-op when the kernel refuses the query so a dying fd never
1953    // panics on this network-facing path. Each query is a syscall that only
1954    // feeds a `debug_assert!`, so release builds skip them on this per-flow path.
1955    #[cfg(debug_assertions)]
1956    {
1957        if let Ok(nonblocking) = sock.nonblocking() {
1958            debug_assert!(
1959                nonblocking,
1960                "udp_connect must return a non-blocking socket (the worker event loop is edge-triggered)"
1961            );
1962        }
1963        // The connected return socket's local addr family must match the backend,
1964        // and the kernel must have assigned a concrete source port (no longer 0).
1965        if let Ok(local) = sock.local_addr() {
1966            debug_assert_eq!(
1967                local.is_ipv4(),
1968                backend.is_ipv4(),
1969                "connected UDP socket family must match the backend family"
1970            );
1971            if let Some(local) = local.as_socket() {
1972                debug_assert_ne!(
1973                    local.port(),
1974                    0,
1975                    "connect must bind a concrete ephemeral source port (the return-demux key)"
1976                );
1977            }
1978        }
1979        // `connect` pinned the peer 4-tuple — `getpeername(2)` must echo the backend.
1980        if let Ok(peer) = sock.peer_addr()
1981            && let Some(peer) = peer.as_socket()
1982        {
1983            debug_assert_eq!(
1984                peer, backend,
1985                "connect must pin the peer to the requested backend (symmetric-NAT return-demux key)"
1986            );
1987        }
1988    }
1989
1990    Ok(UdpSocket::from_std(sock.into()))
1991}
1992
1993/// Socket statistics
1994pub mod stats {
1995    use std::{os::fd::AsRawFd, time::Duration};
1996
1997    use internal::{OPT_LEVEL, OPT_NAME, TcpInfo};
1998
1999    /// Point-in-time snapshot of kernel TCP bookkeeping for a socket. Populated
2000    /// from a single `getsockopt(TCP_INFO)` syscall so callers that want both
2001    /// the smoothed RTT and the FSM state don't pay for two trips into the
2002    /// kernel. Field set is deliberately narrow — extend with more `tcp_info`
2003    /// members if the log prefix grows.
2004    #[derive(Clone, Debug)]
2005    pub struct TcpSnapshot {
2006        pub rtt: Duration,
2007        pub state: &'static str,
2008    }
2009
2010    /// Round trip time for a TCP socket. Kept for existing metric callers;
2011    /// log-prefix callers should prefer [`socket_snapshot`] which returns the
2012    /// RTT **and** the TCP FSM state from a single syscall.
2013    pub fn socket_rtt<A: AsRawFd>(socket: &A) -> Option<Duration> {
2014        socket_info(socket.as_raw_fd()).map(|info| Duration::from_micros(info.rtt() as u64))
2015    }
2016
2017    /// Smoothed RTT + human-readable TCP state (`"ESTABLISHED"`, `"SYN_SENT"`,
2018    /// `"CLOSE_WAIT"`, …) pulled from a single `getsockopt(TCP_INFO)` call.
2019    /// Returns `None` when the kernel refuses the call — e.g. the socket has
2020    /// been closed, or the FSM is in a state where `TCP_INFO` is not usable.
2021    /// Safe on dying/refused sockets: the inner syscall's `status != 0`
2022    /// branch is the only failure mode and it degrades to `None`.
2023    pub fn socket_snapshot<A: AsRawFd>(socket: &A) -> Option<TcpSnapshot> {
2024        socket_info(socket.as_raw_fd()).map(|info| TcpSnapshot {
2025            rtt: Duration::from_micros(info.rtt() as u64),
2026            state: info.state(),
2027        })
2028    }
2029
2030    #[cfg(unix)]
2031    pub fn socket_info(fd: libc::c_int) -> Option<TcpInfo> {
2032        // SAFETY: `TcpInfo` is a C POD whose every byte pattern is a legal
2033        // representation; zero-init satisfies `assume_init`'s invariant
2034        // (and `std::mem::zeroed` is the canonical idiom for that).
2035        let mut tcp_info: TcpInfo = unsafe { std::mem::zeroed() };
2036        let struct_len = std::mem::size_of::<TcpInfo>() as libc::socklen_t;
2037        let mut len = struct_len;
2038        // SAFETY: `tcp_info` and `len` are fully initialised above; libc
2039        // reads only `len` bytes through the pointer and writes back the
2040        // resulting length. We check the return value (`status != 0`) to
2041        // distinguish success from validation failure.
2042        let status = unsafe {
2043            libc::getsockopt(
2044                fd,
2045                OPT_LEVEL,
2046                OPT_NAME,
2047                &mut tcp_info as *mut _ as *mut _,
2048                &mut len,
2049            )
2050        };
2051        if status != 0 {
2052            None
2053        } else {
2054            // The kernel writes back the number of bytes it populated. It must
2055            // never claim to have written more than the buffer we handed it —
2056            // that would mean it overran `tcp_info`, an out-of-bounds write we
2057            // could not have detected by the return code alone.
2058            debug_assert!(
2059                len <= struct_len,
2060                "getsockopt(TCP_INFO) wrote back len {len} > struct size {struct_len} (buffer overrun)"
2061            );
2062            Some(tcp_info)
2063        }
2064    }
2065    #[cfg(not(unix))]
2066    pub fn socketinfo(fd: libc::c_int) -> Option<TcpInfo> {
2067        None
2068    }
2069
2070    #[cfg(unix)]
2071    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
2072    mod internal {
2073        #[cfg(target_os = "linux")]
2074        pub const OPT_LEVEL: libc::c_int = libc::SOL_TCP;
2075
2076        #[cfg(any(
2077            target_os = "freebsd",
2078            target_os = "dragonfly",
2079            target_os = "openbsd",
2080            target_os = "netbsd"
2081        ))]
2082        pub const OPT_LEVEL: libc::c_int = libc::IPPROTO_TCP;
2083
2084        pub const OPT_NAME: libc::c_int = libc::TCP_INFO;
2085
2086        #[derive(Clone, Debug)]
2087        #[repr(C)]
2088        pub struct TcpInfo {
2089            // State
2090            tcpi_state: u8,
2091            tcpi_ca_state: u8,
2092            tcpi_retransmits: u8,
2093            tcpi_probes: u8,
2094            tcpi_backoff: u8,
2095            tcpi_options: u8,
2096            tcpi_snd_rcv_wscale: u8, // 4bits|4bits
2097
2098            tcpi_rto: u32,
2099            tcpi_ato: u32,
2100            tcpi_snd_mss: u32,
2101            tcpi_rcv_mss: u32,
2102
2103            tcpi_unacked: u32,
2104            tcpi_sacked: u32,
2105            tcpi_lost: u32,
2106            tcpi_retrans: u32,
2107            tcpi_fackets: u32,
2108
2109            // Times
2110            tcpi_last_data_sent: u32,
2111            tcpi_last_ack_sent: u32, // Not remembered
2112            tcpi_last_data_recv: u32,
2113            tcpi_last_ack_recv: u32,
2114
2115            // Metrics
2116            tcpi_pmtu: u32,
2117            tcpi_rcv_ssthresh: u32,
2118            tcpi_rtt: u32,
2119            tcpi_rttvar: u32,
2120            tcpi_snd_ssthresh: u32,
2121            tcpi_snd_cwnd: u32,
2122            tcpi_advmss: u32,
2123            tcpi_reordering: u32,
2124        }
2125        impl TcpInfo {
2126            pub fn rtt(&self) -> u32 {
2127                self.tcpi_rtt
2128            }
2129
2130            /// Human-readable Linux TCP FSM state. Values follow
2131            /// `include/net/tcp_states.h` (`TCP_ESTABLISHED = 1`,
2132            /// `TCP_SYN_SENT = 2`, …). Anything unexpected falls back to
2133            /// `"UNKNOWN"` rather than panicking — the log prefix is a
2134            /// best-effort diagnostic and must not add failure modes.
2135            pub fn state(&self) -> &'static str {
2136                match self.tcpi_state {
2137                    1 => "ESTABLISHED",
2138                    2 => "SYN_SENT",
2139                    3 => "SYN_RECV",
2140                    4 => "FIN_WAIT1",
2141                    5 => "FIN_WAIT2",
2142                    6 => "TIME_WAIT",
2143                    7 => "CLOSE",
2144                    8 => "CLOSE_WAIT",
2145                    9 => "LAST_ACK",
2146                    10 => "LISTEN",
2147                    11 => "CLOSING",
2148                    12 => "NEW_SYN_RECV",
2149                    _ => "UNKNOWN",
2150                }
2151            }
2152        }
2153    }
2154
2155    #[cfg(unix)]
2156    #[cfg(any(target_os = "macos", target_os = "ios"))]
2157    mod internal {
2158        pub const OPT_LEVEL: libc::c_int = libc::IPPROTO_TCP;
2159        pub const OPT_NAME: libc::c_int = 0x106;
2160
2161        #[derive(Clone, Debug)]
2162        #[repr(C)]
2163        pub struct TcpInfo {
2164            tcpi_state: u8,
2165            tcpi_snd_wscale: u8,
2166            tcpi_rcv_wscale: u8,
2167            __pad1: u8,
2168            tcpi_options: u32,
2169            tcpi_flags: u32,
2170            tcpi_rto: u32,
2171            tcpi_maxseg: u32,
2172            tcpi_snd_ssthresh: u32,
2173            tcpi_snd_cwnd: u32,
2174            tcpi_snd_wnd: u32,
2175            tcpi_snd_sbbytes: u32,
2176            tcpi_rcv_wnd: u32,
2177            tcpi_rttcur: u32,
2178            tcpi_srtt: u32,
2179            tcpi_rttvar: u32,
2180            tcpi_tfo: u32,
2181            tcpi_txpackets: u64,
2182            tcpi_txbytes: u64,
2183            tcpi_txretransmitbytes: u64,
2184            tcpi_rxpackets: u64,
2185            tcpi_rxbytes: u64,
2186            tcpi_rxoutoforderbytes: u64,
2187            tcpi_txretransmitpackets: u64,
2188        }
2189        impl TcpInfo {
2190            pub fn rtt(&self) -> u32 {
2191                // tcpi_srtt is in milliseconds not microseconds
2192                self.tcpi_srtt * 1000
2193            }
2194
2195            /// Human-readable Darwin TCP FSM state. Values follow
2196            /// `netinet/tcp_fsm.h` (`TCPS_CLOSED = 0`, `TCPS_LISTEN = 1`,
2197            /// `TCPS_SYN_SENT = 2`, …). Differs from Linux numbering —
2198            /// macOS counts from 0, Linux from 1.
2199            pub fn state(&self) -> &'static str {
2200                match self.tcpi_state {
2201                    0 => "CLOSED",
2202                    1 => "LISTEN",
2203                    2 => "SYN_SENT",
2204                    3 => "SYN_RECEIVED",
2205                    4 => "ESTABLISHED",
2206                    5 => "CLOSE_WAIT",
2207                    6 => "FIN_WAIT_1",
2208                    7 => "CLOSING",
2209                    8 => "LAST_ACK",
2210                    9 => "FIN_WAIT_2",
2211                    10 => "TIME_WAIT",
2212                    _ => "UNKNOWN",
2213                }
2214            }
2215        }
2216    }
2217
2218    #[cfg(not(unix))]
2219    #[derive(Clone, Debug)]
2220    struct TcpInfo {}
2221
2222    #[test]
2223    #[serial_test::serial]
2224    fn test_rtt() {
2225        let sock = std::net::TcpStream::connect("google.com:80").unwrap();
2226        let fd = sock.as_raw_fd();
2227        let info = socket_info(fd);
2228        assert!(info.is_some());
2229        println!("{info:#?}");
2230        println!(
2231            "rtt: {}",
2232            sozu_command::logging::LogDuration(socket_rtt(&sock))
2233        );
2234    }
2235}
2236
2237#[cfg(test)]
2238pub(crate) mod tests {
2239    use super::*;
2240
2241    /// Binding a listener to an interface needs `CAP_NET_RAW` on kernels
2242    /// before 5.7; an environment without it cannot run the positive test.
2243    #[cfg(target_os = "linux")]
2244    fn lacks_bind_to_device_permission(error: &ServerBindError) -> bool {
2245        matches!(
2246            error,
2247            ServerBindError::BindToDevice { error, .. }
2248                if error.kind() == std::io::ErrorKind::PermissionDenied
2249        )
2250    }
2251
2252    /// `server_bind` and `udp_bind` bind a listener with an `interface` to
2253    /// that interface (`SO_BINDTODEVICE`, read back with `getsockopt`), and a
2254    /// listener without one to none — today's behaviour.
2255    #[cfg(target_os = "linux")]
2256    #[test]
2257    fn bind_sets_so_bindtodevice_to_the_listener_interface() {
2258        use socket2::SockRef;
2259
2260        let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
2261
2262        let tcp = match server_bind(addr, Some("lo")) {
2263            Ok(listener) => listener,
2264            Err(error) if lacks_bind_to_device_permission(&error) => {
2265                eprintln!(
2266                    "SKIPPED bind_sets_so_bindtodevice_to_the_listener_interface: this \
2267                     environment may not bind a socket to an interface (needs CAP_NET_RAW \
2268                     before Linux 5.7): {error}"
2269                );
2270                return;
2271            }
2272            Err(error) => panic!("binding a TCP listener to lo: {error}"),
2273        };
2274        assert_eq!(
2275            SockRef::from(&tcp)
2276                .device()
2277                .expect("getsockopt(SO_BINDTODEVICE)"),
2278            Some(b"lo".to_vec()),
2279            "the TCP listener must be bound to lo"
2280        );
2281
2282        let udp = udp_bind(addr, Some("lo")).expect("binding a UDP listener to lo");
2283        assert_eq!(
2284            SockRef::from(&udp)
2285                .device()
2286                .expect("getsockopt(SO_BINDTODEVICE)"),
2287            Some(b"lo".to_vec()),
2288            "the UDP listener must be bound to lo"
2289        );
2290
2291        let plain = server_bind(addr, None).expect("binding a TCP listener");
2292        assert_eq!(
2293            SockRef::from(&plain)
2294                .device()
2295                .expect("getsockopt(SO_BINDTODEVICE)"),
2296            None,
2297            "a listener without interface stays bound to no interface"
2298        );
2299    }
2300
2301    /// An interface that does not exist fails the bind with an explicit error
2302    /// naming the listener address and the interface, and pointing at the two
2303    /// usual causes: the interface must exist, and pre-5.7 kernels require
2304    /// `CAP_NET_RAW`.
2305    #[cfg(target_os = "linux")]
2306    #[test]
2307    fn bind_to_a_missing_interface_names_the_interface_and_the_capability() {
2308        let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
2309        for result in [
2310            server_bind(addr, Some("sozu-nosuch0")).map(|_| ()),
2311            udp_bind(addr, Some("sozu-nosuch0")).map(|_| ()),
2312        ] {
2313            let error = result.expect_err("binding to a missing interface must fail");
2314            assert!(
2315                matches!(&error, ServerBindError::BindToDevice { interface, .. } if interface == "sozu-nosuch0"),
2316                "{error:?}"
2317            );
2318            let message = error.to_string();
2319            for needle in [
2320                "127.0.0.1:0",
2321                "'sozu-nosuch0'",
2322                "SO_BINDTODEVICE",
2323                "must exist",
2324                "CAP_NET_RAW",
2325                "5.7",
2326            ] {
2327                assert!(
2328                    message.contains(needle),
2329                    "{needle:?} missing from: {message}"
2330                );
2331            }
2332        }
2333    }
2334
2335    /// Address a handler caches. Deliberately non-loopback so it can never
2336    /// collide with the ephemeral address a live `getpeername(2)` reports for
2337    /// the test connection.
2338    const CACHED_PEER: &str = "10.0.0.42:12345";
2339
2340    /// A live, established loopback connection plus the address
2341    /// `getpeername(2)` reports for it. The listener is returned so the
2342    /// connection stays up for the whole test: the property under test is that
2343    /// the snapshot wins even while the live lookup is perfectly healthy, and a
2344    /// half-dead socket would weaken that rather than strengthen it.
2345    ///
2346    /// Using a genuinely connected socket instead of an aborted `connect()` is
2347    /// also what makes these tests deterministic: whether a nonblocking connect
2348    /// to a closed port has already collected its RST — and therefore whether
2349    /// `getpeername(2)` has started answering `ENOTCONN` — is a race against the
2350    /// kernel, not something a test may assert on.
2351    fn connected_loopback_stream() -> (std::net::TcpListener, TcpStream, SocketAddr) {
2352        let listener = std::net::TcpListener::bind("127.0.0.1:0")
2353            .expect("test listener must bind to a loopback port");
2354        let live_peer = listener
2355            .local_addr()
2356            .expect("test listener must report its local address");
2357        let stream =
2358            std::net::TcpStream::connect(live_peer).expect("loopback connect must complete");
2359        stream
2360            .set_nonblocking(true)
2361            .expect("mio requires a nonblocking stream");
2362        (listener, TcpStream::from_std(stream), live_peer)
2363    }
2364
2365    /// The cache is the whole point of the snapshot: on a PROXY-protocol
2366    /// frontend it holds the advertised client while the socket's own peer is
2367    /// the load balancer, and on a backend socket it holds the configured
2368    /// backend while `getpeername(2)` answers `ENOTCONN` after a failed
2369    /// `connect()`. A handler that consults the kernel first has neither.
2370    ///
2371    /// To SEE THIS RED: in `impl SocketHandler for SessionTcpStream`, replace
2372    /// the body of `peer_addr` with `self.stream.peer_addr().ok()`. The cached
2373    /// address disappears and the loopback address takes its place.
2374    #[test]
2375    fn session_tcp_stream_peer_addr_prefers_the_cached_address() {
2376        let (_listener, stream, live_peer) = connected_loopback_stream();
2377        let cached: SocketAddr = CACHED_PEER
2378            .parse()
2379            .expect("the cached peer literal must parse");
2380        let handler = SessionTcpStream::new(stream, Ulid::generate(), Some(cached));
2381
2382        // Premise: the live lookup is healthy and disagrees with the cache, so
2383        // the assertion below cannot pass for the wrong reason.
2384        assert_eq!(
2385            handler.socket_ref().peer_addr().ok(),
2386            Some(live_peer),
2387            "the test socket must be genuinely connected, so a live lookup succeeds"
2388        );
2389        assert_ne!(
2390            cached, live_peer,
2391            "the cached and live addresses must differ for this test to discriminate"
2392        );
2393
2394        assert_eq!(
2395            handler.peer_addr(),
2396            Some(cached),
2397            "a cached peer address must win over a live getpeername(2)"
2398        );
2399    }
2400
2401    /// The fallback arm. Without it a handler built with no snapshot would
2402    /// render `peer=None` on every line rather than degrading to the live
2403    /// lookup that was there before the cache existed.
2404    ///
2405    /// To SEE THIS RED: in `impl SocketHandler for SessionTcpStream`, drop the
2406    /// `.or_else(|| self.stream.peer_addr().ok())` from `peer_addr`. The
2407    /// handler then answers `None` for a perfectly healthy connection.
2408    #[test]
2409    fn session_tcp_stream_peer_addr_falls_back_to_the_live_lookup() {
2410        let (_listener, stream, live_peer) = connected_loopback_stream();
2411        let handler = SessionTcpStream::new(stream, Ulid::generate(), None);
2412
2413        assert_eq!(
2414            handler.peer_addr(),
2415            Some(live_peer),
2416            "with nothing cached, peer_addr must degrade to getpeername(2)"
2417        );
2418    }
2419
2420    /// A bare `TcpStream` carries no session context and therefore nothing to
2421    /// cache; its `peer_addr` is the live lookup and nothing else. Pinned so
2422    /// that a later attempt to give `SocketHandler::peer_addr` a default body
2423    /// has to confront this impl explicitly.
2424    ///
2425    /// To SEE THIS RED: in `impl SocketHandler for TcpStream`, replace the body
2426    /// of `peer_addr` with `None`.
2427    #[test]
2428    fn raw_tcp_stream_peer_addr_is_the_live_lookup() {
2429        let (_listener, stream, live_peer) = connected_loopback_stream();
2430
2431        assert_eq!(
2432            SocketHandler::peer_addr(&stream),
2433            Some(live_peer),
2434            "the contextless handler must report the kernel's answer"
2435        );
2436    }
2437
2438    /// The `peer=` slot of a `SOCKET` line is the handler's cached address,
2439    /// the same one `MUX-H2` and `log_socket_module_prefix` render — not a
2440    /// live `getpeername(2)`.
2441    ///
2442    /// Renders through [`log_socket_context!`] itself rather than through
2443    /// [`SocketHandler::peer_addr`], because the accessor was already correct
2444    /// for every impl while the macro consulted the kernel behind its back.
2445    /// The three `peer_addr` tests above therefore all passed while a `SOCKET`
2446    /// line still named the load balancer on a PROXY-protocol TLS frontend.
2447    ///
2448    /// Expanded against [`SessionTcpStream`] and not [`FrontRustls`], which is
2449    /// the macro's only production caller, because a `FrontRustls` needs a
2450    /// completed rustls handshake and this module builds no TLS. The macro is
2451    /// generic over [`SocketHandler`], so what this pins is the slot's
2452    /// resolution for every impl; that the TLS frontend really renders the
2453    /// PROXY-advertised client on the wire is pinned end to end by
2454    /// `e2e::tests::socket_log_context_tests::    /// test_tls_socket_log_peer_is_the_advertised_client`.
2455    ///
2456    /// The palette is empty here — `LOGGER_COLORED` defaults to `false` and
2457    /// this test installs no logger — so the slot is matched as plain text. A
2458    /// coloured palette would split `peer=` with an escape sequence and redden
2459    /// the test rather than silently passing it.
2460    ///
2461    /// To SEE THIS RED: in [`log_socket_context!`], replace
2462    /// `peer = crate::socket::SocketHandler::peer_addr($self),` with the
2463    /// pre-fix `peer = $self.socket_ref().peer_addr().ok(),`.
2464    #[test]
2465    fn log_socket_context_renders_the_cached_peer_not_a_live_lookup() {
2466        let (_listener, stream, live_peer) = connected_loopback_stream();
2467        let cached: SocketAddr = CACHED_PEER
2468            .parse()
2469            .expect("the cached peer literal must parse");
2470        let handler = SessionTcpStream::new(stream, Ulid::generate(), Some(cached));
2471
2472        // Premise: the live lookup is healthy and disagrees with the cache, so
2473        // neither assertion below can pass for the wrong reason.
2474        assert_eq!(
2475            handler.socket_ref().peer_addr().ok(),
2476            Some(live_peer),
2477            "the test socket must be genuinely connected, so a live lookup succeeds"
2478        );
2479        assert_ne!(
2480            cached, live_peer,
2481            "the cached and live addresses must differ for this test to discriminate"
2482        );
2483
2484        // `&handler`, not `handler`: the macro's `peer` slot is a
2485        // fully-qualified `SocketHandler::peer_addr` call, so the expansion
2486        // binds a shared reference. Production call sites pass `self` from a
2487        // `&mut self` method and reach the same place by reborrow.
2488        let rendered = log_socket_context!(&handler);
2489
2490        assert!(
2491            rendered.contains(&format!("peer=Some({cached})")),
2492            "the SOCKET peer= slot must render the cached address; rendered: {rendered}"
2493        );
2494        assert!(
2495            !rendered.contains(&format!("peer=Some({live_peer})")),
2496            "the SOCKET peer= slot must not render a live getpeername(2); rendered: {rendered}"
2497        );
2498        // Scope guard: this change touches `peer` and nothing else. `local` is
2499        // still `getsockname(2)` on the same socket, which is the stream's own
2500        // address and never the cached peer.
2501        assert!(
2502            rendered.contains(&format!(
2503                "local=Some({})",
2504                handler
2505                    .socket_ref()
2506                    .local_addr()
2507                    .expect("a connected socket has a local address")
2508            )),
2509            "the SOCKET local= slot must stay getsockname(2); rendered: {rendered}"
2510        );
2511    }
2512
2513    /// A socket that was never connected, and therefore one whose
2514    /// `getpeername(2)` fails with `ENOTCONN` *deterministically*.
2515    ///
2516    /// This is the one reliable way to stage a failing live lookup in a test.
2517    /// The obvious alternative — connect to a closed port and wait for the RST
2518    /// — is the race `connected_loopback_stream`'s note already rules out:
2519    /// whether the kernel has collected the RST yet, and so whether
2520    /// `getpeername(2)` has started refusing, is not something a test may
2521    /// assert on. An unconnected socket is in the refusing state from birth.
2522    fn unconnected_stream() -> TcpStream {
2523        let socket = Socket::new(Domain::IPV4, Type::STREAM, Some(Protocol::TCP))
2524            .expect("a test socket must be creatable");
2525        socket
2526            .set_nonblocking(true)
2527            .expect("mio requires a nonblocking stream");
2528        TcpStream::from_std(std::net::TcpStream::from(socket))
2529    }
2530
2531    /// The `peer=` slot survives a live lookup that FAILS, which is the arm an
2532    /// operator meets during an incident: `getpeername(2)` answers `ENOTCONN`
2533    /// once the peer has reset, so the pre-fix macro rendered `peer=None` on
2534    /// exactly the error lines being read at the time.
2535    ///
2536    /// Staged with a never-connected socket rather than a reset one, because
2537    /// only the former refuses deterministically — see
2538    /// [`unconnected_stream`]. A peer reset is one way to reach that state;
2539    /// what this pins is the rendering once the socket is in it, which is the
2540    /// part the macro owns.
2541    ///
2542    /// The companion
2543    /// [`log_socket_context_renders_the_cached_peer_not_a_live_lookup`] covers
2544    /// the other half, where the live lookup SUCCEEDS and disagrees. The two
2545    /// are separate tests because a single one cannot be red for both reasons,
2546    /// and the PROXY-protocol defect lives in the succeeding half.
2547    ///
2548    /// To SEE THIS RED: in [`log_socket_context!`], replace
2549    /// `peer = crate::socket::SocketHandler::peer_addr($self),` with the
2550    /// pre-fix `peer = $self.socket_ref().peer_addr().ok(),`. The slot
2551    /// collapses to `peer=None`.
2552    #[test]
2553    fn log_socket_context_renders_the_cached_peer_when_the_live_lookup_fails() {
2554        let stream = unconnected_stream();
2555        let cached: SocketAddr = CACHED_PEER
2556            .parse()
2557            .expect("the cached peer literal must parse");
2558
2559        // Premise: the live lookup really is refusing, so the assertion below
2560        // cannot pass for the wrong reason.
2561        assert_eq!(
2562            stream.peer_addr().ok(),
2563            None,
2564            "an unconnected socket must refuse getpeername(2)"
2565        );
2566
2567        let handler = SessionTcpStream::new(stream, Ulid::generate(), Some(cached));
2568        let rendered = log_socket_context!(&handler);
2569
2570        assert!(
2571            rendered.contains(&format!("peer=Some({cached})")),
2572            "the SOCKET peer= slot must survive a failed live lookup; rendered: {rendered}"
2573        );
2574        assert!(
2575            !rendered.contains("peer=None"),
2576            "the SOCKET peer= slot must not collapse to None while a cache exists; \
2577             rendered: {rendered}"
2578        );
2579    }
2580
2581    /// Counts, with a seccomp user-notification filter, the `fcntl(2)`,
2582    /// `getsockname(2)` and `getpeername(2)` calls one `udp_connect` makes,
2583    /// then checks the returned socket's flags and addresses.
2584    ///
2585    /// The filter is installed on a dedicated thread only (no `TSYNC`), so the
2586    /// rest of the test binary is untouched. Every matching call is reported to
2587    /// this thread, counted, and let through unchanged
2588    /// (`SECCOMP_USER_NOTIF_FLAG_CONTINUE`), so `udp_connect` sees the real
2589    /// kernel answers. Release builds must make none of the three calls: the
2590    /// socket is born non-blocking and the post-condition queries only feed
2591    /// `debug_assert!`s. Debug builds keep exactly those queries: one
2592    /// `F_GETFL`, one `getsockname`, one `getpeername`.
2593    #[cfg(all(target_os = "linux", target_pointer_width = "64"))]
2594    #[test]
2595    fn udp_connect_is_born_nonblocking_and_skips_release_queries() {
2596        use std::os::fd::{AsRawFd as _, FromRawFd as _, OwnedFd};
2597
2598        const WATCHED: [libc::c_long; 3] = [
2599            libc::SYS_fcntl,
2600            libc::SYS_getsockname,
2601            libc::SYS_getpeername,
2602        ];
2603
2604        let backend_sock =
2605            std::net::UdpSocket::bind("127.0.0.1:0").expect("the test backend must bind");
2606        let backend = backend_sock
2607            .local_addr()
2608            .expect("the test backend must report its address");
2609
2610        let (listener_tx, listener_rx) = std::sync::mpsc::channel::<OwnedFd>();
2611        let worker = std::thread::spawn(move || {
2612            let stmt = |code: u32, k: u32| libc::sock_filter {
2613                code: code as u16,
2614                jt: 0,
2615                jf: 0,
2616                k,
2617            };
2618            let jeq = |k: libc::c_long, jt: u8| libc::sock_filter {
2619                code: (libc::BPF_JMP | libc::BPF_JEQ | libc::BPF_K) as u16,
2620                jt,
2621                jf: 0,
2622                k: k as u32,
2623            };
2624            // `seccomp_data.nr` is the first field; any watched number jumps
2625            // to the USER_NOTIF return, everything else is allowed.
2626            let mut program = [
2627                stmt(libc::BPF_LD | libc::BPF_W | libc::BPF_ABS, 0),
2628                jeq(WATCHED[0], 3),
2629                jeq(WATCHED[1], 2),
2630                jeq(WATCHED[2], 1),
2631                stmt(libc::BPF_RET | libc::BPF_K, libc::SECCOMP_RET_ALLOW),
2632                stmt(libc::BPF_RET | libc::BPF_K, libc::SECCOMP_RET_USER_NOTIF),
2633            ];
2634            let fprog = libc::sock_fprog {
2635                len: program.len() as u16,
2636                filter: program.as_mut_ptr(),
2637            };
2638            // SAFETY: plain syscalls on this thread; `fprog` outlives them.
2639            let listener = unsafe {
2640                assert_eq!(
2641                    libc::prctl(libc::PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0),
2642                    0,
2643                    "PR_SET_NO_NEW_PRIVS: {}",
2644                    std::io::Error::last_os_error()
2645                );
2646                libc::syscall(
2647                    libc::SYS_seccomp,
2648                    libc::SECCOMP_SET_MODE_FILTER,
2649                    libc::SECCOMP_FILTER_FLAG_NEW_LISTENER,
2650                    &fprog as *const libc::sock_fprog,
2651                )
2652            };
2653            assert!(
2654                listener >= 0,
2655                "installing the seccomp filter failed: {}",
2656                std::io::Error::last_os_error()
2657            );
2658            // SAFETY: the kernel just returned this descriptor to us.
2659            let listener = unsafe { OwnedFd::from_raw_fd(listener as libc::c_int) };
2660            listener_tx
2661                .send(listener)
2662                .expect("the counting thread must receive the listener");
2663            udp_connect(backend)
2664        });
2665
2666        let listener = listener_rx
2667            .recv()
2668            .expect("the worker must hand over the seccomp listener");
2669        let mut counts = [0usize; 3];
2670        loop {
2671            let mut pollfd = libc::pollfd {
2672                fd: listener.as_raw_fd(),
2673                events: libc::POLLIN,
2674                revents: 0,
2675            };
2676            // SAFETY: one valid pollfd. The 10 s bound only turns a wedged
2677            // worker into a failure instead of a hung test run.
2678            let ready = unsafe { libc::poll(&mut pollfd, 1, 10_000) };
2679            assert!(ready > 0, "no seccomp notification or hang-up within 10 s");
2680            if pollfd.revents & libc::POLLIN == 0 {
2681                // POLLHUP: the filtered thread has exited.
2682                break;
2683            }
2684            // SAFETY: both structs are plain data; RECV requires a zeroed one.
2685            let mut notif: libc::seccomp_notif = unsafe { std::mem::zeroed() };
2686            if unsafe {
2687                libc::ioctl(
2688                    listener.as_raw_fd(),
2689                    libc::SECCOMP_IOCTL_NOTIF_RECV,
2690                    &mut notif,
2691                )
2692            } != 0
2693            {
2694                let error = std::io::Error::last_os_error();
2695                // ENOENT: the notifying call was interrupted before we read it.
2696                assert_eq!(
2697                    error.raw_os_error(),
2698                    Some(libc::ENOENT),
2699                    "SECCOMP_IOCTL_NOTIF_RECV: {error}"
2700                );
2701                continue;
2702            }
2703            let nr = libc::c_long::from(notif.data.nr);
2704            let slot = WATCHED
2705                .iter()
2706                .position(|watched| *watched == nr)
2707                .expect("the filter only reports watched syscalls");
2708            counts[slot] += 1;
2709            let mut resp: libc::seccomp_notif_resp = unsafe { std::mem::zeroed() };
2710            resp.id = notif.id;
2711            resp.flags = libc::SECCOMP_USER_NOTIF_FLAG_CONTINUE as u32;
2712            // SAFETY: `resp` is a valid response for the id just received.
2713            let sent = unsafe {
2714                libc::ioctl(
2715                    listener.as_raw_fd(),
2716                    libc::SECCOMP_IOCTL_NOTIF_SEND,
2717                    &mut resp,
2718                )
2719            };
2720            assert_eq!(
2721                sent,
2722                0,
2723                "SECCOMP_IOCTL_NOTIF_SEND: {}",
2724                std::io::Error::last_os_error()
2725            );
2726        }
2727
2728        let sock = worker
2729            .join()
2730            .expect("the filtered thread must not panic")
2731            .expect("udp_connect must succeed toward a bound loopback backend");
2732
2733        let expected = if cfg!(debug_assertions) {
2734            [1, 1, 1]
2735        } else {
2736            [0, 0, 0]
2737        };
2738        assert_eq!(
2739            counts,
2740            expected,
2741            "udp_connect (fcntl, getsockname, getpeername) calls, debug_assertions = {}",
2742            cfg!(debug_assertions)
2743        );
2744
2745        let fd = sock.as_raw_fd();
2746        // SAFETY: fcntl queries on a descriptor we own.
2747        let (status, fd_flags) = unsafe {
2748            (
2749                libc::fcntl(fd, libc::F_GETFL),
2750                libc::fcntl(fd, libc::F_GETFD),
2751            )
2752        };
2753        assert!(status >= 0 && fd_flags >= 0, "fcntl on the returned socket");
2754        assert_ne!(
2755            status & libc::O_NONBLOCK,
2756            0,
2757            "the socket must be non-blocking"
2758        );
2759        assert_ne!(
2760            fd_flags & libc::FD_CLOEXEC,
2761            0,
2762            "the socket must be close-on-exec"
2763        );
2764        let local = sock
2765            .local_addr()
2766            .expect("the socket must report its local address");
2767        assert!(local.is_ipv4(), "the local family must match the backend's");
2768        assert_ne!(local.port(), 0, "connect must pick a concrete source port");
2769        assert_eq!(
2770            sock.peer_addr().expect("the socket must be connected"),
2771            backend,
2772            "connect must pin the peer to the backend"
2773        );
2774    }
2775
2776    // ---- peer resets (sozu-proxy/sozu#434) ------------------------------
2777
2778    /// The current value of one proxy-level counter on this test thread,
2779    /// absent counting as 0. `METRICS` is a `thread_local!` shared with every
2780    /// test libtest runs on the same thread, so callers assert a DELTA
2781    /// against a baseline, never an absolute value. Mirrors `proxy_metric`
2782    /// in `lib/src/protocol/mux/stream.rs`.
2783    pub(crate) fn proxy_count(name: &str) -> i64 {
2784        use sozu_command::proto::command::filtered_metrics::Inner;
2785        crate::metrics::METRICS.with(|metrics| {
2786            metrics
2787                .borrow_mut()
2788                .dump_local_proxy_metrics()
2789                .get(name)
2790                .and_then(|metric| match metric.inner {
2791                    Some(Inner::Count(value)) => Some(value),
2792                    _ => None,
2793                })
2794                .unwrap_or(0)
2795        })
2796    }
2797
2798    /// A nonblocking loopback stream whose peer reset it: the accepted side
2799    /// sets `SO_LINGER` to zero and closes, which makes the kernel send a
2800    /// RST instead of a FIN.
2801    ///
2802    /// Returns once `poll(2)` reports `POLLERR` on the stream, so the RST has
2803    /// been processed and the next syscall is the one that answers
2804    /// `ECONNRESET`. `poll` does not consume the pending socket error, a
2805    /// blocking read would. Bounded: a RST that never arrives fails the test
2806    /// instead of hanging it.
2807    pub(crate) fn reset_stream() -> TcpStream {
2808        let listener = std::net::TcpListener::bind("127.0.0.1:0")
2809            .expect("test listener must bind to a loopback port");
2810        let stream = std::net::TcpStream::connect(
2811            listener
2812                .local_addr()
2813                .expect("test listener must report its local address"),
2814        )
2815        .expect("loopback connect must complete");
2816        let (peer, _) = listener.accept().expect("loopback accept must complete");
2817        socket2::SockRef::from(&peer)
2818            .set_linger(Some(std::time::Duration::ZERO))
2819            .expect("SO_LINGER must accept a zero timeout");
2820        drop(peer);
2821
2822        let mut pollfd = libc::pollfd {
2823            fd: std::os::unix::io::AsRawFd::as_raw_fd(&stream),
2824            events: libc::POLLIN,
2825            revents: 0,
2826        };
2827        // SAFETY: one valid `pollfd` borrowed for the duration of the call.
2828        let ready = unsafe { libc::poll(&mut pollfd, 1, 5_000) };
2829        assert_eq!(ready, 1, "the peer's RST must arrive within 5 s");
2830        assert_ne!(
2831            pollfd.revents & libc::POLLERR,
2832            0,
2833            "premise: the peer must have reset the connection, not closed it"
2834        );
2835        stream
2836            .set_nonblocking(true)
2837            .expect("mio requires a nonblocking stream");
2838        TcpStream::from_std(stream)
2839    }
2840
2841    /// A read that meets the peer's RST answers `Closed`, as it always did,
2842    /// and counts `tcp.read.reset` once: the kernel reports `ECONNRESET` to
2843    /// that read only, and the next one is an EOF.
2844    ///
2845    /// To SEE THIS RED: drop `incr!(names::tcp::READ_RESET)` from
2846    /// `plain_socket_read`.
2847    #[test]
2848    fn a_plain_read_counts_a_peer_reset_once() {
2849        let mut stream = reset_stream();
2850        let before = proxy_count(names::tcp::READ_RESET);
2851        let mut buf = [0u8; 64];
2852
2853        let (size, result) = stream.socket_read(&mut buf);
2854        assert_eq!((size, result), (0, SocketResult::Closed));
2855        assert_eq!(proxy_count(names::tcp::READ_RESET) - before, 1);
2856
2857        let (size, result) = stream.socket_read(&mut buf);
2858        assert_eq!((size, result), (0, SocketResult::Closed));
2859        assert_eq!(
2860            proxy_count(names::tcp::READ_RESET) - before,
2861            1,
2862            "the EOF after the reset is not another reset"
2863        );
2864    }
2865
2866    /// A write that meets the peer's RST answers `Closed`, as it always did,
2867    /// still counts `tcp.write.error`, and counts `tcp.write.reset` once: the
2868    /// next write answers `EPIPE`, which is not a reset.
2869    ///
2870    /// To SEE THIS RED: drop `incr!(names::tcp::WRITE_RESET)` from
2871    /// `tcp_socket_write`.
2872    #[test]
2873    fn a_plain_write_counts_a_peer_reset_once() {
2874        let mut stream = reset_stream();
2875        let resets = proxy_count(names::tcp::WRITE_RESET);
2876        let errors = proxy_count(names::tcp::WRITE_ERROR);
2877
2878        let (size, result) = stream.socket_write(b"after the reset");
2879        assert_eq!((size, result), (0, SocketResult::Closed));
2880        assert_eq!(proxy_count(names::tcp::WRITE_RESET) - resets, 1);
2881        assert_eq!(proxy_count(names::tcp::WRITE_ERROR) - errors, 1);
2882
2883        let (size, result) = stream.socket_write(b"after the reset");
2884        assert_eq!((size, result), (0, SocketResult::Closed));
2885        assert_eq!(
2886            proxy_count(names::tcp::WRITE_RESET) - resets,
2887            1,
2888            "the EPIPE after the reset is not another reset"
2889        );
2890    }
2891
2892    /// The vectored write path counts a reset exactly as the scalar one.
2893    ///
2894    /// To SEE THIS RED: drop `incr!(names::tcp::WRITE_RESET)` from
2895    /// `tcp_socket_write_vectored`.
2896    #[test]
2897    fn a_plain_vectored_write_counts_a_peer_reset() {
2898        let mut stream = reset_stream();
2899        let before = proxy_count(names::tcp::WRITE_RESET);
2900
2901        let (size, result) =
2902            stream.socket_write_vectored(&[std::io::IoSlice::new(b"after the reset")]);
2903        assert_eq!((size, result), (0, SocketResult::Closed));
2904        assert_eq!(proxy_count(names::tcp::WRITE_RESET) - before, 1);
2905    }
2906}
2907
2908/// [`rustls_socket_read`] and [`plain_socket_read`] against an in-memory
2909/// transport that counts every read a call issues: each one is a `recv(2)` on
2910/// the real socket.
2911#[cfg(test)]
2912pub(crate) mod rustls_read_tests {
2913    use std::{collections::VecDeque, io::Write, sync::Arc};
2914
2915    use super::*;
2916
2917    /// SNI the test certificate is registered under.
2918    pub(crate) const TEST_SNI: &str = "lolcatho.st";
2919
2920    /// A frame header, then its payload: what the H2 read path asks for, one
2921    /// `socket_read` at a time (`lib/src/protocol/mux/h2.rs`, `readable_inner`).
2922    const FRAME_HEADER_LEN: usize = 9;
2923
2924    /// The frames of a client's first flight after the preface — SETTINGS,
2925    /// WINDOW_UPDATE, HEADERS, PING — as `(header, payload)` byte blocks. Only
2926    /// their lengths matter to the transport layer; the contents are
2927    /// distinct so a misordered or duplicated read cannot compare equal.
2928    fn client_frames() -> Vec<Vec<u8>> {
2929        [6usize, 4, 37, 8]
2930            .iter()
2931            .enumerate()
2932            .flat_map(|(index, &payload_len)| {
2933                let mut header = vec![0u8; FRAME_HEADER_LEN];
2934                header[..3].copy_from_slice(&(payload_len as u32).to_be_bytes()[1..]);
2935                header[3] = index as u8;
2936                let payload = (0..payload_len)
2937                    .map(|byte| (index * 64 + byte) as u8)
2938                    .collect();
2939                [header, payload]
2940            })
2941            .collect()
2942    }
2943
2944    /// A non-blocking transport: `wire` is what the kernel holds, served by at
2945    /// most one read, and `eof` is a received FIN once `wire` is drained.
2946    /// `eagains` counts the reads that found nothing, the ones a short read
2947    /// makes unnecessary. The first `interrupts` reads answer `EINTR`.
2948    #[derive(Default)]
2949    pub(crate) struct CountingTransport {
2950        pub(crate) wire: VecDeque<u8>,
2951        pub(crate) eof: bool,
2952        pub(crate) reset: bool,
2953        pub(crate) reads: usize,
2954        pub(crate) eagains: usize,
2955        pub(crate) interrupts: usize,
2956    }
2957
2958    impl Read for CountingTransport {
2959        fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
2960            self.reads += 1;
2961            if self.interrupts > 0 {
2962                self.interrupts -= 1;
2963                return Err(ErrorKind::Interrupted.into());
2964            }
2965            if self.reset {
2966                return Err(ErrorKind::ConnectionReset.into());
2967            }
2968            if self.wire.is_empty() {
2969                return if self.eof {
2970                    Ok(0)
2971                } else {
2972                    self.eagains += 1;
2973                    Err(ErrorKind::WouldBlock.into())
2974                };
2975            }
2976            let len = buf.len().min(self.wire.len());
2977            for (slot, byte) in buf.iter_mut().zip(self.wire.drain(..len)) {
2978                *slot = byte;
2979            }
2980            Ok(len)
2981        }
2982    }
2983
2984    /// Accepts whatever certificate the server presents: the client is the
2985    /// encryption oracle for the bytes under test, not a party whose trust
2986    /// decision is being checked. `lib/assets/certificate.pem` carries no
2987    /// subjectAltName, so rustls's web-PKI verifier would refuse it.
2988    #[derive(Debug)]
2989    struct AcceptAnyServerCertificate;
2990
2991    impl rustls::client::danger::ServerCertVerifier for AcceptAnyServerCertificate {
2992        fn verify_server_cert(
2993            &self,
2994            _end_entity: &rustls::pki_types::CertificateDer<'_>,
2995            _intermediates: &[rustls::pki_types::CertificateDer<'_>],
2996            _server_name: &rustls::pki_types::ServerName<'_>,
2997            _ocsp_response: &[u8],
2998            _now: rustls::pki_types::UnixTime,
2999        ) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
3000            Ok(rustls::client::danger::ServerCertVerified::assertion())
3001        }
3002
3003        fn verify_tls12_signature(
3004            &self,
3005            _message: &[u8],
3006            _cert: &rustls::pki_types::CertificateDer<'_>,
3007            _dss: &rustls::DigitallySignedStruct,
3008        ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
3009            Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
3010        }
3011
3012        fn verify_tls13_signature(
3013            &self,
3014            _message: &[u8],
3015            _cert: &rustls::pki_types::CertificateDer<'_>,
3016            _dss: &rustls::DigitallySignedStruct,
3017        ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
3018            Ok(rustls::client::danger::HandshakeSignatureValid::assertion())
3019        }
3020
3021        fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
3022            crate::crypto::default_provider()
3023                .signature_verification_algorithms
3024                .supported_schemes()
3025        }
3026    }
3027
3028    /// Move every pending TLS byte from `from` to `to`, in memory.
3029    fn pump_tls<A, B>(
3030        from: &mut rustls::ConnectionCommon<A>,
3031        to: &mut rustls::ConnectionCommon<B>,
3032    ) {
3033        let mut wire = Vec::new();
3034        while from.wants_write() {
3035            from.write_tls(&mut wire)
3036                .expect("a TLS flight must serialize into memory");
3037        }
3038        let mut cursor = std::io::Cursor::new(wire.as_slice());
3039        while (cursor.position() as usize) < wire.len() {
3040            to.read_tls(&mut cursor)
3041                .expect("a TLS flight must be readable from memory");
3042            to.process_new_packets()
3043                .expect("a TLS flight must process cleanly");
3044        }
3045    }
3046
3047    /// A TLS 1.3 server session serving the test certificate for
3048    /// [`TEST_SNI`], and a client that accepts it and offers `alpn`, neither
3049    /// started.
3050    pub(crate) fn fresh_pair(alpn: Vec<Vec<u8>>) -> (ServerConnection, rustls::ClientConnection) {
3051        let provider = Arc::new(crate::crypto::default_provider());
3052        let resolver = Arc::new(crate::tls::MutexCertificateResolver::default());
3053        resolver
3054            .0
3055            .lock()
3056            .expect("the test resolver lock must be available")
3057            .add_certificate(&sozu_command::proto::command::AddCertificate {
3058                address: sozu_command::proto::command::SocketAddress::new_v4(127, 0, 0, 1, 8443),
3059                certificate: sozu_command::proto::command::CertificateAndKey {
3060                    certificate: include_str!("../assets/certificate.pem").to_owned(),
3061                    key: include_str!("../assets/key.pem").to_owned(),
3062                    names: vec![TEST_SNI.to_owned()],
3063                    ..Default::default()
3064                },
3065                expired_at: None,
3066            })
3067            .expect("the test certificate must load into the resolver");
3068        let mut server_config = rustls::ServerConfig::builder_with_provider(provider.clone())
3069            .with_protocol_versions(&[&rustls::version::TLS13])
3070            .expect("the test provider must support TLS 1.3")
3071            .with_no_client_auth()
3072            .with_cert_resolver(resolver);
3073        server_config.send_tls13_tickets = 0;
3074        let client_config = rustls::ClientConfig::builder_with_provider(provider)
3075            .with_protocol_versions(&[&rustls::version::TLS13])
3076            .expect("the test provider must support TLS 1.3")
3077            .dangerous()
3078            .with_custom_certificate_verifier(Arc::new(AcceptAnyServerCertificate))
3079            .with_no_client_auth();
3080        let server = ServerConnection::new(Arc::new(server_config))
3081            .expect("the test server session must initialize");
3082        let client = rustls::ClientConnection::new_with_alpn(
3083            Arc::new(client_config),
3084            rustls::pki_types::ServerName::try_from(TEST_SNI)
3085                .expect("the test SNI must be a valid DNS name"),
3086            alpn,
3087        )
3088        .expect("the test client session must initialize");
3089        (server, client)
3090    }
3091
3092    /// A settled TLS 1.3 server session and the client that feeds it.
3093    fn handshaken_pair() -> (ServerConnection, rustls::ClientConnection) {
3094        let (mut server, mut client) = fresh_pair(Vec::new());
3095        for _ in 0..16 {
3096            if !client.is_handshaking() && !server.is_handshaking() && !client.wants_write() {
3097                break;
3098            }
3099            pump_tls(&mut client, &mut server);
3100            pump_tls(&mut server, &mut client);
3101        }
3102        assert!(
3103            !server.is_handshaking() && !client.is_handshaking(),
3104            "premise: the in-memory handshake must complete"
3105        );
3106        (server, client)
3107    }
3108
3109    /// Encrypt `plaintext` as ONE `write_all` + drain, so a flight smaller
3110    /// than a record's 16 KiB limit lands in a single TLS record.
3111    fn seal(client: &mut rustls::ClientConnection, plaintext: &[u8]) -> Vec<u8> {
3112        client
3113            .writer()
3114            .write_all(plaintext)
3115            .expect("the client must absorb the plaintext");
3116        let mut wire = Vec::new();
3117        while client.wants_write() {
3118            client
3119                .write_tls(&mut wire)
3120                .expect("the client record must serialize");
3121        }
3122        wire
3123    }
3124
3125    /// The server side under test: a session plus the flags `FrontRustls`
3126    /// threads through [`rustls_socket_read`].
3127    struct Front {
3128        session: ServerConnection,
3129        peer_disconnected: bool,
3130        peer_reset: bool,
3131        tls_fatal: bool,
3132        memory: RecvMemory,
3133    }
3134
3135    impl Front {
3136        fn read(
3137            &mut self,
3138            transport: &mut CountingTransport,
3139            len: usize,
3140        ) -> (Vec<u8>, SocketResult) {
3141            let mut buf = vec![0u8; len];
3142            let (size, result, fault) = rustls_socket_read(
3143                &mut self.session,
3144                transport,
3145                &mut buf,
3146                &mut self.peer_disconnected,
3147                &mut self.peer_reset,
3148                &mut self.tls_fatal,
3149                &mut self.memory,
3150            );
3151            assert!(fault.is_none(), "unexpected read fault: {fault:?}");
3152            buf.truncate(size);
3153            (buf, result)
3154        }
3155
3156        /// Same as [`Self::read`], for a pass that is expected to fault.
3157        fn read_faulting(
3158            &mut self,
3159            transport: &mut CountingTransport,
3160            len: usize,
3161        ) -> (Vec<u8>, SocketResult) {
3162            let mut buf = vec![0u8; len];
3163            let (size, result, _fault) = rustls_socket_read(
3164                &mut self.session,
3165                transport,
3166                &mut buf,
3167                &mut self.peer_disconnected,
3168                &mut self.peer_reset,
3169                &mut self.tls_fatal,
3170                &mut self.memory,
3171            );
3172            buf.truncate(size);
3173            (buf, result)
3174        }
3175
3176        /// What `FrontRustls::readiness_delivered` does when the event loop
3177        /// delivers `events` for the socket.
3178        fn deliver(&mut self, events: Ready) {
3179            self.memory.event_delivered(events);
3180        }
3181    }
3182
3183    fn front_and_client() -> (Front, rustls::ClientConnection) {
3184        let (session, client) = handshaken_pair();
3185        (
3186            Front {
3187                session,
3188                peer_disconnected: false,
3189                peer_reset: false,
3190                tls_fatal: false,
3191                memory: RecvMemory::default(),
3192            },
3193            client,
3194        )
3195    }
3196
3197    /// Several H2 frames in ONE TLS record, read the way the H2 path reads
3198    /// them: header, payload, header, payload. The record costs one `recv`;
3199    /// every later frame is already decrypted and must be served from
3200    /// rustls's plaintext buffer, and the call that finds that buffer empty
3201    /// answers `WouldBlock` without a `recv`: the first call's short `recv`
3202    /// proved the queue empty and no event was delivered since.
3203    ///
3204    /// Before #1606 every call started with `read_tls`, so each frame block
3205    /// after the first issued one `recv` that returned `EAGAIN`: 1 + 7 + 1.
3206    /// Before #1609 the memory did not outlive a call, and the last call still
3207    /// issued one: 1 + 1.
3208    #[test]
3209    fn frames_sharing_one_record_cost_one_recv() {
3210        let (mut front, mut client) = front_and_client();
3211        let frames = client_frames();
3212        let record = seal(&mut client, &frames.concat());
3213        let mut transport = CountingTransport {
3214            wire: record.into(),
3215            ..Default::default()
3216        };
3217
3218        for (index, block) in frames.iter().enumerate() {
3219            let (read, result) = front.read(&mut transport, block.len());
3220            assert_eq!(
3221                &read, block,
3222                "frame block {index} must arrive intact and in order"
3223            );
3224            assert_eq!(result, SocketResult::Continue, "frame block {index}");
3225        }
3226        let (read, result) = front.read(&mut transport, FRAME_HEADER_LEN);
3227        assert!(read.is_empty(), "nothing is left after the last frame");
3228        assert_eq!(result, SocketResult::WouldBlock);
3229
3230        assert_eq!(
3231            (transport.reads, transport.eagains),
3232            (1, 0),
3233            "one recv for the record and no EAGAIN once the plaintext is drained, \
3234             for {} frame blocks",
3235            frames.len()
3236        );
3237        assert!(!front.peer_disconnected && !front.peer_reset);
3238    }
3239
3240    /// An event delivered after the proof clears it: the bytes that raised it
3241    /// are read by the next call, with no EAGAIN on either side.
3242    #[test]
3243    fn an_event_after_a_short_read_lets_the_next_call_read() {
3244        let (mut front, mut client) = front_and_client();
3245        let frames = client_frames();
3246        let mut transport = CountingTransport {
3247            wire: seal(&mut client, &frames.concat()).into(),
3248            ..Default::default()
3249        };
3250        for block in &frames {
3251            assert_eq!(&front.read(&mut transport, block.len()).0, block);
3252        }
3253        assert_eq!(
3254            front.read(&mut transport, FRAME_HEADER_LEN),
3255            (Vec::new(), SocketResult::WouldBlock),
3256            "no event since the short read: nothing is read"
3257        );
3258
3259        transport.wire.extend(seal(&mut client, &frames[0]));
3260        front.deliver(Ready::READABLE);
3261        let (read, result) = front.read(&mut transport, frames[0].len());
3262        assert_eq!(read, frames[0], "the new arrival is read");
3263        assert_eq!(result, SocketResult::Continue);
3264        assert_eq!((transport.reads, transport.eagains), (2, 0));
3265    }
3266
3267    /// A FIN whose edge is delivered after the proof, as HUP: the memory is
3268    /// off from then on, and the next call reads the EOF.
3269    #[test]
3270    fn a_hup_delivered_after_a_short_read_lets_the_next_call_read_the_eof() {
3271        let (mut front, mut client) = front_and_client();
3272        let frames = client_frames();
3273        let mut transport = CountingTransport {
3274            wire: seal(&mut client, &frames.concat()).into(),
3275            ..Default::default()
3276        };
3277        for block in &frames {
3278            assert_eq!(&front.read(&mut transport, block.len()).0, block);
3279        }
3280
3281        transport.eof = true;
3282        front.deliver(Ready::HUP);
3283        assert_eq!(
3284            front.read(&mut transport, FRAME_HEADER_LEN),
3285            (Vec::new(), SocketResult::Closed)
3286        );
3287        assert!(front.peer_disconnected);
3288        assert_eq!((transport.reads, transport.eagains), (2, 0));
3289    }
3290
3291    /// A caller buffer larger than everything received (the H1 path) takes the
3292    /// whole record in one short `recv` and stops there: the queue is empty,
3293    /// so a second `recv` could only answer EAGAIN.
3294    ///
3295    /// Before the stop on a short read the pass called `read_tls` again and
3296    /// counted 2 reads, the second one EAGAIN.
3297    #[test]
3298    fn a_large_buffer_drains_the_record_in_one_short_recv() {
3299        let (mut front, mut client) = front_and_client();
3300        let plaintext = client_frames().concat();
3301        let mut transport = CountingTransport {
3302            wire: seal(&mut client, &plaintext).into(),
3303            ..Default::default()
3304        };
3305
3306        let (read, result) = front.read(&mut transport, 16 * 1024);
3307        assert_eq!(read, plaintext);
3308        assert_eq!(result, SocketResult::WouldBlock);
3309        assert_eq!(
3310            (transport.reads, transport.eagains),
3311            (1, 0),
3312            "one short recv for the record and no EAGAIN"
3313        );
3314    }
3315
3316    /// `close_notify` in the same arrival as the data, read with a large
3317    /// buffer: the pass stops reading the socket after the short `recv`, but
3318    /// must still report the close rustls already processed, in the same call.
3319    /// A pass that skipped every `read_tls` after a short read would answer
3320    /// `WouldBlock` here and leave the close unreported until a later event.
3321    #[test]
3322    fn close_notify_in_the_short_read_is_reported_in_the_same_call() {
3323        let (mut front, mut client) = front_and_client();
3324        let plaintext = client_frames().concat();
3325        let mut wire = seal(&mut client, &plaintext);
3326        client.send_close_notify();
3327        while client.wants_write() {
3328            client
3329                .write_tls(&mut wire)
3330                .expect("the close_notify alert must serialize");
3331        }
3332        let mut transport = CountingTransport {
3333            wire: wire.into(),
3334            ..Default::default()
3335        };
3336
3337        let (read, result) = front.read(&mut transport, 16 * 1024);
3338        assert_eq!(read, plaintext, "the data precedes the close");
3339        assert_eq!(result, SocketResult::Closed);
3340        assert!(front.peer_disconnected && !front.peer_reset);
3341        assert_eq!((transport.reads, transport.eagains), (1, 0));
3342    }
3343
3344    /// A TCP FIN behind the data, read with a large buffer: the short `recv`
3345    /// delivers the data and stops, and the FIN is read by the next call. The
3346    /// mux makes that call because it saw HUP
3347    /// (`update_readiness_after_read`).
3348    #[test]
3349    fn a_fin_behind_a_short_read_is_reported_by_the_next_call() {
3350        let (mut front, mut client) = front_and_client();
3351        let plaintext = client_frames().concat();
3352        let mut transport = CountingTransport {
3353            wire: seal(&mut client, &plaintext).into(),
3354            eof: true,
3355            ..Default::default()
3356        };
3357        // The FIN came with the data: one edge, delivered as HUP, which turns
3358        // the memory off so the next call reads the EOF.
3359        front.deliver(Ready::READABLE | Ready::HUP);
3360
3361        let (read, result) = front.read(&mut transport, 16 * 1024);
3362        assert_eq!(read, plaintext);
3363        assert_eq!(result, SocketResult::WouldBlock);
3364        assert!(!front.peer_disconnected, "the FIN has not been read yet");
3365
3366        let (read, result) = front.read(&mut transport, 16 * 1024);
3367        assert!(read.is_empty());
3368        assert_eq!(result, SocketResult::Closed);
3369        assert!(front.peer_disconnected && !front.peer_reset);
3370        assert_eq!((transport.reads, transport.eagains), (2, 0));
3371    }
3372
3373    /// A body spanning several records and many 4096-byte `read_tls` calls,
3374    /// read with the H1 buffer size: every byte arrives in order and the full
3375    /// reads keep the pass going.
3376    ///
3377    /// No read answers EAGAIN. The final short `recv` happens in a call whose
3378    /// buffer then fills from the plaintext it decrypted, so that call answers
3379    /// `Continue`; the next call drains the rest and answers `WouldBlock`
3380    /// without a `recv`, because no event was delivered since the short one
3381    /// ([`RecvMemory`]). Before #1609 that call issued one `recv` for an
3382    /// EAGAIN.
3383    #[test]
3384    fn a_large_body_over_tls_arrives_intact() {
3385        let (mut front, mut client) = front_and_client();
3386        let body: Vec<u8> = (0..(64 * 1024 + 123)).map(|i| (i % 251) as u8).collect();
3387        // One record per 16 KiB chunk: the client's outgoing buffer would
3388        // refuse the whole body in one `write_all`.
3389        let mut transport = CountingTransport {
3390            wire: body
3391                .chunks(16 * 1024)
3392                .flat_map(|chunk| seal(&mut client, chunk))
3393                .collect(),
3394            ..Default::default()
3395        };
3396
3397        let mut received = Vec::new();
3398        loop {
3399            let (read, result) = front.read(&mut transport, 16 * 1024);
3400            received.extend_from_slice(&read);
3401            match result {
3402                SocketResult::Continue => assert_eq!(read.len(), 16 * 1024),
3403                SocketResult::WouldBlock => break,
3404                other => panic!("unexpected {other:?} after {} bytes", received.len()),
3405            }
3406        }
3407        assert_eq!(received, body);
3408        assert!(transport.wire.is_empty());
3409        assert_eq!(
3410            transport.eagains, 0,
3411            "the call after the one that filled from the last short read reads nothing"
3412        );
3413    }
3414
3415    /// A record split across two arrivals: the first `read_tls` returns bytes
3416    /// but `process_new_packets` produces no plaintext. That `recv` was short,
3417    /// so the queue is empty and the pass reports `WouldBlock` with nothing
3418    /// delivered, without a second `recv`. The rest of the record then
3419    /// completes it.
3420    #[test]
3421    fn a_fragmented_record_is_read_again_until_it_completes() {
3422        let (mut front, mut client) = front_and_client();
3423        let frames = client_frames();
3424        let record = seal(&mut client, &frames.concat());
3425        let (head, tail) = record.split_at(record.len() / 2);
3426        let mut transport = CountingTransport {
3427            wire: head.iter().copied().collect(),
3428            ..Default::default()
3429        };
3430
3431        let (read, result) = front.read(&mut transport, FRAME_HEADER_LEN);
3432        assert!(read.is_empty(), "half a record decrypts to nothing");
3433        assert_eq!(result, SocketResult::WouldBlock);
3434        assert_eq!(
3435            (transport.reads, transport.eagains),
3436            (1, 0),
3437            "the partial record, in one short recv"
3438        );
3439
3440        transport.wire.extend(tail);
3441        // The tail's arrival raises the edge the event loop delivers.
3442        front.deliver(Ready::READABLE);
3443        for (index, block) in frames.iter().enumerate() {
3444            let (read, result) = front.read(&mut transport, block.len());
3445            assert_eq!(&read, block, "frame block {index}");
3446            assert_eq!(result, SocketResult::Continue, "frame block {index}");
3447        }
3448        assert_eq!(transport.reads, 2, "the rest of the record costs one recv");
3449    }
3450
3451    /// `close_notify` behind the data in the same flight: every frame is
3452    /// still delivered, then the pass reports `Closed` — from rustls's own
3453    /// `read_tls` early return, without another `recv`.
3454    #[test]
3455    fn close_notify_after_the_frames_reports_closed_once_they_are_read() {
3456        let (mut front, mut client) = front_and_client();
3457        let frames = client_frames();
3458        let mut wire = seal(&mut client, &frames.concat());
3459        client.send_close_notify();
3460        while client.wants_write() {
3461            client
3462                .write_tls(&mut wire)
3463                .expect("the close_notify alert must serialize");
3464        }
3465        let mut transport = CountingTransport {
3466            wire: wire.into(),
3467            ..Default::default()
3468        };
3469
3470        for (index, block) in frames.iter().enumerate() {
3471            let (read, result) = front.read(&mut transport, block.len());
3472            assert_eq!(&read, block, "frame block {index}");
3473            assert_eq!(result, SocketResult::Continue, "frame block {index}");
3474        }
3475        let (read, result) = front.read(&mut transport, FRAME_HEADER_LEN);
3476        assert!(read.is_empty());
3477        assert_eq!(
3478            result,
3479            SocketResult::Closed,
3480            "close_notify must close the read side"
3481        );
3482        assert!(
3483            front.peer_disconnected,
3484            "a clean close is a read-side disconnect"
3485        );
3486        assert!(!front.peer_reset, "a clean close is not a reset");
3487        assert_eq!(
3488            transport.reads, 1,
3489            "close_notify needs no recv beyond the flight"
3490        );
3491
3492        let (read, result) = front.read(&mut transport, FRAME_HEADER_LEN);
3493        assert!(read.is_empty());
3494        assert_eq!(
3495            result,
3496            SocketResult::Closed,
3497            "a closed session stays closed"
3498        );
3499    }
3500
3501    /// A TCP FIN without `close_notify`: buffered frames are delivered first,
3502    /// then `Closed` (never `Error`), and a later call is `Closed` again.
3503    #[test]
3504    fn tcp_eof_without_close_notify_reports_closed_after_the_buffered_frames() {
3505        let (mut front, mut client) = front_and_client();
3506        let frames = client_frames();
3507        let mut transport = CountingTransport {
3508            wire: seal(&mut client, &frames.concat()).into(),
3509            eof: true,
3510            ..Default::default()
3511        };
3512        // The FIN came with the data: one edge, delivered as HUP.
3513        front.deliver(Ready::READABLE | Ready::HUP);
3514
3515        for (index, block) in frames.iter().enumerate() {
3516            let (read, result) = front.read(&mut transport, block.len());
3517            assert_eq!(&read, block, "frame block {index}");
3518            assert_eq!(result, SocketResult::Continue, "frame block {index}");
3519        }
3520        let (read, result) = front.read(&mut transport, FRAME_HEADER_LEN);
3521        assert!(read.is_empty());
3522        assert_eq!(
3523            result,
3524            SocketResult::Closed,
3525            "a FIN must close the read side"
3526        );
3527        assert!(front.peer_disconnected && !front.peer_reset);
3528
3529        let (read, result) = front.read(&mut transport, FRAME_HEADER_LEN);
3530        assert!(read.is_empty());
3531        assert_eq!(result, SocketResult::Closed, "EOF stays EOF, not an error");
3532    }
3533
3534    /// A valid record of four frames followed, in the same arrival, by a
3535    /// corrupted one. `process_new_packets` appends the first record's
3536    /// plaintext and then fails on the second: the session is dead. Every
3537    /// later call must answer `Error` without serving that plaintext, or the
3538    /// mux (which only drops READABLE on `Error`) would parse frames from a
3539    /// TLS session that has already failed as soon as the peer sends again.
3540    #[test]
3541    fn a_fatal_tls_error_stays_an_error_and_serves_no_buffered_plaintext() {
3542        let (mut front, mut client) = front_and_client();
3543        let frames = client_frames();
3544        let mut wire = seal(&mut client, &frames.concat());
3545        let mut corrupted = seal(&mut client, b"after the valid record");
3546        let last = corrupted.len() - 1;
3547        corrupted[last] ^= 0xff;
3548        wire.extend(corrupted);
3549        let mut transport = CountingTransport {
3550            wire: wire.into(),
3551            ..Default::default()
3552        };
3553
3554        let (read, result) = front.read_faulting(&mut transport, FRAME_HEADER_LEN);
3555        assert!(read.is_empty(), "the failing pass delivers nothing");
3556        assert_eq!(result, SocketResult::Error);
3557
3558        for call in 0..2 * frames.len() {
3559            transport.wire.extend([0u8; 16]);
3560            let (read, result) = front.read_faulting(&mut transport, FRAME_HEADER_LEN);
3561            assert_eq!(
3562                (read.len(), result),
3563                (0, SocketResult::Error),
3564                "call {call} after a fatal TLS error must stay (0, Error)"
3565            );
3566        }
3567    }
3568
3569    /// The pass that hits the fatal error keeps what it had already copied:
3570    /// plaintext served from the buffer BEFORE `read_tls` met the corrupt
3571    /// record is returned with `Error` (`(n, Error)`), and only later passes
3572    /// are `(0, Error)`.
3573    #[test]
3574    fn plaintext_served_before_the_fatal_error_is_returned_with_it() {
3575        let (mut front, mut client) = front_and_client();
3576        let frames = client_frames();
3577        let plaintext = frames.concat();
3578        let mut transport = CountingTransport {
3579            wire: seal(&mut client, &plaintext).into(),
3580            ..Default::default()
3581        };
3582        let (read, result) = front.read(&mut transport, FRAME_HEADER_LEN);
3583        assert_eq!(read, plaintext[..FRAME_HEADER_LEN]);
3584        assert_eq!(result, SocketResult::Continue);
3585
3586        let mut corrupted = seal(&mut client, b"after the valid record");
3587        let last = corrupted.len() - 1;
3588        corrupted[last] ^= 0xff;
3589        transport.wire.extend(corrupted);
3590        front.deliver(Ready::READABLE);
3591
3592        let (read, result) = front.read_faulting(&mut transport, 16 * 1024);
3593        assert_eq!(
3594            read,
3595            plaintext[FRAME_HEADER_LEN..],
3596            "the rest of the valid record"
3597        );
3598        assert_eq!(result, SocketResult::Error);
3599        let (read, result) = front.read_faulting(&mut transport, 16 * 1024);
3600        assert_eq!((read.len(), result), (0, SocketResult::Error));
3601    }
3602
3603    /// A reset is `Closed` with `peer_reset` set, so writes short-circuit.
3604    #[test]
3605    fn a_reset_reports_closed_and_marks_the_peer_reset() {
3606        let (mut front, _client) = front_and_client();
3607        let mut transport = CountingTransport {
3608            reset: true,
3609            ..Default::default()
3610        };
3611
3612        let (read, result) = front.read(&mut transport, FRAME_HEADER_LEN);
3613        assert!(read.is_empty());
3614        assert_eq!(result, SocketResult::Closed);
3615        assert!(front.peer_disconnected && front.peer_reset);
3616        assert_eq!(transport.reads, 1);
3617    }
3618
3619    /// A settled TLS frontend over a real socket its peer reset
3620    /// (`SO_LINGER` zero, then close).
3621    fn reset_front() -> FrontRustls {
3622        let (session, _client) = handshaken_pair();
3623        FrontRustls {
3624            stream: super::tests::reset_stream(),
3625            session,
3626            peer_disconnected: false,
3627            peer_reset: false,
3628            tls_fatal: false,
3629            session_ulid: Ulid::generate(),
3630            configured_peer: None,
3631            recv_memory: RecvMemory::default(),
3632        }
3633    }
3634
3635    /// A TLS read that meets the peer's RST answers `Closed` and counts
3636    /// `rustls.read.reset` once. The write that follows short-circuits on
3637    /// `peer_reset` without reaching the socket, so it counts nothing, and
3638    /// the reset does not leak into the plain-TCP counter either.
3639    ///
3640    /// To SEE THIS RED: drop `incr!(names::rustls::READ_RESET)` from
3641    /// `rustls_socket_read`.
3642    #[test]
3643    fn a_tls_read_counts_a_peer_reset_once() {
3644        let mut front = reset_front();
3645        let reads = super::tests::proxy_count(names::rustls::READ_RESET);
3646        let writes = super::tests::proxy_count(names::rustls::WRITE_RESET);
3647        let plain = super::tests::proxy_count(names::tcp::READ_RESET);
3648
3649        let mut buf = [0u8; 64];
3650        let (size, result) = front.socket_read(&mut buf);
3651        assert_eq!((size, result), (0, SocketResult::Closed));
3652        assert!(front.peer_reset);
3653        assert_eq!(
3654            super::tests::proxy_count(names::rustls::READ_RESET) - reads,
3655            1
3656        );
3657
3658        let (_, result) = front.socket_write(b"after the reset");
3659        assert_eq!(result, SocketResult::Closed);
3660        assert_eq!(
3661            super::tests::proxy_count(names::rustls::WRITE_RESET) - writes,
3662            0,
3663            "a write after a reset read never reaches the socket"
3664        );
3665        assert_eq!(super::tests::proxy_count(names::tcp::READ_RESET) - plain, 0);
3666    }
3667
3668    /// A TLS write that meets the peer's RST answers `Closed`, still counts
3669    /// `rustls.write.error`, and counts `rustls.write.reset` once: the next
3670    /// write short-circuits on `peer_reset`.
3671    ///
3672    /// To SEE THIS RED: drop `incr!(names::rustls::WRITE_RESET)` from
3673    /// `flush_tls`.
3674    #[test]
3675    fn a_tls_write_counts_a_peer_reset_once() {
3676        let mut front = reset_front();
3677        let resets = super::tests::proxy_count(names::rustls::WRITE_RESET);
3678        let errors = super::tests::proxy_count(names::rustls::WRITE_ERROR);
3679
3680        let (_, result) = front.socket_write(b"after the reset");
3681        assert_eq!(result, SocketResult::Closed);
3682        assert!(front.peer_reset);
3683        assert_eq!(
3684            super::tests::proxy_count(names::rustls::WRITE_RESET) - resets,
3685            1
3686        );
3687        assert_eq!(
3688            super::tests::proxy_count(names::rustls::WRITE_ERROR) - errors,
3689            1
3690        );
3691
3692        let (_, result) = front.socket_write_vectored(&[std::io::IoSlice::new(b"after the reset")]);
3693        assert_eq!(result, SocketResult::Closed);
3694        assert_eq!(
3695            super::tests::proxy_count(names::rustls::WRITE_RESET) - resets,
3696            1,
3697            "the reset is counted once"
3698        );
3699    }
3700
3701    /// A settled TLS frontend over a socket whose connection the kernel
3702    /// refused: its first write answers `ECONNREFUSED`, which no arm but the
3703    /// generic one names.
3704    fn refused_front() -> FrontRustls {
3705        let address = std::net::TcpListener::bind("127.0.0.1:0")
3706            .expect("test listener must bind to a loopback port")
3707            .local_addr()
3708            .expect("test listener must report its local address");
3709        // The listener is gone: the connect below meets a RST.
3710        let socket =
3711            Socket::new(Domain::IPV4, Type::STREAM, None).expect("a TCP socket must be created");
3712        socket
3713            .set_nonblocking(true)
3714            .expect("mio requires a nonblocking stream");
3715        if let Err(e) = socket.connect(&address.into()) {
3716            assert_eq!(
3717                e.raw_os_error(),
3718                Some(libc::EINPROGRESS),
3719                "a nonblocking connect must be in progress, got {e}"
3720            );
3721        }
3722        let mut pollfd = libc::pollfd {
3723            fd: std::os::unix::io::AsRawFd::as_raw_fd(&socket),
3724            events: libc::POLLOUT,
3725            revents: 0,
3726        };
3727        // SAFETY: one valid `pollfd` borrowed for the duration of the call.
3728        let ready = unsafe { libc::poll(&mut pollfd, 1, 5_000) };
3729        assert_eq!(ready, 1, "the refusal must arrive within 5 s");
3730        assert_ne!(
3731            pollfd.revents & libc::POLLERR,
3732            0,
3733            "premise: the kernel must have refused the connection"
3734        );
3735        let (session, _client) = handshaken_pair();
3736        FrontRustls {
3737            stream: TcpStream::from_std(std::net::TcpStream::from(socket)),
3738            session,
3739            peer_disconnected: false,
3740            peer_reset: false,
3741            tls_fatal: false,
3742            session_ulid: Ulid::generate(),
3743            configured_peer: None,
3744            recv_memory: RecvMemory::default(),
3745        }
3746    }
3747
3748    /// A TLS write that meets a socket error no other arm names answers
3749    /// `Error` and marks the channel dead: the record rustls still holds can
3750    /// never be delivered, so `socket_wants_write` stops reporting it, and the
3751    /// next write short-circuits without reaching the socket. Otherwise the
3752    /// record kept the H1 session's flush pending, which delays its close on
3753    /// the hang-up, and a mux pass that re-raised WRITABLE for it retried the
3754    /// failing write (sozu-proxy/sozu#1780).
3755    ///
3756    /// To SEE THIS RED: drop `self.peer_reset = true;` from the generic arm
3757    /// of the `flush_tls` loop in `FrontRustls::socket_write`.
3758    #[test]
3759    fn a_tls_write_that_meets_a_socket_error_stops_wanting_to_write() {
3760        let mut front = refused_front();
3761        let errors = super::tests::proxy_count(names::rustls::WRITE_ERROR);
3762
3763        let (_, result) = front.socket_write(b"refused by the kernel");
3764        assert_eq!(result, SocketResult::Error);
3765        assert_eq!(
3766            super::tests::proxy_count(names::rustls::WRITE_ERROR) - errors,
3767            1
3768        );
3769        assert!(
3770            front.session.wants_write(),
3771            "premise: rustls must still hold the record the kernel refused"
3772        );
3773        assert!(
3774            !front.socket_wants_write(),
3775            "a record no write can deliver must not read as a pending write"
3776        );
3777
3778        let writes = tls_writes();
3779        let (_, result) = front.socket_write_vectored(&[std::io::IoSlice::new(b"after the error")]);
3780        assert_eq!(result, SocketResult::Closed);
3781        assert_eq!(
3782            tls_writes(),
3783            writes,
3784            "a write after the error must not reach the socket"
3785        );
3786    }
3787
3788    /// `refused_front` with records already queued in rustls and nothing
3789    /// written yet, for the empty-buffer flushes that only drain them.
3790    fn refused_front_holding_records() -> FrontRustls {
3791        let mut front = refused_front();
3792        front
3793            .session
3794            .writer()
3795            .write_all(b"queued before the flush")
3796            .expect("rustls must absorb the plaintext");
3797        assert!(
3798            front.session.wants_write(),
3799            "premise: rustls must hold the record the flush will try to write"
3800        );
3801        front
3802    }
3803
3804    /// The write that met the socket error answered `Error`, and the record
3805    /// rustls still holds no longer reads as a pending write.
3806    fn assert_error_marks_the_channel_dead(front: &FrontRustls, result: SocketResult) {
3807        assert_eq!(result, SocketResult::Error);
3808        assert!(
3809            front.session.wants_write(),
3810            "premise: rustls must still hold the record the kernel refused"
3811        );
3812        assert!(
3813            front.peer_reset && !front.socket_wants_write(),
3814            "an Error write must mark the channel dead, or the record keeps the \
3815             session waiting for a WRITABLE edge that never comes"
3816        );
3817    }
3818
3819    /// The empty-buffer flush of `socket_write` — the one `H2Shell` issues to
3820    /// push queued records — marks the channel dead on a socket error.
3821    ///
3822    /// TO SEE THIS RED: drop the `self.peer_reset = true;` of the `is_error`
3823    /// return in `FrontRustls::socket_write`.
3824    #[test]
3825    fn an_empty_tls_flush_that_meets_a_socket_error_marks_the_channel_dead() {
3826        let mut front = refused_front_holding_records();
3827        let (_, result) = front.socket_write(&[]);
3828        assert_error_marks_the_channel_dead(&front, result);
3829    }
3830
3831    /// A vectored write rustls absorbs whole, then flushes in the main loop.
3832    ///
3833    /// TO SEE THIS RED: drop the `self.peer_reset = true;` of the `is_error`
3834    /// return in `FrontRustls::socket_write_vectored`.
3835    #[test]
3836    fn a_vectored_tls_write_that_meets_a_socket_error_marks_the_channel_dead() {
3837        let mut front = refused_front();
3838        let (size, result) = front.socket_write_vectored(&[
3839            std::io::IoSlice::new(b"refused "),
3840            std::io::IoSlice::new(b"by the kernel"),
3841        ]);
3842        assert_eq!(size, 21, "premise: rustls must absorb the whole write");
3843        assert_error_marks_the_channel_dead(&front, result);
3844    }
3845
3846    /// A vectored write rustls absorbs only in part (its send buffer is
3847    /// capped), which takes the partial-write flush before returning.
3848    ///
3849    /// TO SEE THIS RED: the same edit as the whole-write test above.
3850    #[test]
3851    fn a_partial_vectored_tls_write_that_meets_a_socket_error_marks_the_channel_dead() {
3852        let mut front = refused_front();
3853        front.session.set_buffer_limit(Some(64));
3854        let payload = vec![b'x'; 4096];
3855        let (size, result) = front.socket_write_vectored(&[std::io::IoSlice::new(&payload)]);
3856        assert!(
3857            size > 0 && size < payload.len(),
3858            "premise: rustls must absorb part of the write, got {size}"
3859        );
3860        assert_error_marks_the_channel_dead(&front, result);
3861    }
3862
3863    /// The empty-buffer flush of `socket_write_vectored`.
3864    ///
3865    /// TO SEE THIS RED: the same edit as the whole-write test above.
3866    #[test]
3867    fn an_empty_vectored_tls_flush_that_meets_a_socket_error_marks_the_channel_dead() {
3868        let mut front = refused_front_holding_records();
3869        let (_, result) = front.socket_write_vectored(&[]);
3870        assert_error_marks_the_channel_dead(&front, result);
3871    }
3872
3873    /// A transport whose first write is interrupted (`EINTR`) and whose next
3874    /// one takes everything.
3875    #[derive(Default)]
3876    struct InterruptedOnce {
3877        calls: usize,
3878        written: Vec<u8>,
3879    }
3880
3881    impl std::io::Write for InterruptedOnce {
3882        fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
3883            self.calls += 1;
3884            if self.calls == 1 {
3885                return Err(std::io::Error::from(ErrorKind::Interrupted));
3886            }
3887            self.written.extend_from_slice(buf);
3888            Ok(buf.len())
3889        }
3890
3891        fn flush(&mut self) -> std::io::Result<()> {
3892            Ok(())
3893        }
3894    }
3895
3896    /// An interrupted TLS write is retried, not reported: as `WouldBlock` no
3897    /// edge would resume it, and as an error it would mark the channel dead.
3898    ///
3899    /// TO SEE THIS RED: remove the `Interrupted => continue` arm of the retry
3900    /// loop in `flush_tls`.
3901    #[test]
3902    fn an_interrupted_tls_write_is_retried() {
3903        let (mut session, _client) = handshaken_pair();
3904        session
3905            .writer()
3906            .write_all(b"interrupted once")
3907            .expect("rustls must absorb the plaintext");
3908        let mut transport = InterruptedOnce::default();
3909
3910        let written = flush_tls(&mut session, &mut transport)
3911            .expect("an interrupted write must be retried, not reported");
3912
3913        assert!(written > 0 && transport.written.len() == written);
3914        assert_eq!(transport.calls, 2, "one interrupted write, one retry");
3915        assert!(!session.wants_write(), "the retry must deliver the record");
3916    }
3917
3918    /// An interrupted plain TCP write is retried, not reported: as an error it
3919    /// would close the session (the pipe path closes on a front write error).
3920    ///
3921    /// TO SEE THIS RED: remove the `Interrupted` arm of the write loop in
3922    /// `plain_socket_write`.
3923    #[test]
3924    fn an_interrupted_plain_write_is_retried() {
3925        let mut transport = InterruptedOnce::default();
3926
3927        let (size, result, fault) = plain_socket_write(&mut transport, b"interrupted once");
3928
3929        assert!(fault.is_none(), "unexpected write fault: {fault:?}");
3930        assert_eq!((size, result), (16, SocketResult::Continue));
3931        assert_eq!(transport.calls, 2, "one interrupted write, one retry");
3932        assert_eq!(transport.written, b"interrupted once");
3933    }
3934
3935    /// The vectored plain TCP write retries an interruption the same way.
3936    ///
3937    /// TO SEE THIS RED: remove the `Interrupted` arm of the retry loop in
3938    /// `plain_socket_write_vectored`.
3939    #[test]
3940    fn an_interrupted_plain_vectored_write_is_retried() {
3941        let mut transport = InterruptedOnce::default();
3942        let bufs = [std::io::IoSlice::new(b"interrupted once")];
3943
3944        let (size, result, fault) = plain_socket_write_vectored(&mut transport, &bufs);
3945
3946        assert!(fault.is_none(), "unexpected write fault: {fault:?}");
3947        assert_eq!((size, result), (16, SocketResult::Continue));
3948        assert_eq!(transport.calls, 2, "one interrupted write, one retry");
3949        assert_eq!(transport.written, b"interrupted once");
3950    }
3951
3952    /// An interrupted plain TCP read is retried, not reported as an error.
3953    ///
3954    /// TO SEE THIS RED: remove the `Interrupted` arm of the retry loop in
3955    /// `plain_socket_read`.
3956    #[test]
3957    fn an_interrupted_plain_read_is_retried() {
3958        let mut transport = CountingTransport {
3959            wire: b"interrupted once".iter().copied().collect(),
3960            interrupts: 1,
3961            ..Default::default()
3962        };
3963        let mut buf = [0u8; 32];
3964
3965        let (size, result, fault) = plain_socket_read(&mut transport, &mut buf);
3966
3967        assert!(fault.is_none(), "unexpected read fault: {fault:?}");
3968        assert_eq!((size, result), (16, SocketResult::WouldBlock));
3969        assert_eq!(&buf[..size], b"interrupted once");
3970        assert_eq!(transport.reads, 2, "one interrupted read, one retry");
3971    }
3972
3973    /// An interrupted `recv` under `read_tls` is retried, not reported as a
3974    /// `ReadTls` fault.
3975    ///
3976    /// TO SEE THIS RED: remove the `Interrupted` arm of the `read_tls` retry
3977    /// loop in `rustls_socket_read`.
3978    #[test]
3979    fn an_interrupted_tls_read_is_retried() {
3980        let (mut front, mut client) = front_and_client();
3981        let mut transport = CountingTransport {
3982            wire: seal(&mut client, b"interrupted once").into(),
3983            interrupts: 1,
3984            ..Default::default()
3985        };
3986
3987        let (read, result) = front.read(&mut transport, 32);
3988
3989        assert_eq!(read, b"interrupted once");
3990        assert_eq!(result, SocketResult::WouldBlock);
3991        assert_eq!(transport.reads, 2, "one interrupted read, one retry");
3992    }
3993
3994    /// Read everything `transport` holds through [`plain_socket_read`] with a
3995    /// `len`-byte buffer, one call at a time, until a call answers something
3996    /// other than `Continue`.
3997    fn plain_read_all(transport: &mut CountingTransport, len: usize) -> (Vec<u8>, SocketResult) {
3998        let mut received = Vec::new();
3999        loop {
4000            let mut buf = vec![0u8; len];
4001            let (size, result, fault) = plain_socket_read(transport, &mut buf);
4002            assert!(fault.is_none(), "unexpected read fault: {fault:?}");
4003            received.extend_from_slice(&buf[..size]);
4004            if result != SocketResult::Continue {
4005                return (received, result);
4006            }
4007            assert_eq!(size, len, "Continue means the buffer filled");
4008        }
4009    }
4010
4011    /// A request smaller than the buffer (the H1 path, one request per
4012    /// connection) costs one `recv`: it answers fewer bytes than offered, the
4013    /// queue is empty, and the call reports `WouldBlock` with the bytes.
4014    ///
4015    /// Before the stop on a short read `tcp_socket_read` looped and counted 2
4016    /// reads, the second one EAGAIN.
4017    #[test]
4018    fn a_short_plain_read_costs_one_recv_and_no_eagain() {
4019        let request = b"GET /index.html HTTP/1.1\r\nHost: lolcatho.st\r\n\r\n".to_vec();
4020        let mut transport = CountingTransport {
4021            wire: request.iter().copied().collect(),
4022            ..Default::default()
4023        };
4024
4025        let mut buf = vec![0u8; 16 * 1024];
4026        let (size, result, fault) = plain_socket_read(&mut transport, &mut buf);
4027        assert!(fault.is_none());
4028        assert_eq!(&buf[..size], &request[..]);
4029        assert_eq!(result, SocketResult::WouldBlock);
4030        assert_eq!(
4031            (transport.reads, transport.eagains),
4032            (1, 0),
4033            "one short recv and no EAGAIN"
4034        );
4035    }
4036
4037    /// A read that fills the buffer is not a short read: it answers
4038    /// `Continue`, READABLE stays, and the next call reads on.
4039    #[test]
4040    fn a_full_plain_buffer_is_not_a_short_read() {
4041        let mut transport = CountingTransport {
4042            wire: (0..250u8).collect(),
4043            ..Default::default()
4044        };
4045
4046        let mut buf = vec![0u8; 100];
4047        let (size, result, _) = plain_socket_read(&mut transport, &mut buf);
4048        assert_eq!((size, result), (100, SocketResult::Continue));
4049        let (size, result, _) = plain_socket_read(&mut transport, &mut buf);
4050        assert_eq!((size, result), (100, SocketResult::Continue));
4051        let (size, result, _) = plain_socket_read(&mut transport, &mut buf);
4052        assert_eq!((size, result), (50, SocketResult::WouldBlock));
4053        assert_eq!((transport.reads, transport.eagains), (3, 0));
4054    }
4055
4056    /// Data followed by a FIN: the short read delivers the data, and the next
4057    /// call reads the EOF as `Closed`. An empty queue with a FIN is `Closed`
4058    /// at once.
4059    #[test]
4060    fn a_fin_behind_a_short_plain_read_is_closed_on_the_next_call() {
4061        let mut transport = CountingTransport {
4062            wire: (0..50u8).collect(),
4063            eof: true,
4064            ..Default::default()
4065        };
4066
4067        let mut buf = vec![0u8; 16 * 1024];
4068        let (size, result, _) = plain_socket_read(&mut transport, &mut buf);
4069        assert_eq!((size, result), (50, SocketResult::WouldBlock));
4070        assert_eq!(buf[..size], (0..50u8).collect::<Vec<_>>()[..]);
4071        let (size, result, _) = plain_socket_read(&mut transport, &mut buf);
4072        assert_eq!((size, result), (0, SocketResult::Closed));
4073        let (size, result, _) = plain_socket_read(&mut transport, &mut buf);
4074        assert_eq!((size, result), (0, SocketResult::Closed), "EOF stays EOF");
4075        assert_eq!(transport.eagains, 0);
4076    }
4077
4078    /// A message arriving in fragments: each arrival costs one short `recv`
4079    /// and ends its call, and the bytes concatenate in order.
4080    #[test]
4081    fn a_fragmented_plain_message_costs_one_recv_per_arrival() {
4082        let message: Vec<u8> = (0..70u8).collect();
4083        let mut transport = CountingTransport::default();
4084        let mut received = Vec::new();
4085
4086        for chunk in message.chunks(30) {
4087            transport.wire.extend(chunk);
4088            let mut buf = vec![0u8; 16 * 1024];
4089            let (size, result, _) = plain_socket_read(&mut transport, &mut buf);
4090            assert_eq!((size, result), (chunk.len(), SocketResult::WouldBlock));
4091            received.extend_from_slice(&buf[..size]);
4092        }
4093        assert_eq!(received, message);
4094        assert_eq!((transport.reads, transport.eagains), (3, 0));
4095    }
4096
4097    /// A body much larger than the buffer: every full read answers `Continue`,
4098    /// the final short read answers `WouldBlock`, every byte arrives in order,
4099    /// and no read answers EAGAIN.
4100    #[test]
4101    fn a_large_plain_body_arrives_intact_without_eagain() {
4102        let body: Vec<u8> = (0..(1024 * 1024 + 123)).map(|i| (i % 251) as u8).collect();
4103        let mut transport = CountingTransport {
4104            wire: body.iter().copied().collect(),
4105            ..Default::default()
4106        };
4107
4108        let (received, result) = plain_read_all(&mut transport, 16 * 1024);
4109        assert_eq!(result, SocketResult::WouldBlock);
4110        assert_eq!(received, body);
4111        assert_eq!(
4112            (transport.reads, transport.eagains),
4113            (65, 0),
4114            "64 full reads and the short tail"
4115        );
4116    }
4117
4118    /// A body that is an exact multiple of the buffer ends on a full read, so
4119    /// the only way to learn the queue is empty is the EAGAIN that follows: a
4120    /// full buffer is never taken for a short read.
4121    #[test]
4122    fn a_plain_body_ending_on_a_full_buffer_still_needs_its_eagain() {
4123        let body: Vec<u8> = (0..(4 * 16 * 1024)).map(|i| (i % 251) as u8).collect();
4124        let mut transport = CountingTransport {
4125            wire: body.iter().copied().collect(),
4126            ..Default::default()
4127        };
4128
4129        let (received, result) = plain_read_all(&mut transport, 16 * 1024);
4130        assert_eq!(result, SocketResult::WouldBlock);
4131        assert_eq!(received, body);
4132        assert_eq!((transport.reads, transport.eagains), (5, 1));
4133    }
4134
4135    /// The kernel property the stop relies on, on a real socket registered
4136    /// edge-triggered with mio: after a short read, bytes that arrive later
4137    /// raise a new READABLE event, and a FIN raises one too. No event is
4138    /// pending in between, so nothing else would have woken the reader.
4139    #[test]
4140    fn after_a_short_read_new_bytes_raise_a_new_edge() {
4141        use std::io::Write as _;
4142
4143        let token = mio::Token(7);
4144        let mut poll = mio::Poll::new().expect("a poll instance must open");
4145        let mut events = mio::Events::with_capacity(8);
4146        let listener = std::net::TcpListener::bind("127.0.0.1:0")
4147            .expect("test listener must bind to a loopback port");
4148        let mut client = std::net::TcpStream::connect(
4149            listener
4150                .local_addr()
4151                .expect("test listener must report its local address"),
4152        )
4153        .expect("loopback connect must complete");
4154        let (accepted, _) = listener.accept().expect("the connection must be accepted");
4155        accepted
4156            .set_nonblocking(true)
4157            .expect("mio requires a nonblocking stream");
4158        let mut server = TcpStream::from_std(accepted);
4159        poll.registry()
4160            .register(&mut server, token, mio::Interest::READABLE)
4161            .expect("the stream must register");
4162        let wait_for_edge = |poll: &mut mio::Poll, events: &mut mio::Events| {
4163            poll.poll(events, Some(std::time::Duration::from_secs(5)))
4164                .expect("poll must succeed");
4165            events
4166                .iter()
4167                .any(|event| event.token() == token && event.is_readable())
4168        };
4169        let mut buf = vec![0u8; 16 * 1024];
4170
4171        client.write_all(b"first").expect("the client must write");
4172        assert!(wait_for_edge(&mut poll, &mut events), "the first arrival");
4173        assert_eq!(
4174            tcp_socket_read(&mut server, &mut buf, None, None),
4175            (5, SocketResult::WouldBlock)
4176        );
4177
4178        poll.poll(&mut events, Some(std::time::Duration::from_millis(50)))
4179            .expect("poll must succeed");
4180        assert!(events.is_empty(), "edge-triggered: nothing new, no event");
4181
4182        client.write_all(b"second").expect("the client must write");
4183        assert!(
4184            wait_for_edge(&mut poll, &mut events),
4185            "bytes arriving after a short read must raise a new edge"
4186        );
4187        assert_eq!(
4188            tcp_socket_read(&mut server, &mut buf, None, None),
4189            (6, SocketResult::WouldBlock)
4190        );
4191
4192        client
4193            .shutdown(std::net::Shutdown::Write)
4194            .expect("the client must half-close");
4195        assert!(wait_for_edge(&mut poll, &mut events), "the FIN");
4196        assert_eq!(
4197            tcp_socket_read(&mut server, &mut buf, None, None),
4198            (0, SocketResult::Closed)
4199        );
4200    }
4201}