From 9ff22f9c09f2fddc6d5663a7b9a4b383843b2c9b Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Tue, 18 Jun 2019 08:31:27 -0700 Subject: [PATCH] add socketpair, with wip on windows --- filedescriptor/Cargo.toml | 3 +- filedescriptor/src/lib.rs | 7 +++++ filedescriptor/src/unix.rs | 53 +++++++++++++++++++++++++++++++- filedescriptor/src/windows.rs | 58 +++++++++++++++++++++++++++++++++-- 4 files changed, 117 insertions(+), 4 deletions(-) diff --git a/filedescriptor/Cargo.toml b/filedescriptor/Cargo.toml index 07911f6e1..a4f7327ee 100644 --- a/filedescriptor/Cargo.toml +++ b/filedescriptor/Cargo.toml @@ -20,5 +20,6 @@ winapi = { version = "0.3", features = [ "handleapi", "fileapi", "namedpipeapi", - "processthreadsapi" + "processthreadsapi", + "winsock2" ]} diff --git a/filedescriptor/src/lib.rs b/filedescriptor/src/lib.rs index 2c0436ce8..b797a9078 100644 --- a/filedescriptor/src/lib.rs +++ b/filedescriptor/src/lib.rs @@ -241,3 +241,10 @@ use std::time::Duration; pub fn poll(pfd: &mut [pollfd], duration: Option) -> Fallible { poll_impl(pfd, duration) } + +/// Create a pair of connected sockets +/// +/// This implementation creates a pair of SOCK_STREAM sockets. +pub fn socketpair() -> Fallible<(FileDescriptor, FileDescriptor)> { + socketpair_impl() +} diff --git a/filedescriptor/src/unix.rs b/filedescriptor/src/unix.rs index 7eb55ea01..023cfcedc 100644 --- a/filedescriptor/src/unix.rs +++ b/filedescriptor/src/unix.rs @@ -209,6 +209,57 @@ impl Pipe { } } +#[cfg(target_os = "linux")] +#[doc(hidden)] +pub fn socketpair_impl() -> Fallible<(FileDescriptor, FileDescriptor)> { + let mut fds = [-1i32; 2]; + let res = unsafe { + libc::socketpair( + libc::PF_LOCAL, + libc::SOCK_STREAM | libc::SOCK_CLOEXEC, + 0, + fds.as_mut_ptr(), + ) + }; + if res == -1 { + bail!( + "failed to create a socketpair: {:?}", + std::io::Error::last_os_error() + ) + } else { + let mut read = FileDescriptor { + handle: OwnedHandle { handle: fds[0] }, + }; + let mut write = FileDescriptor { + handle: OwnedHandle { handle: fds[1] }, + }; + Ok((read, write)) + } +} + +#[cfg(not(target_os = "linux"))] +#[doc(hidden)] +pub fn socketpair_impl() -> Fallible<(FileDescriptor, FileDescriptor)> { + let mut fds = [-1i32; 2]; + let res = unsafe { libc::socketpair(libc::PF_LOCAL, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; + if res == -1 { + bail!( + "failed to create a socketpair: {:?}", + std::io::Error::last_os_error() + ) + } else { + let mut read = FileDescriptor { + handle: OwnedHandle { handle: fds[0] }, + }; + let mut write = FileDescriptor { + handle: OwnedHandle { handle: fds[1] }, + }; + read.handle.cloexec()?; + write.handle.cloexec()?; + Ok((read, write)) + } +} + pub use libc::{pollfd, POLLERR, POLLHUP, POLLIN, POLLOUT}; use std::time::Duration; @@ -225,7 +276,7 @@ pub fn poll_impl(pfd: &mut [pollfd], duration: Option) -> Fallible FromRawFileDescriptor for T { unsafe impl Send for OwnedHandle {} +enum HandleType { + Char, + Disk, + Pipe, + Socket, + Unknown, +} + +fn handle_type(handle: HANDLE) -> HandleType { + match GetFileType(handle) { + FILE_TYPE_CHAR => HandleType::Char, + FILE_TYPE_DISK => HandleType::Disk, + FILE_TYPE_PIPE => { + // Could be a pipe or a socket. Test if for pipeness + let mut flags = 0; + let mut out_buf = 0; + let mut in_buf = 0; + let mut inst = 0; + if GetNamedPipeInfo(handle, &mut flags, &mut out_buf, &mut in_buf, &mut inst) { + HandleType::Pipe + } else { + HandleType::Socket + } + } + _ => HandleType::Unknown, + } +} + impl Drop for OwnedHandle { fn drop(&mut self) { if self.handle != INVALID_HANDLE_VALUE as _ && !self.handle.is_null() { - unsafe { CloseHandle(self.handle as _) }; + unsafe { + if handle_type(self.handle as _) == HandleType::Socket { + closesocket(self.handle as _); + } else { + CloseHandle(self.handle as _); + } + }; } } } @@ -194,6 +230,24 @@ impl Pipe { } } +fn init_winsock() { + static START: Once = Once::new(); + START.call_once(|| unsafe { + let mut data: WSADATA = mem::zeroed(); + let ret = WSAStartup( + 0x202, // version 2.2 + &mut data, + ); + assert_eq!(ret, 0, "failed to initialize winsock"); + }); +} + +#[doc(hidden)] +pub fn socketpair_impl() -> Fallible<(FileDescriptor, FileDescriptor)> { + init_winsock(); + bail!("not implemented yet"); +} + #[doc(hidden)] pub fn poll_impl(pfd: &mut [pollfd], duration: Option) -> Fallible { let poll_result = unsafe { @@ -206,7 +260,7 @@ pub fn poll_impl(pfd: &mut [pollfd], duration: Option) -> Fallible