@@ -71,3 +71,81 @@ fn test_send_recv() {
71
71
TcpSocket :: recvmsg ( & tcp, & mut recv_buf[ ..] , 10 ) . unwrap ( ) ;
72
72
assert_eq ! ( recv_buf, b"helloworld" ) ;
73
73
}
74
+
75
+ /// This test tries to make sure that an acknowledgement sent while the socket's usable send window
76
+ /// (send window excluding in-flight not-acked data) is empty uses the correct sequence number.
77
+ /// (This test doesn't require that the usable send window is actually empty, just that it's empty
78
+ /// enough that TCP decides it can't/shouldn't send more payload packets.)
79
+ #[ test]
80
+ // this test causes miri to time-out
81
+ #[ cfg_attr( miri, ignore) ]
82
+ fn test_ack_with_empty_usable_send_window ( ) {
83
+ let scheduler = Scheduler :: new ( ) ;
84
+ let mut host = Host :: new ( ) ;
85
+
86
+ /// Helper to get the state from a socket.
87
+ fn s ( tcp : & Rc < RefCell < TcpSocket > > ) -> Ref < TcpState < TestEnvState > > {
88
+ Ref :: map ( tcp. borrow ( ) , |x| x. tcp_state ( ) )
89
+ }
90
+
91
+ // get an established tcp socket
92
+ let tcp = establish_helper ( & scheduler, & mut host) ;
93
+
94
+ // send on the socket until the send buffer has more data than the usable send window allows
95
+ let max_in_flight = s ( & tcp)
96
+ . as_established ( )
97
+ . unwrap ( )
98
+ . connection
99
+ . send
100
+ . window_range ( )
101
+ . len ( ) ;
102
+
103
+ let mut buffered = 0 ;
104
+ while buffered <= max_in_flight as usize {
105
+ buffered += TcpSocket :: sendmsg ( & tcp, & b"hello" [ ..] , 5 ) . unwrap ( ) ;
106
+ }
107
+
108
+ // read all of the packets it sent and make sure the sequence number is consistent
109
+ let mut next_seq = None ;
110
+ while let Some ( ( header, payload) ) = scheduler. pop_packet ( ) {
111
+ if next_seq. is_none ( ) {
112
+ next_seq = Some ( header. seq as usize ) ;
113
+ }
114
+
115
+ let next_seq = next_seq. as_mut ( ) . unwrap ( ) ;
116
+ assert_eq ! ( * next_seq, header. seq as usize ) ;
117
+ * next_seq += payload. len ( ) ;
118
+ }
119
+
120
+ // send a packet with a payload to trigger an acknowledgement
121
+ let header = TcpHeader {
122
+ ip : Ipv4Header {
123
+ src : "5.6.7.8" . parse ( ) . unwrap ( ) ,
124
+ dst : host. ip_addr ,
125
+ } ,
126
+ flags : TcpFlags :: empty ( ) ,
127
+ src_port : 20 ,
128
+ dst_port : 10 ,
129
+ seq : 1 ,
130
+ ack : 1 ,
131
+ window_size : 10000 ,
132
+ selective_acks : None ,
133
+ window_scale : None ,
134
+ timestamp : None ,
135
+ timestamp_echo : None ,
136
+ } ;
137
+ tcp. borrow_mut ( )
138
+ . push_in_packet ( & header, Bytes :: from ( & b"world" [ ..] ) ) ;
139
+
140
+ // check the packet sent by the socket
141
+ let ( header, payload) = scheduler. pop_packet ( ) . unwrap ( ) ;
142
+
143
+ // should have acked the packet we sent above using the correct sequence number
144
+ assert ! ( header. flags. contains( TcpFlags :: ACK ) ) ;
145
+ assert_eq ! ( header. ack, 6 ) ;
146
+ assert_eq ! ( header. seq as usize , next_seq. unwrap( ) ) ;
147
+
148
+ // we haven't acked any of the data it sent, so its usable send window should still be empty and
149
+ // should not have sent any data
150
+ assert ! ( payload. is_empty( ) ) ;
151
+ }
0 commit comments