crate::ix!();
pub const MAX_WAIT_FOR_IO: Duration = Duration::seconds(1);
#[derive(Debug,Getters,MutGetters)]
#[getset(get="pub",get_mut="pub")]
pub struct Sock {
socket: CSocket,
}
impl Drop for Sock {
fn drop(&mut self) {
trace!("Sock::drop");
self.reset();
}
}
pub type SockEvent = u8;
pub const SOCK_RECV: usize = 0b01;
pub const SOCK_SEND: usize = 0b10;
impl Default for Sock {
fn default() -> Self {
trace!("Sock::default – constructing empty Sock");
Self {
socket: INVALID_SOCKET,
}
}
}
impl From<CSocket> for Sock {
fn from(s: CSocket) -> Self {
trace!(socket = s, "Sock::from – taking ownership");
Self { socket: s }
}
}
impl Sock {
pub fn assign_from(&mut self, mut other: Sock) -> &mut Self {
use std::mem::{forget, ManuallyDrop};
self.reset();
let mut other = ManuallyDrop::new(other);
self.socket = other.socket;
other.socket = INVALID_SOCKET;
trace!(
new_socket = self.socket,
"Sock::assign_from – took ownership from peer"
);
self
}
pub fn get(&self) -> CSocket {
trace!(socket = self.socket, "Sock::get");
self.socket
}
pub fn release(&mut self) -> CSocket {
let s = self.socket;
self.socket = INVALID_SOCKET;
trace!(released = s, "Sock::release");
s
}
pub fn reset(&mut self) {
if self.socket != INVALID_SOCKET {
debug!(socket = self.socket, "Sock::reset – closing");
close_socket(&mut self.socket); } else {
trace!("Sock::reset – already empty");
}
}
pub fn send(&self, data: *const c_void, len: usize, flags: i32) -> isize {
#[cfg(target_os = "windows")]
let ret = unsafe {
winapi::um::winsock2::send(
self.socket as winapi::um::winsock2::SOCKET,
data as *const i8,
len as i32,
flags,
)
};
#[cfg(not(target_os = "windows"))]
let ret = unsafe { libc::send(self.socket, data, len, flags) };
trace!(ret, bytes = len, "Sock::send");
ret as isize
}
pub fn recv(&self, buf: *mut c_void, len: usize, flags: i32) -> isize {
#[cfg(target_os = "windows")]
let ret = unsafe {
winapi::um::winsock2::recv(
self.socket as winapi::um::winsock2::SOCKET,
buf as *mut i8,
len as i32,
flags,
)
};
#[cfg(not(target_os = "windows"))]
let ret = unsafe { libc::recv(self.socket, buf, len, flags) };
trace!(ret, bytes = len, "Sock::recv");
ret as isize
}
pub fn connect(&self, addr: *const SocketAddr, addr_len: libc::socklen_t) -> i32 {
#[cfg(target_os = "windows")]
let ret = unsafe {
winapi::um::winsock2::connect(
self.socket as winapi::um::winsock2::SOCKET,
addr as *const _,
addr_len,
)
};
#[cfg(not(target_os = "windows"))]
let ret = unsafe { libc::connect(self.socket, addr as *const _, addr_len) };
trace!(ret, "Sock::connect");
ret
}
pub fn get_sock_opt(
&self,
level: i32,
opt_name: i32,
opt_val: *mut c_void,
opt_len: *mut libc::socklen_t,
) -> i32 {
#[cfg(target_os = "windows")]
let ret = unsafe {
winapi::um::winsock2::getsockopt(
self.socket as winapi::um::winsock2::SOCKET,
level,
opt_name,
opt_val as *mut i8,
opt_len,
)
};
#[cfg(not(target_os = "windows"))]
let ret =
unsafe { libc::getsockopt(self.socket, level, opt_name, opt_val, opt_len) };
trace!(ret, opt = opt_name, "Sock::get_sock_opt");
ret
}
}
#[cfg(test)]
mod sock_basic_io_spec {
use super::*;
#[cfg(unix)]
fn make_socket_pair() -> (libc::c_int, libc::c_int) {
let mut sv = [-1; 2];
let ret =
unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, sv.as_mut_ptr()) };
assert_eq!(ret, 0, "socketpair() failed");
(sv[0], sv[1])
}
#[traced_test]
fn assign_from_transfers_descriptor() {
serialize_fds!();
#[cfg(unix)]
{
use libc::read;
let (a, a_peer) = make_socket_pair();
let (b, _b_peer) = make_socket_pair();
let mut dst = Sock::from(a);
let src = Sock::from(b);
let old_peer = a_peer;
dst.assign_from(src);
let mut tmp = [0u8; 1];
let eof = unsafe { read(old_peer, tmp.as_mut_ptr() as *mut _, 1) };
assert_eq!(eof, 0, "old peer should see EOF after reassign");
assert_eq!(dst.get(), b);
}
info!("assign_from_transfers_descriptor passed");
}
#[traced_test]
fn raw_send_and_recv() {
serialize_fds!(); #[cfg(unix)]
{
let (a, b) = make_socket_pair();
let sock_a = Sock::from(a);
let sock_b = Sock::from(b);
let msg = b"Z";
let sent = sock_a.send(msg.as_ptr() as *const _, 1, 0);
assert_eq!(sent, 1);
let mut buf = [0u8; 1];
let got = sock_b.recv(buf.as_mut_ptr() as *mut _, 1, 0);
assert_eq!(got, 1);
assert_eq!(buf[0], b'Z');
}
info!("raw_send_and_recv passed");
}
}