mio 0.7.0

Lightweight non-blocking IO
Documentation
#![cfg(all(unix, feature = "os-poll", feature = "uds"))]

use mio::net::UnixDatagram;
use mio::{Interest, Token};
use std::io;
use std::net::Shutdown;
use std::os::unix::net;

#[macro_use]
mod util;
use util::{
    assert_send, assert_socket_close_on_exec, assert_socket_non_blocking, assert_sync,
    assert_would_block, expect_events, expect_no_events, init, init_with_poll, temp_file,
    ExpectEvent, Readiness,
};

const DATA1: &[u8] = b"Hello same host!";
const DATA2: &[u8] = b"Why hello mio!";
const DEFAULT_BUF_SIZE: usize = 64;
const TOKEN_1: Token = Token(0);
const TOKEN_2: Token = Token(1);

#[test]
fn is_send_and_sync() {
    assert_send::<UnixDatagram>();
    assert_sync::<UnixDatagram>();
}

#[test]
fn unix_datagram_smoke_unconnected() {
    init();
    let path1 = temp_file("unix_datagram_smoke_unconnected1");
    let path2 = temp_file("unix_datagram_smoke_unconnected2");

    let datagram1 = UnixDatagram::bind(&path1).unwrap();
    let datagram2 = UnixDatagram::bind(&path2).unwrap();
    smoke_test_unconnected(datagram1, datagram2);
}

#[test]
fn unix_datagram_smoke_connected() {
    init();
    let path1 = temp_file("unix_datagram_smoke_connected1");
    let path2 = temp_file("unix_datagram_smoke_connected2");

    let datagram1 = UnixDatagram::bind(&path1).unwrap();
    let datagram2 = UnixDatagram::bind(&path2).unwrap();

    datagram1.connect(&path2).unwrap();
    datagram2.connect(&path1).unwrap();
    smoke_test_connected(datagram1, datagram2);
}

#[test]
fn unix_datagram_smoke_unconnected_from_std() {
    init();
    let path1 = temp_file("unix_datagram_smoke_unconnected_from_std1");
    let path2 = temp_file("unix_datagram_smoke_unconnected_from_std2");

    let datagram1 = net::UnixDatagram::bind(&path1).unwrap();
    let datagram2 = net::UnixDatagram::bind(&path2).unwrap();

    datagram1.set_nonblocking(true).unwrap();
    datagram2.set_nonblocking(true).unwrap();

    let datagram1 = UnixDatagram::from_std(datagram1);
    let datagram2 = UnixDatagram::from_std(datagram2);
    smoke_test_unconnected(datagram1, datagram2);
}

#[test]
fn unix_datagram_smoke_connected_from_std() {
    init();
    let path1 = temp_file("unix_datagram_smoke_connected_from_std1");
    let path2 = temp_file("unix_datagram_smoke_connected_from_std2");

    let datagram1 = net::UnixDatagram::bind(&path1).unwrap();
    let datagram2 = net::UnixDatagram::bind(&path2).unwrap();

    datagram1.connect(&path2).unwrap();
    datagram2.connect(&path1).unwrap();

    datagram1.set_nonblocking(true).unwrap();
    datagram2.set_nonblocking(true).unwrap();

    let datagram1 = UnixDatagram::from_std(datagram1);
    let datagram2 = UnixDatagram::from_std(datagram2);
    smoke_test_connected(datagram1, datagram2);
}

#[test]
fn unix_datagram_connect() {
    init();
    let path1 = temp_file("unix_datagram_connect1");
    let path2 = temp_file("unix_datagram_connect2");

    let datagram1 = UnixDatagram::bind(&path1).unwrap();
    let datagram1_local = datagram1.local_addr().unwrap();
    let datagram2 = UnixDatagram::bind(&path2).unwrap();
    let datagram2_local = datagram2.local_addr().unwrap();

    datagram1
        .connect(
            datagram1_local
                .as_pathname()
                .expect("failed to get pathname"),
        )
        .unwrap();
    datagram2
        .connect(
            datagram2_local
                .as_pathname()
                .expect("failed to get pathname"),
        )
        .unwrap();
}

#[test]
fn unix_datagram_pair() {
    let (mut poll, mut events) = init_with_poll();

    let (mut datagram1, mut datagram2) = UnixDatagram::pair().unwrap();
    poll.registry()
        .register(
            &mut datagram1,
            TOKEN_1,
            Interest::READABLE | Interest::WRITABLE,
        )
        .unwrap();
    poll.registry()
        .register(
            &mut datagram2,
            TOKEN_2,
            Interest::READABLE | Interest::WRITABLE,
        )
        .unwrap();
    expect_events(
        &mut poll,
        &mut events,
        vec![
            ExpectEvent::new(TOKEN_1, Interest::WRITABLE),
            ExpectEvent::new(TOKEN_2, Interest::WRITABLE),
        ],
    );

    let mut buf = [0; DEFAULT_BUF_SIZE];
    assert_would_block(datagram1.recv(&mut buf));
    assert_would_block(datagram2.recv(&mut buf));

    checked_write!(datagram1.send(DATA1));
    checked_write!(datagram2.send(DATA2));
    expect_events(
        &mut poll,
        &mut events,
        vec![
            ExpectEvent::new(TOKEN_1, Interest::READABLE),
            ExpectEvent::new(TOKEN_2, Interest::READABLE),
        ],
    );

    expect_read!(datagram1.recv(&mut buf), DATA2);
    expect_read!(datagram2.recv(&mut buf), DATA1);

    assert!(datagram1.take_error().unwrap().is_none());
    assert!(datagram2.take_error().unwrap().is_none());
}

#[test]
fn unix_datagram_shutdown() {
    let (mut poll, mut events) = init_with_poll();
    let path1 = temp_file("unix_datagram_shutdown1");
    let path2 = temp_file("unix_datagram_shutdown2");

    let mut datagram1 = UnixDatagram::bind(&path1).unwrap();
    let mut datagram2 = UnixDatagram::bind(&path2).unwrap();

    poll.registry()
        .register(
            &mut datagram1,
            TOKEN_1,
            Interest::WRITABLE.add(Interest::READABLE),
        )
        .unwrap();
    poll.registry()
        .register(
            &mut datagram2,
            TOKEN_2,
            Interest::WRITABLE.add(Interest::READABLE),
        )
        .unwrap();

    datagram1.connect(&path2).unwrap();
    expect_events(
        &mut poll,
        &mut events,
        vec![ExpectEvent::new(TOKEN_1, Interest::WRITABLE)],
    );

    checked_write!(datagram1.send(DATA1));
    expect_events(
        &mut poll,
        &mut events,
        vec![ExpectEvent::new(TOKEN_2, Interest::READABLE)],
    );

    datagram1.shutdown(Shutdown::Read).unwrap();
    expect_events(
        &mut poll,
        &mut events,
        vec![ExpectEvent::new(TOKEN_1, Readiness::READ_CLOSED)],
    );

    datagram1.shutdown(Shutdown::Write).unwrap();
    expect_events(
        &mut poll,
        &mut events,
        vec![ExpectEvent::new(TOKEN_1, Readiness::WRITE_CLOSED)],
    );

    let err = datagram1.send(DATA2).unwrap_err();
    assert_eq!(err.kind(), io::ErrorKind::BrokenPipe);

    assert!(datagram1.take_error().unwrap().is_none());
}

#[test]
fn unix_datagram_register() {
    let (mut poll, mut events) = init_with_poll();
    let path = temp_file("unix_datagram_register");

    let mut datagram = UnixDatagram::bind(path).unwrap();
    poll.registry()
        .register(&mut datagram, TOKEN_1, Interest::READABLE)
        .unwrap();
    expect_no_events(&mut poll, &mut events);
}

#[test]
fn unix_datagram_reregister() {
    let (mut poll, mut events) = init_with_poll();
    let path1 = temp_file("unix_datagram_reregister1");
    let path2 = temp_file("unix_datagram_reregister2");

    let mut datagram1 = UnixDatagram::bind(&path1).unwrap();
    poll.registry()
        .register(&mut datagram1, TOKEN_1, Interest::READABLE)
        .unwrap();

    let datagram2 = UnixDatagram::bind(&path2).unwrap();
    datagram2.connect(&path1).unwrap();
    poll.registry()
        .reregister(&mut datagram1, TOKEN_1, Interest::WRITABLE)
        .unwrap();
    expect_events(
        &mut poll,
        &mut events,
        vec![ExpectEvent::new(TOKEN_1, Interest::WRITABLE)],
    );
}

#[test]
fn unix_datagram_deregister() {
    let (mut poll, mut events) = init_with_poll();
    let path1 = temp_file("unix_datagram_deregister1");
    let path2 = temp_file("unix_datagram_deregister2");

    let mut datagram1 = UnixDatagram::bind(&path1).unwrap();
    poll.registry()
        .register(&mut datagram1, TOKEN_1, Interest::WRITABLE)
        .unwrap();

    let datagram2 = UnixDatagram::bind(&path2).unwrap();
    datagram2.connect(&path1).unwrap();
    poll.registry().deregister(&mut datagram1).unwrap();
    expect_no_events(&mut poll, &mut events);
}

fn smoke_test_unconnected(mut datagram1: UnixDatagram, mut datagram2: UnixDatagram) {
    let (mut poll, mut events) = init_with_poll();

    assert_socket_non_blocking(&datagram1);
    assert_socket_close_on_exec(&datagram1);
    assert_socket_non_blocking(&datagram2);
    assert_socket_close_on_exec(&datagram2);

    let addr1 = datagram1.local_addr().unwrap();
    let addr2 = datagram2.local_addr().unwrap();
    let path1 = addr1.as_pathname().expect("failed to get pathname");
    let path2 = addr2.as_pathname().expect("failed to get pathname");

    poll.registry()
        .register(
            &mut datagram1,
            TOKEN_1,
            Interest::READABLE.add(Interest::WRITABLE),
        )
        .unwrap();
    poll.registry()
        .register(
            &mut datagram2,
            TOKEN_2,
            Interest::READABLE.add(Interest::WRITABLE),
        )
        .unwrap();
    expect_events(
        &mut poll,
        &mut events,
        vec![
            ExpectEvent::new(TOKEN_1, Interest::WRITABLE),
            ExpectEvent::new(TOKEN_2, Interest::WRITABLE),
        ],
    );

    let mut buf = [0; DEFAULT_BUF_SIZE];
    assert_would_block(datagram1.recv_from(&mut buf));
    assert_would_block(datagram2.recv_from(&mut buf));

    checked_write!(datagram1.send_to(DATA1, path2));
    checked_write!(datagram2.send_to(DATA2, path1));
    expect_events(
        &mut poll,
        &mut events,
        vec![
            ExpectEvent::new(TOKEN_1, Interest::READABLE),
            ExpectEvent::new(TOKEN_2, Interest::READABLE),
        ],
    );

    expect_read!(datagram1.recv_from(&mut buf), DATA2, path: path2);
    expect_read!(datagram2.recv_from(&mut buf), DATA1, path: path1);

    assert!(datagram1.take_error().unwrap().is_none());
    assert!(datagram2.take_error().unwrap().is_none());
}

fn smoke_test_connected(mut datagram1: UnixDatagram, mut datagram2: UnixDatagram) {
    let (mut poll, mut events) = init_with_poll();

    assert_socket_non_blocking(&datagram1);
    assert_socket_close_on_exec(&datagram1);
    assert_socket_non_blocking(&datagram2);
    assert_socket_close_on_exec(&datagram2);

    let local_addr1 = datagram1.local_addr().unwrap();
    let peer_addr1 = datagram1.peer_addr().unwrap();
    let local_addr2 = datagram2.local_addr().unwrap();
    let peer_addr2 = datagram2.peer_addr().unwrap();
    assert_eq!(
        local_addr1.as_pathname().expect("failed to get pathname"),
        peer_addr2.as_pathname().expect("failed to get pathname")
    );
    assert_eq!(
        local_addr2.as_pathname().expect("failed to get pathname"),
        peer_addr1.as_pathname().expect("failed to get pathname")
    );

    poll.registry()
        .register(
            &mut datagram1,
            TOKEN_1,
            Interest::READABLE.add(Interest::WRITABLE),
        )
        .unwrap();
    poll.registry()
        .register(
            &mut datagram2,
            TOKEN_2,
            Interest::READABLE.add(Interest::WRITABLE),
        )
        .unwrap();
    expect_events(
        &mut poll,
        &mut events,
        vec![
            ExpectEvent::new(TOKEN_1, Interest::WRITABLE),
            ExpectEvent::new(TOKEN_2, Interest::WRITABLE),
        ],
    );

    let mut buf = [0; DEFAULT_BUF_SIZE];
    assert_would_block(datagram1.recv(&mut buf));
    assert_would_block(datagram2.recv(&mut buf));

    checked_write!(datagram1.send(DATA1));
    checked_write!(datagram2.send(DATA2));
    expect_events(
        &mut poll,
        &mut events,
        vec![
            ExpectEvent::new(TOKEN_1, Interest::READABLE),
            ExpectEvent::new(TOKEN_2, Interest::READABLE),
        ],
    );

    expect_read!(datagram1.recv(&mut buf), DATA2);
    expect_read!(datagram2.recv(&mut buf), DATA1);

    assert!(datagram1.take_error().unwrap().is_none());
    assert!(datagram2.take_error().unwrap().is_none());
}