1 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4 // option. This file may not be copied, modified, or distributed
5 // except according to those terms.
6 
7 use super::super::{IdleTimeout, Output, State, LOCAL_IDLE_TIMEOUT};
8 use super::{
9     connect, connect_force_idle, connect_with_rtt, default_client, default_server,
10     maybe_authenticate, send_and_receive, send_something, AT_LEAST_PTO,
11 };
12 use crate::packet::PacketBuilder;
13 use crate::stats::FrameStats;
14 use crate::tparams::{self, TransportParameter};
15 use crate::tracking::PacketNumberSpace;
16 use crate::StreamType;
17 
18 use neqo_common::Encoder;
19 use std::mem;
20 use std::time::Duration;
21 use test_fixture::{self, now, split_datagram};
22 
23 #[test]
idle_timeout()24 fn idle_timeout() {
25     let mut client = default_client();
26     let mut server = default_server();
27     connect_force_idle(&mut client, &mut server);
28 
29     let now = now();
30 
31     let res = client.process(None, now);
32     assert_eq!(res, Output::Callback(LOCAL_IDLE_TIMEOUT));
33 
34     // Still connected after 29 seconds. Idle timer not reset
35     mem::drop(client.process(None, now + LOCAL_IDLE_TIMEOUT - Duration::from_secs(1)));
36     assert!(matches!(client.state(), State::Confirmed));
37 
38     mem::drop(client.process(None, now + LOCAL_IDLE_TIMEOUT));
39 
40     // Not connected after LOCAL_IDLE_TIMEOUT seconds.
41     assert!(matches!(client.state(), State::Closed(_)));
42 }
43 
44 #[test]
asymmetric_idle_timeout()45 fn asymmetric_idle_timeout() {
46     const LOWER_TIMEOUT_MS: u64 = 1000;
47     const LOWER_TIMEOUT: Duration = Duration::from_millis(LOWER_TIMEOUT_MS);
48     // Sanity check the constant.
49     assert!(LOWER_TIMEOUT < LOCAL_IDLE_TIMEOUT);
50 
51     let mut client = default_client();
52     let mut server = default_server();
53 
54     // Overwrite the default at the server.
55     server
56         .tps
57         .borrow_mut()
58         .local
59         .set_integer(tparams::IDLE_TIMEOUT, LOWER_TIMEOUT_MS);
60     server.idle_timeout = IdleTimeout::new(LOWER_TIMEOUT);
61 
62     // Now connect and force idleness manually.
63     // We do that by following what `force_idle` does and have each endpoint
64     // send two packets, which are delivered out of order.  See `force_idle`.
65     connect(&mut client, &mut server);
66     let c1 = send_something(&mut client, now());
67     let c2 = send_something(&mut client, now());
68     server.process_input(c2, now());
69     server.process_input(c1, now());
70     let s1 = send_something(&mut server, now());
71     let s2 = send_something(&mut server, now());
72     client.process_input(s2, now());
73     let ack = client.process(Some(s1), now()).dgram();
74     assert!(ack.is_some());
75     // Now both should have received ACK frames so should be idle.
76     assert_eq!(server.process(ack, now()), Output::Callback(LOWER_TIMEOUT));
77     assert_eq!(client.process(None, now()), Output::Callback(LOWER_TIMEOUT));
78 }
79 
80 #[test]
tiny_idle_timeout()81 fn tiny_idle_timeout() {
82     const RTT: Duration = Duration::from_millis(500);
83     const LOWER_TIMEOUT_MS: u64 = 100;
84     const LOWER_TIMEOUT: Duration = Duration::from_millis(LOWER_TIMEOUT_MS);
85     // We won't respect a value that is lower than 3*PTO, sanity check.
86     assert!(LOWER_TIMEOUT < 3 * RTT);
87 
88     let mut client = default_client();
89     let mut server = default_server();
90 
91     // Overwrite the default at the server.
92     server
93         .set_local_tparam(
94             tparams::IDLE_TIMEOUT,
95             TransportParameter::Integer(LOWER_TIMEOUT_MS),
96         )
97         .unwrap();
98     server.idle_timeout = IdleTimeout::new(LOWER_TIMEOUT);
99 
100     // Now connect with an RTT and force idleness manually.
101     let mut now = connect_with_rtt(&mut client, &mut server, now(), RTT);
102     let c1 = send_something(&mut client, now);
103     let c2 = send_something(&mut client, now);
104     now += RTT / 2;
105     server.process_input(c2, now);
106     server.process_input(c1, now);
107     let s1 = send_something(&mut server, now);
108     let s2 = send_something(&mut server, now);
109     now += RTT / 2;
110     client.process_input(s2, now);
111     let ack = client.process(Some(s1), now).dgram();
112     assert!(ack.is_some());
113 
114     // The client should be idle now, but with a different timer.
115     if let Output::Callback(t) = client.process(None, now) {
116         assert!(t > LOWER_TIMEOUT);
117     } else {
118         panic!("Client not idle");
119     }
120 
121     // The server should go idle after the ACK, but again with a larger timeout.
122     now += RTT / 2;
123     if let Output::Callback(t) = client.process(ack, now) {
124         assert!(t > LOWER_TIMEOUT);
125     } else {
126         panic!("Client not idle");
127     }
128 }
129 
130 #[test]
idle_send_packet1()131 fn idle_send_packet1() {
132     const DELTA: Duration = Duration::from_millis(10);
133 
134     let mut client = default_client();
135     let mut server = default_server();
136     let mut now = now();
137     connect_force_idle(&mut client, &mut server);
138 
139     let timeout = client.process(None, now).callback();
140     assert_eq!(timeout, LOCAL_IDLE_TIMEOUT);
141 
142     now += Duration::from_secs(10);
143     let dgram = send_and_receive(&mut client, &mut server, now);
144     assert!(dgram.is_none());
145 
146     // Still connected after 39 seconds because idle timer reset by the
147     // outgoing packet.
148     now += LOCAL_IDLE_TIMEOUT - DELTA;
149     let dgram = client.process(None, now).dgram();
150     assert!(dgram.is_some()); // PTO
151     assert!(client.state().connected());
152 
153     // Not connected after 40 seconds.
154     now += DELTA;
155     let out = client.process(None, now);
156     assert!(matches!(out, Output::None));
157     assert!(client.state().closed());
158 }
159 
160 #[test]
idle_send_packet2()161 fn idle_send_packet2() {
162     const GAP: Duration = Duration::from_secs(10);
163     const DELTA: Duration = Duration::from_millis(10);
164 
165     let mut client = default_client();
166     let mut server = default_server();
167     connect_force_idle(&mut client, &mut server);
168 
169     let mut now = now();
170 
171     let timeout = client.process(None, now).callback();
172     assert_eq!(timeout, LOCAL_IDLE_TIMEOUT);
173 
174     // First transmission at t=GAP.
175     now += GAP;
176     mem::drop(send_something(&mut client, now));
177 
178     // Second transmission at t=2*GAP.
179     mem::drop(send_something(&mut client, now + GAP));
180     assert!((GAP * 2 + DELTA) < LOCAL_IDLE_TIMEOUT);
181 
182     // Still connected just before GAP + LOCAL_IDLE_TIMEOUT.
183     now += LOCAL_IDLE_TIMEOUT - DELTA;
184     let dgram = client.process(None, now).dgram();
185     assert!(dgram.is_some()); // PTO
186     assert!(matches!(client.state(), State::Confirmed));
187 
188     // Not connected after 40 seconds because timer not reset by second
189     // outgoing packet
190     now += DELTA;
191     let out = client.process(None, now);
192     assert!(matches!(out, Output::None));
193     assert!(matches!(client.state(), State::Closed(_)));
194 }
195 
196 #[test]
idle_recv_packet()197 fn idle_recv_packet() {
198     let mut client = default_client();
199     let mut server = default_server();
200     connect_force_idle(&mut client, &mut server);
201 
202     let now = now();
203 
204     let res = client.process(None, now);
205     assert_eq!(res, Output::Callback(LOCAL_IDLE_TIMEOUT));
206 
207     assert_eq!(client.stream_create(StreamType::BiDi).unwrap(), 0);
208     assert_eq!(client.stream_send(0, b"hello").unwrap(), 5);
209 
210     // Respond with another packet
211     let out = client.process(None, now + Duration::from_secs(10));
212     server.process_input(out.dgram().unwrap(), now + Duration::from_secs(10));
213     assert_eq!(server.stream_send(0, b"world").unwrap(), 5);
214     let out = server.process_output(now + Duration::from_secs(10));
215     assert_ne!(out.as_dgram_ref(), None);
216 
217     mem::drop(client.process(out.dgram(), now + Duration::from_secs(20)));
218     assert!(matches!(client.state(), State::Confirmed));
219 
220     // Still connected after 49 seconds because idle timer reset by received
221     // packet
222     mem::drop(client.process(None, now + LOCAL_IDLE_TIMEOUT + Duration::from_secs(19)));
223     assert!(matches!(client.state(), State::Confirmed));
224 
225     // Not connected after 50 seconds.
226     mem::drop(client.process(None, now + LOCAL_IDLE_TIMEOUT + Duration::from_secs(20)));
227 
228     assert!(matches!(client.state(), State::Closed(_)));
229 }
230 
231 /// Caching packets should not cause the connection to become idle.
232 /// This requires a few tricks to keep the connection from going
233 /// idle while preventing any progress on the handshake.
234 #[test]
idle_caching()235 fn idle_caching() {
236     let mut client = default_client();
237     let mut server = default_server();
238     let start = now();
239     let mut builder = PacketBuilder::short(Encoder::new(), false, &[]);
240 
241     // Perform the first round trip, but drop the Initial from the server.
242     // The client then caches the Handshake packet.
243     let dgram = client.process_output(start).dgram();
244     let dgram = server.process(dgram, start).dgram();
245     let (_, handshake) = split_datagram(&dgram.unwrap());
246     client.process_input(handshake.unwrap(), start);
247 
248     // Perform an exchange and keep the connection alive.
249     // Only allow a packet containing a PING to pass.
250     let middle = start + AT_LEAST_PTO;
251     mem::drop(client.process_output(middle));
252     let dgram = client.process_output(middle).dgram();
253 
254     // Get the server to send its first probe and throw that away.
255     mem::drop(server.process_output(middle).dgram());
256     // Now let the server process the client PING.  This causes the server
257     // to send CRYPTO frames again, so manually extract and discard those.
258     let ping_before_s = server.stats().frame_rx.ping;
259     server.process_input(dgram.unwrap(), middle);
260     assert_eq!(server.stats().frame_rx.ping, ping_before_s + 1);
261     let mut tokens = Vec::new();
262     server
263         .crypto
264         .streams
265         .write_frame(
266             PacketNumberSpace::Initial,
267             &mut builder,
268             &mut tokens,
269             &mut FrameStats::default(),
270         )
271         .unwrap();
272     assert_eq!(tokens.len(), 1);
273     tokens.clear();
274     server
275         .crypto
276         .streams
277         .write_frame(
278             PacketNumberSpace::Initial,
279             &mut builder,
280             &mut tokens,
281             &mut FrameStats::default(),
282         )
283         .unwrap();
284     assert!(tokens.is_empty());
285     let dgram = server.process_output(middle).dgram();
286 
287     // Now only allow the Initial packet from the server through;
288     // it shouldn't contain a CRYPTO frame.
289     let (initial, _) = split_datagram(&dgram.unwrap());
290     let ping_before_c = client.stats().frame_rx.ping;
291     let ack_before = client.stats().frame_rx.ack;
292     client.process_input(initial, middle);
293     assert_eq!(client.stats().frame_rx.ping, ping_before_c + 1);
294     assert_eq!(client.stats().frame_rx.ack, ack_before + 1);
295 
296     let end = start + LOCAL_IDLE_TIMEOUT + (AT_LEAST_PTO / 2);
297     // Now let the server Initial through, with the CRYPTO frame.
298     let dgram = server.process_output(end).dgram();
299     let (initial, _) = split_datagram(&dgram.unwrap());
300     neqo_common::qwarn!("client ingests initial, finally");
301     mem::drop(client.process(Some(initial), end));
302     maybe_authenticate(&mut client);
303     let dgram = client.process_output(end).dgram();
304     let dgram = server.process(dgram, end).dgram();
305     client.process_input(dgram.unwrap(), end);
306     assert_eq!(*client.state(), State::Confirmed);
307     assert_eq!(*server.state(), State::Confirmed);
308 }
309