Skip to main content

detcore_model/
network_engine.rs

1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9//! The pure state machine behind network record and replay.
10//!
11//! The engine models the guest-visible state of each outbound TCP channel:
12//! which inbound bytes have been released to the guest, whether the peer
13//! closed or reset the connection, how many bytes the guest transmitted, and
14//! the receive low-water mark. It performs no I/O. The runtime asks it what a
15//! guest `recv`, `poll` or `send` observes at a given global time, and in
16//! record mode feeds it the bytes it pulled from the host.
17//!
18//! Determinism rests on the release rule of [`NetworkReleaseV1`]: an input
19//! becomes visible once global time has reached the time at which the
20//! recording first observed it *and* the guest has transmitted at least as
21//! many bytes on that channel as it had by then. Both quantities are
22//! functions of the guest's own deterministic execution, so a replay never
23//! depends on host timing, and a replay that follows the recorded schedule
24//! observes every input at the same check that the recording did.
25//!
26//! A blocking receive completes once enough bytes are available to satisfy
27//! its target, all at once. Linux may copy a partial segment into the buffer
28//! of a waiting reader before the rest arrives; the engine instead hands out
29//! the bytes as if they had arrived together, which is one of the outcomes
30//! Linux permits.
31
32use std::collections::BTreeMap;
33use std::collections::VecDeque;
34use std::error::Error;
35use std::fmt;
36
37use chrono::DateTime;
38use chrono::Utc;
39use serde::Deserialize;
40use serde::Serialize;
41
42use crate::fd::OpenFileId;
43use crate::network_trace::NetworkAddressV1;
44use crate::network_trace::NetworkChannelV2;
45use crate::network_trace::NetworkEndpointRoleV1;
46use crate::network_trace::NetworkInputEventV1;
47use crate::network_trace::NetworkInputKindV1;
48use crate::network_trace::NetworkOutputV4;
49use crate::network_trace::NetworkReleaseV1;
50use crate::network_trace::NetworkSendWaitV4;
51use crate::network_trace::NetworkTraceV2;
52use crate::network_trace::NetworkTraceValidationError;
53use crate::network_trace::NetworkTransportV1;
54use crate::time::LogicalTime;
55
56/// Serde for the guest bytes that network requests and replies carry, as one
57/// byte string rather than serde's default for `Vec<u8>`, a sequence of
58/// separately serialized `u8` elements.
59///
60/// Requests cross a serializer on their way to the global state: the RPC
61/// transport of a backend whose tool runs in the guest process, and, in a build
62/// with debug assertions (the `dev` and `validate` profiles), reverie-ptrace's
63/// round trip of every request through bincode. In replay, a blocking send that
64/// waits for buffer space passes its whole unsent remainder on every wait, so the
65/// per-element cost of a sequence is paid again on every wait: a 252 KB
66/// remainder took about 21 ms per bincode round trip in a `dev` build, against
67/// 0.02 ms as a byte string, and the replay of a send that had waited a few
68/// thousand times outran its test's wall bound. Bincode writes both forms
69/// identically, a length and then the raw bytes, so the encoding does not
70/// change; decoding still accepts a sequence, which is how self-describing
71/// formats such as JSON write bytes.
72mod guest_bytes {
73    use std::fmt;
74
75    use serde::Deserializer;
76    use serde::Serializer;
77    use serde::de::Error;
78    use serde::de::SeqAccess;
79    use serde::de::Visitor;
80
81    pub(super) fn serialize<S: Serializer>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
82        serializer.serialize_bytes(bytes)
83    }
84
85    pub(super) fn deserialize<'de, D: Deserializer<'de>>(
86        deserializer: D,
87    ) -> Result<Vec<u8>, D::Error> {
88        deserializer.deserialize_byte_buf(GuestBytes)
89    }
90
91    struct GuestBytes;
92
93    impl<'de> Visitor<'de> for GuestBytes {
94        type Value = Vec<u8>;
95
96        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
97            formatter.write_str("guest bytes")
98        }
99
100        fn visit_bytes<E: Error>(self, bytes: &[u8]) -> Result<Vec<u8>, E> {
101            Ok(bytes.to_vec())
102        }
103
104        fn visit_byte_buf<E: Error>(self, bytes: Vec<u8>) -> Result<Vec<u8>, E> {
105            Ok(bytes)
106        }
107
108        fn visit_seq<A: SeqAccess<'de>>(self, mut sequence: A) -> Result<Vec<u8>, A::Error> {
109            // Never trust a length hint for an allocation.
110            let mut bytes = Vec::with_capacity(sequence.size_hint().unwrap_or(0).min(1 << 16));
111            while let Some(byte) = sequence.next_element()? {
112                bytes.push(byte);
113            }
114            Ok(bytes)
115        }
116    }
117}
118
119/// Something the recorder pulled from a host socket.
120#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
121pub enum NetworkArrival {
122    Bytes(#[serde(with = "guest_bytes")] Vec<u8>),
123    /// The peer shut down its write side (the host `recv` returned 0).
124    PeerWriteClosed,
125    /// The host socket reported this positive errno.
126    Error(i32),
127}
128
129/// What a guest receive observes.
130#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
131pub enum NetworkRecvOutcome {
132    Data(#[serde(with = "guest_bytes")] Vec<u8>),
133    /// End of stream: `recv` returns 0.
134    Eof,
135    /// A pending socket error, consumed by this receive.
136    Error(i32),
137    /// Not enough bytes for the receive's target yet.
138    WouldBlock,
139}
140
141/// A failure that ends the run: the guest asked for something the recording
142/// cannot answer, or that this version does not model.
143#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
144pub enum NetworkEngineError {
145    /// The operation needs a different mode (for example a replay-only call
146    /// during record).
147    WrongMode,
148    UnknownChannel(OpenFileId),
149    /// A channel connected twice.
150    ChannelExists(OpenFileId),
151    /// Replay connected a socket the recording never connected.
152    NotInTrace(OpenFileId),
153    PeerMismatch {
154        channel: OpenFileId,
155        recorded: NetworkAddressV1,
156        attempted: NetworkAddressV1,
157    },
158    /// Replay transmitted bytes that differ from the recording.
159    OutboundMismatch {
160        channel: OpenFileId,
161        offset: u64,
162    },
163    /// Replay transmitted more bytes than the recording holds.
164    OutboundBeyondRecording {
165        channel: OpenFileId,
166        offset: u64,
167    },
168    /// Replay made a blocking send where the recording holds a nonblocking
169    /// send that Linux refused with `EAGAIN`.
170    BlockingSendAtRefusal {
171        channel: OpenFileId,
172        offset: u64,
173    },
174    /// Replay made a nonblocking send where the recording holds a fragment
175    /// that a blocking send waited for buffer space to send.
176    NonblockingSendAtWait {
177        channel: OpenFileId,
178        offset: u64,
179    },
180    /// Record: another send, accepted or refused, reached the stream while a
181    /// blocking send waited for buffer space, so the stream interleaves the
182    /// two.
183    InterleavedSend {
184        channel: OpenFileId,
185        offset: u64,
186    },
187    /// The recorder fed an arrival after the stream ended, or an empty one.
188    InvalidArrival(OpenFileId),
189    /// The finished recording failed validation.
190    Trace(NetworkTraceValidationError),
191    /// Record connected to a peer a trace cannot hold.
192    UntraceablePeer(NetworkAddressV1),
193    /// Replay waited [`REPLAY_STALL_LIMIT`] past the recorded arrival of an
194    /// input that the recording released only after the guest had sent
195    /// `needed` bytes; this replay has sent `sent`.
196    ReplayStalled {
197        channel: OpenFileId,
198        needed: u64,
199        sent: u64,
200    },
201    /// Replay ended without connecting a socket the recording connected.
202    ReplayUnconnected(OpenFileId),
203    /// Replay ended having sent `sent` of the `recorded` bytes on a channel.
204    ReplayUnsent {
205        channel: OpenFileId,
206        sent: u64,
207        recorded: u64,
208    },
209    /// Replay ended without the nonblocking send that the recording holds,
210    /// refused with `EAGAIN`, at stream offset `offset`.
211    ReplayUnrefused {
212        channel: OpenFileId,
213        offset: u64,
214    },
215}
216
217/// How long past an input's recorded arrival, in global (virtual) time,
218/// replay waits for the guest to send the bytes that gate it before declaring
219/// that the guest diverged. It has the same length as the host waits of record
220/// mode, but those are wall-clock waits.
221pub const REPLAY_STALL_LIMIT: std::time::Duration = std::time::Duration::from_secs(60);
222
223/// The remedy for a replay whose guest did something other than what the
224/// recording holds.
225const DIVERGED_REMEDY: &str = "The replayed program diverged from the recording. Replay the same \
226     program with the same arguments, files and environment, or record it again with \
227     --record-networking.";
228
229impl NetworkEngineError {
230    /// What the user can do about this error.
231    pub fn remedy(&self) -> &'static str {
232        match self {
233            Self::NotInTrace(_)
234            | Self::PeerMismatch { .. }
235            | Self::OutboundMismatch { .. }
236            | Self::OutboundBeyondRecording { .. }
237            | Self::BlockingSendAtRefusal { .. }
238            | Self::NonblockingSendAtWait { .. }
239            | Self::ReplayStalled { .. }
240            | Self::ReplayUnconnected(_)
241            | Self::ReplayUnsent { .. }
242            | Self::ReplayUnrefused { .. } => DIVERGED_REMEDY,
243            Self::InterleavedSend { .. } => {
244                "Network record/replay does not model two threads sending on one socket \
245                 while one waits for buffer space; send from one thread at a time, or run \
246                 without --record-networking."
247            }
248            Self::UntraceablePeer(_) => {
249                "Connect to a specific host address and nonzero port, for example \
250                 127.0.0.1 instead of 0.0.0.0, or run without --record-networking."
251            }
252            Self::ChannelExists(_) => {
253                "Network record/replay supports one connect per socket; run this program \
254                 without --record-networking."
255            }
256            Self::Trace(_) => {
257                "The recording is outside what network record/replay supports; run this \
258                 program without --record-networking."
259            }
260            Self::WrongMode | Self::UnknownChannel(_) | Self::InvalidArrival(_) => {
261                "This is a hermit defect; report it with the command line that produced it."
262            }
263        }
264    }
265}
266
267impl fmt::Display for NetworkEngineError {
268    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
269        match self {
270            Self::WrongMode => write!(f, "network engine called in the wrong mode"),
271            Self::UnknownChannel(id) => write!(f, "network trace: {id} is not connected"),
272            Self::ChannelExists(id) => write!(
273                f,
274                "network trace: {id} connected twice, which network record/replay does not support"
275            ),
276            Self::NotInTrace(id) => write!(f, "network trace has no recorded connection for {id}"),
277            Self::PeerMismatch {
278                channel,
279                recorded,
280                attempted,
281            } => write!(
282                f,
283                "network trace mismatch: {channel} connected to {attempted:?}, but the recording connected it to {recorded:?}"
284            ),
285            Self::OutboundMismatch { channel, offset } => write!(
286                f,
287                "network outbound mismatch: {channel} sent different bytes than the recording at stream offset {offset}"
288            ),
289            Self::OutboundBeyondRecording { channel, offset } => write!(
290                f,
291                "network outbound mismatch: {channel} sent bytes past the end of the recording at stream offset {offset}"
292            ),
293            Self::BlockingSendAtRefusal { channel, offset } => write!(
294                f,
295                "network outbound mismatch: {channel} made a blocking send at stream offset \
296                 {offset}, where the recording holds a nonblocking send refused with EAGAIN"
297            ),
298            Self::NonblockingSendAtWait { channel, offset } => write!(
299                f,
300                "network outbound mismatch: {channel} made a nonblocking send at stream \
301                 offset {offset}, where the recording holds a blocking send that waited for \
302                 buffer space"
303            ),
304            Self::InterleavedSend { channel, offset } => write!(
305                f,
306                "network record: another send on {channel}, accepted or refused, reached \
307                 stream offset {offset} while a blocking send waited for buffer space"
308            ),
309            Self::InvalidArrival(id) => write!(
310                f,
311                "network record received input for {id} after its stream ended"
312            ),
313            Self::Trace(error) => write!(f, "network trace: {error}"),
314            Self::UntraceablePeer(peer) => write!(
315                f,
316                "network record cannot trace a connection to {peer:?}, which names no single host"
317            ),
318            Self::ReplayStalled {
319                channel,
320                needed,
321                sent,
322            } => write!(
323                f,
324                "network replay stalled: {channel} is waiting for input that the recording \
325                 delivered after {needed} bytes were sent, but this replay has sent {sent} \
326                 after {} seconds of virtual time past the recorded arrival",
327                REPLAY_STALL_LIMIT.as_secs()
328            ),
329            Self::ReplayUnconnected(id) => write!(
330                f,
331                "network replay ended without connecting {id}, which the recording connected"
332            ),
333            Self::ReplayUnsent {
334                channel,
335                sent,
336                recorded,
337            } => write!(
338                f,
339                "network replay ended after {channel} sent {sent} of the {recorded} bytes the \
340                 recording sent"
341            ),
342            Self::ReplayUnrefused { channel, offset } => write!(
343                f,
344                "network replay ended before {channel} made the nonblocking send at stream \
345                 offset {offset} that the recording holds, refused with EAGAIN"
346            ),
347        }
348    }
349}
350
351impl Error for NetworkEngineError {}
352
353/// One engine operation, carried from a guest thread to the global state.
354///
355/// Every request that observes inbound state carries the arrivals the
356/// recorder pulled from the host just before it, so that one round trip
357/// both records the pull and answers the guest at the same global time.
358/// Replay sends no arrivals.
359#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
360pub enum NetworkRequest {
361    /// See [`NetworkEngine::record_connect`].
362    RecordConnect {
363        id: OpenFileId,
364        peer: NetworkAddressV1,
365        local: Option<NetworkAddressV1>,
366        errno: i32,
367        nonblocking: bool,
368    },
369    /// See [`NetworkEngine::replay_connect`].
370    ReplayConnect {
371        id: OpenFileId,
372        peer: NetworkAddressV1,
373        nonblocking: bool,
374    },
375    /// See [`NetworkEngine::recv`].
376    Recv {
377        id: OpenFileId,
378        arrivals: Vec<NetworkArrival>,
379        max_len: usize,
380        target: usize,
381        peek: bool,
382    },
383    /// The readiness of each channel given its `SO_RCVLOWAT`; see
384    /// [`NetworkEngine::readiness`].
385    Readiness(Vec<(OpenFileId, usize, Vec<NetworkArrival>)>),
386    /// See [`NetworkEngine::take_error`].
387    TakeError(OpenFileId),
388    /// See [`NetworkEngine::send_failure`].
389    SendFailure(OpenFileId),
390    /// See [`NetworkEngine::record_send`].
391    RecordSend {
392        id: OpenFileId,
393        #[serde(with = "guest_bytes")]
394        bytes: Vec<u8>,
395        at: Option<SendMark>,
396        waits: u64,
397    },
398    /// See [`NetworkEngine::record_refused_send`].
399    RecordRefusedSend(OpenFileId),
400    /// See [`NetworkEngine::replay_send`].
401    ReplaySend {
402        id: OpenFileId,
403        #[serde(with = "guest_bytes")]
404        bytes: Vec<u8>,
405        nonblocking: bool,
406        waits: u64,
407    },
408    /// See [`NetworkEngine::shutdown`].
409    Shutdown { id: OpenFileId, how: i32 },
410    /// See [`NetworkEngine::addresses`].
411    Addresses(OpenFileId),
412}
413
414/// Where a recorded send left a channel's outbound stream: its offset, and
415/// how many output events (accepted chunks and refused sends) the channel
416/// has recorded. A blocking send that waits for buffer space passes its mark
417/// back with its next chunk; any output event in between changes `events`,
418/// even a refusal, which does not move `offset`.
419#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
420pub struct SendMark {
421    pub offset: u64,
422    pub events: u64,
423}
424
425/// What [`NetworkEngine::replay_send`] did with a guest send.
426#[derive(Debug, Clone, Copy, PartialEq, Eq)]
427pub enum ReplaySendOutcome {
428    /// The send transmits this many bytes.
429    Sent(usize),
430    /// A nonblocking send that the recording refused with `EAGAIN`.
431    WouldBlock,
432    /// A blocking send whose next fragment is not yet due; it waits again.
433    NotYet,
434}
435
436/// The answer to a [`NetworkRequest`].
437#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
438pub enum NetworkReply {
439    /// `0` or a positive errno.
440    Errno(i32),
441    /// A positive errno, or `None` for success.
442    Failure(Option<i32>),
443    Recv(NetworkRecvOutcome),
444    /// Poll events, one per requested channel.
445    Events(Vec<i16>),
446    Sent(usize),
447    /// Where a recorded send left the outbound stream.
448    Recorded(SendMark),
449    /// A nonblocking send that the recording refused with `EAGAIN`.
450    WouldBlock,
451    /// A blocking send that has not yet waited as long as the recording did
452    /// before Linux accepted the next fragment; it waits again.
453    NotYet,
454    /// Local (if connected) and peer address, or `None` for an unknown channel.
455    Addresses(Option<(Option<NetworkAddressV1>, NetworkAddressV1)>),
456}
457
458#[derive(Debug)]
459enum Mode {
460    Record {
461        epoch: DateTime<Utc>,
462        inputs: Vec<NetworkInputEventV1>,
463        outputs: Vec<NetworkOutputV4>,
464    },
465    Replay {
466        /// Recorded channels the guest has not connected yet, each holding
467        /// its input and output streams.
468        unconnected: BTreeMap<OpenFileId, Channel>,
469    },
470}
471
472#[derive(Debug)]
473struct Channel {
474    record: NetworkChannelV2,
475    /// Released bytes the guest has not read yet.
476    rx: VecDeque<u8>,
477    /// Stream offset just past the last released byte.
478    rx_end: u64,
479    peer_closed: bool,
480    /// The connection was reset or failed: both directions are shut down.
481    reset: bool,
482    /// A socket error the guest has not consumed yet.
483    pending_error: Option<i32>,
484    /// Bytes the guest has transmitted.
485    tx: u64,
486    /// Record: output events recorded, accepted chunks and refused sends.
487    output_events: u64,
488    shut_rd: bool,
489    shut_wr: bool,
490    /// Replay: inputs not yet released, in order.
491    pending_inputs: VecDeque<NetworkInputEventV1>,
492    /// Replay: outbound fragments not yet fully matched, in order.
493    expected_outputs: VecDeque<NetworkOutputV4>,
494}
495
496impl Channel {
497    fn new(record: NetworkChannelV2) -> Self {
498        Channel {
499            reset: record.connect_errno != 0,
500            pending_error: None,
501            record,
502            rx: VecDeque::new(),
503            rx_end: 0,
504            peer_closed: false,
505            tx: 0,
506            output_events: 0,
507            shut_rd: false,
508            shut_wr: false,
509            pending_inputs: VecDeque::new(),
510            expected_outputs: VecDeque::new(),
511        }
512    }
513
514    fn send_mark(&self) -> SendMark {
515        SendMark {
516            offset: self.tx,
517            events: self.output_events,
518        }
519    }
520
521    fn input_ended(&self) -> bool {
522        self.peer_closed || self.reset
523    }
524
525    fn apply(&mut self, event: NetworkInputKindV1) {
526        match event {
527            NetworkInputKindV1::InboundBytes { bytes, .. } => {
528                self.rx_end += bytes.len() as u64;
529                self.rx.extend(bytes);
530            }
531            NetworkInputKindV1::PeerWriteClosed { .. } => self.peer_closed = true,
532            NetworkInputKindV1::SocketError { errno, .. } => {
533                self.reset = true;
534                self.pending_error = Some(errno);
535            }
536        }
537    }
538
539    /// Replay: fail if the next input has been due for [`REPLAY_STALL_LIMIT`]
540    /// and is still held back only by bytes the guest has not sent.
541    fn check_stalled(&self, now: LogicalTime) -> Result<(), NetworkEngineError> {
542        let Some(input) = self.pending_inputs.front() else {
543            return Ok(());
544        };
545        let release = &input.release;
546        if self.tx < release.after_transmitted_offset
547            && now >= release.not_before_global_time + REPLAY_STALL_LIMIT
548        {
549            return Err(NetworkEngineError::ReplayStalled {
550                channel: self.record.id,
551                needed: release.after_transmitted_offset,
552                sent: self.tx,
553            });
554        }
555        Ok(())
556    }
557
558    fn release(&mut self, now: LogicalTime) {
559        while let Some(input) = self.pending_inputs.front() {
560            if !input.release.is_eligible(now, self.tx) {
561                break;
562            }
563            let input = self.pending_inputs.pop_front().expect("front exists");
564            self.apply(input.event);
565        }
566    }
567}
568
569/// The guest-visible network state of one record or replay run.
570#[derive(Debug)]
571pub struct NetworkEngine {
572    mode: Mode,
573    channels: BTreeMap<OpenFileId, Channel>,
574}
575
576impl NetworkEngine {
577    /// Start recording; `epoch` is the run's configured epoch.
578    pub fn new_record(epoch: DateTime<Utc>) -> Self {
579        NetworkEngine {
580            mode: Mode::Record {
581                epoch,
582                inputs: Vec::new(),
583                outputs: Vec::new(),
584            },
585            channels: BTreeMap::new(),
586        }
587    }
588
589    /// Replay `trace`, which must already have passed validation.
590    pub fn new_replay(trace: NetworkTraceV2) -> Self {
591        let mut unconnected: BTreeMap<OpenFileId, Channel> = trace
592            .channels
593            .into_iter()
594            .map(|record| (record.id, Channel::new(record)))
595            .collect();
596        for input in trace.inputs {
597            if let Some(channel) = unconnected.get_mut(&input.channel) {
598                channel.pending_inputs.push_back(input);
599            }
600        }
601        for output in trace.outputs {
602            if let Some(channel) = unconnected.get_mut(&output.channel) {
603                channel.expected_outputs.push_back(output);
604            }
605        }
606        NetworkEngine {
607            mode: Mode::Replay { unconnected },
608            channels: BTreeMap::new(),
609        }
610    }
611
612    pub fn is_record(&self) -> bool {
613        matches!(self.mode, Mode::Record { .. })
614    }
615
616    /// Whether the guest connected `id` as a network channel.
617    pub fn is_channel(&self, id: OpenFileId) -> bool {
618        self.channels.contains_key(&id)
619    }
620
621    fn channel(&mut self, id: OpenFileId) -> Result<&mut Channel, NetworkEngineError> {
622        self.channels
623            .get_mut(&id)
624            .ok_or(NetworkEngineError::UnknownChannel(id))
625    }
626
627    fn check_new(&self, id: OpenFileId) -> Result<(), NetworkEngineError> {
628        if self.channels.contains_key(&id) {
629            return Err(NetworkEngineError::ChannelExists(id));
630        }
631        Ok(())
632    }
633
634    /// Start the guest-visible life of `channel` and return what the guest
635    /// `connect` returns: `0` or a positive errno. A nonblocking connect
636    /// always returns `EINPROGRESS` and leaves the outcome for `SO_ERROR`,
637    /// which is one of the behaviours Linux permits even on loopback.
638    fn connected(&mut self, mut channel: Channel, nonblocking: bool) -> i32 {
639        let errno = channel.record.connect_errno;
640        let result = if nonblocking {
641            channel.pending_error = (errno != 0).then_some(errno);
642            libc::EINPROGRESS
643        } else {
644            errno
645        };
646        self.channels.insert(channel.record.id, channel);
647        result
648    }
649
650    /// Record a connect the runtime performed on the host. `errno` is `0` on
651    /// success, and `local` is the host-assigned local address.
652    pub fn record_connect(
653        &mut self,
654        id: OpenFileId,
655        peer: NetworkAddressV1,
656        local: Option<NetworkAddressV1>,
657        errno: i32,
658        nonblocking: bool,
659    ) -> Result<i32, NetworkEngineError> {
660        if !self.is_record() {
661            return Err(NetworkEngineError::WrongMode);
662        }
663        self.check_new(id)?;
664        if !peer.is_traceable_peer() {
665            return Err(NetworkEngineError::UntraceablePeer(peer));
666        }
667        let record = NetworkChannelV2 {
668            id,
669            transport: NetworkTransportV1::Tcp,
670            role: NetworkEndpointRoleV1::OutboundClient,
671            local_address: if errno == 0 { local } else { None },
672            peer_address: peer,
673            connect_errno: errno,
674        };
675        Ok(self.connected(Channel::new(record), nonblocking))
676    }
677
678    /// Replay the recorded connect of `id`, which must target the recorded peer.
679    pub fn replay_connect(
680        &mut self,
681        id: OpenFileId,
682        peer: &NetworkAddressV1,
683        nonblocking: bool,
684    ) -> Result<i32, NetworkEngineError> {
685        self.check_new(id)?;
686        let Mode::Replay { unconnected } = &mut self.mode else {
687            return Err(NetworkEngineError::WrongMode);
688        };
689        let recorded = &unconnected
690            .get(&id)
691            .ok_or(NetworkEngineError::NotInTrace(id))?
692            .record
693            .peer_address;
694        if recorded != peer {
695            return Err(NetworkEngineError::PeerMismatch {
696                channel: id,
697                recorded: recorded.clone(),
698                attempted: peer.clone(),
699            });
700        }
701        let channel = unconnected.remove(&id).expect("checked above");
702        Ok(self.connected(channel, nonblocking))
703    }
704
705    /// The local and peer addresses of a connected channel, for
706    /// `getsockname` and `getpeername`.
707    pub fn addresses(
708        &self,
709        id: OpenFileId,
710    ) -> Option<(Option<&NetworkAddressV1>, &NetworkAddressV1)> {
711        self.channels.get(&id).map(|channel| {
712            (
713                channel.record.local_address.as_ref(),
714                &channel.record.peer_address,
715            )
716        })
717    }
718
719    /// Whether the recorder should pull more input for `id` from the host.
720    pub fn needs_pull(&self, id: OpenFileId) -> bool {
721        self.is_record()
722            && self
723                .channels
724                .get(&id)
725                .is_some_and(|channel| !channel.input_ended())
726    }
727
728    /// Record what the runtime pulled from the host for `id` at global time
729    /// `now`, and make it visible to the guest at once.
730    pub fn record_arrival(
731        &mut self,
732        id: OpenFileId,
733        now: LogicalTime,
734        arrival: NetworkArrival,
735    ) -> Result<(), NetworkEngineError> {
736        let channel = self
737            .channels
738            .get_mut(&id)
739            .ok_or(NetworkEngineError::UnknownChannel(id))?;
740        let Mode::Record { inputs, .. } = &mut self.mode else {
741            return Err(NetworkEngineError::WrongMode);
742        };
743        if channel.input_ended() || matches!(&arrival, NetworkArrival::Bytes(b) if b.is_empty()) {
744            return Err(NetworkEngineError::InvalidArrival(id));
745        }
746        let stream_offset = channel.rx_end;
747        let event = match arrival {
748            NetworkArrival::Bytes(bytes) => NetworkInputKindV1::InboundBytes {
749                stream_offset,
750                bytes,
751            },
752            NetworkArrival::PeerWriteClosed => {
753                NetworkInputKindV1::PeerWriteClosed { stream_offset }
754            }
755            NetworkArrival::Error(errno) => NetworkInputKindV1::SocketError {
756                stream_offset,
757                errno,
758            },
759        };
760        inputs.push(NetworkInputEventV1 {
761            ordinal: inputs.len() as u64,
762            channel: id,
763            release: NetworkReleaseV1 {
764                not_before_global_time: now,
765                after_transmitted_offset: channel.tx,
766            },
767            event: event.clone(),
768        });
769        channel.apply(event);
770        Ok(())
771    }
772
773    /// A guest receive of at most `max_len` bytes at global time `now`.
774    ///
775    /// `target` is the byte count that completes a blocking receive:
776    /// `min(SO_RCVLOWAT, max_len)`, or `max_len` under `MSG_WAITALL`. A
777    /// nonblocking receive, or one whose timeout expired, passes `1`. With
778    /// `peek` the bytes stay queued.
779    pub fn recv(
780        &mut self,
781        id: OpenFileId,
782        now: LogicalTime,
783        max_len: usize,
784        target: usize,
785        peek: bool,
786    ) -> Result<NetworkRecvOutcome, NetworkEngineError> {
787        let channel = self.channel(id)?;
788        channel.release(now);
789        let available = channel.rx.len();
790        // After `SHUT_RD` Linux still delivers the bytes already queued, then
791        // reports end of file without waiting.
792        if available > 0
793            && (available >= target.max(1)
794                || channel.input_ended()
795                || channel.shut_rd
796                || channel.pending_error.is_some())
797        {
798            let len = available.min(max_len);
799            let bytes = if peek {
800                channel.rx.iter().take(len).copied().collect()
801            } else {
802                channel.rx.drain(..len).collect()
803            };
804            return Ok(NetworkRecvOutcome::Data(bytes));
805        }
806        if available == 0 {
807            // Linux consumes a pending error even under MSG_PEEK.
808            if let Some(errno) = channel.pending_error.take() {
809                return Ok(NetworkRecvOutcome::Error(errno));
810            }
811            if channel.input_ended() || channel.shut_rd {
812                return Ok(NetworkRecvOutcome::Eof);
813            }
814        }
815        channel.check_stalled(now)?;
816        Ok(NetworkRecvOutcome::WouldBlock)
817    }
818
819    /// The `poll` events `id` reports at global time `now`, before masking
820    /// with the requested events. Mirrors Linux `tcp_poll`; `lowat` is the
821    /// socket's `SO_RCVLOWAT`, which the guest may set before it connects.
822    pub fn readiness(
823        &mut self,
824        id: OpenFileId,
825        now: LogicalTime,
826        lowat: usize,
827    ) -> Result<i16, NetworkEngineError> {
828        let channel = self.channel(id)?;
829        channel.release(now);
830        channel.check_stalled(now)?;
831        let rcv_shutdown = channel.shut_rd || channel.input_ended();
832        let snd_shutdown = channel.shut_wr || channel.reset;
833        let mut events = 0;
834        if (rcv_shutdown && snd_shutdown) || channel.reset {
835            events |= libc::POLLHUP;
836        }
837        if rcv_shutdown {
838            events |= libc::POLLIN | libc::POLLRDNORM | libc::POLLRDHUP;
839        } else if channel.rx.len() >= lowat.max(1) {
840            events |= libc::POLLIN | libc::POLLRDNORM;
841        }
842        // Linux reports a socket shut down for writing as writable, so that
843        // the write fails instead of blocking.
844        events |= libc::POLLOUT | libc::POLLWRNORM;
845        if channel.pending_error.is_some() {
846            events |= libc::POLLERR;
847        }
848        Ok(events)
849    }
850
851    /// Consume and return the pending socket error at global time `now`, as
852    /// `SO_ERROR` does; `0` when there is none. Inputs due by `now` are
853    /// released first, so the first observer of a recorded error sees it
854    /// whichever operation it uses.
855    pub fn take_error(
856        &mut self,
857        id: OpenFileId,
858        now: LogicalTime,
859    ) -> Result<i32, NetworkEngineError> {
860        let channel = self.channel(id)?;
861        channel.release(now);
862        Ok(channel.pending_error.take().unwrap_or(0))
863    }
864
865    /// The errno a guest send at global time `now` fails with before
866    /// transmitting anything, or `None` when the send may proceed. Inputs due
867    /// by `now` are released first. A pending error is consumed first;
868    /// otherwise a socket shut down for writing fails with `EPIPE`.
869    pub fn send_failure(
870        &mut self,
871        id: OpenFileId,
872        now: LogicalTime,
873    ) -> Result<Option<i32>, NetworkEngineError> {
874        let channel = self.channel(id)?;
875        channel.release(now);
876        if channel.reset || channel.shut_wr {
877            return Ok(Some(channel.pending_error.take().unwrap_or(libc::EPIPE)));
878        }
879        Ok(None)
880    }
881
882    /// Record the bytes a host send accepted at `now` and return where they
883    /// left the stream. Empty `sent` records nothing and returns the current
884    /// mark, which a blocking send takes before its first wait. `at` is the
885    /// mark of a send that then waited for buffer space; any output event on
886    /// the channel in the meantime, accepted or refused, is refused, because
887    /// replay would order the two the other way. `waits` counts the send's
888    /// waits since it started or since its previous accepted chunk; when it
889    /// is nonzero the fragment records that count and `now`, so that replay
890    /// accepts it only after waiting as long.
891    pub fn record_send(
892        &mut self,
893        id: OpenFileId,
894        sent: &[u8],
895        at: Option<SendMark>,
896        now: LogicalTime,
897        waits: u64,
898    ) -> Result<SendMark, NetworkEngineError> {
899        let channel = self
900            .channels
901            .get_mut(&id)
902            .ok_or(NetworkEngineError::UnknownChannel(id))?;
903        let Mode::Record { outputs, .. } = &mut self.mode else {
904            return Err(NetworkEngineError::WrongMode);
905        };
906        if let Some(at) = at
907            && at != channel.send_mark()
908        {
909            return Err(NetworkEngineError::InterleavedSend {
910                channel: id,
911                offset: at.offset,
912            });
913        }
914        if sent.is_empty() {
915            return Ok(channel.send_mark());
916        }
917        outputs.push(NetworkOutputV4 {
918            channel: id,
919            stream_offset: channel.tx,
920            bytes: sent.to_vec(),
921            wait: (waits > 0).then_some(NetworkSendWaitV4 {
922                waits,
923                not_before_global_time: now,
924            }),
925        });
926        channel.tx += sent.len() as u64;
927        channel.output_events += 1;
928        Ok(channel.send_mark())
929    }
930
931    /// Record a nonblocking send that the host refused with `EAGAIN`, as an
932    /// empty fragment at the current stream offset.
933    pub fn record_refused_send(&mut self, id: OpenFileId) -> Result<(), NetworkEngineError> {
934        let channel = self
935            .channels
936            .get_mut(&id)
937            .ok_or(NetworkEngineError::UnknownChannel(id))?;
938        let Mode::Record { outputs, .. } = &mut self.mode else {
939            return Err(NetworkEngineError::WrongMode);
940        };
941        outputs.push(NetworkOutputV4 {
942            channel: id,
943            stream_offset: channel.tx,
944            bytes: Vec::new(),
945            wait: None,
946        });
947        channel.output_events += 1;
948        Ok(())
949    }
950
951    /// Match a guest send at `now` against the recording and return how
952    /// many bytes it transmits: the bytes left in the current recorded
953    /// fragment, at most `bytes.len()`. A recorded short write therefore
954    /// replays as the same short write. [`ReplaySendOutcome::WouldBlock`] is
955    /// a nonblocking send that the recording refused with `EAGAIN`; a
956    /// blocking send at that point diverged.
957    ///
958    /// A fragment that the recording accepted only after its send waited is
959    /// due once this send has waited `waits` times as many and `now` has
960    /// reached the recorded acceptance time; before that the send gets
961    /// [`ReplaySendOutcome::NotYet`] and waits again. The check and the
962    /// consumption happen in this one call, so nothing can run between them.
963    pub fn replay_send(
964        &mut self,
965        id: OpenFileId,
966        bytes: &[u8],
967        nonblocking: bool,
968        now: LogicalTime,
969        waits: u64,
970    ) -> Result<ReplaySendOutcome, NetworkEngineError> {
971        if self.is_record() {
972            return Err(NetworkEngineError::WrongMode);
973        }
974        let channel = self.channel(id)?;
975        if bytes.is_empty() {
976            return Ok(ReplaySendOutcome::Sent(0));
977        }
978        let offset = channel.tx;
979        let fragment = channel.expected_outputs.front().ok_or(
980            NetworkEngineError::OutboundBeyondRecording {
981                channel: id,
982                offset,
983            },
984        )?;
985        if fragment.bytes.is_empty() {
986            if !nonblocking {
987                return Err(NetworkEngineError::BlockingSendAtRefusal {
988                    channel: id,
989                    offset,
990                });
991            }
992            channel.expected_outputs.pop_front();
993            return Ok(ReplaySendOutcome::WouldBlock);
994        }
995        let start = (offset - fragment.stream_offset) as usize;
996        if start == 0
997            && let Some(wait) = &fragment.wait
998        {
999            if nonblocking {
1000                return Err(NetworkEngineError::NonblockingSendAtWait {
1001                    channel: id,
1002                    offset,
1003                });
1004            }
1005            if waits < wait.waits || now < wait.not_before_global_time {
1006                return Ok(ReplaySendOutcome::NotYet);
1007            }
1008        }
1009        let remaining = &fragment.bytes[start..];
1010        let len = remaining.len().min(bytes.len());
1011        if remaining[..len] != bytes[..len] {
1012            let first_difference = remaining
1013                .iter()
1014                .zip(bytes)
1015                .position(|(expected, actual)| expected != actual)
1016                .unwrap_or(len);
1017            return Err(NetworkEngineError::OutboundMismatch {
1018                channel: id,
1019                offset: offset + first_difference as u64,
1020            });
1021        }
1022        channel.tx += len as u64;
1023        if len == remaining.len() {
1024            channel.expected_outputs.pop_front();
1025        }
1026        Ok(ReplaySendOutcome::Sent(len))
1027    }
1028
1029    /// Apply `shutdown(how)`; returns `0` or the errno the guest sees.
1030    pub fn shutdown(&mut self, id: OpenFileId, how: i32) -> Result<i32, NetworkEngineError> {
1031        let channel = self.channel(id)?;
1032        if channel.record.connect_errno != 0 {
1033            return Ok(libc::ENOTCONN);
1034        }
1035        match how {
1036            libc::SHUT_RD => channel.shut_rd = true,
1037            libc::SHUT_WR => channel.shut_wr = true,
1038            libc::SHUT_RDWR => {
1039                channel.shut_rd = true;
1040                channel.shut_wr = true;
1041            }
1042            _ => return Ok(libc::EINVAL),
1043        }
1044        Ok(0)
1045    }
1046
1047    /// Record pulled arrivals at `now`. Pulls that follow the end of the
1048    /// stream are dropped: a drained host socket keeps reporting it.
1049    fn record_arrivals(
1050        &mut self,
1051        id: OpenFileId,
1052        now: LogicalTime,
1053        arrivals: Vec<NetworkArrival>,
1054    ) -> Result<(), NetworkEngineError> {
1055        for arrival in arrivals {
1056            if !self.needs_pull(id) {
1057                break;
1058            }
1059            self.record_arrival(id, now, arrival)?;
1060        }
1061        Ok(())
1062    }
1063
1064    /// Perform `request` at global time `now`.
1065    pub fn apply(
1066        &mut self,
1067        now: LogicalTime,
1068        request: NetworkRequest,
1069    ) -> Result<NetworkReply, NetworkEngineError> {
1070        Ok(match request {
1071            NetworkRequest::RecordConnect {
1072                id,
1073                peer,
1074                local,
1075                errno,
1076                nonblocking,
1077            } => NetworkReply::Errno(self.record_connect(id, peer, local, errno, nonblocking)?),
1078            NetworkRequest::ReplayConnect {
1079                id,
1080                peer,
1081                nonblocking,
1082            } => NetworkReply::Errno(self.replay_connect(id, &peer, nonblocking)?),
1083            NetworkRequest::Recv {
1084                id,
1085                arrivals,
1086                max_len,
1087                target,
1088                peek,
1089            } => {
1090                self.record_arrivals(id, now, arrivals)?;
1091                NetworkReply::Recv(self.recv(id, now, max_len, target, peek)?)
1092            }
1093            NetworkRequest::Readiness(channels) => {
1094                let mut events = Vec::with_capacity(channels.len());
1095                for (id, lowat, arrivals) in channels {
1096                    self.record_arrivals(id, now, arrivals)?;
1097                    events.push(self.readiness(id, now, lowat)?);
1098                }
1099                NetworkReply::Events(events)
1100            }
1101            NetworkRequest::TakeError(id) => NetworkReply::Errno(self.take_error(id, now)?),
1102            NetworkRequest::SendFailure(id) => NetworkReply::Failure(self.send_failure(id, now)?),
1103            NetworkRequest::RecordSend {
1104                id,
1105                bytes,
1106                at,
1107                waits,
1108            } => NetworkReply::Recorded(self.record_send(id, &bytes, at, now, waits)?),
1109            NetworkRequest::RecordRefusedSend(id) => {
1110                self.record_refused_send(id)?;
1111                NetworkReply::WouldBlock
1112            }
1113            NetworkRequest::ReplaySend {
1114                id,
1115                bytes,
1116                nonblocking,
1117                waits,
1118            } => match self.replay_send(id, &bytes, nonblocking, now, waits)? {
1119                ReplaySendOutcome::Sent(sent) => NetworkReply::Sent(sent),
1120                ReplaySendOutcome::WouldBlock => NetworkReply::WouldBlock,
1121                ReplaySendOutcome::NotYet => NetworkReply::NotYet,
1122            },
1123            NetworkRequest::Shutdown { id, how } => NetworkReply::Errno(self.shutdown(id, how)?),
1124            NetworkRequest::Addresses(id) => NetworkReply::Addresses(
1125                self.addresses(id)
1126                    .map(|(local, peer)| (local.cloned(), peer.clone())),
1127            ),
1128        })
1129    }
1130
1131    /// End a replay: fail if the guest left part of the recording unused, by
1132    /// never connecting a recorded socket, by sending fewer bytes than the
1133    /// recording holds, or by never making a recorded refused send. Inputs the guest never read are not checked: when an
1134    /// input is released depends on the schedule, so a replay may end before
1135    /// a final input the recording happened to observe.
1136    pub fn finish_replay(self) -> Result<(), NetworkEngineError> {
1137        let Mode::Replay { unconnected } = self.mode else {
1138            return Err(NetworkEngineError::WrongMode);
1139        };
1140        if let Some(id) = unconnected.into_keys().next() {
1141            return Err(NetworkEngineError::ReplayUnconnected(id));
1142        }
1143        for (id, channel) in self.channels {
1144            if let Some(last) = channel.expected_outputs.back() {
1145                let recorded = last.stream_offset + last.bytes.len() as u64;
1146                return Err(if recorded > channel.tx {
1147                    NetworkEngineError::ReplayUnsent {
1148                        channel: id,
1149                        sent: channel.tx,
1150                        recorded,
1151                    }
1152                } else {
1153                    NetworkEngineError::ReplayUnrefused {
1154                        channel: id,
1155                        offset: channel.tx,
1156                    }
1157                });
1158            }
1159        }
1160        Ok(())
1161    }
1162
1163    /// The trace of a record run. Fails if the run was a replay or the
1164    /// recording does not validate.
1165    pub fn finish(mut self) -> Result<NetworkTraceV2, NetworkEngineError> {
1166        let Mode::Record {
1167            epoch,
1168            inputs,
1169            outputs,
1170        } = self.mode
1171        else {
1172            return Err(NetworkEngineError::WrongMode);
1173        };
1174        let trace = NetworkTraceV2 {
1175            epoch,
1176            channels: std::mem::take(&mut self.channels)
1177                .into_values()
1178                .map(|channel| channel.record)
1179                .collect(),
1180            inputs,
1181            outputs,
1182        };
1183        trace.validate().map_err(NetworkEngineError::Trace)?;
1184        Ok(trace)
1185    }
1186}
1187
1188#[cfg(test)]
1189mod tests {
1190    use std::io::Cursor;
1191
1192    use chrono::TimeZone;
1193
1194    use super::*;
1195    use crate::pid::DetTid;
1196
1197    fn epoch() -> DateTime<Utc> {
1198        Utc.timestamp_opt(1_790_000_000, 0).unwrap()
1199    }
1200
1201    /// Global time `n` microseconds after the epoch.
1202    fn at(n: u64) -> LogicalTime {
1203        LogicalTime::from_nanos(1_790_000_000 * 1_000_000_000 + n * 1_000)
1204    }
1205
1206    fn sock(n: u64) -> OpenFileId {
1207        OpenFileId::new_socket(DetTid::from_raw(1), n)
1208    }
1209
1210    fn mark(offset: u64, events: u64) -> SendMark {
1211        SendMark { offset, events }
1212    }
1213
1214    /// Round-trips `request` through bincode in `config`, and checks that its
1215    /// guest `bytes` are written exactly as a plain `Vec<u8>` would be: their
1216    /// length, then the raw bytes.
1217    fn assert_bincode_round_trip<C: bincode::config::Config>(
1218        request: &NetworkRequest,
1219        bytes: &[u8],
1220        config: C,
1221    ) {
1222        let encoded = bincode::serde::encode_to_vec(request, config).unwrap();
1223        let (decoded, read): (NetworkRequest, usize) =
1224            bincode::serde::decode_from_slice(&encoded, config).unwrap();
1225        assert_eq!((&decoded, read), (request, encoded.len()));
1226        let plain = bincode::serde::encode_to_vec(bytes.to_vec(), config).unwrap();
1227        assert!(
1228            encoded.windows(plain.len()).any(|window| window == plain),
1229            "{request:?} does not carry its bytes as bincode writes a Vec<u8>"
1230        );
1231    }
1232
1233    /// Round-trips `request` through bincode's legacy configuration, which the
1234    /// RPC transports and reverie-ptrace's debug round trip use, and, as
1235    /// compatibility checks, through bincode's standard configuration and
1236    /// through JSON, which writes guest bytes as a sequence.
1237    fn assert_survives_rpc_encodings(request: &NetworkRequest, bytes: &[u8]) {
1238        assert_bincode_round_trip(request, bytes, bincode::config::legacy());
1239        assert_bincode_round_trip(request, bytes, bincode::config::standard());
1240        let json = serde_json::to_string(request).unwrap();
1241        assert_eq!(
1242            &serde_json::from_str::<NetworkRequest>(&json).unwrap(),
1243            request
1244        );
1245    }
1246
1247    fn peer() -> NetworkAddressV1 {
1248        NetworkAddressV1::Inet4 {
1249            address: [127, 0, 0, 1],
1250            port: 8080,
1251        }
1252    }
1253
1254    fn local() -> Option<NetworkAddressV1> {
1255        Some(NetworkAddressV1::Inet4 {
1256            address: [127, 0, 0, 1],
1257            port: 40_000,
1258        })
1259    }
1260
1261    fn data(bytes: &[u8]) -> NetworkRecvOutcome {
1262        NetworkRecvOutcome::Data(bytes.to_vec())
1263    }
1264
1265    /// A request/response exchange: the response is pulled at time 20,
1266    /// after the guest sent "req", and the peer closes at time 30.
1267    fn recorded_exchange() -> NetworkTraceV2 {
1268        let mut engine = NetworkEngine::new_record(epoch());
1269        let id = sock(0);
1270        assert_eq!(engine.record_connect(id, peer(), local(), 0, false), Ok(0));
1271        assert!(engine.needs_pull(id));
1272        assert_eq!(
1273            engine.recv(id, at(10), 64, 1, false),
1274            Ok(NetworkRecvOutcome::WouldBlock)
1275        );
1276        engine.record_send(id, b"req", None, at(0), 0).unwrap();
1277        engine
1278            .record_arrival(id, at(20), NetworkArrival::Bytes(b"abcdef".to_vec()))
1279            .unwrap();
1280        assert_eq!(engine.recv(id, at(20), 3, 1, false), Ok(data(b"abc")));
1281        engine
1282            .record_arrival(id, at(30), NetworkArrival::PeerWriteClosed)
1283            .unwrap();
1284        assert!(!engine.needs_pull(id));
1285        assert_eq!(engine.recv(id, at(30), 64, 1, false), Ok(data(b"def")));
1286        assert_eq!(
1287            engine.recv(id, at(31), 64, 1, false),
1288            Ok(NetworkRecvOutcome::Eof)
1289        );
1290        engine.finish().unwrap()
1291    }
1292
1293    #[test]
1294    fn record_produces_a_valid_trace_that_round_trips() {
1295        let trace = recorded_exchange();
1296        assert_eq!(trace.inputs.len(), 2);
1297        assert_eq!(
1298            trace.inputs[0].release,
1299            NetworkReleaseV1 {
1300                not_before_global_time: at(20),
1301                after_transmitted_offset: 3,
1302            }
1303        );
1304        let mut bytes = Vec::new();
1305        trace.write_framed(&mut bytes).unwrap();
1306        assert_eq!(
1307            NetworkTraceV2::read_framed(Cursor::new(bytes)).unwrap(),
1308            trace
1309        );
1310    }
1311
1312    #[test]
1313    fn replay_with_the_recorded_schedule_observes_the_same_outcomes() {
1314        let mut engine = NetworkEngine::new_replay(recorded_exchange());
1315        let id = sock(0);
1316        assert_eq!(engine.replay_connect(id, &peer(), false), Ok(0));
1317        assert_eq!(
1318            engine.recv(id, at(10), 64, 1, false),
1319            Ok(NetworkRecvOutcome::WouldBlock)
1320        );
1321        assert_eq!(
1322            engine.replay_send(id, b"req", false, at(0), 0),
1323            Ok(ReplaySendOutcome::Sent(3))
1324        );
1325        assert_eq!(engine.recv(id, at(20), 3, 1, false), Ok(data(b"abc")));
1326        assert_eq!(engine.recv(id, at(30), 64, 1, false), Ok(data(b"def")));
1327        assert_eq!(
1328            engine.recv(id, at(31), 64, 1, false),
1329            Ok(NetworkRecvOutcome::Eof)
1330        );
1331    }
1332
1333    #[test]
1334    fn replay_input_waits_for_both_time_and_transmission() {
1335        let mut engine = NetworkEngine::new_replay(recorded_exchange());
1336        let id = sock(0);
1337        engine.replay_connect(id, &peer(), false).unwrap();
1338        // Late enough, but the request has not been sent.
1339        assert_eq!(
1340            engine.recv(id, at(1_000), 64, 1, false),
1341            Ok(NetworkRecvOutcome::WouldBlock)
1342        );
1343        assert_eq!(
1344            engine.replay_send(id, b"req", false, at(0), 0),
1345            Ok(ReplaySendOutcome::Sent(3))
1346        );
1347        // Sent, but too early.
1348        assert_eq!(
1349            engine.recv(id, at(19), 64, 1, false),
1350            Ok(NetworkRecvOutcome::WouldBlock)
1351        );
1352        // Both: everything due by now is released together.
1353        assert_eq!(
1354            engine.recv(id, at(1_000), 64, 1, false),
1355            Ok(data(b"abcdef"))
1356        );
1357        assert_eq!(
1358            engine.recv(id, at(1_000), 64, 1, false),
1359            Ok(NetworkRecvOutcome::Eof)
1360        );
1361    }
1362
1363    #[test]
1364    fn receive_target_follows_the_low_water_mark() {
1365        let mut engine = NetworkEngine::new_record(epoch());
1366        let id = sock(0);
1367        engine
1368            .record_connect(id, peer(), local(), 0, false)
1369            .unwrap();
1370        engine
1371            .record_arrival(id, at(1), NetworkArrival::Bytes(b"ab".to_vec()))
1372            .unwrap();
1373        assert_eq!(
1374            engine.readiness(id, at(1), 3),
1375            Ok(libc::POLLOUT | libc::POLLWRNORM)
1376        );
1377        assert_eq!(
1378            engine.recv(id, at(1), 3, 3, false),
1379            Ok(NetworkRecvOutcome::WouldBlock)
1380        );
1381        assert_eq!(engine.recv(id, at(1), 3, 1, true), Ok(data(b"ab")));
1382        engine
1383            .record_arrival(id, at(2), NetworkArrival::Bytes(b"cd".to_vec()))
1384            .unwrap();
1385        assert_eq!(
1386            engine.readiness(id, at(2), 3),
1387            Ok(libc::POLLIN | libc::POLLRDNORM | libc::POLLOUT | libc::POLLWRNORM)
1388        );
1389        assert_eq!(engine.recv(id, at(2), 3, 3, false), Ok(data(b"abc")));
1390        // With the stream ended, fewer bytes than the target complete the receive.
1391        engine
1392            .record_arrival(id, at(3), NetworkArrival::PeerWriteClosed)
1393            .unwrap();
1394        assert_eq!(engine.recv(id, at(3), 3, 3, false), Ok(data(b"d")));
1395        assert_eq!(
1396            engine.readiness(id, at(3), 3),
1397            Ok(libc::POLLIN
1398                | libc::POLLRDNORM
1399                | libc::POLLRDHUP
1400                | libc::POLLOUT
1401                | libc::POLLWRNORM)
1402        );
1403    }
1404
1405    #[test]
1406    fn a_reset_delivers_queued_bytes_then_the_error_once_then_eof() {
1407        let mut engine = NetworkEngine::new_record(epoch());
1408        let id = sock(0);
1409        engine
1410            .record_connect(id, peer(), local(), 0, false)
1411            .unwrap();
1412        engine
1413            .record_arrival(id, at(1), NetworkArrival::Bytes(b"x".to_vec()))
1414            .unwrap();
1415        engine
1416            .record_arrival(id, at(1), NetworkArrival::Error(libc::ECONNRESET))
1417            .unwrap();
1418        assert_eq!(
1419            engine.record_arrival(id, at(2), NetworkArrival::PeerWriteClosed),
1420            Err(NetworkEngineError::InvalidArrival(id))
1421        );
1422        let readiness = engine.readiness(id, at(1), 1).unwrap();
1423        assert_eq!(readiness & libc::POLLERR, libc::POLLERR);
1424        assert_eq!(readiness & libc::POLLHUP, libc::POLLHUP);
1425        assert_eq!(engine.recv(id, at(1), 64, 64, false), Ok(data(b"x")));
1426        assert_eq!(
1427            engine.recv(id, at(1), 64, 1, true),
1428            Ok(NetworkRecvOutcome::Error(libc::ECONNRESET))
1429        );
1430        assert_eq!(
1431            engine.recv(id, at(1), 64, 1, false),
1432            Ok(NetworkRecvOutcome::Eof)
1433        );
1434        assert_eq!(engine.send_failure(id, at(1)), Ok(Some(libc::EPIPE)));
1435        engine.finish().unwrap();
1436    }
1437
1438    /// A reset pulled at time 20, after the guest sent "req".
1439    fn recorded_reset() -> NetworkTraceV2 {
1440        let mut engine = NetworkEngine::new_record(epoch());
1441        let id = sock(0);
1442        engine
1443            .record_connect(id, peer(), local(), 0, false)
1444            .unwrap();
1445        engine.record_send(id, b"req", None, at(0), 0).unwrap();
1446        engine
1447            .record_arrival(id, at(20), NetworkArrival::Error(libc::ECONNRESET))
1448            .unwrap();
1449        assert_eq!(engine.take_error(id, at(20)), Ok(libc::ECONNRESET));
1450        engine.finish().unwrap()
1451    }
1452
1453    #[test]
1454    fn so_error_and_send_release_a_due_error_as_its_first_observer() {
1455        let id = sock(0);
1456        // SO_ERROR first: not before the recorded time, then exactly once.
1457        let mut engine = NetworkEngine::new_replay(recorded_reset());
1458        engine.replay_connect(id, &peer(), false).unwrap();
1459        assert_eq!(
1460            engine.replay_send(id, b"req", false, at(0), 0),
1461            Ok(ReplaySendOutcome::Sent(3))
1462        );
1463        assert_eq!(engine.take_error(id, at(19)), Ok(0));
1464        assert_eq!(
1465            engine.apply(at(20), NetworkRequest::TakeError(id)),
1466            Ok(NetworkReply::Errno(libc::ECONNRESET))
1467        );
1468        assert_eq!(engine.take_error(id, at(21)), Ok(0));
1469
1470        // A send first: not before "req" is sent, then the error once, then
1471        // EPIPE, without matching any byte against the recording.
1472        let mut engine = NetworkEngine::new_replay(recorded_reset());
1473        engine.replay_connect(id, &peer(), false).unwrap();
1474        assert_eq!(engine.send_failure(id, at(99)), Ok(None));
1475        assert_eq!(
1476            engine.replay_send(id, b"req", false, at(0), 0),
1477            Ok(ReplaySendOutcome::Sent(3))
1478        );
1479        assert_eq!(engine.send_failure(id, at(19)), Ok(None));
1480        assert_eq!(
1481            engine.apply(at(20), NetworkRequest::SendFailure(id)),
1482            Ok(NetworkReply::Failure(Some(libc::ECONNRESET)))
1483        );
1484        assert_eq!(engine.send_failure(id, at(21)), Ok(Some(libc::EPIPE)));
1485        assert_eq!(engine.take_error(id, at(21)), Ok(0));
1486    }
1487
1488    #[test]
1489    fn failed_connects_replay_without_the_host() {
1490        let mut engine = NetworkEngine::new_record(epoch());
1491        assert_eq!(
1492            engine.record_connect(sock(0), peer(), None, libc::ECONNREFUSED, false),
1493            Ok(libc::ECONNREFUSED)
1494        );
1495        assert_eq!(
1496            engine.record_connect(sock(1), peer(), None, libc::ECONNREFUSED, true),
1497            Ok(libc::EINPROGRESS)
1498        );
1499        let trace = engine.finish().unwrap();
1500
1501        let mut engine = NetworkEngine::new_replay(trace);
1502        assert_eq!(
1503            engine.replay_connect(sock(0), &peer(), false),
1504            Ok(libc::ECONNREFUSED)
1505        );
1506        assert_eq!(engine.take_error(sock(0), at(1)), Ok(0));
1507        assert_eq!(
1508            engine.replay_connect(sock(1), &peer(), true),
1509            Ok(libc::EINPROGRESS)
1510        );
1511        let readiness = engine.readiness(sock(1), at(1), 1).unwrap();
1512        assert_eq!(
1513            readiness & (libc::POLLOUT | libc::POLLERR | libc::POLLHUP),
1514            libc::POLLOUT | libc::POLLERR | libc::POLLHUP
1515        );
1516        assert_eq!(engine.take_error(sock(1), at(1)), Ok(libc::ECONNREFUSED));
1517        assert_eq!(engine.take_error(sock(1), at(1)), Ok(0));
1518        assert_eq!(engine.shutdown(sock(1), libc::SHUT_WR), Ok(libc::ENOTCONN));
1519    }
1520
1521    #[test]
1522    fn replay_refuses_connections_the_recording_lacks() {
1523        let mut engine = NetworkEngine::new_replay(recorded_exchange());
1524        assert_eq!(
1525            engine.replay_connect(sock(5), &peer(), false),
1526            Err(NetworkEngineError::NotInTrace(sock(5)))
1527        );
1528        let other = NetworkAddressV1::Inet4 {
1529            address: [127, 0, 0, 1],
1530            port: 9,
1531        };
1532        assert!(matches!(
1533            engine.replay_connect(sock(0), &other, false),
1534            Err(NetworkEngineError::PeerMismatch { .. })
1535        ));
1536        engine.replay_connect(sock(0), &peer(), false).unwrap();
1537        assert_eq!(
1538            engine.replay_connect(sock(0), &peer(), false),
1539            Err(NetworkEngineError::ChannelExists(sock(0)))
1540        );
1541    }
1542
1543    #[test]
1544    fn replay_send_matches_bytes_and_preserves_fragments() {
1545        let mut engine = NetworkEngine::new_record(epoch());
1546        let id = sock(0);
1547        engine
1548            .record_connect(id, peer(), local(), 0, false)
1549            .unwrap();
1550        // A short write: the host accepted 4 of the guest's 8 bytes.
1551        engine.record_send(id, b"requ", None, at(0), 0).unwrap();
1552        engine.record_send(id, b"est\n", None, at(0), 0).unwrap();
1553        let trace = engine.finish().unwrap();
1554
1555        let mut engine = NetworkEngine::new_replay(trace.clone());
1556        engine.replay_connect(id, &peer(), false).unwrap();
1557        assert_eq!(
1558            engine.replay_send(id, b"request\n", false, at(0), 0),
1559            Ok(ReplaySendOutcome::Sent(4))
1560        );
1561        assert_eq!(
1562            engine.replay_send(id, b"es", false, at(0), 0),
1563            Ok(ReplaySendOutcome::Sent(2))
1564        );
1565        assert_eq!(
1566            engine.replay_send(id, b"t\n", false, at(0), 0),
1567            Ok(ReplaySendOutcome::Sent(2))
1568        );
1569        assert_eq!(
1570            engine.replay_send(id, b"more", false, at(0), 0),
1571            Err(NetworkEngineError::OutboundBeyondRecording {
1572                channel: id,
1573                offset: 8
1574            })
1575        );
1576
1577        let mut engine = NetworkEngine::new_replay(trace);
1578        engine.replay_connect(id, &peer(), false).unwrap();
1579        let error = engine
1580            .replay_send(id, b"reqX", false, at(0), 0)
1581            .unwrap_err();
1582        assert_eq!(
1583            error,
1584            NetworkEngineError::OutboundMismatch {
1585                channel: id,
1586                offset: 3
1587            }
1588        );
1589        let message = error.to_string();
1590        for word in ["network", "outbound", "mismatch"] {
1591            assert!(message.contains(word), "{message}");
1592        }
1593    }
1594
1595    #[test]
1596    fn refused_nonblocking_sends_replay_as_eagain_at_the_same_offset() {
1597        let mut engine = NetworkEngine::new_record(epoch());
1598        let id = sock(0);
1599        engine
1600            .record_connect(id, peer(), local(), 0, false)
1601            .unwrap();
1602        // The host accepted a prefix of a nonblocking send, then refused
1603        // the next two attempts with EAGAIN before accepting the rest.
1604        assert_eq!(
1605            engine.record_send(id, b"re", None, at(0), 0),
1606            Ok(mark(2, 1))
1607        );
1608        engine.record_refused_send(id).unwrap();
1609        engine.record_refused_send(id).unwrap();
1610        assert_eq!(engine.record_send(id, b"q", None, at(0), 0), Ok(mark(3, 4)));
1611        engine.record_refused_send(id).unwrap();
1612        let trace = engine.finish().unwrap();
1613        assert!(trace.records_refused_sends());
1614
1615        let mut engine = NetworkEngine::new_replay(trace.clone());
1616        engine.replay_connect(id, &peer(), false).unwrap();
1617        assert_eq!(
1618            engine.replay_send(id, b"req", true, at(0), 0),
1619            Ok(ReplaySendOutcome::Sent(2))
1620        );
1621        assert_eq!(
1622            engine.replay_send(id, b"q", true, at(0), 0),
1623            Ok(ReplaySendOutcome::WouldBlock)
1624        );
1625        assert_eq!(
1626            engine.replay_send(id, b"q", true, at(0), 0),
1627            Ok(ReplaySendOutcome::WouldBlock)
1628        );
1629        assert_eq!(
1630            engine.replay_send(id, b"q", true, at(0), 0),
1631            Ok(ReplaySendOutcome::Sent(1))
1632        );
1633        // The final refusal is part of the recording, too.
1634        let unfinished = NetworkEngineError::ReplayUnrefused {
1635            channel: id,
1636            offset: 3,
1637        };
1638        assert_eq!(unfinished.remedy(), DIVERGED_REMEDY);
1639        assert!(unfinished.to_string().contains("EAGAIN"), "{unfinished}");
1640        let mut finished = NetworkEngine::new_replay(trace.clone());
1641        finished.replay_connect(id, &peer(), false).unwrap();
1642        for (bytes, expected) in [
1643            (&b"req"[..], ReplaySendOutcome::Sent(2)),
1644            (b"q", ReplaySendOutcome::WouldBlock),
1645            (b"q", ReplaySendOutcome::WouldBlock),
1646        ] {
1647            assert_eq!(
1648                finished.replay_send(id, bytes, true, at(0), 0),
1649                Ok(expected)
1650            );
1651        }
1652        assert_eq!(
1653            finished.replay_send(id, b"q", true, at(0), 0),
1654            Ok(ReplaySendOutcome::Sent(1))
1655        );
1656        assert_eq!(
1657            finished.replay_send(id, b"x", true, at(0), 0),
1658            Ok(ReplaySendOutcome::WouldBlock)
1659        );
1660        assert_eq!(finished.finish_replay(), Ok(()));
1661
1662        // A blocking send cannot reproduce a refusal: it diverged.
1663        let mut engine = NetworkEngine::new_replay(trace);
1664        engine.replay_connect(id, &peer(), false).unwrap();
1665        assert_eq!(
1666            engine.replay_send(id, b"req", false, at(0), 0),
1667            Ok(ReplaySendOutcome::Sent(2))
1668        );
1669        let error = engine.replay_send(id, b"q", false, at(0), 0).unwrap_err();
1670        assert_eq!(
1671            error,
1672            NetworkEngineError::BlockingSendAtRefusal {
1673                channel: id,
1674                offset: 2
1675            }
1676        );
1677        assert_eq!(error.remedy(), DIVERGED_REMEDY);
1678        assert_eq!(
1679            engine.finish_replay(),
1680            Err(NetworkEngineError::ReplayUnsent {
1681                channel: id,
1682                sent: 2,
1683                recorded: 3,
1684            })
1685        );
1686    }
1687
1688    #[test]
1689    fn replay_accepts_a_waited_fragment_only_after_as_many_waits_and_as_long() {
1690        let mut engine = NetworkEngine::new_record(epoch());
1691        let id = sock(0);
1692        engine
1693            .record_connect(id, peer(), local(), 0, false)
1694            .unwrap();
1695        // Accepted on its first attempt: no wait.
1696        assert_eq!(
1697            engine.record_send(id, b"ab", None, at(1), 0),
1698            Ok(mark(2, 1))
1699        );
1700        // The send then took its mark, waited three times and had "cd"
1701        // accepted at time 50; then waited once more, and "ef" went at 60.
1702        let waiting = engine.record_send(id, b"", None, at(2), 0).unwrap();
1703        assert_eq!(waiting, mark(2, 1));
1704        assert_eq!(
1705            engine.record_send(id, b"cd", Some(waiting), at(50), 3),
1706            Ok(mark(4, 2))
1707        );
1708        assert_eq!(
1709            engine.record_send(id, b"ef", Some(mark(4, 2)), at(60), 1),
1710            Ok(mark(6, 3))
1711        );
1712        let trace = engine.finish().unwrap();
1713        let waits: Vec<_> = trace.outputs.iter().map(|output| output.wait).collect();
1714        let wait = |waits, time| {
1715            Some(NetworkSendWaitV4 {
1716                waits,
1717                not_before_global_time: at(time),
1718            })
1719        };
1720        assert_eq!(waits, vec![None, wait(3, 50), wait(1, 60)]);
1721        assert!(trace.records_send_waits());
1722
1723        let mut engine = NetworkEngine::new_replay(trace.clone());
1724        engine.replay_connect(id, &peer(), false).unwrap();
1725        let sent = ReplaySendOutcome::Sent(2);
1726        assert_eq!(engine.replay_send(id, b"abcdef", false, at(1), 0), Ok(sent));
1727        // Not yet due: no wait, too few waits, or too early.
1728        for (time, waits) in [(10, 0), (60, 2), (49, 3)] {
1729            assert_eq!(
1730                engine.replay_send(id, b"cdef", false, at(time), waits),
1731                Ok(ReplaySendOutcome::NotYet),
1732                "time {time}, waits {waits}"
1733            );
1734        }
1735        assert_eq!(engine.replay_send(id, b"cdef", false, at(50), 3), Ok(sent));
1736        assert_eq!(
1737            engine.replay_send(id, b"ef", false, at(70), 0),
1738            Ok(ReplaySendOutcome::NotYet)
1739        );
1740        // A nonblocking send never waited in the recording, so one here
1741        // diverged rather than waiting.
1742        let error = engine.replay_send(id, b"ef", true, at(70), 0).unwrap_err();
1743        assert_eq!(
1744            error,
1745            NetworkEngineError::NonblockingSendAtWait {
1746                channel: id,
1747                offset: 4
1748            }
1749        );
1750        assert_eq!(error.remedy(), DIVERGED_REMEDY);
1751        assert_eq!(engine.replay_send(id, b"ef", false, at(70), 1), Ok(sent));
1752        assert_eq!(engine.finish_replay(), Ok(()));
1753
1754        // The wait gates only the start of the fragment: a shorter guest
1755        // send that took part of it continues without waiting again.
1756        let mut engine = NetworkEngine::new_replay(trace);
1757        engine.replay_connect(id, &peer(), false).unwrap();
1758        let one = ReplaySendOutcome::Sent(1);
1759        assert_eq!(engine.replay_send(id, b"ab", false, at(1), 0), Ok(sent));
1760        assert_eq!(engine.replay_send(id, b"c", false, at(50), 3), Ok(one));
1761        assert_eq!(engine.replay_send(id, b"d", false, at(50), 0), Ok(one));
1762    }
1763
1764    #[test]
1765    fn apply_stamps_a_waited_send_with_the_global_time_of_its_request() {
1766        let mut engine = NetworkEngine::new_record(epoch());
1767        let id = sock(0);
1768        engine
1769            .record_connect(id, peer(), local(), 0, false)
1770            .unwrap();
1771        let send = |bytes: &[u8], waits| NetworkRequest::RecordSend {
1772            id,
1773            bytes: bytes.to_vec(),
1774            at: None,
1775            waits,
1776        };
1777        engine.apply(at(5), send(b"a", 0)).unwrap();
1778        engine.apply(at(7), send(b"b", 2)).unwrap();
1779        let trace = engine.finish().unwrap();
1780        assert_eq!(trace.outputs[0].wait, None);
1781        assert_eq!(
1782            trace.outputs[1].wait,
1783            Some(NetworkSendWaitV4 {
1784                waits: 2,
1785                not_before_global_time: at(7),
1786            })
1787        );
1788
1789        let mut engine = NetworkEngine::new_replay(trace);
1790        engine.replay_connect(id, &peer(), false).unwrap();
1791        let replay = |bytes: &[u8], waits| NetworkRequest::ReplaySend {
1792            id,
1793            bytes: bytes.to_vec(),
1794            nonblocking: false,
1795            waits,
1796        };
1797        assert_eq!(
1798            engine.apply(at(5), replay(b"ab", 0)),
1799            Ok(NetworkReply::Sent(1))
1800        );
1801        assert_eq!(
1802            engine.apply(at(6), replay(b"b", 2)),
1803            Ok(NetworkReply::NotYet)
1804        );
1805        assert_eq!(
1806            engine.apply(at(7), replay(b"b", 2)),
1807            Ok(NetworkReply::Sent(1))
1808        );
1809
1810        // Both kinds of request reach the global state through a serializer
1811        // with their guest bytes intact.
1812        let every_byte: Vec<u8> = (0..=u8::MAX).collect();
1813        assert_survives_rpc_encodings(&send(&every_byte, 2), &every_byte);
1814        assert_survives_rpc_encodings(&replay(&every_byte, 2), &every_byte);
1815    }
1816
1817    #[test]
1818    fn finished_replay_refuses_an_unmade_refused_send() {
1819        let mut engine = NetworkEngine::new_record(epoch());
1820        let id = sock(0);
1821        engine
1822            .record_connect(id, peer(), local(), 0, false)
1823            .unwrap();
1824        engine.record_send(id, b"req", None, at(0), 0).unwrap();
1825        engine.record_refused_send(id).unwrap();
1826        let mut engine = NetworkEngine::new_replay(engine.finish().unwrap());
1827        engine.replay_connect(id, &peer(), false).unwrap();
1828        assert_eq!(
1829            engine.replay_send(id, b"req", true, at(0), 0),
1830            Ok(ReplaySendOutcome::Sent(3))
1831        );
1832        assert_eq!(
1833            engine.finish_replay(),
1834            Err(NetworkEngineError::ReplayUnrefused {
1835                channel: id,
1836                offset: 3
1837            })
1838        );
1839    }
1840
1841    #[test]
1842    fn record_refuses_a_send_interleaved_with_a_waiting_send() {
1843        let mut engine = NetworkEngine::new_record(epoch());
1844        let id = sock(0);
1845        engine
1846            .record_connect(id, peer(), local(), 0, false)
1847            .unwrap();
1848        // A blocking send accepted a prefix and waits; its continuation
1849        // lands where it left the stream.
1850        assert_eq!(
1851            engine.record_send(id, b"ab", None, at(0), 0),
1852            Ok(mark(2, 1))
1853        );
1854        assert_eq!(
1855            engine.record_send(id, b"cd", Some(mark(2, 1)), at(0), 0),
1856            Ok(mark(4, 2))
1857        );
1858        // Another send reached the stream while it waited.
1859        assert_eq!(
1860            engine.record_send(id, b"xy", None, at(0), 0),
1861            Ok(mark(6, 3))
1862        );
1863        let error = engine
1864            .record_send(id, b"ef", Some(mark(4, 2)), at(0), 0)
1865            .unwrap_err();
1866        assert_eq!(
1867            error,
1868            NetworkEngineError::InterleavedSend {
1869                channel: id,
1870                offset: 4
1871            }
1872        );
1873        assert!(error.remedy().contains("one thread at a time"));
1874        assert_eq!(
1875            engine.finish().unwrap().outputs.len(),
1876            3,
1877            "a refused continuation must not be recorded"
1878        );
1879    }
1880
1881    #[test]
1882    fn record_refuses_a_send_that_overtook_a_zero_byte_wait() {
1883        let mut engine = NetworkEngine::new_record(epoch());
1884        let id = sock(0);
1885        engine
1886            .record_connect(id, peer(), local(), 0, false)
1887            .unwrap();
1888        assert_eq!(
1889            engine.record_send(id, b"ab", None, at(0), 0),
1890            Ok(mark(2, 1))
1891        );
1892        // A blocking send found the buffer full before accepting any byte
1893        // and took its mark before waiting; taking it records nothing.
1894        let waiting = engine.record_send(id, b"", None, at(0), 0).unwrap();
1895        assert_eq!(waiting, mark(2, 1));
1896        // Another thread's send was accepted while it waited. Replay never
1897        // waits there, so it would give the waiting send these offsets.
1898        assert_eq!(
1899            engine.record_send(id, b"xy", None, at(0), 0),
1900            Ok(mark(4, 2))
1901        );
1902        let error = engine
1903            .record_send(id, b"cd", Some(waiting), at(0), 0)
1904            .unwrap_err();
1905        assert_eq!(
1906            error,
1907            NetworkEngineError::InterleavedSend {
1908                channel: id,
1909                offset: 2
1910            }
1911        );
1912        assert_eq!(engine.finish().unwrap().outputs.len(), 2);
1913    }
1914
1915    #[test]
1916    fn record_refuses_a_refusal_pushed_during_a_wait() {
1917        let mut engine = NetworkEngine::new_record(epoch());
1918        let id = sock(0);
1919        engine
1920            .record_connect(id, peer(), local(), 0, false)
1921            .unwrap();
1922        assert_eq!(
1923            engine.record_send(id, b"ab", None, at(0), 0),
1924            Ok(mark(2, 1))
1925        );
1926        // Another thread's nonblocking send was refused while this send
1927        // waited. The refusal does not move the offset, but replay would
1928        // hand it to the waiting blocking send.
1929        engine.record_refused_send(id).unwrap();
1930        let error = engine
1931            .record_send(id, b"cd", Some(mark(2, 1)), at(0), 0)
1932            .unwrap_err();
1933        assert_eq!(
1934            error,
1935            NetworkEngineError::InterleavedSend {
1936                channel: id,
1937                offset: 2
1938            }
1939        );
1940        assert_eq!(engine.finish().unwrap().outputs.len(), 2);
1941    }
1942
1943    #[test]
1944    fn shutdown_follows_linux() {
1945        let mut engine = NetworkEngine::new_record(epoch());
1946        let id = sock(0);
1947        engine
1948            .record_connect(id, peer(), local(), 0, false)
1949            .unwrap();
1950        assert_eq!(engine.send_failure(id, at(1)), Ok(None));
1951        assert_eq!(engine.shutdown(id, libc::SHUT_WR), Ok(0));
1952        assert_eq!(engine.send_failure(id, at(1)), Ok(Some(libc::EPIPE)));
1953        assert_eq!(engine.shutdown(id, 7), Ok(libc::EINVAL));
1954        assert_eq!(engine.shutdown(id, libc::SHUT_RD), Ok(0));
1955        assert_eq!(
1956            engine.recv(id, at(1), 64, 1, false),
1957            Ok(NetworkRecvOutcome::Eof)
1958        );
1959        assert_eq!(
1960            engine.readiness(id, at(1), 1).unwrap() & libc::POLLHUP,
1961            libc::POLLHUP
1962        );
1963    }
1964
1965    #[test]
1966    fn shut_rd_delivers_queued_bytes_before_end_of_file() {
1967        let mut engine = NetworkEngine::new_record(epoch());
1968        let id = sock(0);
1969        engine
1970            .record_connect(id, peer(), local(), 0, false)
1971            .unwrap();
1972        engine
1973            .record_arrival(id, at(1), NetworkArrival::Bytes(b"abc".to_vec()))
1974            .unwrap();
1975        assert_eq!(engine.shutdown(id, libc::SHUT_RD), Ok(0));
1976        // A blocking receive whose target exceeds the queue still returns it.
1977        assert_eq!(engine.recv(id, at(2), 64, 64, true), Ok(data(b"abc")));
1978        assert_eq!(engine.recv(id, at(2), 2, 64, false), Ok(data(b"ab")));
1979        assert_eq!(engine.recv(id, at(2), 64, 64, false), Ok(data(b"c")));
1980        assert_eq!(
1981            engine.recv(id, at(3), 64, 64, false),
1982            Ok(NetworkRecvOutcome::Eof)
1983        );
1984    }
1985
1986    #[test]
1987    fn requests_record_pulls_at_the_time_they_answer() {
1988        let mut engine = NetworkEngine::new_record(epoch());
1989        let id = sock(0);
1990        let reply = engine.apply(
1991            at(1),
1992            NetworkRequest::RecordConnect {
1993                id,
1994                peer: peer(),
1995                local: local(),
1996                errno: 0,
1997                nonblocking: false,
1998            },
1999        );
2000        assert_eq!(reply, Ok(NetworkReply::Errno(0)));
2001        let reply = engine.apply(
2002            at(5),
2003            NetworkRequest::Readiness(vec![(id, 1, vec![NetworkArrival::Bytes(b"hi".to_vec())])]),
2004        );
2005        assert_eq!(
2006            reply,
2007            Ok(NetworkReply::Events(vec![
2008                libc::POLLIN | libc::POLLRDNORM | libc::POLLOUT | libc::POLLWRNORM
2009            ]))
2010        );
2011        // A drained host socket keeps reporting end of stream; only the
2012        // first report is recorded.
2013        let reply = engine.apply(
2014            at(9),
2015            NetworkRequest::Recv {
2016                id,
2017                arrivals: vec![
2018                    NetworkArrival::PeerWriteClosed,
2019                    NetworkArrival::PeerWriteClosed,
2020                ],
2021                max_len: 64,
2022                target: 1,
2023                peek: false,
2024            },
2025        );
2026        assert_eq!(reply, Ok(NetworkReply::Recv(data(b"hi"))));
2027        assert_eq!(
2028            engine.apply(at(9), NetworkRequest::Addresses(id)),
2029            Ok(NetworkReply::Addresses(Some((local(), peer()))))
2030        );
2031        let trace = engine.finish().unwrap();
2032        assert_eq!(trace.inputs.len(), 2);
2033        assert_eq!(trace.inputs[0].release.not_before_global_time, at(5));
2034        assert_eq!(trace.inputs[1].release.not_before_global_time, at(9));
2035    }
2036
2037    #[test]
2038    fn modes_are_not_interchangeable() {
2039        let mut engine = NetworkEngine::new_replay(recorded_exchange());
2040        assert_eq!(
2041            engine.record_connect(sock(0), peer(), local(), 0, false),
2042            Err(NetworkEngineError::WrongMode)
2043        );
2044        assert!(matches!(
2045            engine.finish(),
2046            Err(NetworkEngineError::WrongMode)
2047        ));
2048        let mut engine = NetworkEngine::new_record(epoch());
2049        assert_eq!(
2050            engine.replay_connect(sock(0), &peer(), false),
2051            Err(NetworkEngineError::WrongMode)
2052        );
2053        assert_eq!(
2054            engine.recv(sock(9), at(1), 1, 1, false),
2055            Err(NetworkEngineError::UnknownChannel(sock(9)))
2056        );
2057    }
2058
2059    /// `n` seconds after `at(0)`.
2060    fn after_secs(n: u64) -> LogicalTime {
2061        at(0) + std::time::Duration::from_secs(n)
2062    }
2063
2064    #[test]
2065    fn replay_refuses_an_input_held_back_by_bytes_never_sent() {
2066        let mut engine = NetworkEngine::new_replay(recorded_exchange());
2067        let id = sock(0);
2068        engine.replay_connect(id, &peer(), false).unwrap();
2069        // Short of the limit past the recorded arrival at 20 us: still waiting.
2070        let waiting = at(19) + REPLAY_STALL_LIMIT;
2071        assert_eq!(
2072            engine.recv(id, waiting, 64, 1, false),
2073            Ok(NetworkRecvOutcome::WouldBlock)
2074        );
2075        let stalled = Err(NetworkEngineError::ReplayStalled {
2076            channel: id,
2077            needed: 3,
2078            sent: 0,
2079        });
2080        assert_eq!(engine.recv(id, after_secs(61), 64, 1, false), stalled);
2081        assert_eq!(engine.readiness(id, after_secs(61), 1), stalled.map(|_| 0));
2082    }
2083
2084    #[test]
2085    fn replay_that_sends_what_gates_an_input_never_stalls() {
2086        let mut engine = NetworkEngine::new_replay(recorded_exchange());
2087        let id = sock(0);
2088        engine.replay_connect(id, &peer(), false).unwrap();
2089        assert_eq!(
2090            engine.replay_send(id, b"req", false, at(0), 0),
2091            Ok(ReplaySendOutcome::Sent(3))
2092        );
2093        assert_eq!(
2094            engine.recv(id, after_secs(3_600), 64, 1, false),
2095            Ok(data(b"abcdef"))
2096        );
2097    }
2098
2099    #[test]
2100    fn finished_replay_accepts_a_complete_run_even_with_input_unread() {
2101        let mut engine = NetworkEngine::new_replay(recorded_exchange());
2102        let id = sock(0);
2103        engine.replay_connect(id, &peer(), false).unwrap();
2104        assert_eq!(
2105            engine.replay_send(id, b"req", false, at(0), 0),
2106            Ok(ReplaySendOutcome::Sent(3))
2107        );
2108        // The response was never read: release depends on the schedule.
2109        assert_eq!(engine.finish_replay(), Ok(()));
2110    }
2111
2112    #[test]
2113    fn finished_replay_refuses_unsent_output_and_unmade_connections() {
2114        let mut engine = NetworkEngine::new_replay(recorded_exchange());
2115        let id = sock(0);
2116        engine.replay_connect(id, &peer(), false).unwrap();
2117        assert_eq!(
2118            engine.replay_send(id, b"r", false, at(0), 0),
2119            Ok(ReplaySendOutcome::Sent(1))
2120        );
2121        assert_eq!(
2122            engine.finish_replay(),
2123            Err(NetworkEngineError::ReplayUnsent {
2124                channel: id,
2125                sent: 1,
2126                recorded: 3,
2127            })
2128        );
2129        let engine = NetworkEngine::new_replay(recorded_exchange());
2130        assert_eq!(
2131            engine.finish_replay(),
2132            Err(NetworkEngineError::ReplayUnconnected(sock(0)))
2133        );
2134        let record = NetworkEngine::new_record(epoch());
2135        assert_eq!(record.finish_replay(), Err(NetworkEngineError::WrongMode));
2136    }
2137
2138    #[test]
2139    fn record_refuses_a_peer_naming_no_single_host() {
2140        let mut engine = NetworkEngine::new_record(epoch());
2141        for peer in [
2142            NetworkAddressV1::Inet4 {
2143                address: [0, 0, 0, 0],
2144                port: 8080,
2145            },
2146            NetworkAddressV1::Inet4 {
2147                address: [127, 0, 0, 1],
2148                port: 0,
2149            },
2150        ] {
2151            assert_eq!(
2152                engine.record_connect(sock(0), peer.clone(), local(), 0, false),
2153                Err(NetworkEngineError::UntraceablePeer(peer))
2154            );
2155        }
2156        assert!(engine.finish().unwrap().channels.is_empty());
2157    }
2158
2159    #[test]
2160    fn every_error_names_a_remedy() {
2161        let divergence = NetworkEngineError::ReplayUnsent {
2162            channel: sock(0),
2163            sent: 1,
2164            recorded: 3,
2165        };
2166        assert!(divergence.to_string().contains("sent 1 of the 3 bytes"));
2167        assert!(divergence.remedy().contains("--record-networking"));
2168        assert!(
2169            NetworkEngineError::UnknownChannel(sock(0))
2170                .remedy()
2171                .contains("hermit defect")
2172        );
2173        assert!(
2174            NetworkEngineError::UntraceablePeer(peer())
2175                .remedy()
2176                .contains("nonzero port")
2177        );
2178    }
2179}