use crate::{BlockingSocket, CompletionPort};
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::os::windows::io::OwnedSocket;
#[test]
fn iocp_socket_recv_and_send_round_trip() {
let listener = TcpListener::bind("127.0.0.1:0").expect("bind loopback");
let addr = listener.local_addr().expect("local addr");
let client = TcpStream::connect(addr).expect("connect");
let (mut server, _peer) = listener.accept().expect("accept");
let port = CompletionPort::new(0).expect("create port");
let endpoint = port
.associate_socket(OwnedSocket::from(client), 0)
.expect("associate_socket");
let recv_token = endpoint
.recv(vec![0_u8; 64])
.expect("submit recv")
.expect_pending("this socket is not in skip-on-success mode");
server.write_all(b"ping").expect("peer write");
let completion = port.get(5_000).expect("get").expect("recv completion");
let (mut buffer, result) = match recv_token.claim(&completion) {
Ok(pair) => pair,
Err(_) => panic!("recv completion did not match its token"),
};
let received = result.expect("recv result");
buffer.truncate(received);
assert_eq!(buffer, b"ping");
assert_eq!(port.outstanding(), 0);
let send_token = endpoint
.send(b"pong".to_vec())
.expect("submit send")
.expect_pending("this socket is not in skip-on-success mode");
let completion = port.get(5_000).expect("get").expect("send completion");
let (_data, result) = match send_token.claim(&completion) {
Ok(pair) => pair,
Err(_) => panic!("send completion did not match its token"),
};
assert_eq!(result.expect("send result"), 4);
let mut got = [0_u8; 4];
server.read_exact(&mut got).expect("peer read");
assert_eq!(&got, b"pong");
assert_eq!(port.outstanding(), 0);
drop(endpoint);
}
#[test]
fn blocking_socket_recv_and_send_round_trip() {
let listener = TcpListener::bind("127.0.0.1:0").expect("bind loopback");
let addr = listener.local_addr().expect("local addr");
let client = TcpStream::connect(addr).expect("connect");
let (mut server, _peer) = listener.accept().expect("accept");
let blocking = BlockingSocket::new(OwnedSocket::from(client));
server.write_all(b"ping").expect("peer write");
let mut buffer = vec![0_u8; 64];
let received = blocking.recv(&mut buffer).expect("recv");
assert_eq!(received, 4);
assert_eq!(&buffer[..received], b"ping");
let sent = blocking.send(b"pong").expect("send");
assert_eq!(sent, 4);
let mut got = [0_u8; 4];
server.read_exact(&mut got).expect("peer read");
assert_eq!(&got, b"pong");
}
#[test]
fn checked_len_rejects_lengths_beyond_u32() {
use crate::socket::checked_len;
assert_eq!(checked_len(0, "receive buffer").expect("empty fits"), 0);
assert_eq!(
checked_len(u32::MAX as usize, "receive buffer").expect("the largest fitting length"),
u32::MAX
);
#[cfg(target_pointer_width = "64")]
{
let too_long = u32::MAX as usize + 1;
let error = checked_len(too_long, "receive buffer").expect_err("must not cap");
assert_eq!(error.kind(), std::io::ErrorKind::InvalidInput);
assert!(
error.to_string().contains("receive buffer"),
"the error should name the offending buffer: {error}"
);
assert!(
checked_len(too_long, "send buffer").is_err(),
"the send buffer has the same limit"
);
}
}
#[cfg(target_pointer_width = "64")]
fn connected_pair() -> (OwnedSocket, TcpStream) {
let listener = TcpListener::bind("127.0.0.1:0").expect("bind loopback");
let addr = listener.local_addr().expect("local addr");
let client = TcpStream::connect(addr).expect("connect");
let (server, _peer) = listener.accept().expect("accept");
(OwnedSocket::from(client), server)
}
#[cfg(target_pointer_width = "64")]
#[test]
fn submitted_recv_rejects_an_oversized_length() {
let (client, _server) = connected_pair();
let port = CompletionPort::new(0).expect("create port");
let socket = port.associate_socket(client, 0).expect("associate socket");
let error = socket
.recv(crate::buf::OversizedBuffer)
.expect_err("an unrepresentable length must be rejected");
assert_eq!(error.kind(), std::io::ErrorKind::InvalidInput);
assert!(
error.raw_os_error().is_none(),
"the request should be rejected before reaching Winsock: {error}"
);
}
#[test]
fn require_ifs_handles_refuses_a_provider_without_the_flag() {
use crate::socket::require_ifs_handles;
use windows_sys::Win32::Networking::WinSock::{XP1_GUARANTEED_DELIVERY, XP1_IFS_HANDLES};
let error = require_ifs_handles(0).expect_err("a provider with no flags cannot support it");
assert_eq!(error.kind(), std::io::ErrorKind::Unsupported);
assert!(
error.raw_os_error().is_none(),
"nothing failed -- the question was asked and answered: {error}"
);
assert!(
require_ifs_handles(XP1_GUARANTEED_DELIVERY).is_err(),
"only XP1_IFS_HANDLES answers this question"
);
require_ifs_handles(XP1_IFS_HANDLES).expect("the flag alone is sufficient");
require_ifs_handles(XP1_IFS_HANDLES | XP1_GUARANTEED_DELIVERY)
.expect("other flags alongside it are irrelevant");
}
#[test]
fn the_probe_accepts_an_ordinary_tcp_socket() {
let listener = TcpListener::bind("127.0.0.1:0").expect("bind loopback");
let addr = listener.local_addr().expect("local addr");
let client = TcpStream::connect(addr).expect("connect");
let (_server, _peer) = listener.accept().expect("accept");
let port = CompletionPort::new(0).expect("create port");
let mut socket = port
.associate_socket(OwnedSocket::from(client), 0)
.expect("associate socket");
assert_eq!(
socket.notification_modes(),
crate::NotificationModes::default(),
"a freshly associated socket has taken no shortcuts"
);
socket
.set_notification_modes(skip_on_success())
.expect("the base Winsock provider returns IFS handles");
assert!(
socket.notification_modes().skip_completion_port_on_success,
"the socket must record what it established"
);
}
#[test]
fn setting_a_second_mode_does_not_clear_the_first() {
let listener = TcpListener::bind("127.0.0.1:0").expect("bind loopback");
let addr = listener.local_addr().expect("local addr");
let client = TcpStream::connect(addr).expect("connect");
let (_server, _peer) = listener.accept().expect("accept");
let port = CompletionPort::new(0).expect("create port");
let mut socket = port
.associate_socket(OwnedSocket::from(client), 0)
.expect("associate socket");
socket
.set_notification_modes(skip_on_success())
.expect("set skip-on-success");
socket
.set_notification_modes(crate::NotificationModes {
skip_set_event_on_handle: true,
..crate::NotificationModes::default()
})
.expect("set skip-set-event");
let modes = socket.notification_modes();
assert!(
modes.skip_completion_port_on_success && modes.skip_set_event_on_handle,
"the record must be the union of everything ever set: {modes:?}"
);
socket
.set_notification_modes(crate::NotificationModes::default())
.expect("an empty request is a no-op");
assert_eq!(socket.notification_modes(), modes);
}
fn skip_on_success() -> crate::NotificationModes {
crate::NotificationModes {
skip_completion_port_on_success: true,
..crate::NotificationModes::default()
}
}