1use 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
56mod 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 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#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
121pub enum NetworkArrival {
122 Bytes(#[serde(with = "guest_bytes")] Vec<u8>),
123 PeerWriteClosed,
125 Error(i32),
127}
128
129#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
131pub enum NetworkRecvOutcome {
132 Data(#[serde(with = "guest_bytes")] Vec<u8>),
133 Eof,
135 Error(i32),
137 WouldBlock,
139}
140
141#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
144pub enum NetworkEngineError {
145 WrongMode,
148 UnknownChannel(OpenFileId),
149 ChannelExists(OpenFileId),
151 NotInTrace(OpenFileId),
153 PeerMismatch {
154 channel: OpenFileId,
155 recorded: NetworkAddressV1,
156 attempted: NetworkAddressV1,
157 },
158 OutboundMismatch {
160 channel: OpenFileId,
161 offset: u64,
162 },
163 OutboundBeyondRecording {
165 channel: OpenFileId,
166 offset: u64,
167 },
168 BlockingSendAtRefusal {
171 channel: OpenFileId,
172 offset: u64,
173 },
174 NonblockingSendAtWait {
177 channel: OpenFileId,
178 offset: u64,
179 },
180 InterleavedSend {
184 channel: OpenFileId,
185 offset: u64,
186 },
187 InvalidArrival(OpenFileId),
189 Trace(NetworkTraceValidationError),
191 UntraceablePeer(NetworkAddressV1),
193 ReplayStalled {
197 channel: OpenFileId,
198 needed: u64,
199 sent: u64,
200 },
201 ReplayUnconnected(OpenFileId),
203 ReplayUnsent {
205 channel: OpenFileId,
206 sent: u64,
207 recorded: u64,
208 },
209 ReplayUnrefused {
212 channel: OpenFileId,
213 offset: u64,
214 },
215}
216
217pub const REPLAY_STALL_LIMIT: std::time::Duration = std::time::Duration::from_secs(60);
222
223const 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 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#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
360pub enum NetworkRequest {
361 RecordConnect {
363 id: OpenFileId,
364 peer: NetworkAddressV1,
365 local: Option<NetworkAddressV1>,
366 errno: i32,
367 nonblocking: bool,
368 },
369 ReplayConnect {
371 id: OpenFileId,
372 peer: NetworkAddressV1,
373 nonblocking: bool,
374 },
375 Recv {
377 id: OpenFileId,
378 arrivals: Vec<NetworkArrival>,
379 max_len: usize,
380 target: usize,
381 peek: bool,
382 },
383 Readiness(Vec<(OpenFileId, usize, Vec<NetworkArrival>)>),
386 TakeError(OpenFileId),
388 SendFailure(OpenFileId),
390 RecordSend {
392 id: OpenFileId,
393 #[serde(with = "guest_bytes")]
394 bytes: Vec<u8>,
395 at: Option<SendMark>,
396 waits: u64,
397 },
398 RecordRefusedSend(OpenFileId),
400 ReplaySend {
402 id: OpenFileId,
403 #[serde(with = "guest_bytes")]
404 bytes: Vec<u8>,
405 nonblocking: bool,
406 waits: u64,
407 },
408 Shutdown { id: OpenFileId, how: i32 },
410 Addresses(OpenFileId),
412}
413
414#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
420pub struct SendMark {
421 pub offset: u64,
422 pub events: u64,
423}
424
425#[derive(Debug, Clone, Copy, PartialEq, Eq)]
427pub enum ReplaySendOutcome {
428 Sent(usize),
430 WouldBlock,
432 NotYet,
434}
435
436#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
438pub enum NetworkReply {
439 Errno(i32),
441 Failure(Option<i32>),
443 Recv(NetworkRecvOutcome),
444 Events(Vec<i16>),
446 Sent(usize),
447 Recorded(SendMark),
449 WouldBlock,
451 NotYet,
454 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 unconnected: BTreeMap<OpenFileId, Channel>,
469 },
470}
471
472#[derive(Debug)]
473struct Channel {
474 record: NetworkChannelV2,
475 rx: VecDeque<u8>,
477 rx_end: u64,
479 peer_closed: bool,
480 reset: bool,
482 pending_error: Option<i32>,
484 tx: u64,
486 output_events: u64,
488 shut_rd: bool,
489 shut_wr: bool,
490 pending_inputs: VecDeque<NetworkInputEventV1>,
492 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 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#[derive(Debug)]
571pub struct NetworkEngine {
572 mode: Mode,
573 channels: BTreeMap<OpenFileId, Channel>,
574}
575
576impl NetworkEngine {
577 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 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 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 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 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 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 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 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 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 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 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 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 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 events |= libc::POLLOUT | libc::POLLWRNORM;
845 if channel.pending_error.is_some() {
846 events |= libc::POLLERR;
847 }
848 Ok(events)
849 }
850
851 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 assert_eq!(
1349 engine.recv(id, at(19), 64, 1, false),
1350 Ok(NetworkRecvOutcome::WouldBlock)
1351 );
1352 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 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 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 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 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 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 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 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 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 assert_eq!(
1697 engine.record_send(id, b"ab", None, at(1), 0),
1698 Ok(mark(2, 1))
1699 );
1700 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 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 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 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 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 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 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 let waiting = engine.record_send(id, b"", None, at(0), 0).unwrap();
1895 assert_eq!(waiting, mark(2, 1));
1896 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 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 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 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 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 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 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}