1
//! Functions to help test this crate.
2

            
3
use std::io;
4

            
5
use crate::nb_stream::MioStream;
6

            
7
/// The type of blocking stream returned by `construct_socketpair`.
8
#[cfg(not(windows))]
9
pub(crate) type SocketpairStream = socketpair::SocketpairStream;
10
#[cfg(windows)]
11
pub(crate) type SocketpairStream = std::net::TcpStream;
12

            
13
/// Test helper: construct a socketpair.
14
10
fn construct_socketpair_inner() -> io::Result<(SocketpairStream, SocketpairStream)> {
15
    #[cfg(not(windows))]
16
    {
17
10
        socketpair::socketpair_stream()
18
    }
19
    #[cfg(windows)]
20
    {
21
        // Alas, we can't use the socketpair crate on Windows!  It creates a Windows
22
        // "named pipe".  Windows "named pipe"s are not named pipes.  They are strange
23
        // things which a bit like an unholy cross between a Unix named pipe (aka a FIFO)
24
        // and an AF_UNIX socket.  This makes them bizarre and awkward.  They are best
25
        // avoided if possible.
26
        //
27
        // We have to use this nonsense instead.  It will cause these tests to fail on
28
        // some absurdly restrictive windows firewalls; that's a price we can afford.
29
        //
30
        // For details see
31
        // https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/2758#note_3155460
32
        let listener = std::net::TcpListener::bind("127.0.0.1:0")?;
33
        let addr = listener.local_addr()?;
34
        let s1 = std::net::TcpStream::connect(addr)?;
35
        let (s2, s2_addr) = listener.accept()?;
36
        assert_eq!(s1.local_addr().unwrap(), s2_addr);
37
        Ok((s1, s2))
38
    }
39
10
}
40

            
41
/// Test helper: Construct a socketpair,
42
/// wrapping the first element in a MIO wrapper and making it nonblocking.
43
10
pub(crate) fn construct_socketpair() -> io::Result<(Box<dyn MioStream>, SocketpairStream)> {
44
10
    let (s1, s2) = construct_socketpair_inner()?;
45

            
46
    #[cfg(not(windows))]
47
10
    let s1 = {
48
        use std::os::fd::OwnedFd;
49

            
50
10
        let owned_fd = OwnedFd::from(s1);
51
10
        std::os::unix::net::UnixStream::from(owned_fd)
52
    };
53

            
54
10
    s1.set_nonblocking(true)?;
55

            
56
    #[cfg(not(windows))]
57
10
    let s1 = mio::net::UnixStream::from_std(s1);
58
    #[cfg(windows)]
59
    let s1 = mio::net::TcpStream::from_std(s1);
60

            
61
10
    Ok((Box::new(s1), s2))
62
10
}