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::{Connection, Output, State};
8 use super::{connect, connect_force_idle, default_client, default_server, send_something};
9 use crate::tparams::{self, TransportParameter};
10 use crate::{AppError, ConnectionError, Error, ERROR_APPLICATION_CLOSE};
11 
12 use neqo_common::Datagram;
13 use std::time::Duration;
14 use test_fixture::{self, addr, now};
15 
assert_draining(c: &Connection, expected: &Error)16 fn assert_draining(c: &Connection, expected: &Error) {
17     assert!(c.state().closed());
18     if let State::Draining {
19         error: ConnectionError::Transport(error),
20         ..
21     } = c.state()
22     {
23         assert_eq!(error, expected);
24     } else {
25         panic!();
26     }
27 }
28 
29 #[test]
connection_close()30 fn connection_close() {
31     let mut client = default_client();
32     let mut server = default_server();
33     connect(&mut client, &mut server);
34 
35     let now = now();
36 
37     client.close(now, 42, "");
38 
39     let out = client.process(None, now);
40 
41     server.process_input(out.dgram().unwrap(), now);
42     assert_draining(&server, &Error::PeerApplicationError(42));
43 }
44 
45 #[test]
connection_close_with_long_reason_string()46 fn connection_close_with_long_reason_string() {
47     let mut client = default_client();
48     let mut server = default_server();
49     connect(&mut client, &mut server);
50 
51     let now = now();
52     // Create a long string and use it as the close reason.
53     let long_reason = String::from_utf8([0x61; 2048].to_vec()).unwrap();
54     client.close(now, 42, long_reason);
55 
56     let out = client.process(None, now);
57 
58     server.process_input(out.dgram().unwrap(), now);
59     assert_draining(&server, &Error::PeerApplicationError(42));
60 }
61 
62 // During the handshake, an application close should be sanitized.
63 #[test]
early_application_close()64 fn early_application_close() {
65     let mut client = default_client();
66     let mut server = default_server();
67 
68     // One flight each.
69     let dgram = client.process(None, now()).dgram();
70     assert!(dgram.is_some());
71     let dgram = server.process(dgram, now()).dgram();
72     assert!(dgram.is_some());
73 
74     server.close(now(), 77, String::from(""));
75     assert!(server.state().closed());
76     let dgram = server.process(None, now()).dgram();
77     assert!(dgram.is_some());
78 
79     client.process_input(dgram.unwrap(), now());
80     assert_draining(&client, &Error::PeerError(ERROR_APPLICATION_CLOSE));
81 }
82 
83 #[test]
bad_tls_version()84 fn bad_tls_version() {
85     let mut client = default_client();
86     // Do a bad, bad thing.
87     client
88         .crypto
89         .tls
90         .set_option(neqo_crypto::Opt::Tls13CompatMode, true)
91         .unwrap();
92     let mut server = default_server();
93 
94     let dgram = client.process(None, now()).dgram();
95     assert!(dgram.is_some());
96     let dgram = server.process(dgram, now()).dgram();
97     assert_eq!(
98         *server.state(),
99         State::Closed(ConnectionError::Transport(Error::ProtocolViolation))
100     );
101     assert!(dgram.is_some());
102     client.process_input(dgram.unwrap(), now());
103     assert_draining(&client, &Error::PeerError(Error::ProtocolViolation.code()));
104 }
105 
106 /// Test the interaction between the loss recovery timer
107 /// and the closing timer.
108 #[test]
closing_timers_interation()109 fn closing_timers_interation() {
110     let mut client = default_client();
111     let mut server = default_server();
112     connect(&mut client, &mut server);
113 
114     let mut now = now();
115 
116     // We're going to induce time-based loss recovery so that timer is set.
117     let _p1 = send_something(&mut client, now);
118     let p2 = send_something(&mut client, now);
119     let ack = server.process(Some(p2), now).dgram();
120     assert!(ack.is_some()); // This is an ACK.
121 
122     // After processing the ACK, we should be on the loss recovery timer.
123     let cb = client.process(ack, now).callback();
124     assert_ne!(cb, Duration::from_secs(0));
125     now += cb;
126 
127     // Rather than let the timer pop, close the connection.
128     client.close(now, 0, "");
129     let client_close = client.process(None, now).dgram();
130     assert!(client_close.is_some());
131     // This should now report the end of the closing period, not a
132     // zero-duration wait driven by the (now defunct) loss recovery timer.
133     let client_close_timer = client.process(None, now).callback();
134     assert_ne!(client_close_timer, Duration::from_secs(0));
135 }
136 
137 #[test]
closing_and_draining()138 fn closing_and_draining() {
139     const APP_ERROR: AppError = 7;
140     let mut client = default_client();
141     let mut server = default_server();
142     connect(&mut client, &mut server);
143 
144     // Save a packet from the client for later.
145     let p1 = send_something(&mut client, now());
146 
147     // Close the connection.
148     client.close(now(), APP_ERROR, "");
149     let client_close = client.process(None, now()).dgram();
150     assert!(client_close.is_some());
151     let client_close_timer = client.process(None, now()).callback();
152     assert_ne!(client_close_timer, Duration::from_secs(0));
153 
154     // The client will spit out the same packet in response to anything it receives.
155     let p3 = send_something(&mut server, now());
156     let client_close2 = client.process(Some(p3), now()).dgram();
157     assert_eq!(
158         client_close.as_ref().unwrap().len(),
159         client_close2.as_ref().unwrap().len()
160     );
161 
162     // After this time, the client should transition to closed.
163     let end = client.process(None, now() + client_close_timer);
164     assert_eq!(end, Output::None);
165     assert_eq!(
166         *client.state(),
167         State::Closed(ConnectionError::Application(APP_ERROR))
168     );
169 
170     // When the server receives the close, it too should generate CONNECTION_CLOSE.
171     let server_close = server.process(client_close, now()).dgram();
172     assert!(server.state().closed());
173     assert!(server_close.is_some());
174     // .. but it ignores any further close packets.
175     let server_close_timer = server.process(client_close2, now()).callback();
176     assert_ne!(server_close_timer, Duration::from_secs(0));
177     // Even a legitimate packet without a close in it.
178     let server_close_timer2 = server.process(Some(p1), now()).callback();
179     assert_eq!(server_close_timer, server_close_timer2);
180 
181     let end = server.process(None, now() + server_close_timer);
182     assert_eq!(end, Output::None);
183     assert_eq!(
184         *server.state(),
185         State::Closed(ConnectionError::Transport(Error::PeerApplicationError(
186             APP_ERROR
187         )))
188     );
189 }
190 
191 /// Test that a client can handle a stateless reset correctly.
192 #[test]
stateless_reset_client()193 fn stateless_reset_client() {
194     let mut client = default_client();
195     let mut server = default_server();
196     server
197         .set_local_tparam(
198             tparams::STATELESS_RESET_TOKEN,
199             TransportParameter::Bytes(vec![77; 16]),
200         )
201         .unwrap();
202     connect_force_idle(&mut client, &mut server);
203 
204     client.process_input(Datagram::new(addr(), addr(), vec![77; 21]), now());
205     assert_draining(&client, &Error::StatelessReset);
206 }
207