| ... | @@ -70,6 +70,292 @@ fn peers_meet_and_follow_presence() { | ... | @@ -70,6 +70,292 @@ fn peers_meet_and_follow_presence() { |
| 70 | until(&grace, <[Peer]>::is_empty); | 70 | until(&grace, <[Peer]>::is_empty); |
| 71 | } | 71 | } |
| 72 | | 72 | |
| | 73 | fn lan_accept(listener: &TcpListener) -> TcpStream { |
| | 74 | let deadline = Instant::now() + Duration::from_secs(10); |
| | 75 | loop { |
| | 76 | match listener.accept() { |
| | 77 | Ok((stream, _)) => { |
| | 78 | stream.set_nonblocking(false).unwrap(); |
| | 79 | stream.set_read_timeout(Some(OPENING)).unwrap(); |
| | 80 | stream.set_write_timeout(Some(OPENING)).unwrap(); |
| | 81 | return stream; |
| | 82 | } |
| | 83 | Err(error) if error.kind() == io::ErrorKind::WouldBlock => { |
| | 84 | assert!(Instant::now() < deadline, "LAN did not reconnect"); |
| | 85 | thread::sleep(Duration::from_millis(10)); |
| | 86 | } |
| | 87 | Err(error) => panic!("{error}"), |
| | 88 | } |
| | 89 | } |
| | 90 | } |
| | 91 | |
| | 92 | fn lan_opening(stream: &mut TcpStream) -> Vec<u8> { |
| | 93 | let mut length = [0; 4]; |
| | 94 | stream.read_exact(&mut length).unwrap(); |
| | 95 | let length = u32::from_be_bytes(length) as usize; |
| | 96 | assert!(length < 1 << 20); |
| | 97 | let mut opening = vec![0; length]; |
| | 98 | stream.read_exact(&mut opening).unwrap(); |
| | 99 | opening |
| | 100 | } |
| | 101 | |
| | 102 | #[test] |
| | 103 | fn lan_retries_opening_io_and_reconnect_refusal_with_fresh_keys() { |
| | 104 | let room = Room::Notebook([71; 16]); |
| | 105 | let listener = TcpListener::bind("127.0.0.1:0").unwrap(); |
| | 106 | let address = listener.local_addr().unwrap(); |
| | 107 | listener.set_nonblocking(true).unwrap(); |
| | 108 | let (fault, faults) = mpsc::channel(); |
| | 109 | let (resume, resumed) = mpsc::channel(); |
| | 110 | let server_room = room.clone(); |
| | 111 | let server = thread::spawn(move || { |
| | 112 | let mut abandoned = lan_accept(&listener); |
| | 113 | let first = lan_opening(&mut abandoned); |
| | 114 | drop(abandoned); |
| | 115 | let host = hello("Host"); |
| | 116 | let mut openings = vec![first]; |
| | 117 | let mut delivered = Vec::new(); |
| | 118 | let mut listener = Some(listener); |
| | 119 | for edit in [41_u64, 42] { |
| | 120 | let mut stream = lan_accept(listener.as_ref().unwrap()); |
| | 121 | let theirs = lan_opening(&mut stream); |
| | 122 | assert!(openings.iter().all(|old| *old != theirs), "LAN reused keys"); |
| | 123 | openings.push(theirs.clone()); |
| | 124 | let (opening, ours) = wire::Opening::new( |
| | 125 | Side::Responder, |
| | 126 | &server_room.tag().unwrap(), |
| | 127 | &server_room.secret(), |
| | 128 | ) |
| | 129 | .unwrap(); |
| | 130 | stream |
| | 131 | .write_all(&(ours.len() as u32).to_be_bytes()) |
| | 132 | .unwrap(); |
| | 133 | stream.write_all(&ours).unwrap(); |
| | 134 | let (mut send, mut receive) = opening.finish(&theirs).unwrap(); |
| | 135 | send.send(&mut stream, kind::HELLO, &host).unwrap(); |
| | 136 | assert_eq!(receive.receive(&mut stream).unwrap().0, kind::HELLO); |
| | 137 | send.send(&mut stream, kind::EDITS, &edit).unwrap(); |
| | 138 | loop { |
| | 139 | let (kind, body) = receive.receive(&mut stream).unwrap(); |
| | 140 | if kind == kind::EDITS { |
| | 141 | delivered.push(minicbor::decode::<u64>(&body).unwrap()); |
| | 142 | break; |
| | 143 | } |
| | 144 | } |
| | 145 | assert_eq!( |
| | 146 | listener.as_ref().unwrap().accept().unwrap_err().kind(), |
| | 147 | io::ErrorKind::WouldBlock, |
| | 148 | "duplicate LAN dial workers connected", |
| | 149 | ); |
| | 150 | if edit == 41 { |
| | 151 | drop(listener.take()); |
| | 152 | stream.shutdown(Shutdown::Both).unwrap(); |
| | 153 | fault.send(()).unwrap(); |
| | 154 | resumed.recv_timeout(Duration::from_secs(10)).unwrap(); |
| | 155 | let reopened = TcpListener::bind(address).unwrap(); |
| | 156 | reopened.set_nonblocking(true).unwrap(); |
| | 157 | listener = Some(reopened); |
| | 158 | } else { |
| | 159 | loop { |
| | 160 | let (kind, _) = receive.receive(&mut stream).unwrap(); |
| | 161 | assert_ne!(kind, kind::EDITS, "an edit was delivered twice"); |
| | 162 | if kind == kind::BYE { |
| | 163 | break; |
| | 164 | } |
| | 165 | } |
| | 166 | } |
| | 167 | } |
| | 168 | delivered |
| | 169 | }); |
| | 170 | let (frame, frames) = mpsc::channel(); |
| | 171 | let guest = Live::start(hello("Guest"), &room, None, None, move |event| { |
| | 172 | if let Event::Frame { kind, body, .. } = event { |
| | 173 | frame.send((kind, body.to_vec())).unwrap(); |
| | 174 | } |
| | 175 | }) |
| | 176 | .unwrap(); |
| | 177 | for _ in 0..20 { |
| | 178 | guest.connect(address); |
| | 179 | } |
| | 180 | for edit in [41_u64, 42] { |
| | 181 | let (kind, body) = frames.recv_timeout(Duration::from_secs(10)).unwrap(); |
| | 182 | assert_eq!(kind, kind::EDITS); |
| | 183 | assert_eq!(minicbor::decode::<u64>(&body).unwrap(), edit); |
| | 184 | let peer = until(&guest, |peers| peers.len() == 1).remove(0); |
| | 185 | let line = guest.line(&peer.hello.peer).unwrap(); |
| | 186 | line.send(kind::EDITS, &edit).unwrap(); |
| | 187 | if edit == 41 { |
| | 188 | faults.recv_timeout(Duration::from_secs(10)).unwrap(); |
| | 189 | until(&guest, <[Peer]>::is_empty); |
| | 190 | assert_eq!(guest.failed(), 0); |
| | 191 | assert_eq!( |
| | 192 | TcpStream::connect(address).unwrap_err().kind(), |
| | 193 | io::ErrorKind::ConnectionRefused |
| | 194 | ); |
| | 195 | thread::sleep(Duration::from_millis(2300)); |
| | 196 | resume.send(()).unwrap(); |
| | 197 | } else { |
| | 198 | line.hang_up("left"); |
| | 199 | } |
| | 200 | } |
| | 201 | assert_eq!(server.join().unwrap(), [41, 42]); |
| | 202 | assert!(matches!(frames.try_recv(), Err(mpsc::TryRecvError::Empty))); |
| | 203 | assert_eq!(guest.failed(), 0); |
| | 204 | until(&guest, <[Peer]>::is_empty); |
| | 205 | let stopped = Arc::downgrade(&guest.shared); |
| | 206 | drop(guest); |
| | 207 | let deadline = Instant::now() + Duration::from_secs(1); |
| | 208 | while stopped.upgrade().is_some() { |
| | 209 | assert!( |
| | 210 | Instant::now() < deadline, |
| | 211 | "LAN helpers retained stopped Live" |
| | 212 | ); |
| | 213 | thread::sleep(Duration::from_millis(10)); |
| | 214 | } |
| | 215 | } |
| | 216 | |
| | 217 | #[test] |
| | 218 | fn lan_retries_initial_refusal_and_stops_its_backoff() { |
| | 219 | let listener = TcpListener::bind("127.0.0.1:0").unwrap(); |
| | 220 | let address = listener.local_addr().unwrap(); |
| | 221 | drop(listener); |
| | 222 | let room = Room::Notebook([72; 16]); |
| | 223 | let guest = Live::start(hello("Guest"), &room, None, None, |_| {}).unwrap(); |
| | 224 | guest.connect(address); |
| | 225 | thread::sleep(Duration::from_millis(1200)); |
| | 226 | let listener = TcpListener::bind(address).unwrap(); |
| | 227 | listener.set_nonblocking(true).unwrap(); |
| | 228 | let mut stream = lan_accept(&listener); |
| | 229 | let first = lan_opening(&mut stream); |
| | 230 | assert!(!first.is_empty()); |
| | 231 | drop(listener); |
| | 232 | drop(stream); |
| | 233 | thread::sleep(Duration::from_millis(100)); |
| | 234 | let stopped = Arc::downgrade(&guest.shared); |
| | 235 | drop(guest); |
| | 236 | let deadline = Instant::now() + Duration::from_secs(1); |
| | 237 | while stopped.upgrade().is_some() { |
| | 238 | assert!( |
| | 239 | Instant::now() < deadline, |
| | 240 | "LAN backoff retained stopped Live" |
| | 241 | ); |
| | 242 | thread::sleep(Duration::from_millis(10)); |
| | 243 | } |
| | 244 | let listener = TcpListener::bind(address).unwrap(); |
| | 245 | listener.set_nonblocking(true).unwrap(); |
| | 246 | thread::sleep(Duration::from_millis(2200)); |
| | 247 | assert_eq!( |
| | 248 | listener.accept().unwrap_err().kind(), |
| | 249 | io::ErrorKind::WouldBlock |
| | 250 | ); |
| | 251 | } |
| | 252 | |
| | 253 | #[test] |
| | 254 | fn lan_authentication_and_version_failures_stop_retrying() { |
| | 255 | for version in [false, true] { |
| | 256 | let room = Room::Notebook([73; 16]); |
| | 257 | let listener = TcpListener::bind("127.0.0.1:0").unwrap(); |
| | 258 | listener.set_nonblocking(true).unwrap(); |
| | 259 | let address = listener.local_addr().unwrap(); |
| | 260 | let guest = Live::start(hello("Guest"), &room, None, None, |_| {}).unwrap(); |
| | 261 | guest.connect(address); |
| | 262 | let mut stream = lan_accept(&listener); |
| | 263 | if version { |
| | 264 | lan_opening(&mut stream); |
| | 265 | let mut opening = minicbor::Encoder::new(Vec::new()); |
| | 266 | opening |
| | 267 | .map(3) |
| | 268 | .unwrap() |
| | 269 | .u8(0) |
| | 270 | .unwrap() |
| | 271 | .u16(wire::VERSION + 1) |
| | 272 | .unwrap() |
| | 273 | .u8(1) |
| | 274 | .unwrap() |
| | 275 | .str(&room.tag().unwrap()) |
| | 276 | .unwrap() |
| | 277 | .u8(2) |
| | 278 | .unwrap() |
| | 279 | .bytes(&[0; 33]) |
| | 280 | .unwrap(); |
| | 281 | let opening = opening.into_writer(); |
| | 282 | stream |
| | 283 | .write_all(&(opening.len() as u32).to_be_bytes()) |
| | 284 | .unwrap(); |
| | 285 | stream.write_all(&opening).unwrap(); |
| | 286 | until(&guest, |_| guest.other_version() == Some(wire::VERSION + 1)); |
| | 287 | assert_eq!(guest.failed(), 0); |
| | 288 | } else { |
| | 289 | let (mut send, _) = wire::open( |
| | 290 | &mut stream, |
| | 291 | Side::Responder, |
| | 292 | &room.tag().unwrap(), |
| | 293 | b"wrong secret", |
| | 294 | ) |
| | 295 | .unwrap(); |
| | 296 | send.send(&mut stream, kind::HELLO, &hello("Host")).unwrap(); |
| | 297 | until(&guest, |_| guest.failed() == 1); |
| | 298 | } |
| | 299 | drop(stream); |
| | 300 | thread::sleep(Duration::from_millis(1200)); |
| | 301 | assert_eq!( |
| | 302 | listener.accept().unwrap_err().kind(), |
| | 303 | io::ErrorKind::WouldBlock |
| | 304 | ); |
| | 305 | assert_eq!(guest.failed(), u32::from(!version)); |
| | 306 | guest.connect(address); |
| | 307 | let mut stream = lan_accept(&listener); |
| | 308 | assert!( |
| | 309 | !lan_opening(&mut stream).is_empty(), |
| | 310 | "finished dial was never released" |
| | 311 | ); |
| | 312 | drop(guest); |
| | 313 | } |
| | 314 | } |
| | 315 | |
| | 316 | #[test] |
| | 317 | fn lan_duplicate_peer_stops_retrying_without_replacing_its_line() { |
| | 318 | let room = Room::Notebook([74; 16]); |
| | 319 | let host_hello = hello("Host"); |
| | 320 | let (frame, frames) = mpsc::channel(); |
| | 321 | let host = Live::start(host_hello.clone(), &room, None, None, move |event| { |
| | 322 | if let Event::Frame { kind, body, .. } = event { |
| | 323 | frame.send((kind, body.to_vec())).unwrap(); |
| | 324 | } |
| | 325 | }) |
| | 326 | .unwrap(); |
| | 327 | let guest = Live::start(hello("Guest"), &room, None, None, |_| {}).unwrap(); |
| | 328 | guest.connect(host.address()); |
| | 329 | until(&guest, |peers| peers.len() == 1); |
| | 330 | let line = guest.line(&host_hello.peer).unwrap(); |
| | 331 | let listener = TcpListener::bind("127.0.0.1:0").unwrap(); |
| | 332 | listener.set_nonblocking(true).unwrap(); |
| | 333 | guest.connect(listener.local_addr().unwrap()); |
| | 334 | let mut stream = lan_accept(&listener); |
| | 335 | let (mut send, mut receive) = wire::open( |
| | 336 | &mut stream, |
| | 337 | Side::Responder, |
| | 338 | &room.tag().unwrap(), |
| | 339 | &room.secret(), |
| | 340 | ) |
| | 341 | .unwrap(); |
| | 342 | send.send(&mut stream, kind::HELLO, &host_hello).unwrap(); |
| | 343 | assert_eq!(receive.receive(&mut stream).unwrap().0, kind::HELLO); |
| | 344 | assert_eq!(stream.read(&mut [0; 1]).unwrap(), 0); |
| | 345 | thread::sleep(Duration::from_millis(1200)); |
| | 346 | assert_eq!( |
| | 347 | listener.accept().unwrap_err().kind(), |
| | 348 | io::ErrorKind::WouldBlock |
| | 349 | ); |
| | 350 | assert_eq!(guest.peers().len(), 1); |
| | 351 | assert_eq!(guest.failed(), 0); |
| | 352 | line.send(kind::EDITS, &43_u64).unwrap(); |
| | 353 | let (kind, body) = frames.recv_timeout(Duration::from_secs(10)).unwrap(); |
| | 354 | assert_eq!(kind, kind::EDITS); |
| | 355 | assert_eq!(minicbor::decode::<u64>(&body).unwrap(), 43); |
| | 356 | assert!(matches!(frames.try_recv(), Err(mpsc::TryRecvError::Empty))); |
| | 357 | } |
| | 358 | |
| 73 | /// A peer holding another code never meets: its first frame does not open. | 359 | /// A peer holding another code never meets: its first frame does not open. |
| 74 | #[test] | 360 | #[test] |
| 75 | fn another_code_never_meets() { | 361 | fn another_code_never_meets() { |