]>
Commit | Line | Data |
---|---|---|
1b1a35ee XL |
1 | use crate::fmt; |
2 | use crate::io::prelude::*; | |
3 | use crate::io::{ErrorKind, IoSlice, IoSliceMut}; | |
4 | use crate::net::test::{next_test_ip4, next_test_ip6}; | |
5 | use crate::net::*; | |
6 | use crate::sync::mpsc::channel; | |
7 | use crate::thread; | |
8 | use crate::time::{Duration, Instant}; | |
9 | ||
10 | fn each_ip(f: &mut dyn FnMut(SocketAddr)) { | |
11 | f(next_test_ip4()); | |
12 | f(next_test_ip6()); | |
13 | } | |
14 | ||
15 | macro_rules! t { | |
16 | ($e:expr) => { | |
17 | match $e { | |
18 | Ok(t) => t, | |
19 | Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), | |
20 | } | |
21 | }; | |
22 | } | |
23 | ||
24 | #[test] | |
25 | fn bind_error() { | |
26 | match TcpListener::bind("1.1.1.1:9999") { | |
27 | Ok(..) => panic!(), | |
28 | Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), | |
29 | } | |
30 | } | |
31 | ||
32 | #[test] | |
33 | fn connect_error() { | |
34 | match TcpStream::connect("0.0.0.0:1") { | |
35 | Ok(..) => panic!(), | |
36 | Err(e) => assert!( | |
37 | e.kind() == ErrorKind::ConnectionRefused | |
38 | || e.kind() == ErrorKind::InvalidInput | |
39 | || e.kind() == ErrorKind::AddrInUse | |
40 | || e.kind() == ErrorKind::AddrNotAvailable, | |
41 | "bad error: {} {:?}", | |
42 | e, | |
43 | e.kind() | |
44 | ), | |
45 | } | |
46 | } | |
47 | ||
48 | #[test] | |
49 | fn listen_localhost() { | |
50 | let socket_addr = next_test_ip4(); | |
51 | let listener = t!(TcpListener::bind(&socket_addr)); | |
52 | ||
53 | let _t = thread::spawn(move || { | |
54 | let mut stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); | |
55 | t!(stream.write(&[144])); | |
56 | }); | |
57 | ||
58 | let mut stream = t!(listener.accept()).0; | |
59 | let mut buf = [0]; | |
60 | t!(stream.read(&mut buf)); | |
61 | assert!(buf[0] == 144); | |
62 | } | |
63 | ||
64 | #[test] | |
65 | fn connect_loopback() { | |
66 | each_ip(&mut |addr| { | |
67 | let acceptor = t!(TcpListener::bind(&addr)); | |
68 | ||
69 | let _t = thread::spawn(move || { | |
70 | let host = match addr { | |
71 | SocketAddr::V4(..) => "127.0.0.1", | |
72 | SocketAddr::V6(..) => "::1", | |
73 | }; | |
74 | let mut stream = t!(TcpStream::connect(&(host, addr.port()))); | |
75 | t!(stream.write(&[66])); | |
76 | }); | |
77 | ||
78 | let mut stream = t!(acceptor.accept()).0; | |
79 | let mut buf = [0]; | |
80 | t!(stream.read(&mut buf)); | |
81 | assert!(buf[0] == 66); | |
82 | }) | |
83 | } | |
84 | ||
85 | #[test] | |
86 | fn smoke_test() { | |
87 | each_ip(&mut |addr| { | |
88 | let acceptor = t!(TcpListener::bind(&addr)); | |
89 | ||
90 | let (tx, rx) = channel(); | |
91 | let _t = thread::spawn(move || { | |
92 | let mut stream = t!(TcpStream::connect(&addr)); | |
93 | t!(stream.write(&[99])); | |
94 | tx.send(t!(stream.local_addr())).unwrap(); | |
95 | }); | |
96 | ||
97 | let (mut stream, addr) = t!(acceptor.accept()); | |
98 | let mut buf = [0]; | |
99 | t!(stream.read(&mut buf)); | |
100 | assert!(buf[0] == 99); | |
101 | assert_eq!(addr, t!(rx.recv())); | |
102 | }) | |
103 | } | |
104 | ||
105 | #[test] | |
106 | fn read_eof() { | |
107 | each_ip(&mut |addr| { | |
108 | let acceptor = t!(TcpListener::bind(&addr)); | |
109 | ||
110 | let _t = thread::spawn(move || { | |
111 | let _stream = t!(TcpStream::connect(&addr)); | |
112 | // Close | |
113 | }); | |
114 | ||
115 | let mut stream = t!(acceptor.accept()).0; | |
116 | let mut buf = [0]; | |
117 | let nread = t!(stream.read(&mut buf)); | |
118 | assert_eq!(nread, 0); | |
119 | let nread = t!(stream.read(&mut buf)); | |
120 | assert_eq!(nread, 0); | |
121 | }) | |
122 | } | |
123 | ||
124 | #[test] | |
125 | fn write_close() { | |
126 | each_ip(&mut |addr| { | |
127 | let acceptor = t!(TcpListener::bind(&addr)); | |
128 | ||
129 | let (tx, rx) = channel(); | |
130 | let _t = thread::spawn(move || { | |
131 | drop(t!(TcpStream::connect(&addr))); | |
132 | tx.send(()).unwrap(); | |
133 | }); | |
134 | ||
135 | let mut stream = t!(acceptor.accept()).0; | |
136 | rx.recv().unwrap(); | |
137 | let buf = [0]; | |
138 | match stream.write(&buf) { | |
139 | Ok(..) => {} | |
140 | Err(e) => { | |
141 | assert!( | |
142 | e.kind() == ErrorKind::ConnectionReset | |
143 | || e.kind() == ErrorKind::BrokenPipe | |
144 | || e.kind() == ErrorKind::ConnectionAborted, | |
5e7ed085 | 145 | "unknown error: {e}" |
1b1a35ee XL |
146 | ); |
147 | } | |
148 | } | |
149 | }) | |
150 | } | |
151 | ||
152 | #[test] | |
153 | fn multiple_connect_serial() { | |
154 | each_ip(&mut |addr| { | |
155 | let max = 10; | |
156 | let acceptor = t!(TcpListener::bind(&addr)); | |
157 | ||
158 | let _t = thread::spawn(move || { | |
159 | for _ in 0..max { | |
160 | let mut stream = t!(TcpStream::connect(&addr)); | |
161 | t!(stream.write(&[99])); | |
162 | } | |
163 | }); | |
164 | ||
165 | for stream in acceptor.incoming().take(max) { | |
166 | let mut stream = t!(stream); | |
167 | let mut buf = [0]; | |
168 | t!(stream.read(&mut buf)); | |
169 | assert_eq!(buf[0], 99); | |
170 | } | |
171 | }) | |
172 | } | |
173 | ||
174 | #[test] | |
175 | fn multiple_connect_interleaved_greedy_schedule() { | |
176 | const MAX: usize = 10; | |
177 | each_ip(&mut |addr| { | |
178 | let acceptor = t!(TcpListener::bind(&addr)); | |
179 | ||
180 | let _t = thread::spawn(move || { | |
181 | let acceptor = acceptor; | |
182 | for (i, stream) in acceptor.incoming().enumerate().take(MAX) { | |
183 | // Start another thread to handle the connection | |
184 | let _t = thread::spawn(move || { | |
185 | let mut stream = t!(stream); | |
186 | let mut buf = [0]; | |
187 | t!(stream.read(&mut buf)); | |
188 | assert!(buf[0] == i as u8); | |
189 | }); | |
190 | } | |
191 | }); | |
192 | ||
193 | connect(0, addr); | |
194 | }); | |
195 | ||
196 | fn connect(i: usize, addr: SocketAddr) { | |
197 | if i == MAX { | |
198 | return; | |
199 | } | |
200 | ||
201 | let t = thread::spawn(move || { | |
202 | let mut stream = t!(TcpStream::connect(&addr)); | |
203 | // Connect again before writing | |
204 | connect(i + 1, addr); | |
205 | t!(stream.write(&[i as u8])); | |
206 | }); | |
207 | t.join().ok().expect("thread panicked"); | |
208 | } | |
209 | } | |
210 | ||
211 | #[test] | |
212 | fn multiple_connect_interleaved_lazy_schedule() { | |
213 | const MAX: usize = 10; | |
214 | each_ip(&mut |addr| { | |
215 | let acceptor = t!(TcpListener::bind(&addr)); | |
216 | ||
217 | let _t = thread::spawn(move || { | |
218 | for stream in acceptor.incoming().take(MAX) { | |
219 | // Start another thread to handle the connection | |
220 | let _t = thread::spawn(move || { | |
221 | let mut stream = t!(stream); | |
222 | let mut buf = [0]; | |
223 | t!(stream.read(&mut buf)); | |
224 | assert!(buf[0] == 99); | |
225 | }); | |
226 | } | |
227 | }); | |
228 | ||
229 | connect(0, addr); | |
230 | }); | |
231 | ||
232 | fn connect(i: usize, addr: SocketAddr) { | |
233 | if i == MAX { | |
234 | return; | |
235 | } | |
236 | ||
237 | let t = thread::spawn(move || { | |
238 | let mut stream = t!(TcpStream::connect(&addr)); | |
239 | connect(i + 1, addr); | |
240 | t!(stream.write(&[99])); | |
241 | }); | |
242 | t.join().ok().expect("thread panicked"); | |
243 | } | |
244 | } | |
245 | ||
246 | #[test] | |
247 | fn socket_and_peer_name() { | |
248 | each_ip(&mut |addr| { | |
249 | let listener = t!(TcpListener::bind(&addr)); | |
250 | let so_name = t!(listener.local_addr()); | |
251 | assert_eq!(addr, so_name); | |
252 | let _t = thread::spawn(move || { | |
253 | t!(listener.accept()); | |
254 | }); | |
255 | ||
256 | let stream = t!(TcpStream::connect(&addr)); | |
257 | assert_eq!(addr, t!(stream.peer_addr())); | |
258 | }) | |
259 | } | |
260 | ||
261 | #[test] | |
262 | fn partial_read() { | |
263 | each_ip(&mut |addr| { | |
264 | let (tx, rx) = channel(); | |
265 | let srv = t!(TcpListener::bind(&addr)); | |
266 | let _t = thread::spawn(move || { | |
267 | let mut cl = t!(srv.accept()).0; | |
268 | cl.write(&[10]).unwrap(); | |
269 | let mut b = [0]; | |
270 | t!(cl.read(&mut b)); | |
271 | tx.send(()).unwrap(); | |
272 | }); | |
273 | ||
274 | let mut c = t!(TcpStream::connect(&addr)); | |
275 | let mut b = [0; 10]; | |
276 | assert_eq!(c.read(&mut b).unwrap(), 1); | |
277 | t!(c.write(&[1])); | |
278 | rx.recv().unwrap(); | |
279 | }) | |
280 | } | |
281 | ||
282 | #[test] | |
283 | fn read_vectored() { | |
284 | each_ip(&mut |addr| { | |
285 | let srv = t!(TcpListener::bind(&addr)); | |
286 | let mut s1 = t!(TcpStream::connect(&addr)); | |
287 | let mut s2 = t!(srv.accept()).0; | |
288 | ||
289 | let len = s1.write(&[10, 11, 12]).unwrap(); | |
290 | assert_eq!(len, 3); | |
291 | ||
292 | let mut a = []; | |
293 | let mut b = [0]; | |
294 | let mut c = [0; 3]; | |
295 | let len = t!(s2.read_vectored(&mut [ | |
296 | IoSliceMut::new(&mut a), | |
297 | IoSliceMut::new(&mut b), | |
298 | IoSliceMut::new(&mut c) | |
299 | ],)); | |
300 | assert!(len > 0); | |
301 | assert_eq!(b, [10]); | |
302 | // some implementations don't support readv, so we may only fill the first buffer | |
303 | assert!(len == 1 || c == [11, 12, 0]); | |
304 | }) | |
305 | } | |
306 | ||
307 | #[test] | |
308 | fn write_vectored() { | |
309 | each_ip(&mut |addr| { | |
310 | let srv = t!(TcpListener::bind(&addr)); | |
311 | let mut s1 = t!(TcpStream::connect(&addr)); | |
312 | let mut s2 = t!(srv.accept()).0; | |
313 | ||
314 | let a = []; | |
315 | let b = [10]; | |
316 | let c = [11, 12]; | |
317 | t!(s1.write_vectored(&[IoSlice::new(&a), IoSlice::new(&b), IoSlice::new(&c)])); | |
318 | ||
319 | let mut buf = [0; 4]; | |
320 | let len = t!(s2.read(&mut buf)); | |
321 | // some implementations don't support writev, so we may only write the first buffer | |
322 | if len == 1 { | |
323 | assert_eq!(buf, [10, 0, 0, 0]); | |
324 | } else { | |
325 | assert_eq!(len, 3); | |
326 | assert_eq!(buf, [10, 11, 12, 0]); | |
327 | } | |
328 | }) | |
329 | } | |
330 | ||
331 | #[test] | |
332 | fn double_bind() { | |
333 | each_ip(&mut |addr| { | |
334 | let listener1 = t!(TcpListener::bind(&addr)); | |
335 | match TcpListener::bind(&addr) { | |
336 | Ok(listener2) => panic!( | |
337 | "This system (perhaps due to options set by TcpListener::bind) \ | |
338 | permits double binding: {:?} and {:?}", | |
339 | listener1, listener2 | |
340 | ), | |
341 | Err(e) => { | |
342 | assert!( | |
343 | e.kind() == ErrorKind::ConnectionRefused | |
136023e0 | 344 | || e.kind() == ErrorKind::Uncategorized |
1b1a35ee XL |
345 | || e.kind() == ErrorKind::AddrInUse, |
346 | "unknown error: {} {:?}", | |
347 | e, | |
348 | e.kind() | |
349 | ); | |
350 | } | |
351 | } | |
352 | }) | |
353 | } | |
354 | ||
355 | #[test] | |
356 | fn tcp_clone_smoke() { | |
357 | each_ip(&mut |addr| { | |
358 | let acceptor = t!(TcpListener::bind(&addr)); | |
359 | ||
360 | let _t = thread::spawn(move || { | |
361 | let mut s = t!(TcpStream::connect(&addr)); | |
362 | let mut buf = [0, 0]; | |
363 | assert_eq!(s.read(&mut buf).unwrap(), 1); | |
364 | assert_eq!(buf[0], 1); | |
365 | t!(s.write(&[2])); | |
366 | }); | |
367 | ||
368 | let mut s1 = t!(acceptor.accept()).0; | |
369 | let s2 = t!(s1.try_clone()); | |
370 | ||
371 | let (tx1, rx1) = channel(); | |
372 | let (tx2, rx2) = channel(); | |
373 | let _t = thread::spawn(move || { | |
374 | let mut s2 = s2; | |
375 | rx1.recv().unwrap(); | |
376 | t!(s2.write(&[1])); | |
377 | tx2.send(()).unwrap(); | |
378 | }); | |
379 | tx1.send(()).unwrap(); | |
380 | let mut buf = [0, 0]; | |
381 | assert_eq!(s1.read(&mut buf).unwrap(), 1); | |
382 | rx2.recv().unwrap(); | |
383 | }) | |
384 | } | |
385 | ||
386 | #[test] | |
387 | fn tcp_clone_two_read() { | |
388 | each_ip(&mut |addr| { | |
389 | let acceptor = t!(TcpListener::bind(&addr)); | |
390 | let (tx1, rx) = channel(); | |
391 | let tx2 = tx1.clone(); | |
392 | ||
393 | let _t = thread::spawn(move || { | |
394 | let mut s = t!(TcpStream::connect(&addr)); | |
395 | t!(s.write(&[1])); | |
396 | rx.recv().unwrap(); | |
397 | t!(s.write(&[2])); | |
398 | rx.recv().unwrap(); | |
399 | }); | |
400 | ||
401 | let mut s1 = t!(acceptor.accept()).0; | |
402 | let s2 = t!(s1.try_clone()); | |
403 | ||
404 | let (done, rx) = channel(); | |
405 | let _t = thread::spawn(move || { | |
406 | let mut s2 = s2; | |
407 | let mut buf = [0, 0]; | |
408 | t!(s2.read(&mut buf)); | |
409 | tx2.send(()).unwrap(); | |
410 | done.send(()).unwrap(); | |
411 | }); | |
412 | let mut buf = [0, 0]; | |
413 | t!(s1.read(&mut buf)); | |
414 | tx1.send(()).unwrap(); | |
415 | ||
416 | rx.recv().unwrap(); | |
417 | }) | |
418 | } | |
419 | ||
420 | #[test] | |
421 | fn tcp_clone_two_write() { | |
422 | each_ip(&mut |addr| { | |
423 | let acceptor = t!(TcpListener::bind(&addr)); | |
424 | ||
425 | let _t = thread::spawn(move || { | |
426 | let mut s = t!(TcpStream::connect(&addr)); | |
427 | let mut buf = [0, 1]; | |
428 | t!(s.read(&mut buf)); | |
429 | t!(s.read(&mut buf)); | |
430 | }); | |
431 | ||
432 | let mut s1 = t!(acceptor.accept()).0; | |
433 | let s2 = t!(s1.try_clone()); | |
434 | ||
435 | let (done, rx) = channel(); | |
436 | let _t = thread::spawn(move || { | |
437 | let mut s2 = s2; | |
438 | t!(s2.write(&[1])); | |
439 | done.send(()).unwrap(); | |
440 | }); | |
441 | t!(s1.write(&[2])); | |
442 | ||
443 | rx.recv().unwrap(); | |
444 | }) | |
445 | } | |
446 | ||
447 | #[test] | |
448 | // FIXME: https://github.com/fortanix/rust-sgx/issues/110 | |
449 | #[cfg_attr(target_env = "sgx", ignore)] | |
450 | fn shutdown_smoke() { | |
451 | each_ip(&mut |addr| { | |
452 | let a = t!(TcpListener::bind(&addr)); | |
453 | let _t = thread::spawn(move || { | |
454 | let mut c = t!(a.accept()).0; | |
455 | let mut b = [0]; | |
456 | assert_eq!(c.read(&mut b).unwrap(), 0); | |
457 | t!(c.write(&[1])); | |
458 | }); | |
459 | ||
460 | let mut s = t!(TcpStream::connect(&addr)); | |
461 | t!(s.shutdown(Shutdown::Write)); | |
462 | assert!(s.write(&[1]).is_err()); | |
463 | let mut b = [0, 0]; | |
464 | assert_eq!(t!(s.read(&mut b)), 1); | |
465 | assert_eq!(b[0], 1); | |
466 | }) | |
467 | } | |
468 | ||
469 | #[test] | |
470 | // FIXME: https://github.com/fortanix/rust-sgx/issues/110 | |
471 | #[cfg_attr(target_env = "sgx", ignore)] | |
472 | fn close_readwrite_smoke() { | |
473 | each_ip(&mut |addr| { | |
474 | let a = t!(TcpListener::bind(&addr)); | |
475 | let (tx, rx) = channel::<()>(); | |
476 | let _t = thread::spawn(move || { | |
477 | let _s = t!(a.accept()); | |
478 | let _ = rx.recv(); | |
479 | }); | |
480 | ||
481 | let mut b = [0]; | |
482 | let mut s = t!(TcpStream::connect(&addr)); | |
483 | let mut s2 = t!(s.try_clone()); | |
484 | ||
485 | // closing should prevent reads/writes | |
486 | t!(s.shutdown(Shutdown::Write)); | |
487 | assert!(s.write(&[0]).is_err()); | |
488 | t!(s.shutdown(Shutdown::Read)); | |
489 | assert_eq!(s.read(&mut b).unwrap(), 0); | |
490 | ||
491 | // closing should affect previous handles | |
492 | assert!(s2.write(&[0]).is_err()); | |
493 | assert_eq!(s2.read(&mut b).unwrap(), 0); | |
494 | ||
495 | // closing should affect new handles | |
496 | let mut s3 = t!(s.try_clone()); | |
497 | assert!(s3.write(&[0]).is_err()); | |
498 | assert_eq!(s3.read(&mut b).unwrap(), 0); | |
499 | ||
500 | // make sure these don't die | |
501 | let _ = s2.shutdown(Shutdown::Read); | |
502 | let _ = s2.shutdown(Shutdown::Write); | |
503 | let _ = s3.shutdown(Shutdown::Read); | |
504 | let _ = s3.shutdown(Shutdown::Write); | |
505 | drop(tx); | |
506 | }) | |
507 | } | |
508 | ||
509 | #[test] | |
5e7ed085 | 510 | #[cfg_attr(target_env = "sgx", ignore)] |
1b1a35ee XL |
511 | fn close_read_wakes_up() { |
512 | each_ip(&mut |addr| { | |
513 | let a = t!(TcpListener::bind(&addr)); | |
514 | let (tx1, rx) = channel::<()>(); | |
515 | let _t = thread::spawn(move || { | |
516 | let _s = t!(a.accept()); | |
517 | let _ = rx.recv(); | |
518 | }); | |
519 | ||
520 | let s = t!(TcpStream::connect(&addr)); | |
521 | let s2 = t!(s.try_clone()); | |
522 | let (tx, rx) = channel(); | |
523 | let _t = thread::spawn(move || { | |
524 | let mut s2 = s2; | |
525 | assert_eq!(t!(s2.read(&mut [0])), 0); | |
526 | tx.send(()).unwrap(); | |
527 | }); | |
528 | // this should wake up the child thread | |
529 | t!(s.shutdown(Shutdown::Read)); | |
530 | ||
531 | // this test will never finish if the child doesn't wake up | |
532 | rx.recv().unwrap(); | |
533 | drop(tx1); | |
534 | }) | |
535 | } | |
536 | ||
537 | #[test] | |
538 | fn clone_while_reading() { | |
539 | each_ip(&mut |addr| { | |
540 | let accept = t!(TcpListener::bind(&addr)); | |
541 | ||
542 | // Enqueue a thread to write to a socket | |
543 | let (tx, rx) = channel(); | |
544 | let (txdone, rxdone) = channel(); | |
545 | let txdone2 = txdone.clone(); | |
546 | let _t = thread::spawn(move || { | |
547 | let mut tcp = t!(TcpStream::connect(&addr)); | |
548 | rx.recv().unwrap(); | |
549 | t!(tcp.write(&[0])); | |
550 | txdone2.send(()).unwrap(); | |
551 | }); | |
552 | ||
553 | // Spawn off a reading clone | |
554 | let tcp = t!(accept.accept()).0; | |
555 | let tcp2 = t!(tcp.try_clone()); | |
556 | let txdone3 = txdone.clone(); | |
557 | let _t = thread::spawn(move || { | |
558 | let mut tcp2 = tcp2; | |
559 | t!(tcp2.read(&mut [0])); | |
560 | txdone3.send(()).unwrap(); | |
561 | }); | |
562 | ||
563 | // Try to ensure that the reading clone is indeed reading | |
564 | for _ in 0..50 { | |
565 | thread::yield_now(); | |
566 | } | |
567 | ||
568 | // clone the handle again while it's reading, then let it finish the | |
569 | // read. | |
570 | let _ = t!(tcp.try_clone()); | |
571 | tx.send(()).unwrap(); | |
572 | rxdone.recv().unwrap(); | |
573 | rxdone.recv().unwrap(); | |
574 | }) | |
575 | } | |
576 | ||
577 | #[test] | |
578 | fn clone_accept_smoke() { | |
579 | each_ip(&mut |addr| { | |
580 | let a = t!(TcpListener::bind(&addr)); | |
581 | let a2 = t!(a.try_clone()); | |
582 | ||
583 | let _t = thread::spawn(move || { | |
584 | let _ = TcpStream::connect(&addr); | |
585 | }); | |
586 | let _t = thread::spawn(move || { | |
587 | let _ = TcpStream::connect(&addr); | |
588 | }); | |
589 | ||
590 | t!(a.accept()); | |
591 | t!(a2.accept()); | |
592 | }) | |
593 | } | |
594 | ||
595 | #[test] | |
596 | fn clone_accept_concurrent() { | |
597 | each_ip(&mut |addr| { | |
598 | let a = t!(TcpListener::bind(&addr)); | |
599 | let a2 = t!(a.try_clone()); | |
600 | ||
601 | let (tx, rx) = channel(); | |
602 | let tx2 = tx.clone(); | |
603 | ||
604 | let _t = thread::spawn(move || { | |
605 | tx.send(t!(a.accept())).unwrap(); | |
606 | }); | |
607 | let _t = thread::spawn(move || { | |
608 | tx2.send(t!(a2.accept())).unwrap(); | |
609 | }); | |
610 | ||
611 | let _t = thread::spawn(move || { | |
612 | let _ = TcpStream::connect(&addr); | |
613 | }); | |
614 | let _t = thread::spawn(move || { | |
615 | let _ = TcpStream::connect(&addr); | |
616 | }); | |
617 | ||
618 | rx.recv().unwrap(); | |
619 | rx.recv().unwrap(); | |
620 | }) | |
621 | } | |
622 | ||
623 | #[test] | |
624 | fn debug() { | |
625 | #[cfg(not(target_env = "sgx"))] | |
626 | fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { | |
627 | addr | |
628 | } | |
629 | #[cfg(target_env = "sgx")] | |
630 | fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { | |
631 | addr.to_string() | |
632 | } | |
633 | ||
634 | #[cfg(target_env = "sgx")] | |
635 | use crate::os::fortanix_sgx::io::AsRawFd; | |
636 | #[cfg(unix)] | |
637 | use crate::os::unix::io::AsRawFd; | |
638 | #[cfg(not(windows))] | |
639 | fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug { | |
640 | addr.as_raw_fd() | |
641 | } | |
642 | #[cfg(windows)] | |
643 | fn render_inner(addr: &dyn crate::os::windows::io::AsRawSocket) -> impl fmt::Debug { | |
644 | addr.as_raw_socket() | |
645 | } | |
646 | ||
647 | let inner_name = if cfg!(windows) { "socket" } else { "fd" }; | |
648 | let socket_addr = next_test_ip4(); | |
649 | ||
650 | let listener = t!(TcpListener::bind(&socket_addr)); | |
651 | let compare = format!( | |
652 | "TcpListener {{ addr: {:?}, {}: {:?} }}", | |
653 | render_socket_addr(&socket_addr), | |
654 | inner_name, | |
655 | render_inner(&listener) | |
656 | ); | |
5e7ed085 | 657 | assert_eq!(format!("{listener:?}"), compare); |
1b1a35ee XL |
658 | |
659 | let stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); | |
660 | let compare = format!( | |
661 | "TcpStream {{ addr: {:?}, peer: {:?}, {}: {:?} }}", | |
662 | render_socket_addr(&stream.local_addr().unwrap()), | |
663 | render_socket_addr(&stream.peer_addr().unwrap()), | |
664 | inner_name, | |
665 | render_inner(&stream) | |
666 | ); | |
5e7ed085 | 667 | assert_eq!(format!("{stream:?}"), compare); |
1b1a35ee XL |
668 | } |
669 | ||
670 | // FIXME: re-enabled openbsd tests once their socket timeout code | |
671 | // no longer has rounding errors. | |
672 | // VxWorks ignores SO_SNDTIMEO. | |
673 | #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)] | |
674 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 | |
675 | #[test] | |
676 | fn timeouts() { | |
677 | let addr = next_test_ip4(); | |
678 | let listener = t!(TcpListener::bind(&addr)); | |
679 | ||
680 | let stream = t!(TcpStream::connect(&("localhost", addr.port()))); | |
681 | let dur = Duration::new(15410, 0); | |
682 | ||
683 | assert_eq!(None, t!(stream.read_timeout())); | |
684 | ||
685 | t!(stream.set_read_timeout(Some(dur))); | |
686 | assert_eq!(Some(dur), t!(stream.read_timeout())); | |
687 | ||
688 | assert_eq!(None, t!(stream.write_timeout())); | |
689 | ||
690 | t!(stream.set_write_timeout(Some(dur))); | |
691 | assert_eq!(Some(dur), t!(stream.write_timeout())); | |
692 | ||
693 | t!(stream.set_read_timeout(None)); | |
694 | assert_eq!(None, t!(stream.read_timeout())); | |
695 | ||
696 | t!(stream.set_write_timeout(None)); | |
697 | assert_eq!(None, t!(stream.write_timeout())); | |
698 | drop(listener); | |
699 | } | |
700 | ||
701 | #[test] | |
702 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 | |
703 | fn test_read_timeout() { | |
704 | let addr = next_test_ip4(); | |
705 | let listener = t!(TcpListener::bind(&addr)); | |
706 | ||
707 | let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); | |
708 | t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); | |
709 | ||
710 | let mut buf = [0; 10]; | |
711 | let start = Instant::now(); | |
712 | let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); | |
713 | assert!( | |
714 | kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, | |
715 | "unexpected_error: {:?}", | |
716 | kind | |
717 | ); | |
718 | assert!(start.elapsed() > Duration::from_millis(400)); | |
719 | drop(listener); | |
720 | } | |
721 | ||
722 | #[test] | |
723 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 | |
724 | fn test_read_with_timeout() { | |
725 | let addr = next_test_ip4(); | |
726 | let listener = t!(TcpListener::bind(&addr)); | |
727 | ||
728 | let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); | |
729 | t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); | |
730 | ||
731 | let mut other_end = t!(listener.accept()).0; | |
732 | t!(other_end.write_all(b"hello world")); | |
733 | ||
734 | let mut buf = [0; 11]; | |
735 | t!(stream.read(&mut buf)); | |
736 | assert_eq!(b"hello world", &buf[..]); | |
737 | ||
738 | let start = Instant::now(); | |
739 | let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); | |
740 | assert!( | |
741 | kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, | |
742 | "unexpected_error: {:?}", | |
743 | kind | |
744 | ); | |
745 | assert!(start.elapsed() > Duration::from_millis(400)); | |
746 | drop(listener); | |
747 | } | |
748 | ||
749 | // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors | |
750 | // when passed zero Durations | |
751 | #[test] | |
752 | fn test_timeout_zero_duration() { | |
753 | let addr = next_test_ip4(); | |
754 | ||
755 | let listener = t!(TcpListener::bind(&addr)); | |
756 | let stream = t!(TcpStream::connect(&addr)); | |
757 | ||
758 | let result = stream.set_write_timeout(Some(Duration::new(0, 0))); | |
759 | let err = result.unwrap_err(); | |
760 | assert_eq!(err.kind(), ErrorKind::InvalidInput); | |
761 | ||
762 | let result = stream.set_read_timeout(Some(Duration::new(0, 0))); | |
763 | let err = result.unwrap_err(); | |
764 | assert_eq!(err.kind(), ErrorKind::InvalidInput); | |
765 | ||
766 | drop(listener); | |
767 | } | |
768 | ||
94222f64 XL |
769 | #[test] |
770 | #[cfg_attr(target_env = "sgx", ignore)] | |
771 | fn linger() { | |
772 | let addr = next_test_ip4(); | |
773 | let _listener = t!(TcpListener::bind(&addr)); | |
774 | ||
775 | let stream = t!(TcpStream::connect(&("localhost", addr.port()))); | |
776 | ||
777 | assert_eq!(None, t!(stream.linger())); | |
778 | t!(stream.set_linger(Some(Duration::from_secs(1)))); | |
779 | assert_eq!(Some(Duration::from_secs(1)), t!(stream.linger())); | |
780 | t!(stream.set_linger(None)); | |
781 | assert_eq!(None, t!(stream.linger())); | |
782 | } | |
783 | ||
1b1a35ee XL |
784 | #[test] |
785 | #[cfg_attr(target_env = "sgx", ignore)] | |
786 | fn nodelay() { | |
787 | let addr = next_test_ip4(); | |
788 | let _listener = t!(TcpListener::bind(&addr)); | |
789 | ||
790 | let stream = t!(TcpStream::connect(&("localhost", addr.port()))); | |
791 | ||
792 | assert_eq!(false, t!(stream.nodelay())); | |
793 | t!(stream.set_nodelay(true)); | |
794 | assert_eq!(true, t!(stream.nodelay())); | |
795 | t!(stream.set_nodelay(false)); | |
796 | assert_eq!(false, t!(stream.nodelay())); | |
797 | } | |
798 | ||
799 | #[test] | |
800 | #[cfg_attr(target_env = "sgx", ignore)] | |
801 | fn ttl() { | |
802 | let ttl = 100; | |
803 | ||
804 | let addr = next_test_ip4(); | |
805 | let listener = t!(TcpListener::bind(&addr)); | |
806 | ||
807 | t!(listener.set_ttl(ttl)); | |
808 | assert_eq!(ttl, t!(listener.ttl())); | |
809 | ||
810 | let stream = t!(TcpStream::connect(&("localhost", addr.port()))); | |
811 | ||
812 | t!(stream.set_ttl(ttl)); | |
813 | assert_eq!(ttl, t!(stream.ttl())); | |
814 | } | |
815 | ||
816 | #[test] | |
817 | #[cfg_attr(target_env = "sgx", ignore)] | |
818 | fn set_nonblocking() { | |
819 | let addr = next_test_ip4(); | |
820 | let listener = t!(TcpListener::bind(&addr)); | |
821 | ||
822 | t!(listener.set_nonblocking(true)); | |
823 | t!(listener.set_nonblocking(false)); | |
824 | ||
825 | let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); | |
826 | ||
827 | t!(stream.set_nonblocking(false)); | |
828 | t!(stream.set_nonblocking(true)); | |
829 | ||
830 | let mut buf = [0]; | |
831 | match stream.read(&mut buf) { | |
832 | Ok(_) => panic!("expected error"), | |
833 | Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} | |
5e7ed085 | 834 | Err(e) => panic!("unexpected error {e}"), |
1b1a35ee XL |
835 | } |
836 | } | |
837 | ||
838 | #[test] | |
839 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 | |
840 | fn peek() { | |
841 | each_ip(&mut |addr| { | |
842 | let (txdone, rxdone) = channel(); | |
843 | ||
844 | let srv = t!(TcpListener::bind(&addr)); | |
845 | let _t = thread::spawn(move || { | |
846 | let mut cl = t!(srv.accept()).0; | |
847 | cl.write(&[1, 3, 3, 7]).unwrap(); | |
848 | t!(rxdone.recv()); | |
849 | }); | |
850 | ||
851 | let mut c = t!(TcpStream::connect(&addr)); | |
852 | let mut b = [0; 10]; | |
853 | for _ in 1..3 { | |
854 | let len = c.peek(&mut b).unwrap(); | |
855 | assert_eq!(len, 4); | |
856 | } | |
857 | let len = c.read(&mut b).unwrap(); | |
858 | assert_eq!(len, 4); | |
859 | ||
860 | t!(c.set_nonblocking(true)); | |
861 | match c.peek(&mut b) { | |
862 | Ok(_) => panic!("expected error"), | |
863 | Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} | |
5e7ed085 | 864 | Err(e) => panic!("unexpected error {e}"), |
1b1a35ee XL |
865 | } |
866 | t!(txdone.send(())); | |
867 | }) | |
868 | } | |
869 | ||
870 | #[test] | |
871 | #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 | |
872 | fn connect_timeout_valid() { | |
873 | let listener = TcpListener::bind("127.0.0.1:0").unwrap(); | |
874 | let addr = listener.local_addr().unwrap(); | |
875 | TcpStream::connect_timeout(&addr, Duration::from_secs(2)).unwrap(); | |
876 | } |