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