From a2b44dce0e26c3e943de21cba8943d12a0fda33d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 2 Jan 2019 14:08:53 -0800 Subject: [PATCH 01/51] Update travis config --- .travis.yml | 19 +++++++++---------- README.md | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7375a515..fd7b3643 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,13 +9,16 @@ matrix: - rust: beta - rust: nightly - - rust: nightly - before_script: - - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH + - name: "master doc to gh-pages" + rust: nightly script: - - cargo doc --no-deps --all-features - after_success: - - travis-cargo --only nightly doc-upload + - cargo doc --no-deps + deploy: + provider: script + script: curl -LsSf https://git.io/fhJ8n | rustc - && (cd target/doc && ../../rust_out) + skip_cleanup: true + on: + branch: master - rust: nightly before_script: @@ -27,10 +30,6 @@ script: - cargo test - cargo test --features "reuseport unix pair" -env: - global: - secure: "qibsiOrfM/GjYgYFXycSqKMwIK9ZR4cvHZsSqTtqrtxGq5Q7jTwMqdDl8KHDgX1a4it4tGay+7joex8k2zL6OQ+FljQGQq54EDiGw82HWix/fBpOMjMszw+GEDMG/9hUSb6HFdzAKLPAsBRvIs2QteJ60GhL/w4Z/EmfHlVKMnVsYUjfBf5BNlkv8yFvRMY6QqL+F85N7dDQ7JAgdiP79jR7LP8IlCEu/8pgSrf9pSqAHSC1Co1CaN8uhhMlcIIOZ5qYAK4Xty26r2EDzPm5Lw2Bd7a4maN0x+Be2DJvrnX30QkJNNU1XhxYkeZEeUCYAlUhBE5nBHpyyrbAxv+rJodPeyRl5EVpyqi8htPVmcnuA2XpNoHCud7CnzxaFytGvAC5kp0EgS7f3ac4hTnZXCfP0CvnT5UyWfWv9yLwQycdYcAsV4TnKxVAw4ykApGey+h0dyIM2VnzRPOo9D2ZS+JpzPHtx/PXD7aN7IungfTj4PmT+i00QNzkzJR9BqYKmEDBUcz6MLctg4D6xChhN8Go4hvk22F0RVyvEg1MAvXc07EKeWXG/VZ+H2frcPEceMGRBBHiOfOEE/2utNYgvIcmQxd1hvbm3cQOIjeXU2rGneN86cSmx7zNlfOyJUoBfsgGvSEzRxUueibUCaujB/El70HGrMlTnXeERiyd/2Y=" - notifications: email: on_success: never diff --git a/README.md b/README.md index 2936503f..0e9e9148 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # socket2-rs -[![Build Status](https://travis-ci.org/alexcrichton/socket2-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/socket2-rs) +[![Build Status](https://travis-ci.com/alexcrichton/socket2-rs.svg?branch=master)](https://travis-ci.com/alexcrichton/socket2-rs) [![Build status](https://ci.appveyor.com/api/projects/status/hovebj1gr4bgm3d9?svg=true)](https://ci.appveyor.com/project/alexcrichton/socket2-rs) [Documentation](https://docs.rs/socket2) From 70f15f03be2a9eadb0b8821137af4f9d7ac0dd6f Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Sun, 5 May 2019 14:46:21 +0200 Subject: [PATCH 02/51] Added tests for Socket::nodelay() --- src/socket.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/socket.rs b/src/socket.rs index b3297d66..43960022 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -982,4 +982,16 @@ mod test { #[cfg(unix)] assert_eq!(socket.keepalive().unwrap(), None); } + + #[test] + fn nodelay() { + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + + assert!(socket.set_nodelay(true).is_ok()); + + let result = socket.nodelay(); + + assert!(result.is_ok()); + assert!(result.unwrap()); + } } From 2bdd3c320b4ea575f742357bb8e7ffbde5b4b21c Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Sun, 5 May 2019 15:02:25 +0200 Subject: [PATCH 03/51] Use c_char for Socket::nodelay() on Windows When using getsockopt() on Windows with TCP_NODELAY, the returned value is 1 byte (= c_char) long instead of 4 bytes (= c_int). Using c_int would then result in an assertion failure, due to the input and output sizes being different. --- src/sys/windows.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/windows.rs b/src/sys/windows.rs index e6c8f114..eb9329f2 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -445,13 +445,13 @@ impl Socket { pub fn nodelay(&self) -> io::Result { unsafe { - let raw: c_int = self.getsockopt(IPPROTO_TCP, TCP_NODELAY)?; + let raw: c_char = self.getsockopt(IPPROTO_TCP, TCP_NODELAY)?; Ok(raw != 0) } } pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - unsafe { self.setsockopt(IPPROTO_TCP, TCP_NODELAY, nodelay as c_int) } + unsafe { self.setsockopt(IPPROTO_TCP, TCP_NODELAY, nodelay as c_char) } } pub fn broadcast(&self) -> io::Result { From 3c9b9daa10750f84e816cd73a2646b43d620e77f Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Sun, 5 May 2019 15:07:26 +0200 Subject: [PATCH 04/51] Fix documentation for Socket::as_inet6() The documentation incorrectly mentioned returning an SocketAddrV4 instead of a SocketAddrV6. This fixes https://github.com/alexcrichton/socket2-rs/issues/30 --- src/sockaddr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 5e335db9..9806ad83 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -123,7 +123,7 @@ impl SockAddr { unsafe { self.as_(AF_INET as sa_family_t) } } - /// Returns this address as a `SocketAddrV4` if it is in the `AF_INET6` + /// Returns this address as a `SocketAddrV6` if it is in the `AF_INET6` /// family. pub fn as_inet6(&self) -> Option { unsafe { self.as_(AF_INET6 as sa_family_t) } From 28bdf727744dd9b6094a0bca47062acb6161c20c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 May 2019 10:45:36 -0700 Subject: [PATCH 05/51] Bump to 0.3.9 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f783047f..66eed6dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "socket2" -version = "0.3.8" +version = "0.3.9" authors = ["Alex Crichton "] license = "MIT/Apache-2.0" readme = "README.md" From f1140476dab9506032d64c4d5956c2dc04a31566 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 May 2019 10:47:05 -0700 Subject: [PATCH 06/51] Remove deprecated usage --- src/sys/unix/mod.rs | 4 ++-- src/sys/unix/weak.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sys/unix/mod.rs b/src/sys/unix/mod.rs index 96e01b78..5d0d91d0 100644 --- a/src/sys/unix/mod.rs +++ b/src/sys/unix/mod.rs @@ -17,7 +17,7 @@ use std::net::Shutdown; use std::net::{self, Ipv4Addr, Ipv6Addr}; use std::ops::Neg; use std::os::unix::prelude::*; -use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT}; +use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; #[cfg(feature = "unix")] use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; @@ -248,7 +248,7 @@ impl Socket { #[cfg(not(any(target_os = "android", target_os = "haiku")))] use libc::F_DUPFD_CLOEXEC; - static CLOEXEC_FAILED: AtomicBool = ATOMIC_BOOL_INIT; + static CLOEXEC_FAILED: AtomicBool = AtomicBool::new(false); unsafe { if !CLOEXEC_FAILED.load(Ordering::Relaxed) { match cvt(libc::fcntl(self.fd, F_DUPFD_CLOEXEC, 0)) { diff --git a/src/sys/unix/weak.rs b/src/sys/unix/weak.rs index 6767a0f9..78559f38 100644 --- a/src/sys/unix/weak.rs +++ b/src/sys/unix/weak.rs @@ -20,7 +20,7 @@ macro_rules! weak { static $name: ::sys::weak::Weak $ret> = ::sys::weak::Weak { name: concat!(stringify!($name), "\0"), - addr: ::std::sync::atomic::ATOMIC_USIZE_INIT, + addr: ::std::sync::atomic::AtomicUsize::new(0), _marker: ::std::marker::PhantomData, }; ) From 763b8a59a28324ddcd981a9243375a309eb81679 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 May 2019 10:56:46 -0700 Subject: [PATCH 07/51] Use `syscall` on Linux instead of `dlsym` More robust for all platforms! --- src/lib.rs | 2 +- src/sys/{unix/mod.rs => unix.rs} | 34 +++++++----------- src/sys/unix/weak.rs | 59 -------------------------------- 3 files changed, 14 insertions(+), 81 deletions(-) rename src/sys/{unix/mod.rs => unix.rs} (97%) delete mode 100644 src/sys/unix/weak.rs diff --git a/src/lib.rs b/src/lib.rs index 16e745d4..fd70ad9e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,7 +66,7 @@ mod sockaddr; mod socket; mod utils; -#[cfg_attr(unix, path = "sys/unix/mod.rs")] +#[cfg_attr(unix, path = "sys/unix.rs")] #[cfg_attr(target_os = "redox", path = "sys/redox/mod.rs")] #[cfg_attr(windows, path = "sys/windows.rs")] mod sys; diff --git a/src/sys/unix/mod.rs b/src/sys/unix.rs similarity index 97% rename from src/sys/unix/mod.rs rename to src/sys/unix.rs index 5d0d91d0..d5bef3c6 100644 --- a/src/sys/unix/mod.rs +++ b/src/sys/unix.rs @@ -68,10 +68,6 @@ pub const IPPROTO_UDP: i32 = libc::IPPROTO_UDP; pub const SOCK_SEQPACKET: i32 = libc::SOCK_SEQPACKET; pub const SOCK_RAW: i32 = libc::SOCK_RAW; -#[macro_use] -#[cfg(target_os = "linux")] -mod weak; - pub struct Socket { fd: c_int, } @@ -280,23 +276,19 @@ impl Socket { let mut socket = None; #[cfg(target_os = "linux")] { - weak! { - fn accept4(c_int, *mut libc::sockaddr, *mut socklen_t, c_int) -> c_int - } - if let Some(f) = accept4.get() { - let res = cvt_r(|| unsafe { - f( - self.fd, - &mut storage as *mut _ as *mut _, - &mut len, - libc::SOCK_CLOEXEC, - ) - }); - match res { - Ok(fd) => socket = Some(Socket { fd: fd }), - Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} - Err(e) => return Err(e), - } + let res = cvt_r(|| unsafe { + libc::syscall( + libc::SYS_accept4, + self.fd as libc::c_long, + &mut storage as *mut _ as libc::c_long, + len as libc::c_long, + libc::SOCK_CLOEXEC as libc::c_long, + ) as libc::c_int + }); + match res { + Ok(fd) => socket = Some(Socket { fd: fd }), + Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} + Err(e) => return Err(e), } } diff --git a/src/sys/unix/weak.rs b/src/sys/unix/weak.rs deleted file mode 100644 index 78559f38..00000000 --- a/src/sys/unix/weak.rs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::marker; -use std::mem; -use std::sync::atomic::{AtomicUsize, Ordering}; - -use libc; - -macro_rules! weak { - (fn $name:ident($($t:ty),*) -> $ret:ty) => ( - #[allow(bad_style)] - static $name: ::sys::weak::Weak $ret> = - ::sys::weak::Weak { - name: concat!(stringify!($name), "\0"), - addr: ::std::sync::atomic::AtomicUsize::new(0), - _marker: ::std::marker::PhantomData, - }; - ) -} - -pub struct Weak { - pub name: &'static str, - pub addr: AtomicUsize, - pub _marker: marker::PhantomData, -} - -impl Weak { - pub fn get(&self) -> Option<&F> { - assert_eq!(mem::size_of::(), mem::size_of::()); - unsafe { - if self.addr.load(Ordering::SeqCst) == 0 { - let ptr = match fetch(self.name) { - 1 => 1, - n => n, - }; - self.addr.store(ptr, Ordering::SeqCst); - } - if self.addr.load(Ordering::SeqCst) == 0 { - None - } else { - mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr) - } - } - } -} - -unsafe fn fetch(name: &str) -> usize { - let name = name.as_bytes(); - assert_eq!(name[name.len() - 1], 0); - libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize -} From 8ba4bc03a34f93972a0d606f70530af706fa7d0c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 May 2019 10:58:19 -0700 Subject: [PATCH 08/51] Run `cargo fmt` --- src/lib.rs | 11 +++++--- src/sockaddr.rs | 19 ++++++++------ src/socket.rs | 2 +- src/sys/redox/mod.rs | 62 +++++++++++++++++++++----------------------- src/sys/unix.rs | 41 +++++++++++++---------------- src/sys/windows.rs | 13 ++++++---- 6 files changed, 75 insertions(+), 73 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fd70ad9e..82a75439 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,9 +66,14 @@ mod sockaddr; mod socket; mod utils; -#[cfg_attr(unix, path = "sys/unix.rs")] -#[cfg_attr(target_os = "redox", path = "sys/redox/mod.rs")] -#[cfg_attr(windows, path = "sys/windows.rs")] +#[cfg(unix)] +#[path = "sys/unix.rs"] +mod sys; +#[cfg(windows)] +#[path = "sys/windows.rs"] +mod sys; +#[cfg(redox)] +#[path = "sys/redox/mod.rs"] mod sys; /// Newtype, owned, wrapper around a system socket. diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 9806ad83..a5e769d3 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -4,16 +4,19 @@ use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; use std::ptr; #[cfg(any(unix, target_os = "redox"))] -use libc::{sa_family_t, sockaddr, sockaddr_in, sockaddr_storage, socklen_t, AF_INET6, - sockaddr_in6, AF_INET}; +use libc::{ + sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET, + AF_INET6, +}; #[cfg(windows)] -use winapi::shared::ws2def::{ADDRESS_FAMILY as sa_family_t, AF_INET6, SOCKADDR as sockaddr, - SOCKADDR_IN as sockaddr_in, SOCKADDR_STORAGE as sockaddr_storage, - AF_INET}; -#[cfg(windows)] -use winapi::um::ws2tcpip::socklen_t; +use winapi::shared::ws2def::{ + ADDRESS_FAMILY as sa_family_t, AF_INET, AF_INET6, SOCKADDR as sockaddr, + SOCKADDR_IN as sockaddr_in, SOCKADDR_STORAGE as sockaddr_storage, +}; #[cfg(windows)] use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6; +#[cfg(windows)] +use winapi::um::ws2tcpip::socklen_t; use SockAddr; @@ -59,10 +62,10 @@ impl SockAddr { where P: AsRef<::std::path::Path>, { + use libc::{c_char, sockaddr_un, AF_UNIX}; use std::cmp::Ordering; use std::io; use std::os::unix::ffi::OsStrExt; - use libc::{c_char, sockaddr_un, AF_UNIX}; unsafe { let mut addr = mem::zeroed::(); diff --git a/src/socket.rs b/src/socket.rs index 43960022..bb4db64a 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -11,9 +11,9 @@ use std::fmt; use std::io::{self, Read, Write}; use std::net::{self, Ipv4Addr, Ipv6Addr, Shutdown}; -use std::time::Duration; #[cfg(all(unix, feature = "unix"))] use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; +use std::time::Duration; #[cfg(any(unix, target_os = "redox"))] use libc as c; diff --git a/src/sys/redox/mod.rs b/src/sys/redox/mod.rs index 3882fc99..211538e3 100644 --- a/src/sys/redox/mod.rs +++ b/src/sys/redox/mod.rs @@ -10,8 +10,9 @@ use std::cmp; use std::fmt; -use std::io::{ErrorKind, Read, Write}; +use std::fs::File; use std::io; +use std::io::{ErrorKind, Read, Write}; use std::mem; use std::net::Shutdown; use std::net::{self, Ipv4Addr, Ipv6Addr}; @@ -19,9 +20,8 @@ use std::ops::Neg; use std::os::unix::prelude::*; use std::time::Duration; use syscall; -use std::fs::File; -use libc::{self, c_uint, c_int, c_void, socklen_t, ssize_t}; +use libc::{self, c_int, c_uint, c_void, socklen_t, ssize_t}; use libc::IPV6_ADD_MEMBERSHIP; use libc::IPV6_DROP_MEMBERSHIP; @@ -30,8 +30,8 @@ const MSG_NOSIGNAL: c_int = 0x0; use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION; -use SockAddr; use utils::One; +use SockAddr; pub const IPPROTO_TCP: i32 = libc::IPPROTO_TCP; @@ -51,7 +51,10 @@ impl Socket { return Err(io::Error::new(ErrorKind::Other, "Type not implemented yet")); } if protocol == -1 { - return Err(io::Error::new(ErrorKind::Other, "Protocol not implemented yet")); + return Err(io::Error::new( + ErrorKind::Other, + "Protocol not implemented yet", + )); } unsafe { let fd = cvt(libc::socket(family, ty, protocol))?; @@ -94,18 +97,18 @@ impl Socket { self.connect(addr)?; let mut event = File::open("event:")?; - let mut time = File::open("time:")?; + let mut time = File::open("time:")?; event.write(&syscall::Event { id: self.fd as usize, flags: syscall::EVENT_WRITE, - data: 0 + data: 0, })?; event.write(&syscall::Event { id: time.as_raw_fd(), flags: syscall::EVENT_WRITE, - data: 1 + data: 1, })?; let mut current = syscall::TimeSpec::default(); @@ -117,11 +120,9 @@ impl Socket { let mut out = syscall::Event::default(); event.read(&mut out)?; - if out.data == 1 { // the timeout we registered - return Err(io::Error::new( - ErrorKind::TimedOut, - "connection timed out", - )); + if out.data == 1 { + // the timeout we registered + return Err(io::Error::new(ErrorKind::TimedOut, "connection timed out")); } Ok(()) @@ -150,7 +151,7 @@ impl Socket { cvt(libc::getpeername( self.fd, &mut storage as *mut _ as *mut _, - &mut len + &mut len, ))?; Ok(SockAddr::from_raw_parts( &storage as *const _ as *const _, @@ -308,10 +309,9 @@ impl Socket { pub fn read_timeout(&self) -> io::Result> { unsafe { - Ok(timeval2dur(self.getsockopt( - libc::SOL_SOCKET, - libc::SO_RCVTIMEO, - )?)) + Ok(timeval2dur( + self.getsockopt(libc::SOL_SOCKET, libc::SO_RCVTIMEO)?, + )) } } @@ -321,10 +321,9 @@ impl Socket { pub fn write_timeout(&self) -> io::Result> { unsafe { - Ok(timeval2dur(self.getsockopt( - libc::SOL_SOCKET, - libc::SO_SNDTIMEO, - )?)) + Ok(timeval2dur( + self.getsockopt(libc::SOL_SOCKET, libc::SO_SNDTIMEO)?, + )) } } @@ -469,10 +468,9 @@ impl Socket { pub fn linger(&self) -> io::Result> { unsafe { - Ok(linger2dur(self.getsockopt( - libc::SOL_SOCKET, - libc::SO_LINGER, - )?)) + Ok(linger2dur( + self.getsockopt(libc::SOL_SOCKET, libc::SO_LINGER)?, + )) } } @@ -539,11 +537,7 @@ impl Socket { )?; if let Some(dur) = keepalive { // TODO: checked cast here - self.setsockopt( - libc::IPPROTO_TCP, - KEEPALIVE_OPTION, - dur.as_secs() as c_int, - )?; + self.setsockopt(libc::IPPROTO_TCP, KEEPALIVE_OPTION, dur.as_secs() as c_int)?; } Ok(()) } @@ -789,8 +783,10 @@ fn timeval2dur(raw: libc::timeval) -> Option { fn to_s_addr(addr: &Ipv4Addr) -> libc::in_addr_t { let octets = addr.octets(); ::hton( - ((octets[0] as libc::in_addr_t) << 24) | ((octets[1] as libc::in_addr_t) << 16) - | ((octets[2] as libc::in_addr_t) << 8) | ((octets[3] as libc::in_addr_t) << 0), + ((octets[0] as libc::in_addr_t) << 24) + | ((octets[1] as libc::in_addr_t) << 16) + | ((octets[2] as libc::in_addr_t) << 8) + | ((octets[3] as libc::in_addr_t) << 0), ) } diff --git a/src/sys/unix.rs b/src/sys/unix.rs index d5bef3c6..0b25490d 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -10,17 +10,17 @@ use std::cmp; use std::fmt; -use std::io::{ErrorKind, Read, Write}; use std::io; +use std::io::{ErrorKind, Read, Write}; use std::mem; use std::net::Shutdown; use std::net::{self, Ipv4Addr, Ipv6Addr}; use std::ops::Neg; +#[cfg(feature = "unix")] +use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; use std::os::unix::prelude::*; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; -#[cfg(feature = "unix")] -use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; use libc::{self, c_int, c_void, socklen_t, ssize_t}; @@ -58,8 +58,8 @@ cfg_if! { } } -use SockAddr; use utils::One; +use SockAddr; pub const IPPROTO_ICMP: i32 = libc::IPPROTO_ICMP; pub const IPPROTO_ICMPV6: i32 = libc::IPPROTO_ICMPV6; @@ -471,10 +471,9 @@ impl Socket { pub fn read_timeout(&self) -> io::Result> { unsafe { - Ok(timeval2dur(self.getsockopt( - libc::SOL_SOCKET, - libc::SO_RCVTIMEO, - )?)) + Ok(timeval2dur( + self.getsockopt(libc::SOL_SOCKET, libc::SO_RCVTIMEO)?, + )) } } @@ -484,10 +483,9 @@ impl Socket { pub fn write_timeout(&self) -> io::Result> { unsafe { - Ok(timeval2dur(self.getsockopt( - libc::SOL_SOCKET, - libc::SO_SNDTIMEO, - )?)) + Ok(timeval2dur( + self.getsockopt(libc::SOL_SOCKET, libc::SO_SNDTIMEO)?, + )) } } @@ -651,10 +649,9 @@ impl Socket { pub fn linger(&self) -> io::Result> { unsafe { - Ok(linger2dur(self.getsockopt( - libc::SOL_SOCKET, - libc::SO_LINGER, - )?)) + Ok(linger2dur( + self.getsockopt(libc::SOL_SOCKET, libc::SO_LINGER)?, + )) } } @@ -721,11 +718,7 @@ impl Socket { )?; if let Some(dur) = keepalive { // TODO: checked cast here - self.setsockopt( - libc::IPPROTO_TCP, - KEEPALIVE_OPTION, - dur.as_secs() as c_int, - )?; + self.setsockopt(libc::IPPROTO_TCP, KEEPALIVE_OPTION, dur.as_secs() as c_int)?; } Ok(()) } @@ -1048,8 +1041,10 @@ fn timeval2dur(raw: libc::timeval) -> Option { fn to_s_addr(addr: &Ipv4Addr) -> libc::in_addr_t { let octets = addr.octets(); ::hton( - ((octets[0] as libc::in_addr_t) << 24) | ((octets[1] as libc::in_addr_t) << 16) - | ((octets[2] as libc::in_addr_t) << 8) | ((octets[3] as libc::in_addr_t) << 0), + ((octets[0] as libc::in_addr_t) << 24) + | ((octets[1] as libc::in_addr_t) << 16) + | ((octets[2] as libc::in_addr_t) << 8) + | ((octets[3] as libc::in_addr_t) << 0), ) } diff --git a/src/sys/windows.rs b/src/sys/windows.rs index eb9329f2..d2faf64d 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -10,8 +10,8 @@ use std::cmp; use std::fmt; -use std::io::{Read, Write}; use std::io; +use std::io::{Read, Write}; use std::mem; use std::net::Shutdown; use std::net::{self, Ipv4Addr, Ipv6Addr}; @@ -21,12 +21,12 @@ use std::sync::{Once, ONCE_INIT}; use std::time::Duration; use winapi::ctypes::{c_char, c_int, c_long, c_ulong}; -use winapi::shared::inaddr::*; use winapi::shared::in6addr::*; +use winapi::shared::inaddr::*; use winapi::shared::minwindef::DWORD; use winapi::shared::ntdef::{HANDLE, ULONG}; -use winapi::shared::ws2def::*; use winapi::shared::ws2def; +use winapi::shared::ws2def::*; use winapi::shared::ws2ipdef::*; use winapi::um::handleapi::SetHandleInformation; use winapi::um::processthreadsapi::GetCurrentProcessId; @@ -876,7 +876,8 @@ fn dur2ms(dur: Option) -> io::Result { // * Nanosecond precision is rounded up // * Greater than u32::MAX milliseconds (50 days) is rounded up to // INFINITE (never time out). - let ms = dur.as_secs() + let ms = dur + .as_secs() .checked_mul(1000) .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000)) .and_then(|ms| { @@ -919,7 +920,9 @@ fn ms2dur(raw: DWORD) -> Option { fn to_s_addr(addr: &Ipv4Addr) -> in_addr_S_un { let octets = addr.octets(); let res = ::hton( - ((octets[0] as ULONG) << 24) | ((octets[1] as ULONG) << 16) | ((octets[2] as ULONG) << 8) + ((octets[0] as ULONG) << 24) + | ((octets[1] as ULONG) << 16) + | ((octets[2] as ULONG) << 8) | ((octets[3] as ULONG) << 0), ); let mut new_addr: in_addr_S_un = unsafe { mem::zeroed() }; From c0513ee1221313016ad1a855668d28971129b058 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 May 2019 11:02:08 -0700 Subject: [PATCH 09/51] Migrate to the 2018 edition --- Cargo.toml | 1 + src/lib.rs | 20 ++------------------ src/sockaddr.rs | 2 +- src/socket.rs | 14 +++++++------- src/sys/redox/mod.rs | 16 ++++++++-------- src/sys/unix.rs | 24 ++++++++++++------------ src/sys/windows.rs | 16 ++++++++-------- 7 files changed, 39 insertions(+), 54 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 66eed6dc..a6828a7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ description = """ Utilities for handling networking sockets with a maximal amount of configuration possible intended. """ +edition = "2018" [package.metadata.docs.rs] all-features = true diff --git a/src/lib.rs b/src/lib.rs index 82a75439..cf599c8e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,23 +37,7 @@ #![doc(html_root_url = "https://docs.rs/socket2/0.3")] #![deny(missing_docs)] -#[cfg(unix)] -#[macro_use] -extern crate cfg_if; -#[cfg(target_os = "redox")] -extern crate cfg_if; -#[cfg(any(unix, target_os = "redox"))] -extern crate libc; -#[cfg(target_os = "redox")] -extern crate syscall; - -#[cfg(windows)] -extern crate winapi; - -#[cfg(test)] -extern crate tempdir; - -use utils::NetInt; +use crate::utils::NetInt; #[cfg(any(unix, target_os = "redox"))] use libc::{sockaddr_storage, socklen_t}; @@ -72,7 +56,7 @@ mod sys; #[cfg(windows)] #[path = "sys/windows.rs"] mod sys; -#[cfg(redox)] +#[cfg(target_os = "redox")] #[path = "sys/redox/mod.rs"] mod sys; diff --git a/src/sockaddr.rs b/src/sockaddr.rs index a5e769d3..c6c9ef1d 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -18,7 +18,7 @@ use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6; #[cfg(windows)] use winapi::um::ws2tcpip::socklen_t; -use SockAddr; +use crate::SockAddr; impl fmt::Debug for SockAddr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/socket.rs b/src/socket.rs index bb4db64a..190a0d11 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -20,8 +20,8 @@ use libc as c; #[cfg(windows)] use winapi::shared::ws2def as c; -use sys; -use {Domain, Protocol, SockAddr, Socket, Type}; +use crate::sys; +use crate::{Domain, Protocol, SockAddr, Socket, Type}; impl Socket { /// Creates a new socket ready to be configured. @@ -838,25 +838,25 @@ impl Type { } } -impl ::Protocol { +impl crate::Protocol { /// Protocol corresponding to `ICMPv4` pub fn icmpv4() -> Self { - ::Protocol(sys::IPPROTO_ICMP) + crate::Protocol(sys::IPPROTO_ICMP) } /// Protocol corresponding to `ICMPv6` pub fn icmpv6() -> Self { - ::Protocol(sys::IPPROTO_ICMPV6) + crate::Protocol(sys::IPPROTO_ICMPV6) } /// Protocol corresponding to `TCP` pub fn tcp() -> Self { - ::Protocol(sys::IPPROTO_TCP) + crate::Protocol(sys::IPPROTO_TCP) } /// Protocol corresponding to `UDP` pub fn udp() -> Self { - ::Protocol(sys::IPPROTO_UDP) + crate::Protocol(sys::IPPROTO_UDP) } } diff --git a/src/sys/redox/mod.rs b/src/sys/redox/mod.rs index 211538e3..bd1ebfcb 100644 --- a/src/sys/redox/mod.rs +++ b/src/sys/redox/mod.rs @@ -30,8 +30,8 @@ const MSG_NOSIGNAL: c_int = 0x0; use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION; -use utils::One; -use SockAddr; +use crate::utils::One; +use crate::SockAddr; pub const IPPROTO_TCP: i32 = libc::IPPROTO_TCP; @@ -648,21 +648,21 @@ impl FromRawFd for Socket { } } -impl AsRawFd for ::Socket { +impl AsRawFd for crate::Socket { fn as_raw_fd(&self) -> RawFd { self.inner.as_raw_fd() } } -impl IntoRawFd for ::Socket { +impl IntoRawFd for crate::Socket { fn into_raw_fd(self) -> RawFd { self.inner.into_raw_fd() } } -impl FromRawFd for ::Socket { - unsafe fn from_raw_fd(fd: RawFd) -> ::Socket { - ::Socket { +impl FromRawFd for crate::Socket { + unsafe fn from_raw_fd(fd: RawFd) -> crate::Socket { + crate::Socket { inner: Socket::from_raw_fd(fd), } } @@ -782,7 +782,7 @@ fn timeval2dur(raw: libc::timeval) -> Option { fn to_s_addr(addr: &Ipv4Addr) -> libc::in_addr_t { let octets = addr.octets(); - ::hton( + crate::hton( ((octets[0] as libc::in_addr_t) << 24) | ((octets[1] as libc::in_addr_t) << 16) | ((octets[2] as libc::in_addr_t) << 8) diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 0b25490d..cacbcb5f 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -24,7 +24,7 @@ use std::time::{Duration, Instant}; use libc::{self, c_int, c_void, socklen_t, ssize_t}; -cfg_if! { +cfg_if::cfg_if! { if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "openbsd", target_os = "netbsd", @@ -37,7 +37,7 @@ cfg_if! { } } -cfg_if! { +cfg_if::cfg_if! { if #[cfg(any(target_os = "linux", target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", @@ -48,7 +48,7 @@ cfg_if! { } } -cfg_if! { +cfg_if::cfg_if! { if #[cfg(any(target_os = "macos", target_os = "ios"))] { use libc::TCP_KEEPALIVE as KEEPALIVE_OPTION; } else if #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "haiku"))] { @@ -58,8 +58,8 @@ cfg_if! { } } -use utils::One; -use SockAddr; +use crate::utils::One; +use crate::SockAddr; pub const IPPROTO_ICMP: i32 = libc::IPPROTO_ICMP; pub const IPPROTO_ICMPV6: i32 = libc::IPPROTO_ICMPV6; @@ -842,21 +842,21 @@ impl FromRawFd for Socket { } } -impl AsRawFd for ::Socket { +impl AsRawFd for crate::Socket { fn as_raw_fd(&self) -> c_int { self.inner.as_raw_fd() } } -impl IntoRawFd for ::Socket { +impl IntoRawFd for crate::Socket { fn into_raw_fd(self) -> c_int { self.inner.into_raw_fd() } } -impl FromRawFd for ::Socket { - unsafe fn from_raw_fd(fd: c_int) -> ::Socket { - ::Socket { +impl FromRawFd for crate::Socket { + unsafe fn from_raw_fd(fd: c_int) -> crate::Socket { + crate::Socket { inner: Socket::from_raw_fd(fd), } } @@ -1040,7 +1040,7 @@ fn timeval2dur(raw: libc::timeval) -> Option { fn to_s_addr(addr: &Ipv4Addr) -> libc::in_addr_t { let octets = addr.octets(); - ::hton( + crate::hton( ((octets[0] as libc::in_addr_t) << 24) | ((octets[1] as libc::in_addr_t) << 16) | ((octets[2] as libc::in_addr_t) << 8) @@ -1049,7 +1049,7 @@ fn to_s_addr(addr: &Ipv4Addr) -> libc::in_addr_t { } fn from_s_addr(in_addr: libc::in_addr_t) -> Ipv4Addr { - let h_addr = ::ntoh(in_addr); + let h_addr = crate::ntoh(in_addr); let a: u8 = (h_addr >> 24) as u8; let b: u8 = (h_addr >> 16) as u8; diff --git a/src/sys/windows.rs b/src/sys/windows.rs index d2faf64d..d2c5a882 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -33,7 +33,7 @@ use winapi::um::processthreadsapi::GetCurrentProcessId; use winapi::um::winbase::INFINITE; use winapi::um::winsock2 as sock; -use SockAddr; +use crate::SockAddr; const HANDLE_FLAG_INHERIT: DWORD = 0x00000001; const MSG_PEEK: c_int = 0x2; @@ -798,21 +798,21 @@ impl FromRawSocket for Socket { } } -impl AsRawSocket for ::Socket { +impl AsRawSocket for crate::Socket { fn as_raw_socket(&self) -> RawSocket { self.inner.as_raw_socket() } } -impl IntoRawSocket for ::Socket { +impl IntoRawSocket for crate::Socket { fn into_raw_socket(self) -> RawSocket { self.inner.into_raw_socket() } } -impl FromRawSocket for ::Socket { - unsafe fn from_raw_socket(socket: RawSocket) -> ::Socket { - ::Socket { +impl FromRawSocket for crate::Socket { + unsafe fn from_raw_socket(socket: RawSocket) -> crate::Socket { + crate::Socket { inner: Socket::from_raw_socket(socket), } } @@ -919,7 +919,7 @@ fn ms2dur(raw: DWORD) -> Option { fn to_s_addr(addr: &Ipv4Addr) -> in_addr_S_un { let octets = addr.octets(); - let res = ::hton( + let res = crate::hton( ((octets[0] as ULONG) << 24) | ((octets[1] as ULONG) << 16) | ((octets[2] as ULONG) << 8) @@ -931,7 +931,7 @@ fn to_s_addr(addr: &Ipv4Addr) -> in_addr_S_un { } fn from_s_addr(in_addr: in_addr_S_un) -> Ipv4Addr { - let h_addr = ::ntoh(unsafe { *in_addr.S_addr() }); + let h_addr = crate::ntoh(unsafe { *in_addr.S_addr() }); let a: u8 = (h_addr >> 24) as u8; let b: u8 = (h_addr >> 16) as u8; From c4429c694251071c1d8518445dad981e78986b88 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 May 2019 11:02:38 -0700 Subject: [PATCH 10/51] Fix travis --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fd7b3643..26622de6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ sudo: false matrix: include: - - rust: 1.21.0 - rust: stable - os: osx - rust: beta From 2eae1194b728afdc74680706ea6081d300db1046 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 24 Jul 2019 08:06:06 -0700 Subject: [PATCH 11/51] Bump to 0.3.10 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a6828a7c..7b6bc116 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "socket2" -version = "0.3.9" +version = "0.3.10" authors = ["Alex Crichton "] license = "MIT/Apache-2.0" readme = "README.md" From 61dbe30187461160cd9e5d25c67dd1ffc58af27b Mon Sep 17 00:00:00 2001 From: Andrew Kilroy <7545475+andykilroy@users.noreply.github.com> Date: Fri, 26 Jul 2019 15:10:39 +0100 Subject: [PATCH 12/51] Fix compilation on illumos if reuseport is enabled --- src/sys/unix/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sys/unix/mod.rs b/src/sys/unix/mod.rs index 96e01b78..5e6e7cdb 100644 --- a/src/sys/unix/mod.rs +++ b/src/sys/unix/mod.rs @@ -741,15 +741,22 @@ impl Socket { #[cfg(all(unix, feature = "reuseport"))] pub fn reuse_port(&self) -> io::Result { + #[cfg(not(target_os = "solaris"))] unsafe { let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT)?; Ok(raw != 0) } + #[cfg(target_os = "solaris")] + Ok(false) } #[cfg(all(unix, feature = "reuseport"))] pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> { + #[cfg(not(target_os = "solaris"))] unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT, reuse as c_int) } + + #[cfg(target_os = "solaris")] + Ok(()) } unsafe fn setsockopt(&self, opt: c_int, val: c_int, payload: T) -> io::Result<()> From 744f59de199fd61b13272c8484d091a3dcf35ba4 Mon Sep 17 00:00:00 2001 From: Andrew Kilroy <7545475+andykilroy@users.noreply.github.com> Date: Sat, 27 Jul 2019 00:18:12 +0100 Subject: [PATCH 13/51] Tidy some cfgs detecting solaris --- src/socket.rs | 6 +++--- src/sys/unix/mod.rs | 11 ++--------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/socket.rs b/src/socket.rs index 43960022..39ffbdc8 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -632,20 +632,20 @@ impl Socket { /// /// This function is only available on Unix when the `reuseport` feature is /// enabled. - #[cfg(all(unix, feature = "reuseport"))] + #[cfg(all(unix, not(target_os = "solaris"), feature = "reuseport"))] pub fn reuse_port(&self) -> io::Result { self.inner.reuse_port() } /// Set value for the `SO_REUSEPORT` option on this socket. /// - /// This indicates that futher calls to `bind` may allow reuse of local + /// This indicates that further calls to `bind` may allow reuse of local /// addresses. For IPv4 sockets this means that a socket may bind even when /// there's a socket already listening on this port. /// /// This function is only available on Unix when the `reuseport` feature is /// enabled. - #[cfg(all(unix, feature = "reuseport"))] + #[cfg(all(unix, not(target_os = "solaris"), feature = "reuseport"))] pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> { self.inner.set_reuse_port(reuse) } diff --git a/src/sys/unix/mod.rs b/src/sys/unix/mod.rs index 5e6e7cdb..a72279c9 100644 --- a/src/sys/unix/mod.rs +++ b/src/sys/unix/mod.rs @@ -739,24 +739,17 @@ impl Socket { } } - #[cfg(all(unix, feature = "reuseport"))] + #[cfg(all(unix, not(target_os = "solaris"), feature = "reuseport"))] pub fn reuse_port(&self) -> io::Result { - #[cfg(not(target_os = "solaris"))] unsafe { let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT)?; Ok(raw != 0) } - #[cfg(target_os = "solaris")] - Ok(false) } - #[cfg(all(unix, feature = "reuseport"))] + #[cfg(all(unix, not(target_os = "solaris"), feature = "reuseport"))] pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> { - #[cfg(not(target_os = "solaris"))] unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT, reuse as c_int) } - - #[cfg(target_os = "solaris")] - Ok(()) } unsafe fn setsockopt(&self, opt: c_int, val: c_int, payload: T) -> io::Result<()> From 8596a9da019478497d3e3ba7b1136ac9282f01a0 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 7 Aug 2019 03:09:45 +0200 Subject: [PATCH 14/51] Fix invalid use of accept4() system call The accept4 system call is supposed to be given a pointer to an address length, and not a length as an int. Doing so will lead to an EFAULT error. --- src/sys/unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys/unix.rs b/src/sys/unix.rs index a480a147..e138e684 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -281,7 +281,7 @@ impl Socket { libc::SYS_accept4, self.fd as libc::c_long, &mut storage as *mut _ as libc::c_long, - len as libc::c_long, + &mut len, libc::SOCK_CLOEXEC as libc::c_long, ) as libc::c_int }); From ffe02a037b2b1c851f17b666fe47de889152de0b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 7 Aug 2019 07:03:16 -0700 Subject: [PATCH 15/51] Bump to 0.3.11 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7b6bc116..ce82e243 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "socket2" -version = "0.3.10" +version = "0.3.11" authors = ["Alex Crichton "] license = "MIT/Apache-2.0" readme = "README.md" From 78c3ed1cdbc394d3bc398fa5b9edd28fe677523a Mon Sep 17 00:00:00 2001 From: Dror Levin Date: Sat, 7 Sep 2019 00:59:33 +0300 Subject: [PATCH 16/51] Add packet domain (AF_PACKET) --- src/socket.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/socket.rs b/src/socket.rs index 8ca52c12..ce69a0eb 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -798,6 +798,15 @@ impl Domain { pub fn unix() -> Domain { Domain(c::AF_UNIX) } + + /// Domain for low-level packet interface, corresponding to `AF_PACKET`. + /// + /// This function is only available on Unix when the `unix` feature is + /// activated. + #[cfg(all(unix, feature = "unix"))] + pub fn packet() -> Domain { + Domain(c::AF_PACKET) + } } impl From for Domain { From b07cae627b9b97d5cbc1c77ad453f9bb65f0c30a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 9 Sep 2019 08:30:00 -0700 Subject: [PATCH 17/51] Migrate to Github Actions for CI --- .appveyor.yml | 16 -------- .github/workflows/main.yml | 82 ++++++++++++++++++++++++++++++++++++++ .travis.yml | 34 ---------------- README.md | 3 -- 4 files changed, 82 insertions(+), 53 deletions(-) delete mode 100644 .appveyor.yml create mode 100644 .github/workflows/main.yml delete mode 100644 .travis.yml diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 4880006c..00000000 --- a/.appveyor.yml +++ /dev/null @@ -1,16 +0,0 @@ -environment: - matrix: - - TARGET: x86_64-pc-windows-msvc -install: - - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - - rustup-init.exe -y --default-host x86_64-pc-windows-msvc - - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - - if NOT "%TARGET%" == "x86_64-pc-windows-msvc" rustup target add %TARGET% - - rustc -V - - cargo -V - -build: false - -test_script: - - cargo test - - cargo test --features reuseport diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..07052345 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,82 @@ +name: CI +on: [push, pull_request] + +jobs: + test: + name: Test + runs-on: ${{ matrix.os }} + strategy: + matrix: + build: [stable, beta, nightly, macos, windows] + include: + - build: stable + os: ubuntu-latest + rust: stable + - build: beta + os: ubuntu-latest + rust: beta + - build: nightly + os: ubuntu-latest + rust: nightly + - build: macos + os: macos-latest + rust: stable + - build: windows + os: windows-latest + rust: stable + steps: + - uses: actions/checkout@master + - name: Install Rust (rustup) + run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} + if: matrix.os != 'macos-latest' + - name: Install Rust (macos) + run: | + curl https://sh.rustup.rs | sh -s -- -y + echo "##[add-path]$HOME/.cargo/bin" + if: matrix.os == 'macos-latest' + - run: cargo test + - run: cargo test --features reuseport + - run: cargo test --features unix + - run: cargo test --features pair + - run: cargo test --features "reuseport unix pair" + + rustfmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update stable && rustup default stable && rustup component add rustfmt + - run: cargo fmt -- --check + + check: + name: Check + runs-on: ubuntu-latest + strategy: + matrix: + target: [x86_64-unknown-redox] + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update nightly && rustup default nightly + - run: rustup target add ${{ matrix.target }} + - run: cargo check --target ${{ matrix.target }} + continue-on-error: true + + publish_docs: + name: Publish Documentation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update stable && rustup default stable + - name: Build documentation + run: cargo doc --no-deps --all-features + - name: Publish documentation + run: | + cd target/doc + git init + git add . + git -c user.name='ci' -c user.email='ci' commit -m init + git push -f -q https://git:${{ secrets.github_token }}@github.com/${{ github.repository }} HEAD:gh-pages + if: github.event_name == 'push' && github.event.ref == 'refs/heads/master' diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 26622de6..00000000 --- a/.travis.yml +++ /dev/null @@ -1,34 +0,0 @@ -language: rust -sudo: false - -matrix: - include: - - rust: stable - - os: osx - - rust: beta - - rust: nightly - - - name: "master doc to gh-pages" - rust: nightly - script: - - cargo doc --no-deps - deploy: - provider: script - script: curl -LsSf https://git.io/fhJ8n | rustc - && (cd target/doc && ../../rust_out) - skip_cleanup: true - on: - branch: master - - - rust: nightly - before_script: - - rustup target add x86_64-unknown-redox --toolchain nightly - script: - - cargo check --target x86_64-unknown-redox - -script: - - cargo test - - cargo test --features "reuseport unix pair" - -notifications: - email: - on_success: never diff --git a/README.md b/README.md index 0e9e9148..10d9b1c8 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,5 @@ # socket2-rs -[![Build Status](https://travis-ci.com/alexcrichton/socket2-rs.svg?branch=master)](https://travis-ci.com/alexcrichton/socket2-rs) -[![Build status](https://ci.appveyor.com/api/projects/status/hovebj1gr4bgm3d9?svg=true)](https://ci.appveyor.com/project/alexcrichton/socket2-rs) - [Documentation](https://docs.rs/socket2) # License From 386e6d58affc76f7d3373c5860042df287200ee2 Mon Sep 17 00:00:00 2001 From: Dror Levin Date: Mon, 9 Sep 2019 20:15:24 +0300 Subject: [PATCH 18/51] Define packet domain only on Linux --- src/socket.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/socket.rs b/src/socket.rs index ce69a0eb..3d5fe7e7 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -801,9 +801,9 @@ impl Domain { /// Domain for low-level packet interface, corresponding to `AF_PACKET`. /// - /// This function is only available on Unix when the `unix` feature is + /// This function is only available on Linux when the `unix` feature is /// activated. - #[cfg(all(unix, feature = "unix"))] + #[cfg(all(unix, feature = "unix", target_os = "linux"))] pub fn packet() -> Domain { Domain(c::AF_PACKET) } From 5b8b716f0a558acffa9f8889186bbbfb997499ba Mon Sep 17 00:00:00 2001 From: jean-airoldie <25088801+jean-airoldie@users.noreply.github.com> Date: Thu, 19 Sep 2019 17:23:34 -0400 Subject: [PATCH 19/51] Add as_std convenience method This adds as_std with tries to convert the `SockAddr` into a `SocketAddr` if possible. --- src/sockaddr.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index c6c9ef1d..79f3c61d 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -132,6 +132,18 @@ impl SockAddr { unsafe { self.as_(AF_INET6 as sa_family_t) } } + /// Returns this address as a `SocketAddr` if it is in the `AF_INET` + /// or `AF_INET6` family, otherwise returns `None`. + pub fn as_std(&self) -> Option { + if let Some(addr) = self.as_inet() { + Some(SocketAddr::V4(addr)) + } else if let Some(addr) = self.as_inet6() { + Some(SocketAddr::V6(addr)) + } else { + None + } + } + /// Returns this address's family. pub fn family(&self) -> sa_family_t { self.storage.ss_family From 9ea50133a5f10267bfce201f24f532b1f4425ad1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 28 Oct 2019 07:42:44 -0700 Subject: [PATCH 20/51] Fix Github Actions for recent system changes --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 07052345..417f8889 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,6 +29,7 @@ jobs: - name: Install Rust (rustup) run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} if: matrix.os != 'macos-latest' + shell: bash - name: Install Rust (macos) run: | curl https://sh.rustup.rs | sh -s -- -y From d810e9d17614622515265e6d592a39f3815a832e Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Sun, 10 Nov 2019 21:43:45 -0500 Subject: [PATCH 21/51] cfg-if: require 0.1.6 This version compiles with modern toolchains. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ce82e243..b0fcc3ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ version = "0.3.3" features = ["handleapi", "ws2def", "ws2ipdef", "ws2tcpip", "minwindef"] [target."cfg(any(unix, target_os = \"redox\"))".dependencies] -cfg-if = "0.1" +cfg-if = "0.1.6" libc = "0.2.42" [target."cfg(target_os = \"redox\")".dependencies] From fb966b9c629c15954b72e88a673d92f2fd8f731c Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Sun, 10 Nov 2019 21:45:15 -0500 Subject: [PATCH 22/51] gitignore: ignore target as a symlink --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 39ad86cc..75c73087 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -target/ +/target **/*.rs.bk Cargo.lock From 1996c472838619ef2a03ede76463776d495b6a17 Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Sun, 12 Jan 2020 20:27:16 -0600 Subject: [PATCH 23/51] Deduplicate sys::redox with sys::unix, as redox is a unix OS --- Cargo.toml | 2 +- src/lib.rs | 4 - src/sys/redox/mod.rs | 828 ------------------------------------------- src/sys/unix.rs | 11 +- 4 files changed, 10 insertions(+), 835 deletions(-) delete mode 100644 src/sys/redox/mod.rs diff --git a/Cargo.toml b/Cargo.toml index b0fcc3ee..2a345931 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ features = ["handleapi", "ws2def", "ws2ipdef", "ws2tcpip", "minwindef"] [target."cfg(any(unix, target_os = \"redox\"))".dependencies] cfg-if = "0.1.6" -libc = "0.2.42" +libc = "0.2" [target."cfg(target_os = \"redox\")".dependencies] redox_syscall = "0.1.38" diff --git a/src/lib.rs b/src/lib.rs index cf599c8e..0bd17aba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,9 +56,6 @@ mod sys; #[cfg(windows)] #[path = "sys/windows.rs"] mod sys; -#[cfg(target_os = "redox")] -#[path = "sys/redox/mod.rs"] -mod sys; /// Newtype, owned, wrapper around a system socket. /// @@ -136,7 +133,6 @@ fn hton(i: I) -> I { i.to_be() } -#[cfg(not(target_os = "redox"))] fn ntoh(i: I) -> I { I::from_be(i) } diff --git a/src/sys/redox/mod.rs b/src/sys/redox/mod.rs deleted file mode 100644 index bd1ebfcb..00000000 --- a/src/sys/redox/mod.rs +++ /dev/null @@ -1,828 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::cmp; -use std::fmt; -use std::fs::File; -use std::io; -use std::io::{ErrorKind, Read, Write}; -use std::mem; -use std::net::Shutdown; -use std::net::{self, Ipv4Addr, Ipv6Addr}; -use std::ops::Neg; -use std::os::unix::prelude::*; -use std::time::Duration; -use syscall; - -use libc::{self, c_int, c_uint, c_void, socklen_t, ssize_t}; - -use libc::IPV6_ADD_MEMBERSHIP; -use libc::IPV6_DROP_MEMBERSHIP; - -const MSG_NOSIGNAL: c_int = 0x0; - -use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION; - -use crate::utils::One; -use crate::SockAddr; - -pub const IPPROTO_TCP: i32 = libc::IPPROTO_TCP; - -pub const IPPROTO_ICMP: i32 = -1; -pub const IPPROTO_ICMPV6: i32 = -1; -pub const IPPROTO_UDP: i32 = -1; -pub const SOCK_RAW: i32 = -1; -pub const SOCK_SEQPACKET: i32 = -1; - -pub struct Socket { - fd: c_int, -} - -impl Socket { - pub fn new(family: c_int, ty: c_int, protocol: c_int) -> io::Result { - if ty == -1 { - return Err(io::Error::new(ErrorKind::Other, "Type not implemented yet")); - } - if protocol == -1 { - return Err(io::Error::new( - ErrorKind::Other, - "Protocol not implemented yet", - )); - } - unsafe { - let fd = cvt(libc::socket(family, ty, protocol))?; - let fd = Socket::from_raw_fd(fd as RawFd); - set_cloexec(fd.as_raw_fd() as c_int)?; - Ok(fd) - } - } - - pub fn pair(_family: c_int, _ty: c_int, _protocol: c_int) -> io::Result<(Socket, Socket)> { - return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); - } - - pub fn bind(&self, addr: &SockAddr) -> io::Result<()> { - unsafe { cvt(libc::bind(self.fd, addr.as_ptr(), addr.len() as _)).map(|_| ()) } - } - - pub fn listen(&self, backlog: i32) -> io::Result<()> { - unsafe { cvt(libc::listen(self.fd, backlog)).map(|_| ()) } - } - - pub fn connect(&self, addr: &SockAddr) -> io::Result<()> { - unsafe { cvt(libc::connect(self.fd, addr.as_ptr(), addr.len())).map(|_| ()) } - } - - pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> { - if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::Error::new( - ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); - } - if timeout.as_secs() > ::std::i64::MAX as u64 { - return Err(io::Error::new( - ErrorKind::InvalidInput, - "too large duration", - )); - } - - self.connect(addr)?; - - let mut event = File::open("event:")?; - let mut time = File::open("time:")?; - - event.write(&syscall::Event { - id: self.fd as usize, - flags: syscall::EVENT_WRITE, - data: 0, - })?; - - event.write(&syscall::Event { - id: time.as_raw_fd(), - flags: syscall::EVENT_WRITE, - data: 1, - })?; - - let mut current = syscall::TimeSpec::default(); - time.read(&mut current)?; - current.tv_sec += timeout.as_secs() as i64; - current.tv_nsec += timeout.subsec_nanos() as i32; - time.write(¤t)?; - - let mut out = syscall::Event::default(); - event.read(&mut out)?; - - if out.data == 1 { - // the timeout we registered - return Err(io::Error::new(ErrorKind::TimedOut, "connection timed out")); - } - - Ok(()) - } - - pub fn local_addr(&self) -> io::Result { - unsafe { - let mut storage: libc::sockaddr_storage = mem::zeroed(); - let mut len = mem::size_of_val(&storage) as libc::socklen_t; - cvt(libc::getsockname( - self.fd, - &mut storage as *mut _ as *mut _, - &mut len, - ))?; - Ok(SockAddr::from_raw_parts( - &storage as *const _ as *const _, - len, - )) - } - } - - pub fn peer_addr(&self) -> io::Result { - unsafe { - let mut storage: libc::sockaddr_storage = mem::zeroed(); - let mut len = mem::size_of_val(&storage) as libc::socklen_t; - cvt(libc::getpeername( - self.fd, - &mut storage as *mut _ as *mut _, - &mut len, - ))?; - Ok(SockAddr::from_raw_parts( - &storage as *const _ as *const _, - len as c_uint, - )) - } - } - - pub fn try_clone(&self) -> io::Result { - return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); - } - - #[allow(unused_mut)] - pub fn accept(&self) -> io::Result<(Socket, SockAddr)> { - return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); - } - - pub fn take_error(&self) -> io::Result> { - unsafe { - let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_ERROR)?; - if raw == 0 { - Ok(None) - } else { - Ok(Some(io::Error::from_raw_os_error(raw as i32))) - } - } - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - unsafe { - let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?; - let new = if nonblocking { - previous | libc::O_NONBLOCK - } else { - previous & !libc::O_NONBLOCK - }; - if new != previous { - cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?; - } - Ok(()) - } - } - - pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> { - return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); - } - - pub fn recv(&self, buf: &mut [u8]) -> io::Result { - unsafe { - let n = cvt({ - libc::recv( - self.fd, - buf.as_mut_ptr() as *mut c_void, - cmp::min(buf.len(), max_len()), - 0, - ) - })?; - Ok(n as usize) - } - } - - pub fn peek(&self, _buf: &mut [u8]) -> io::Result { - return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); - } - - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { - self.recvfrom(buf, 0) - } - - pub fn peek_from(&self, _buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { - return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); - } - - fn recvfrom(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> { - unsafe { - let mut storage: libc::sockaddr_storage = mem::zeroed(); - let mut addrlen = mem::size_of_val(&storage) as socklen_t; - - let n = cvt({ - libc::recvfrom( - self.fd, - buf.as_mut_ptr() as *mut c_void, - cmp::min(buf.len(), max_len()), - flags, - &mut storage as *mut _ as *mut _, - &mut addrlen, - ) - })?; - let addr = SockAddr::from_raw_parts(&storage as *const _ as *const _, addrlen); - Ok((n as usize, addr)) - } - } - - pub fn send(&self, buf: &[u8]) -> io::Result { - unsafe { - let n = cvt({ - libc::send( - self.fd, - buf.as_ptr() as *const c_void, - cmp::min(buf.len(), max_len()), - MSG_NOSIGNAL, - ) - })?; - Ok(n as usize) - } - } - - pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result { - unsafe { - let n = cvt({ - libc::sendto( - self.fd, - buf.as_ptr() as *const c_void, - cmp::min(buf.len(), max_len()), - MSG_NOSIGNAL, - addr.as_ptr(), - addr.len(), - ) - })?; - Ok(n as usize) - } - } - - // ================================================ - - pub fn ttl(&self) -> io::Result { - unsafe { - let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_TTL)?; - Ok(raw as u32) - } - } - - pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { - unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int) } - } - - pub fn unicast_hops_v6(&self) -> io::Result { - return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); - } - - pub fn set_unicast_hops_v6(&self, _hops: u32) -> io::Result<()> { - return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); - } - - pub fn only_v6(&self) -> io::Result { - unsafe { - let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_V6ONLY)?; - Ok(raw != 0) - } - } - - pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { - unsafe { self.setsockopt(libc::IPPROTO_IPV6, libc::IPV6_V6ONLY, only_v6 as c_int) } - } - - pub fn read_timeout(&self) -> io::Result> { - unsafe { - Ok(timeval2dur( - self.getsockopt(libc::SOL_SOCKET, libc::SO_RCVTIMEO)?, - )) - } - } - - pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { - unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_RCVTIMEO, dur2timeval(dur)?) } - } - - pub fn write_timeout(&self) -> io::Result> { - unsafe { - Ok(timeval2dur( - self.getsockopt(libc::SOL_SOCKET, libc::SO_SNDTIMEO)?, - )) - } - } - - pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { - unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_SNDTIMEO, dur2timeval(dur)?) } - } - - pub fn nodelay(&self) -> io::Result { - unsafe { - let raw: c_int = self.getsockopt(libc::IPPROTO_TCP, libc::TCP_NODELAY)?; - Ok(raw != 0) - } - } - - pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - unsafe { self.setsockopt(libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) } - } - - pub fn broadcast(&self) -> io::Result { - unsafe { - let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_BROADCAST)?; - Ok(raw != 0) - } - } - - pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { - unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_BROADCAST, broadcast as c_int) } - } - - pub fn multicast_loop_v4(&self) -> io::Result { - unsafe { - let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP)?; - Ok(raw != 0) - } - } - - pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { - unsafe { - self.setsockopt( - libc::IPPROTO_IP, - libc::IP_MULTICAST_LOOP, - multicast_loop_v4 as c_int, - ) - } - } - - pub fn multicast_ttl_v4(&self) -> io::Result { - unsafe { - let raw: c_int = self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_TTL)?; - Ok(raw as u32) - } - } - - pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { - unsafe { - self.setsockopt( - libc::IPPROTO_IP, - libc::IP_MULTICAST_TTL, - multicast_ttl_v4 as c_int, - ) - } - } - - pub fn multicast_hops_v6(&self) -> io::Result { - return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); - } - - pub fn set_multicast_hops_v6(&self, _hops: u32) -> io::Result<()> { - return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); - } - - pub fn multicast_if_v4(&self) -> io::Result { - return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); - } - - pub fn set_multicast_if_v4(&self, _interface: &Ipv4Addr) -> io::Result<()> { - return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); - } - - pub fn multicast_if_v6(&self) -> io::Result { - return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); - } - - pub fn set_multicast_if_v6(&self, _interface: u32) -> io::Result<()> { - return Err(io::Error::new(ErrorKind::Other, "Not implemented yet")); - } - - pub fn multicast_loop_v6(&self) -> io::Result { - unsafe { - let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_LOOP)?; - Ok(raw != 0) - } - } - - pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { - unsafe { - self.setsockopt( - libc::IPPROTO_IPV6, - libc::IPV6_MULTICAST_LOOP, - multicast_loop_v6 as c_int, - ) - } - } - - pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { - let multiaddr = to_s_addr(multiaddr); - let interface = to_s_addr(interface); - let mreq = libc::ip_mreq { - imr_multiaddr: libc::in_addr { s_addr: multiaddr }, - imr_interface: libc::in_addr { s_addr: interface }, - }; - unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, mreq) } - } - - pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { - let multiaddr = to_in6_addr(multiaddr); - let mreq = libc::ipv6_mreq { - ipv6mr_multiaddr: multiaddr, - ipv6mr_interface: to_ipv6mr_interface(interface), - }; - unsafe { self.setsockopt(libc::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq) } - } - - pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { - let multiaddr = to_s_addr(multiaddr); - let interface = to_s_addr(interface); - let mreq = libc::ip_mreq { - imr_multiaddr: libc::in_addr { s_addr: multiaddr }, - imr_interface: libc::in_addr { s_addr: interface }, - }; - unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, mreq) } - } - - pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { - let multiaddr = to_in6_addr(multiaddr); - let mreq = libc::ipv6_mreq { - ipv6mr_multiaddr: multiaddr, - ipv6mr_interface: to_ipv6mr_interface(interface), - }; - unsafe { self.setsockopt(libc::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq) } - } - - pub fn linger(&self) -> io::Result> { - unsafe { - Ok(linger2dur( - self.getsockopt(libc::SOL_SOCKET, libc::SO_LINGER)?, - )) - } - } - - pub fn set_linger(&self, dur: Option) -> io::Result<()> { - unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_LINGER, dur2linger(dur)) } - } - - pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> { - unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEADDR, reuse as c_int) } - } - - pub fn reuse_address(&self) -> io::Result { - unsafe { - let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEADDR)?; - Ok(raw != 0) - } - } - - pub fn recv_buffer_size(&self) -> io::Result { - unsafe { - let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_RCVBUF)?; - Ok(raw as usize) - } - } - - pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { - unsafe { - // TODO: casting usize to a c_int should be a checked cast - self.setsockopt(libc::SOL_SOCKET, libc::SO_RCVBUF, size as c_int) - } - } - - pub fn send_buffer_size(&self) -> io::Result { - unsafe { - let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_SNDBUF)?; - Ok(raw as usize) - } - } - - pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { - unsafe { - // TODO: casting usize to a c_int should be a checked cast - self.setsockopt(libc::SOL_SOCKET, libc::SO_SNDBUF, size as c_int) - } - } - - pub fn keepalive(&self) -> io::Result> { - unsafe { - let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_KEEPALIVE)?; - if raw == 0 { - return Ok(None); - } - let secs: c_int = self.getsockopt(libc::IPPROTO_TCP, KEEPALIVE_OPTION)?; - Ok(Some(Duration::new(secs as u64, 0))) - } - } - - pub fn set_keepalive(&self, keepalive: Option) -> io::Result<()> { - unsafe { - self.setsockopt( - libc::SOL_SOCKET, - libc::SO_KEEPALIVE, - keepalive.is_some() as c_int, - )?; - if let Some(dur) = keepalive { - // TODO: checked cast here - self.setsockopt(libc::IPPROTO_TCP, KEEPALIVE_OPTION, dur.as_secs() as c_int)?; - } - Ok(()) - } - } - - unsafe fn setsockopt(&self, opt: c_int, val: c_int, payload: T) -> io::Result<()> - where - T: Copy, - { - let payload = &payload as *const T as *const c_void; - cvt(libc::setsockopt( - self.fd, - opt, - val, - payload, - mem::size_of::() as libc::socklen_t, - ))?; - Ok(()) - } - - unsafe fn getsockopt(&self, opt: c_int, val: c_int) -> io::Result { - let mut slot: T = mem::zeroed(); - let mut len = mem::size_of::() as libc::socklen_t; - cvt(libc::getsockopt( - self.fd, - opt, - val, - &mut slot as *mut _ as *mut _, - &mut len, - ))?; - assert_eq!(len as usize, mem::size_of::()); - Ok(slot) - } -} - -impl Read for Socket { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - <&Socket>::read(&mut &*self, buf) - } -} - -impl<'a> Read for &'a Socket { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - unsafe { - let n = cvt({ - libc::read( - self.fd, - buf.as_mut_ptr() as *mut c_void, - cmp::min(buf.len(), max_len()), - ) - })?; - Ok(n as usize) - } - } -} - -impl Write for Socket { - fn write(&mut self, buf: &[u8]) -> io::Result { - <&Socket>::write(&mut &*self, buf) - } - - fn flush(&mut self) -> io::Result<()> { - <&Socket>::flush(&mut &*self) - } -} - -impl<'a> Write for &'a Socket { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.send(buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl fmt::Debug for Socket { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut f = f.debug_struct("Socket"); - f.field("fd", &self.fd); - if let Ok(addr) = self.local_addr() { - f.field("local_addr", &addr); - } - if let Ok(addr) = self.peer_addr() { - f.field("peer_addr", &addr); - } - f.finish() - } -} - -impl AsRawFd for Socket { - fn as_raw_fd(&self) -> RawFd { - self.fd as RawFd - } -} - -impl IntoRawFd for Socket { - fn into_raw_fd(self) -> RawFd { - let fd = self.fd as RawFd; - mem::forget(self); - return fd; - } -} - -impl FromRawFd for Socket { - unsafe fn from_raw_fd(fd: RawFd) -> Socket { - Socket { fd: fd as c_int } - } -} - -impl AsRawFd for crate::Socket { - fn as_raw_fd(&self) -> RawFd { - self.inner.as_raw_fd() - } -} - -impl IntoRawFd for crate::Socket { - fn into_raw_fd(self) -> RawFd { - self.inner.into_raw_fd() - } -} - -impl FromRawFd for crate::Socket { - unsafe fn from_raw_fd(fd: RawFd) -> crate::Socket { - crate::Socket { - inner: Socket::from_raw_fd(fd), - } - } -} - -impl Drop for Socket { - fn drop(&mut self) { - unsafe { - let _ = libc::close(self.fd); - } - } -} - -impl From for net::TcpStream { - fn from(socket: Socket) -> net::TcpStream { - unsafe { net::TcpStream::from_raw_fd(socket.into_raw_fd()) } - } -} - -impl From for net::TcpListener { - fn from(socket: Socket) -> net::TcpListener { - unsafe { net::TcpListener::from_raw_fd(socket.into_raw_fd()) } - } -} - -impl From for net::UdpSocket { - fn from(socket: Socket) -> net::UdpSocket { - unsafe { net::UdpSocket::from_raw_fd(socket.into_raw_fd()) } - } -} - -impl From for Socket { - fn from(socket: net::TcpStream) -> Socket { - unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } - } -} - -impl From for Socket { - fn from(socket: net::TcpListener) -> Socket { - unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } - } -} - -impl From for Socket { - fn from(socket: net::UdpSocket) -> Socket { - unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } - } -} - -fn max_len() -> usize { - // The maximum read limit on most posix-like systems is `SSIZE_MAX`, - // with the man page quoting that if the count of bytes to read is - // greater than `SSIZE_MAX` the result is "unspecified". - ::max_value() as usize -} - -fn cvt>(t: T) -> io::Result { - let one: T = T::one(); - if t == -one { - Err(io::Error::last_os_error()) - } else { - Ok(t) - } -} - -fn set_cloexec(fd: c_int) -> io::Result<()> { - unsafe { - let previous = cvt(libc::fcntl(fd, libc::F_GETFD))?; - let new = previous | syscall::O_CLOEXEC as i32; - if new != previous { - cvt(libc::fcntl(fd, libc::F_SETFD, new))?; - } - Ok(()) - } -} - -fn dur2timeval(dur: Option) -> io::Result { - match dur { - Some(dur) => { - if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { - return Err(io::Error::new( - ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); - } - - let secs = if dur.as_secs() > libc::time_t::max_value() as u64 { - libc::time_t::max_value() - } else { - dur.as_secs() as libc::time_t - }; - let mut timeout = libc::timeval { - tv_sec: secs, - tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t, - }; - if timeout.tv_sec == 0 && timeout.tv_usec == 0 { - timeout.tv_usec = 1; - } - Ok(timeout) - } - None => Ok(libc::timeval { - tv_sec: 0, - tv_usec: 0, - }), - } -} - -fn timeval2dur(raw: libc::timeval) -> Option { - if raw.tv_sec == 0 && raw.tv_usec == 0 { - None - } else { - let sec = raw.tv_sec as u64; - let nsec = (raw.tv_usec as u32) * 1000; - Some(Duration::new(sec, nsec)) - } -} - -fn to_s_addr(addr: &Ipv4Addr) -> libc::in_addr_t { - let octets = addr.octets(); - crate::hton( - ((octets[0] as libc::in_addr_t) << 24) - | ((octets[1] as libc::in_addr_t) << 16) - | ((octets[2] as libc::in_addr_t) << 8) - | ((octets[3] as libc::in_addr_t) << 0), - ) -} - -fn to_in6_addr(addr: &Ipv6Addr) -> libc::in6_addr { - let mut ret: libc::in6_addr = unsafe { mem::zeroed() }; - ret.s6_addr = addr.octets(); - return ret; -} - -fn to_ipv6mr_interface(value: u32) -> libc::c_uint { - value as libc::c_uint -} - -fn linger2dur(linger_opt: libc::linger) -> Option { - if linger_opt.l_onoff == 0 { - None - } else { - Some(Duration::from_secs(linger_opt.l_linger as u64)) - } -} - -fn dur2linger(dur: Option) -> libc::linger { - match dur { - Some(d) => libc::linger { - l_onoff: 1, - l_linger: d.as_secs() as c_int, - }, - None => libc::linger { - l_onoff: 0, - l_linger: 0, - }, - } -} - -#[test] -fn test_ip() { - let ip = Ipv4Addr::new(127, 0, 0, 1); - assert_eq!(ip, from_s_addr(to_s_addr(&ip))); -} diff --git a/src/sys/unix.rs b/src/sys/unix.rs index e138e684..8c2b2c45 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -65,8 +65,15 @@ pub const IPPROTO_ICMP: i32 = libc::IPPROTO_ICMP; pub const IPPROTO_ICMPV6: i32 = libc::IPPROTO_ICMPV6; pub const IPPROTO_TCP: i32 = libc::IPPROTO_TCP; pub const IPPROTO_UDP: i32 = libc::IPPROTO_UDP; -pub const SOCK_SEQPACKET: i32 = libc::SOCK_SEQPACKET; -pub const SOCK_RAW: i32 = libc::SOCK_RAW; +cfg_if::cfg_if! { + if #[cfg(target_os = "redox")] { + pub const SOCK_RAW: i32 = -1; + pub const SOCK_SEQPACKET: i32 = -1; + } else { + pub const SOCK_SEQPACKET: i32 = libc::SOCK_SEQPACKET; + pub const SOCK_RAW: i32 = libc::SOCK_RAW; + } +} pub struct Socket { fd: c_int, From 75fe3f2fe0e3079ad9d4dfb3a19e60bea3f2f055 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 13 Jan 2020 08:55:33 -0800 Subject: [PATCH 24/51] Bump libc version req --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2a345931..2a3fe5b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ features = ["handleapi", "ws2def", "ws2ipdef", "ws2tcpip", "minwindef"] [target."cfg(any(unix, target_os = \"redox\"))".dependencies] cfg-if = "0.1.6" -libc = "0.2" +libc = "0.2.66" [target."cfg(target_os = \"redox\")".dependencies] redox_syscall = "0.1.38" From ec8df47a430da6c0343c2f3e908742ac0d8fe0b6 Mon Sep 17 00:00:00 2001 From: oskardrums <60015476+oskardrums@users.noreply.github.com> Date: Tue, 21 Jan 2020 22:41:33 +0200 Subject: [PATCH 25/51] Support Out-of-Band related functionality (#51) * sys/unix/Socket: support OOBINLINE socket option * Socket: add flags argument where appropriate allow callers to specify flags for send/recv * Windows: set flags in send/recv for Read/Write * satisfy rustfmt * Socket: retain the current public interface Maintain send/recv's current signature and expose the flags argument via _with_flags methods --- src/socket.rs | 138 +++++++++++++++++++++++++++++++++++++++++++-- src/sys/unix.rs | 42 +++++++++----- src/sys/windows.rs | 44 ++++++++++----- 3 files changed, 193 insertions(+), 31 deletions(-) diff --git a/src/socket.rs b/src/socket.rs index 3d5fe7e7..9ef64703 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -20,6 +20,11 @@ use libc as c; #[cfg(windows)] use winapi::shared::ws2def as c; +#[cfg(any(unix, target_os = "redox"))] +use libc::MSG_OOB; +#[cfg(windows)] +use winapi::um::winsock2::MSG_OOB; + use crate::sys; use crate::{Domain, Protocol, SockAddr, Socket, Type}; @@ -213,7 +218,26 @@ impl Socket { /// /// [`connect`]: #method.connect pub fn recv(&self, buf: &mut [u8]) -> io::Result { - self.inner.recv(buf) + self.inner.recv(buf, 0) + } + + /// Identical to [`recv`] but allows for specification of arbitrary flags to the underlying + /// `recv` call. + /// + /// [`recv`]: #method.recv + pub fn recv_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result { + self.inner.recv(buf, flags) + } + + /// Receives out-of-band (OOB) data on the socket from the remote address to + /// which it is connected by setting the `MSG_OOB` flag for this call. + /// + /// For more information, see [`recv`], [`out_of_band_inline`]. + /// + /// [`recv`]: #method.recv + /// [`out_of_band_inline`]: #method.out_of_band_inline + pub fn recv_out_of_band(&self, buf: &mut [u8]) -> io::Result { + self.inner.recv(buf, MSG_OOB) } /// Receives data on the socket from the remote adress to which it is @@ -229,7 +253,15 @@ impl Socket { /// Receives data from the socket. On success, returns the number of bytes /// read and the address from whence the data came. pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { - self.inner.recv_from(buf) + self.inner.recv_from(buf, 0) + } + + /// Identical to [`recv_from`] but allows for specification of arbitrary flags to the underlying + /// `recvfrom` call. + /// + /// [`recv_from`]: #method.recv_from + pub fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result { + self.inner.recv(buf, flags) } /// Receives data from the socket, without removing it from the queue. @@ -250,7 +282,26 @@ impl Socket { /// /// On success returns the number of bytes that were sent. pub fn send(&self, buf: &[u8]) -> io::Result { - self.inner.send(buf) + self.inner.send(buf, 0) + } + + /// Identical to [`send`] but allows for specification of arbitrary flags to the underlying + /// `send` call. + /// + /// [`send`]: #method.send + pub fn send_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result { + self.inner.send(buf, flags) + } + + /// Sends out-of-band (OOB) data on the socket to connected peer + /// by setting the `MSG_OOB` flag for this call. + /// + /// For more information, see [`send`], [`out_of_band_inline`]. + /// + /// [`send`]: #method.send + /// [`out_of_band_inline`]: #method.out_of_band_inline + pub fn send_out_of_band(&self, buf: &mut [u8]) -> io::Result { + self.inner.send(buf, MSG_OOB) } /// Sends data on the socket to the given address. On success, returns the @@ -259,7 +310,15 @@ impl Socket { /// This is typically used on UDP or datagram-oriented sockets. On success /// returns the number of bytes that were sent. pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result { - self.inner.send_to(buf, addr) + self.inner.send_to(buf, 0, addr) + } + + /// Identical to [`send_to`] but allows for specification of arbitrary flags to the underlying + /// `sendto` call. + /// + /// [`send_to`]: #method.send_to + pub fn send_to_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result { + self.inner.recv(buf, flags) } // ================================================ @@ -628,6 +687,24 @@ impl Socket { self.inner.set_keepalive(keepalive) } + /// Returns the value of the `SO_OOBINLINE` flag of the underlying socket. + /// For more information about this option, see [`set_out_of_band_inline`][link]. + /// + /// [link]: #method.set_out_of_band_inline + pub fn out_of_band_inline(&self) -> io::Result { + self.inner.out_of_band_inline() + } + + /// Sets the `SO_OOBINLINE` flag of the underlying socket. + /// as per RFC6093, TCP sockets using the Urgent mechanism + /// are encouraged to set this flag. + /// + /// If this flag is not set, the `MSG_OOB` flag is needed + /// while `recv`ing to aquire the out-of-band data. + pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> { + self.inner.set_out_of_band_inline(oob_inline) + } + /// Check the value of the `SO_REUSEPORT` option on this socket. /// /// This function is only available on Unix when the `reuseport` feature is @@ -1003,4 +1080,57 @@ mod test { assert!(result.is_ok()); assert!(result.unwrap()); } + + #[test] + fn out_of_band_inline() { + let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + + assert_eq!(socket.out_of_band_inline().unwrap(), false); + + socket.set_out_of_band_inline(true).unwrap(); + assert_eq!(socket.out_of_band_inline().unwrap(), true); + } + + #[test] + #[cfg(any(target_os = "windows", target_os = "linux"))] + fn out_of_band_send_recv() { + let s1 = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + s1.bind(&"127.0.0.1:0".parse::().unwrap().into()) + .unwrap(); + let s1_addr = s1.local_addr().unwrap(); + s1.listen(1).unwrap(); + + let s2 = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + s2.connect(&s1_addr).unwrap(); + + let (s3, _) = s1.accept().unwrap(); + + let mut buf = [0; 10]; + // send some plain inband data + s2.send(&mut buf).unwrap(); + // send a single out of band byte + assert_eq!(s2.send_out_of_band(&mut [b"!"[0]]).unwrap(), 1); + // recv the OOB data first + assert_eq!(s3.recv_out_of_band(&mut buf).unwrap(), 1); + assert_eq!(buf[0], b"!"[0]); + assert_eq!(s3.recv(&mut buf).unwrap(), 10); + } + + #[test] + fn tcp() { + let s1 = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + s1.bind(&"127.0.0.1:0".parse::().unwrap().into()) + .unwrap(); + let s1_addr = s1.local_addr().unwrap(); + s1.listen(1).unwrap(); + + let s2 = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); + s2.connect(&s1_addr).unwrap(); + + let (s3, _) = s1.accept().unwrap(); + + let mut buf = [0; 11]; + assert_eq!(s2.send(&mut buf).unwrap(), 11); + assert_eq!(s3.recv(&mut buf).unwrap(), 11); + } } diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 8c2b2c45..757802ce 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -349,14 +349,14 @@ impl Socket { Ok(()) } - pub fn recv(&self, buf: &mut [u8]) -> io::Result { + pub fn recv(&self, buf: &mut [u8], flags: c_int) -> io::Result { unsafe { let n = cvt({ libc::recv( self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), max_len()), - 0, + flags, ) })?; Ok(n as usize) @@ -377,15 +377,11 @@ impl Socket { } } - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { - self.recvfrom(buf, 0) - } - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { - self.recvfrom(buf, libc::MSG_PEEK) + self.recv_from(buf, libc::MSG_PEEK) } - fn recvfrom(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> { + pub fn recv_from(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> { unsafe { let mut storage: libc::sockaddr_storage = mem::zeroed(); let mut addrlen = mem::size_of_val(&storage) as socklen_t; @@ -405,28 +401,28 @@ impl Socket { } } - pub fn send(&self, buf: &[u8]) -> io::Result { + pub fn send(&self, buf: &[u8], flags: c_int) -> io::Result { unsafe { let n = cvt({ libc::send( self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), max_len()), - MSG_NOSIGNAL, + flags, ) })?; Ok(n as usize) } } - pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result { + pub fn send_to(&self, buf: &[u8], flags: c_int, addr: &SockAddr) -> io::Result { unsafe { let n = cvt({ libc::sendto( self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), max_len()), - MSG_NOSIGNAL, + flags, addr.as_ptr(), addr.len(), ) @@ -744,6 +740,17 @@ impl Socket { unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT, reuse as c_int) } } + pub fn out_of_band_inline(&self) -> io::Result { + unsafe { + let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_OOBINLINE)?; + Ok(raw != 0) + } + } + + pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> { + unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_OOBINLINE, oob_inline as c_int) } + } + unsafe fn setsockopt(&self, opt: c_int, val: c_int, payload: T) -> io::Result<()> where T: Copy, @@ -807,7 +814,7 @@ impl Write for Socket { impl<'a> Write for &'a Socket { fn write(&mut self, buf: &[u8]) -> io::Result { - self.send(buf) + self.send(buf, 0) } fn flush(&mut self) -> io::Result<()> { @@ -1108,3 +1115,12 @@ fn test_ip() { let ip = Ipv4Addr::new(127, 0, 0, 1); assert_eq!(ip, from_s_addr(to_s_addr(&ip))); } + +#[test] +fn test_out_of_band_inline() { + let tcp = Socket::new(libc::AF_INET, libc::SOCK_STREAM, 0).unwrap(); + assert_eq!(tcp.out_of_band_inline().unwrap(), false); + + tcp.set_out_of_band_inline(true).unwrap(); + assert_eq!(tcp.out_of_band_inline().unwrap(), true); +} diff --git a/src/sys/windows.rs b/src/sys/windows.rs index d2c5a882..be651f19 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -285,14 +285,14 @@ impl Socket { } } - pub fn recv(&self, buf: &mut [u8]) -> io::Result { + pub fn recv(&self, buf: &mut [u8], flags: c_int) -> io::Result { unsafe { let n = { sock::recv( self.socket, buf.as_mut_ptr() as *mut c_char, clamp(buf.len()), - 0, + flags, ) }; match n { @@ -321,15 +321,11 @@ impl Socket { } } - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { - self.recvfrom(buf, 0) - } - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { - self.recvfrom(buf, MSG_PEEK) + self.recv_from(buf, MSG_PEEK) } - fn recvfrom(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> { + pub fn recv_from(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> { unsafe { let mut storage: SOCKADDR_STORAGE = mem::zeroed(); let mut addrlen = mem::size_of_val(&storage) as c_int; @@ -354,14 +350,14 @@ impl Socket { } } - pub fn send(&self, buf: &[u8]) -> io::Result { + pub fn send(&self, buf: &[u8], flags: c_int) -> io::Result { unsafe { let n = { sock::send( self.socket, buf.as_ptr() as *const c_char, clamp(buf.len()), - 0, + flags, ) }; if n == sock::SOCKET_ERROR { @@ -372,14 +368,14 @@ impl Socket { } } - pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result { + pub fn send_to(&self, buf: &[u8], flags: c_int, addr: &SockAddr) -> io::Result { unsafe { let n = { sock::sendto( self.socket, buf.as_ptr() as *const c_char, clamp(buf.len()), - 0, + flags, addr.as_ptr(), addr.len(), ) @@ -688,6 +684,17 @@ impl Socket { } } + pub fn out_of_band_inline(&self) -> io::Result { + unsafe { + let raw: c_int = self.getsockopt(SOL_SOCKET, SO_OOBINLINE)?; + Ok(raw != 0) + } + } + + pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> { + unsafe { self.setsockopt(SOL_SOCKET, SO_OOBINLINE, oob_inline as c_int) } + } + unsafe fn setsockopt(&self, opt: c_int, val: c_int, payload: T) -> io::Result<()> where T: Copy, @@ -738,7 +745,7 @@ impl Read for Socket { impl<'a> Read for &'a Socket { fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.recv(buf) + self.recv(buf, 0) } } @@ -754,7 +761,7 @@ impl Write for Socket { impl<'a> Write for &'a Socket { fn write(&mut self, buf: &[u8]) -> io::Result { - self.send(buf) + self.send(buf, 0) } fn flush(&mut self) -> io::Result<()> { @@ -975,3 +982,12 @@ fn test_ip() { let ip = Ipv4Addr::new(127, 0, 0, 1); assert_eq!(ip, from_s_addr(to_s_addr(&ip))); } + +#[test] +fn test_out_of_band_inline() { + let tcp = Socket::new(AF_INET, SOCK_STREAM, 0).unwrap(); + assert_eq!(tcp.out_of_band_inline().unwrap(), false); + + tcp.set_out_of_band_inline(true).unwrap(); + assert_eq!(tcp.out_of_band_inline().unwrap(), true); +} From 8a55a007cab7135b18a7f812b2ae57786ae6f63d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 28 Jan 2020 00:38:38 -0800 Subject: [PATCH 26/51] Update CI installation of Rust on macos --- .github/workflows/main.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 417f8889..c82a077e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,13 +28,7 @@ jobs: - uses: actions/checkout@master - name: Install Rust (rustup) run: rustup update ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} - if: matrix.os != 'macos-latest' shell: bash - - name: Install Rust (macos) - run: | - curl https://sh.rustup.rs | sh -s -- -y - echo "##[add-path]$HOME/.cargo/bin" - if: matrix.os == 'macos-latest' - run: cargo test - run: cargo test --features reuseport - run: cargo test --features unix From 230d413459911812bb9647b697b681217aae008d Mon Sep 17 00:00:00 2001 From: Patrick Mooney Date: Thu, 26 Mar 2020 10:28:00 -0500 Subject: [PATCH 27/51] Add support for illumos target (#54) --- src/socket.rs | 12 ++++++++++-- src/sys/unix.rs | 15 ++++++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/socket.rs b/src/socket.rs index 9ef64703..e49bdfe2 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -709,7 +709,11 @@ impl Socket { /// /// This function is only available on Unix when the `reuseport` feature is /// enabled. - #[cfg(all(unix, not(target_os = "solaris"), feature = "reuseport"))] + #[cfg(all( + unix, + not(any(target_os = "solaris", target_os = "illumos")), + feature = "reuseport" + ))] pub fn reuse_port(&self) -> io::Result { self.inner.reuse_port() } @@ -722,7 +726,11 @@ impl Socket { /// /// This function is only available on Unix when the `reuseport` feature is /// enabled. - #[cfg(all(unix, not(target_os = "solaris"), feature = "reuseport"))] + #[cfg(all( + unix, + not(any(target_os = "solaris", target_os = "illumos")), + feature = "reuseport" + ))] pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> { self.inner.set_reuse_port(reuse) } diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 757802ce..00272274 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -28,7 +28,8 @@ cfg_if::cfg_if! { if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "openbsd", target_os = "netbsd", - target_os = "solaris", target_os = "haiku"))] { + target_os = "solaris", target_os = "illumos", + target_os = "haiku"))] { use libc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; use libc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; } else { @@ -727,7 +728,11 @@ impl Socket { } } - #[cfg(all(unix, not(target_os = "solaris"), feature = "reuseport"))] + #[cfg(all( + unix, + not(any(target_os = "solaris", target_os = "illumos")), + feature = "reuseport" + ))] pub fn reuse_port(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT)?; @@ -735,7 +740,11 @@ impl Socket { } } - #[cfg(all(unix, not(target_os = "solaris"), feature = "reuseport"))] + #[cfg(all( + unix, + not(any(target_os = "solaris", target_os = "illumos")), + feature = "reuseport" + ))] pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> { unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT, reuse as c_int) } } From 850ad9078fe1f2b4d8e1a07ed7dfbd72c0c712d2 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Mon, 30 Mar 2020 15:02:58 +0000 Subject: [PATCH 28/51] Use Once::new on Windows (#58) ONCE_INIT is deprecated. --- src/sys/windows.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/windows.rs b/src/sys/windows.rs index be651f19..952407b6 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -17,7 +17,7 @@ use std::net::Shutdown; use std::net::{self, Ipv4Addr, Ipv6Addr}; use std::os::windows::prelude::*; use std::ptr; -use std::sync::{Once, ONCE_INIT}; +use std::sync::Once; use std::time::Duration; use winapi::ctypes::{c_char, c_int, c_long, c_ulong}; @@ -58,7 +58,7 @@ struct tcp_keepalive { } fn init() { - static INIT: Once = ONCE_INIT; + static INIT: Once = Once::new(); INIT.call_once(|| { // Initialize winsock through the standard library by just creating a From 536121a6e005311d8edd52dc50cb6ce16dc1c535 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Mon, 30 Mar 2020 15:03:16 +0000 Subject: [PATCH 29/51] Replace mem::uninitialized with MaybeUninit (#55) mem::uninitialized is deprecated. --- src/sockaddr.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 79f3c61d..59701085 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -1,5 +1,5 @@ use std::fmt; -use std::mem; +use std::mem::{self, MaybeUninit}; use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; use std::ptr; @@ -36,7 +36,7 @@ impl fmt::Debug for SockAddr { impl SockAddr { /// Constructs a `SockAddr` from its raw components. pub unsafe fn from_raw_parts(addr: *const sockaddr, len: socklen_t) -> SockAddr { - let mut storage = mem::uninitialized::(); + let mut storage = MaybeUninit::::uninit(); ptr::copy_nonoverlapping( addr as *const _ as *const u8, &mut storage as *mut _ as *mut u8, @@ -44,7 +44,8 @@ impl SockAddr { ); SockAddr { - storage: storage, + // This is safe as we written the address to `storage` above. + storage: storage.assume_init(), len: len, } } From 3de176f2c82a724969fb96766b4288f9cb549de0 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Mon, 30 Mar 2020 15:16:57 +0000 Subject: [PATCH 30/51] Move Domain (#57) * Move Domain impl to where the type is defined * Move Unix only Domain methods to unix file * Fix compilation on Windows --- src/lib.rs | 26 ++++++++++++++++++++++++++ src/socket.rs | 42 ------------------------------------------ src/sys/unix.rs | 34 ++++++++++++++++++++++++++-------- src/sys/windows.rs | 12 +++++++++--- 4 files changed, 61 insertions(+), 53 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0bd17aba..677c059f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,6 +57,8 @@ mod sys; #[path = "sys/windows.rs"] mod sys; +use sys::c_int; + /// Newtype, owned, wrapper around a system socket. /// /// This type simply wraps an instance of a file descriptor (`c_int`) on Unix @@ -107,6 +109,30 @@ pub struct SockAddr { #[derive(Copy, Clone)] pub struct Domain(i32); +impl Domain { + /// Domain for IPv4 communication, corresponding to `AF_INET`. + pub fn ipv4() -> Domain { + Domain(sys::AF_INET) + } + + /// Domain for IPv6 communication, corresponding to `AF_INET6`. + pub fn ipv6() -> Domain { + Domain(sys::AF_INET6) + } +} + +impl From for Domain { + fn from(d: c_int) -> Domain { + Domain(d) + } +} + +impl From for c_int { + fn from(d: Domain) -> c_int { + d.0 + } +} + /// Specification of communication semantics on a socket. /// /// This is a newtype wrapper around an integer which provides a nicer API in diff --git a/src/socket.rs b/src/socket.rs index e49bdfe2..d793ea1e 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -864,48 +864,6 @@ impl From for UnixDatagram { } } -impl Domain { - /// Domain for IPv4 communication, corresponding to `AF_INET`. - pub fn ipv4() -> Domain { - Domain(c::AF_INET) - } - - /// Domain for IPv6 communication, corresponding to `AF_INET6`. - pub fn ipv6() -> Domain { - Domain(c::AF_INET6) - } - - /// Domain for Unix socket communication, corresponding to `AF_UNIX`. - /// - /// This function is only available on Unix when the `unix` feature is - /// activated. - #[cfg(all(unix, feature = "unix"))] - pub fn unix() -> Domain { - Domain(c::AF_UNIX) - } - - /// Domain for low-level packet interface, corresponding to `AF_PACKET`. - /// - /// This function is only available on Linux when the `unix` feature is - /// activated. - #[cfg(all(unix, feature = "unix", target_os = "linux"))] - pub fn packet() -> Domain { - Domain(c::AF_PACKET) - } -} - -impl From for Domain { - fn from(a: i32) -> Domain { - Domain(a) - } -} - -impl From for i32 { - fn from(a: Domain) -> i32 { - a.0 - } -} - impl Type { /// Type corresponding to `SOCK_STREAM` /// diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 00272274..d5ebce16 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -22,8 +22,15 @@ use std::os::unix::prelude::*; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; -use libc::{self, c_int, c_void, socklen_t, ssize_t}; +use libc::{self, c_void, socklen_t, ssize_t}; +use crate::Domain; + +#[allow(non_camel_case_types)] +pub(crate) type c_int = libc::c_int; + +// Used in `Domain`. +pub(crate) use libc::{AF_INET, AF_INET6}; cfg_if::cfg_if! { if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", @@ -37,6 +44,8 @@ cfg_if::cfg_if! { use libc::IPV6_DROP_MEMBERSHIP; } } +// Used in `Type`. +pub(crate) use libc::{SOCK_RAW, SOCK_SEQPACKET}; cfg_if::cfg_if! { if #[cfg(any(target_os = "linux", target_os = "android", @@ -66,13 +75,22 @@ pub const IPPROTO_ICMP: i32 = libc::IPPROTO_ICMP; pub const IPPROTO_ICMPV6: i32 = libc::IPPROTO_ICMPV6; pub const IPPROTO_TCP: i32 = libc::IPPROTO_TCP; pub const IPPROTO_UDP: i32 = libc::IPPROTO_UDP; -cfg_if::cfg_if! { - if #[cfg(target_os = "redox")] { - pub const SOCK_RAW: i32 = -1; - pub const SOCK_SEQPACKET: i32 = -1; - } else { - pub const SOCK_SEQPACKET: i32 = libc::SOCK_SEQPACKET; - pub const SOCK_RAW: i32 = libc::SOCK_RAW; + +/// Unix only API. +impl Domain { + /// Domain for Unix socket communication, corresponding to `AF_UNIX`. + pub fn unix() -> Domain { + Domain(libc::AF_UNIX) + } + + /// Domain for low-level packet interface, corresponding to `AF_PACKET`. + /// + /// # Notes + /// + /// This function is only available on Linux. + #[cfg(target_os = "linux")] + pub fn packet() -> Domain { + Domain(libc::AF_PACKET) } } diff --git a/src/sys/windows.rs b/src/sys/windows.rs index 952407b6..d7bcbbb4 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -20,7 +20,7 @@ use std::ptr; use std::sync::Once; use std::time::Duration; -use winapi::ctypes::{c_char, c_int, c_long, c_ulong}; +use winapi::ctypes::{c_char, c_long, c_ulong}; use winapi::shared::in6addr::*; use winapi::shared::inaddr::*; use winapi::shared::minwindef::DWORD; @@ -47,8 +47,14 @@ pub const IPPROTO_ICMP: i32 = ws2def::IPPROTO_ICMP as i32; pub const IPPROTO_ICMPV6: i32 = ws2def::IPPROTO_ICMPV6 as i32; pub const IPPROTO_TCP: i32 = ws2def::IPPROTO_TCP as i32; pub const IPPROTO_UDP: i32 = ws2def::IPPROTO_UDP as i32; -pub const SOCK_SEQPACKET: i32 = ws2def::SOCK_SEQPACKET as i32; -pub const SOCK_RAW: i32 = ws2def::SOCK_RAW as i32; + +#[allow(non_camel_case_types)] +pub(crate) type c_int = winapi::ctypes::c_int; + +// Used in `Domain`. +pub(crate) use winapi::shared::ws2def::{AF_INET, AF_INET6}; +// Used in `Type`. +pub(crate) use winapi::shared::ws2def::{SOCK_RAW, SOCK_SEQPACKET}; #[repr(C)] struct tcp_keepalive { From 085762e090ead2029ddc45b52bca732caafd0a7b Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Tue, 31 Mar 2020 18:11:15 +0000 Subject: [PATCH 31/51] Move Type impl where its defined (#59) Also add Type::{non_blocking, cloexec} on OSes that support it. --- src/lib.rs | 39 +++++++++++++++++++++++++++++++ src/socket.rs | 43 ---------------------------------- src/sys/unix.rs | 57 ++++++++++++++++++++++++++++++++++------------ src/sys/windows.rs | 2 +- 4 files changed, 83 insertions(+), 58 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 677c059f..e2388da5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -145,6 +145,45 @@ impl From for c_int { #[derive(Copy, Clone)] pub struct Type(i32); +impl Type { + /// Type corresponding to `SOCK_STREAM`. + /// + /// Used for protocols such as TCP. + pub fn stream() -> Type { + Type(sys::SOCK_STREAM) + } + + /// Type corresponding to `SOCK_DGRAM`. + /// + /// Used for protocols such as UDP. + pub fn dgram() -> Type { + Type(sys::SOCK_DGRAM) + } + + /// Type corresponding to `SOCK_SEQPACKET`. + pub fn seqpacket() -> Type { + Type(sys::SOCK_SEQPACKET) + } + + /// Type corresponding to `SOCK_RAW`. + #[cfg(not(target_os = "redox"))] + pub fn raw() -> Type { + Type(sys::SOCK_RAW) + } +} + +impl From for Type { + fn from(t: c_int) -> Type { + Type(t) + } +} + +impl From for c_int { + fn from(t: Type) -> c_int { + t.0 + } +} + /// Protocol specification used for creating sockets via `Socket::new`. /// /// This is a newtype wrapper around an integer which provides a nicer API in diff --git a/src/socket.rs b/src/socket.rs index d793ea1e..53d34896 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -15,11 +15,6 @@ use std::net::{self, Ipv4Addr, Ipv6Addr, Shutdown}; use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; use std::time::Duration; -#[cfg(any(unix, target_os = "redox"))] -use libc as c; -#[cfg(windows)] -use winapi::shared::ws2def as c; - #[cfg(any(unix, target_os = "redox"))] use libc::MSG_OOB; #[cfg(windows)] @@ -864,32 +859,6 @@ impl From for UnixDatagram { } } -impl Type { - /// Type corresponding to `SOCK_STREAM` - /// - /// Used for protocols such as TCP. - pub fn stream() -> Type { - Type(c::SOCK_STREAM) - } - - /// Type corresponding to `SOCK_DGRAM` - /// - /// Used for protocols such as UDP. - pub fn dgram() -> Type { - Type(c::SOCK_DGRAM) - } - - /// Type corresponding to `SOCK_SEQPACKET` - pub fn seqpacket() -> Type { - Type(sys::SOCK_SEQPACKET) - } - - /// Type corresponding to `SOCK_RAW` - pub fn raw() -> Type { - Type(sys::SOCK_RAW) - } -} - impl crate::Protocol { /// Protocol corresponding to `ICMPv4` pub fn icmpv4() -> Self { @@ -912,18 +881,6 @@ impl crate::Protocol { } } -impl From for Type { - fn from(a: i32) -> Type { - Type(a) - } -} - -impl From for i32 { - fn from(a: Type) -> i32 { - a.0 - } -} - impl From for Protocol { fn from(a: i32) -> Protocol { Protocol(a) diff --git a/src/sys/unix.rs b/src/sys/unix.rs index d5ebce16..856500f6 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -24,13 +24,16 @@ use std::time::{Duration, Instant}; use libc::{self, c_void, socklen_t, ssize_t}; -use crate::Domain; +use crate::{Domain, Type}; #[allow(non_camel_case_types)] pub(crate) type c_int = libc::c_int; // Used in `Domain`. pub(crate) use libc::{AF_INET, AF_INET6}; +// Used in `Type`. +pub(crate) use libc::{SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET, SOCK_STREAM}; + cfg_if::cfg_if! { if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", @@ -44,19 +47,6 @@ cfg_if::cfg_if! { use libc::IPV6_DROP_MEMBERSHIP; } } -// Used in `Type`. -pub(crate) use libc::{SOCK_RAW, SOCK_SEQPACKET}; - -cfg_if::cfg_if! { - if #[cfg(any(target_os = "linux", target_os = "android", - target_os = "dragonfly", target_os = "freebsd", - target_os = "openbsd", target_os = "netbsd", - target_os = "haiku", target_os = "bitrig"))] { - use libc::MSG_NOSIGNAL; - } else { - const MSG_NOSIGNAL: c_int = 0x0; - } -} cfg_if::cfg_if! { if #[cfg(any(target_os = "macos", target_os = "ios"))] { @@ -94,6 +84,45 @@ impl Domain { } } +/// Unix only API. +impl Type { + /// Set `SOCK_NONBLOCK` on the `Type`. + /// + /// # Notes + /// + /// This function is only available on Android, DragonFlyBSD, FreeBSD, + /// Linux, NetBSD and OpenBSD. + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd" + ))] + pub fn non_blocking(self) -> Type { + Type(self.0 | libc::SOCK_NONBLOCK) + } + + /// Set `SOCK_CLOEXEC` on the `Type`. + /// + /// # Notes + /// + /// This function is only available on Android, DragonFlyBSD, FreeBSD, + /// Linux, NetBSD and OpenBSD. + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd" + ))] + pub fn cloexec(self) -> Type { + Type(self.0 | libc::SOCK_CLOEXEC) + } +} + pub struct Socket { fd: c_int, } diff --git a/src/sys/windows.rs b/src/sys/windows.rs index d7bcbbb4..871dd4f6 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -54,7 +54,7 @@ pub(crate) type c_int = winapi::ctypes::c_int; // Used in `Domain`. pub(crate) use winapi::shared::ws2def::{AF_INET, AF_INET6}; // Used in `Type`. -pub(crate) use winapi::shared::ws2def::{SOCK_RAW, SOCK_SEQPACKET}; +pub(crate) use winapi::shared::ws2def::{SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET, SOCK_STREAM}; #[repr(C)] struct tcp_keepalive { From 7dd551fe8e5816184102b39a0b2e814b5c787e42 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Tue, 31 Mar 2020 18:11:43 +0000 Subject: [PATCH 32/51] Always use C's int type (#60) Although most platforms use a signed 32bit integer (i32) as C's int type it is allowed to only be 16 bits or larger then 32 bit. Using the type as defined by libc/winapi ensures we don't have to worry about it. --- src/lib.rs | 12 ++++++------ src/sys/unix.rs | 3 +-- src/sys/windows.rs | 3 +-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e2388da5..a85cffed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,10 +104,10 @@ pub struct SockAddr { /// such as `Domain::ipv4`, `Domain::ipv6`, etc, are provided to avoid reaching /// into libc for various constants. /// -/// This type is freely interconvertible with the `i32` type, however, if a raw +/// This type is freely interconvertible with C's `int` type, however, if a raw /// value needs to be provided. #[derive(Copy, Clone)] -pub struct Domain(i32); +pub struct Domain(c_int); impl Domain { /// Domain for IPv4 communication, corresponding to `AF_INET`. @@ -140,10 +140,10 @@ impl From for c_int { /// such as `Type::stream`, `Type::dgram`, etc, are provided to avoid reaching /// into libc for various constants. /// -/// This type is freely interconvertible with the `i32` type, however, if a raw +/// This type is freely interconvertible with C's `int` type, however, if a raw /// value needs to be provided. #[derive(Copy, Clone)] -pub struct Type(i32); +pub struct Type(c_int); impl Type { /// Type corresponding to `SOCK_STREAM`. @@ -189,10 +189,10 @@ impl From for c_int { /// This is a newtype wrapper around an integer which provides a nicer API in /// addition to an injection point for documentation. /// -/// This type is freely interconvertible with the `i32` type, however, if a raw +/// This type is freely interconvertible with C's `int` type, however, if a raw /// value needs to be provided. #[derive(Copy, Clone)] -pub struct Protocol(i32); +pub struct Protocol(c_int); fn hton(i: I) -> I { i.to_be() diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 856500f6..83c9396c 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -26,8 +26,7 @@ use libc::{self, c_void, socklen_t, ssize_t}; use crate::{Domain, Type}; -#[allow(non_camel_case_types)] -pub(crate) type c_int = libc::c_int; +pub use libc::c_int; // Used in `Domain`. pub(crate) use libc::{AF_INET, AF_INET6}; diff --git a/src/sys/windows.rs b/src/sys/windows.rs index 871dd4f6..191a9934 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -48,8 +48,7 @@ pub const IPPROTO_ICMPV6: i32 = ws2def::IPPROTO_ICMPV6 as i32; pub const IPPROTO_TCP: i32 = ws2def::IPPROTO_TCP as i32; pub const IPPROTO_UDP: i32 = ws2def::IPPROTO_UDP as i32; -#[allow(non_camel_case_types)] -pub(crate) type c_int = winapi::ctypes::c_int; +pub use winapi::ctypes::c_int; // Used in `Domain`. pub(crate) use winapi::shared::ws2def::{AF_INET, AF_INET6}; From 8cf72802a1ffe824dd9cc69cd0c2438d5d1722de Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Tue, 31 Mar 2020 18:12:37 +0000 Subject: [PATCH 33/51] Move socket and SocketAddr (#62) * Move Socket to socket.rs * Move SockAddr to sockaddr.rs --- src/lib.rs | 46 ++-------------------------------------------- src/sockaddr.rs | 9 ++++++++- src/socket.rs | 32 +++++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 46 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a85cffed..d64570d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,13 +39,6 @@ use crate::utils::NetInt; -#[cfg(any(unix, target_os = "redox"))] -use libc::{sockaddr_storage, socklen_t}; -#[cfg(windows)] -use winapi::shared::ws2def::SOCKADDR_STORAGE as sockaddr_storage; -#[cfg(windows)] -use winapi::um::ws2tcpip::socklen_t; - mod sockaddr; mod socket; mod utils; @@ -59,43 +52,8 @@ mod sys; use sys::c_int; -/// Newtype, owned, wrapper around a system socket. -/// -/// This type simply wraps an instance of a file descriptor (`c_int`) on Unix -/// and an instance of `SOCKET` on Windows. This is the main type exported by -/// this crate and is intended to mirror the raw semantics of sockets on -/// platforms as closely as possible. Almost all methods correspond to -/// precisely one libc or OS API call which is essentially just a "Rustic -/// translation" of what's below. -/// -/// # Examples -/// -/// ```no_run -/// use std::net::SocketAddr; -/// use socket2::{Socket, Domain, Type, SockAddr}; -/// -/// // create a TCP listener bound to two addresses -/// let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); -/// -/// socket.bind(&"127.0.0.1:12345".parse::().unwrap().into()).unwrap(); -/// socket.bind(&"127.0.0.1:12346".parse::().unwrap().into()).unwrap(); -/// socket.listen(128).unwrap(); -/// -/// let listener = socket.into_tcp_listener(); -/// // ... -/// ``` -pub struct Socket { - inner: sys::Socket, -} - -/// The address of a socket. -/// -/// `SockAddr`s may be constructed directly to and from the standard library -/// `SocketAddr`, `SocketAddrV4`, and `SocketAddrV6` types. -pub struct SockAddr { - storage: sockaddr_storage, - len: socklen_t, -} +pub use sockaddr::SockAddr; +pub use socket::Socket; /// Specification of the communication domain for a socket. /// diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 59701085..7bdf38ca 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -18,7 +18,14 @@ use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6; #[cfg(windows)] use winapi::um::ws2tcpip::socklen_t; -use crate::SockAddr; +/// The address of a socket. +/// +/// `SockAddr`s may be constructed directly to and from the standard library +/// `SocketAddr`, `SocketAddrV4`, and `SocketAddrV6` types. +pub struct SockAddr { + storage: sockaddr_storage, + len: socklen_t, +} impl fmt::Debug for SockAddr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/socket.rs b/src/socket.rs index 53d34896..8e954ef4 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -21,7 +21,37 @@ use libc::MSG_OOB; use winapi::um::winsock2::MSG_OOB; use crate::sys; -use crate::{Domain, Protocol, SockAddr, Socket, Type}; +use crate::{Domain, Protocol, SockAddr, Type}; + +/// Newtype, owned, wrapper around a system socket. +/// +/// This type simply wraps an instance of a file descriptor (`c_int`) on Unix +/// and an instance of `SOCKET` on Windows. This is the main type exported by +/// this crate and is intended to mirror the raw semantics of sockets on +/// platforms as closely as possible. Almost all methods correspond to +/// precisely one libc or OS API call which is essentially just a "Rustic +/// translation" of what's below. +/// +/// # Examples +/// +/// ```no_run +/// use std::net::SocketAddr; +/// use socket2::{Socket, Domain, Type, SockAddr}; +/// +/// // create a TCP listener bound to two addresses +/// let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); +/// +/// socket.bind(&"127.0.0.1:12345".parse::().unwrap().into()).unwrap(); +/// socket.bind(&"127.0.0.1:12346".parse::().unwrap().into()).unwrap(); +/// socket.listen(128).unwrap(); +/// +/// let listener = socket.into_tcp_listener(); +/// // ... +/// ``` +pub struct Socket { + // The `sys` module most have access to the socket. + pub(crate) inner: sys::Socket, +} impl Socket { /// Creates a new socket ready to be configured. From 1d66f9fb578a04e9e7c47a76c2d0354ee21d18dc Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Tue, 31 Mar 2020 18:33:28 +0000 Subject: [PATCH 34/51] Move Protocol impl to src/lib.rs (#61) --- src/lib.rs | 34 ++++++++++++++++++++++++++++++++++ src/socket.rs | 34 ---------------------------------- src/sys/unix.rs | 7 ++----- src/sys/windows.rs | 11 +++++------ 4 files changed, 41 insertions(+), 45 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d64570d9..a653270e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -152,6 +152,40 @@ impl From for c_int { #[derive(Copy, Clone)] pub struct Protocol(c_int); +impl Protocol { + /// Protocol corresponding to `ICMPv4`. + pub fn icmpv4() -> Self { + Protocol(sys::IPPROTO_ICMP) + } + + /// Protocol corresponding to `ICMPv6`. + pub fn icmpv6() -> Self { + Protocol(sys::IPPROTO_ICMPV6) + } + + /// Protocol corresponding to `TCP`. + pub fn tcp() -> Self { + Protocol(sys::IPPROTO_TCP) + } + + /// Protocol corresponding to `UDP`. + pub fn udp() -> Self { + Protocol(sys::IPPROTO_UDP) + } +} + +impl From for Protocol { + fn from(p: c_int) -> Protocol { + Protocol(p) + } +} + +impl From for c_int { + fn from(p: Protocol) -> c_int { + p.0 + } +} + fn hton(i: I) -> I { i.to_be() } diff --git a/src/socket.rs b/src/socket.rs index 8e954ef4..4b7905d3 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -889,40 +889,6 @@ impl From for UnixDatagram { } } -impl crate::Protocol { - /// Protocol corresponding to `ICMPv4` - pub fn icmpv4() -> Self { - crate::Protocol(sys::IPPROTO_ICMP) - } - - /// Protocol corresponding to `ICMPv6` - pub fn icmpv6() -> Self { - crate::Protocol(sys::IPPROTO_ICMPV6) - } - - /// Protocol corresponding to `TCP` - pub fn tcp() -> Self { - crate::Protocol(sys::IPPROTO_TCP) - } - - /// Protocol corresponding to `UDP` - pub fn udp() -> Self { - crate::Protocol(sys::IPPROTO_UDP) - } -} - -impl From for Protocol { - fn from(a: i32) -> Protocol { - Protocol(a) - } -} - -impl From for i32 { - fn from(a: Protocol) -> i32 { - a.0 - } -} - #[cfg(test)] mod test { use std::net::SocketAddr; diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 83c9396c..ec5d7a29 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -32,6 +32,8 @@ pub use libc::c_int; pub(crate) use libc::{AF_INET, AF_INET6}; // Used in `Type`. pub(crate) use libc::{SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET, SOCK_STREAM}; +// Used in `Protocol`. +pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP}; cfg_if::cfg_if! { if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", @@ -60,11 +62,6 @@ cfg_if::cfg_if! { use crate::utils::One; use crate::SockAddr; -pub const IPPROTO_ICMP: i32 = libc::IPPROTO_ICMP; -pub const IPPROTO_ICMPV6: i32 = libc::IPPROTO_ICMPV6; -pub const IPPROTO_TCP: i32 = libc::IPPROTO_TCP; -pub const IPPROTO_UDP: i32 = libc::IPPROTO_UDP; - /// Unix only API. impl Domain { /// Domain for Unix socket communication, corresponding to `AF_UNIX`. diff --git a/src/sys/windows.rs b/src/sys/windows.rs index 191a9934..d5abd5dc 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -25,7 +25,6 @@ use winapi::shared::in6addr::*; use winapi::shared::inaddr::*; use winapi::shared::minwindef::DWORD; use winapi::shared::ntdef::{HANDLE, ULONG}; -use winapi::shared::ws2def; use winapi::shared::ws2def::*; use winapi::shared::ws2ipdef::*; use winapi::um::handleapi::SetHandleInformation; @@ -43,17 +42,17 @@ const SD_SEND: c_int = 1; const SIO_KEEPALIVE_VALS: DWORD = 0x98000004; const WSA_FLAG_OVERLAPPED: DWORD = 0x01; -pub const IPPROTO_ICMP: i32 = ws2def::IPPROTO_ICMP as i32; -pub const IPPROTO_ICMPV6: i32 = ws2def::IPPROTO_ICMPV6 as i32; -pub const IPPROTO_TCP: i32 = ws2def::IPPROTO_TCP as i32; -pub const IPPROTO_UDP: i32 = ws2def::IPPROTO_UDP as i32; - pub use winapi::ctypes::c_int; // Used in `Domain`. pub(crate) use winapi::shared::ws2def::{AF_INET, AF_INET6}; // Used in `Type`. pub(crate) use winapi::shared::ws2def::{SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET, SOCK_STREAM}; +// Used in `Protocol`. +pub(crate) const IPPROTO_ICMP: c_int = winapi::shared::ws2def::IPPROTO_ICMP as c_int; +pub(crate) const IPPROTO_ICMPV6: c_int = winapi::shared::ws2def::IPPROTO_ICMPV6 as c_int; +pub(crate) const IPPROTO_TCP: c_int = winapi::shared::ws2def::IPPROTO_TCP as c_int; +pub(crate) const IPPROTO_UDP: c_int = winapi::shared::ws2def::IPPROTO_UDP as c_int; #[repr(C)] struct tcp_keepalive { From 4206876f230066d88103cfa261c10f8997cbe54c Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Tue, 31 Mar 2020 21:53:23 +0000 Subject: [PATCH 35/51] Implement fmt::Debug for Domain, Protocol and Type (#63) * Implement fmt::Debug for Domain * Implement fmt::Debug for Protocol * Implement fmt::Debug for Type * Fix fmt::Debug for Domain on Windows --- src/lib.rs | 35 ++++++++++++++++++++++++++ src/sys/unix.rs | 45 +++++++++++++++++++++++++++++++++ src/sys/windows.rs | 27 +++++++++++++++++++- src/tests.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 src/tests.rs diff --git a/src/lib.rs b/src/lib.rs index a653270e..c0354f12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,10 +39,45 @@ use crate::utils::NetInt; +/// Macro to implement `fmt::Debug` for a type, printing the constant names +/// rather than a number. +/// +/// Note this is used in the `sys` module and thus must be defined before +/// defining the modules. +macro_rules! impl_debug { + ( + // Type name for which to implement `fmt::Debug`. + $type: path, + $( + $(#[$target: meta])* + // The flag(s) to check. + // Need to specific the libc crate because Windows doesn't use + // `libc` but `winapi`. + $libc: ident :: $flag: ident + ),+ $(,)* + ) => { + impl std::fmt::Debug for $type { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let string = match self.0 { + $( + $(#[$target])* + $libc :: $flag => stringify!($flag), + )+ + n => return write!(f, "{}", n), + }; + f.write_str(string) + } + } + }; +} + mod sockaddr; mod socket; mod utils; +#[cfg(test)] +mod tests; + #[cfg(unix)] #[path = "sys/unix.rs"] mod sys; diff --git a/src/sys/unix.rs b/src/sys/unix.rs index ec5d7a29..b330fe1e 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -80,6 +80,14 @@ impl Domain { } } +impl_debug!( + Domain, + libc::AF_INET, + libc::AF_INET6, + libc::AF_UNIX, + libc::AF_UNSPEC, // = 0. +); + /// Unix only API. impl Type { /// Set `SOCK_NONBLOCK` on the `Type`. @@ -119,6 +127,43 @@ impl Type { } } +impl_debug!( + crate::Type, + libc::SOCK_STREAM, + libc::SOCK_DGRAM, + libc::SOCK_RAW, + libc::SOCK_RDM, + libc::SOCK_SEQPACKET, + /* TODO: add these optional bit OR-ed flags: + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd" + ))] + libc::SOCK_NONBLOCK, + #[cfg(any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd" + ))] + libc::SOCK_CLOEXEC, + */ +); + +impl_debug!( + crate::Protocol, + libc::IPPROTO_ICMP, + libc::IPPROTO_ICMPV6, + libc::IPPROTO_TCP, + libc::IPPROTO_UDP, +); + pub struct Socket { fd: c_int, } diff --git a/src/sys/windows.rs b/src/sys/windows.rs index d5abd5dc..443ef265 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -25,7 +25,7 @@ use winapi::shared::in6addr::*; use winapi::shared::inaddr::*; use winapi::shared::minwindef::DWORD; use winapi::shared::ntdef::{HANDLE, ULONG}; -use winapi::shared::ws2def::*; +use winapi::shared::ws2def::{self, *}; use winapi::shared::ws2ipdef::*; use winapi::um::handleapi::SetHandleInformation; use winapi::um::processthreadsapi::GetCurrentProcessId; @@ -54,6 +54,31 @@ pub(crate) const IPPROTO_ICMPV6: c_int = winapi::shared::ws2def::IPPROTO_ICMPV6 pub(crate) const IPPROTO_TCP: c_int = winapi::shared::ws2def::IPPROTO_TCP as c_int; pub(crate) const IPPROTO_UDP: c_int = winapi::shared::ws2def::IPPROTO_UDP as c_int; +impl_debug!( + crate::Domain, + ws2def::AF_INET, + ws2def::AF_INET6, + ws2def::AF_UNIX, + ws2def::AF_UNSPEC, // = 0. +); + +impl_debug!( + crate::Type, + ws2def::SOCK_STREAM, + ws2def::SOCK_DGRAM, + ws2def::SOCK_RAW, + ws2def::SOCK_RDM, + ws2def::SOCK_SEQPACKET, +); + +impl_debug!( + crate::Protocol, + self::IPPROTO_ICMP, + self::IPPROTO_ICMPV6, + self::IPPROTO_TCP, + self::IPPROTO_UDP, +); + #[repr(C)] struct tcp_keepalive { onoff: c_ulong, diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 00000000..4a2f1f8e --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,62 @@ +use std::io::Write; +use std::str; + +use crate::{Domain, Protocol, Type}; + +#[test] +fn domain_fmt_debug() { + let tests = &[ + (Domain::ipv4(), "AF_INET"), + (Domain::ipv6(), "AF_INET6"), + #[cfg(unix)] + (Domain::unix(), "AF_UNIX"), + (0.into(), "AF_UNSPEC"), + (500.into(), "500"), + ]; + + let mut buf = Vec::new(); + for (input, want) in tests { + buf.clear(); + write!(buf, "{:?}", input).unwrap(); + let got = str::from_utf8(&buf).unwrap(); + assert_eq!(got, *want); + } +} + +#[test] +fn type_fmt_debug() { + let tests = &[ + (Type::stream(), "SOCK_STREAM"), + (Type::dgram(), "SOCK_DGRAM"), + (Type::seqpacket(), "SOCK_SEQPACKET"), + (Type::raw(), "SOCK_RAW"), + (500.into(), "500"), + ]; + + let mut buf = Vec::new(); + for (input, want) in tests { + buf.clear(); + write!(buf, "{:?}", input).unwrap(); + let got = str::from_utf8(&buf).unwrap(); + assert_eq!(got, *want); + } +} + +#[test] +fn protocol_fmt_debug() { + let tests = &[ + (Protocol::icmpv4(), "IPPROTO_ICMP"), + (Protocol::icmpv6(), "IPPROTO_ICMPV6"), + (Protocol::tcp(), "IPPROTO_TCP"), + (Protocol::udp(), "IPPROTO_UDP"), + (500.into(), "500"), + ]; + + let mut buf = Vec::new(); + for (input, want) in tests { + buf.clear(); + write!(buf, "{:?}", input).unwrap(); + let got = str::from_utf8(&buf).unwrap(); + assert_eq!(got, *want); + } +} From c22d0e55c4dff90ad1f0c6cfed6708cc79764408 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 1 Apr 2020 06:54:29 -0700 Subject: [PATCH 36/51] Bump to 0.3.12 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2a3fe5b3..1b4ba24a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "socket2" -version = "0.3.11" +version = "0.3.12" authors = ["Alex Crichton "] license = "MIT/Apache-2.0" readme = "README.md" From 063b1a89e477ea28bfe37cea77148a108f4429a4 Mon Sep 17 00:00:00 2001 From: PerfectLaugh Date: Thu, 21 May 2020 23:41:26 +0800 Subject: [PATCH 37/51] fix: correct recv_from_with_flags and sendto (#81) The behavior is wrong with original function. Fix with simple lines. --- src/socket.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/socket.rs b/src/socket.rs index 4b7905d3..d4ab2d77 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -285,8 +285,12 @@ impl Socket { /// `recvfrom` call. /// /// [`recv_from`]: #method.recv_from - pub fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result { - self.inner.recv(buf, flags) + pub fn recv_from_with_flags( + &self, + buf: &mut [u8], + flags: i32, + ) -> io::Result<(usize, SockAddr)> { + self.inner.recv_from(buf, flags) } /// Receives data from the socket, without removing it from the queue. @@ -342,8 +346,8 @@ impl Socket { /// `sendto` call. /// /// [`send_to`]: #method.send_to - pub fn send_to_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result { - self.inner.recv(buf, flags) + pub fn send_to_with_flags(&self, buf: &[u8], addr: &SockAddr, flags: i32) -> io::Result { + self.inner.send_to(buf, flags, addr) } // ================================================ From 70efe5c791ba545a264cb40af857360f2cdd429b Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Mon, 17 Aug 2020 12:31:16 +0200 Subject: [PATCH 38/51] Unify sigpipe settings for macOS and iOS Original commit: 7bf31f95af1905880e73a169b0eb3894597e6f0f --- src/sys/unix.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sys/unix.rs b/src/sys/unix.rs index b330fe1e..ba85ae59 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -188,7 +188,7 @@ impl Socket { let fd = cvt(libc::socket(family, ty, protocol))?; let fd = Socket::from_raw_fd(fd); set_cloexec(fd.as_raw_fd())?; - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] { fd.setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; } @@ -203,7 +203,7 @@ impl Socket { let fds = (Socket::from_raw_fd(fds[0]), Socket::from_raw_fd(fds[1])); set_cloexec(fds.0.as_raw_fd())?; set_cloexec(fds.1.as_raw_fd())?; - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "ios"))] { fds.0 .setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; From 670ca5f5bb4922359102435f976399884aff082b Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Thu, 13 Aug 2020 03:09:54 -0500 Subject: [PATCH 39/51] Fix mutability of buffers for a few send_* functions (#92) --- src/socket.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/socket.rs b/src/socket.rs index d4ab2d77..95eb31d6 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -318,7 +318,7 @@ impl Socket { /// `send` call. /// /// [`send`]: #method.send - pub fn send_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result { + pub fn send_with_flags(&self, buf: &[u8], flags: i32) -> io::Result { self.inner.send(buf, flags) } @@ -329,7 +329,7 @@ impl Socket { /// /// [`send`]: #method.send /// [`out_of_band_inline`]: #method.out_of_band_inline - pub fn send_out_of_band(&self, buf: &mut [u8]) -> io::Result { + pub fn send_out_of_band(&self, buf: &[u8]) -> io::Result { self.inner.send(buf, MSG_OOB) } From b806433d6b3af647bf9fcc003959daaf3d8e12f5 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Wed, 9 Sep 2020 18:42:24 +0200 Subject: [PATCH 40/51] Bump to v0.3.15 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1b4ba24a..3a1f95cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "socket2" -version = "0.3.12" +version = "0.3.15" authors = ["Alex Crichton "] license = "MIT/Apache-2.0" readme = "README.md" From 99da5c22a3ad4658b6c793726d1e0342fbccd3b3 Mon Sep 17 00:00:00 2001 From: Niels Sascha Reedijk Date: Sat, 2 May 2020 09:27:39 +0000 Subject: [PATCH 41/51] Haiku: no SOCK_RDM support in Haiku --- src/sys/unix.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sys/unix.rs b/src/sys/unix.rs index ba85ae59..5e55fa81 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -132,6 +132,7 @@ impl_debug!( libc::SOCK_STREAM, libc::SOCK_DGRAM, libc::SOCK_RAW, + #[cfg(not(target_os = "haiku"))] libc::SOCK_RDM, libc::SOCK_SEQPACKET, /* TODO: add these optional bit OR-ed flags: From d2c15de84991947b6577bea92763efe0a2eecf28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20F=C3=A4rnstrand?= Date: Sat, 7 Nov 2020 14:37:31 +0100 Subject: [PATCH 42/51] Don't assume memory layout of std::net::SocketAddr Fixes #120 --- Cargo.toml | 2 +- src/sockaddr.rs | 169 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 129 insertions(+), 42 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3a1f95cc..c8bf0d96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ features = ["handleapi", "ws2def", "ws2ipdef", "ws2tcpip", "minwindef"] [target."cfg(any(unix, target_os = \"redox\"))".dependencies] cfg-if = "0.1.6" -libc = "0.2.66" +libc = { version = "0.2.66", features = ["align"] } [target."cfg(target_os = \"redox\")".dependencies] redox_syscall = "0.1.38" diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 7bdf38ca..434163fe 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -1,20 +1,24 @@ use std::fmt; use std::mem::{self, MaybeUninit}; -use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::ptr; #[cfg(any(unix, target_os = "redox"))] use libc::{ - sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET, - AF_INET6, + in6_addr, in_addr, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, + socklen_t, AF_INET, AF_INET6, }; #[cfg(windows)] +use winapi::shared::in6addr::{in6_addr_u, IN6_ADDR as in6_addr}; +#[cfg(windows)] +use winapi::shared::inaddr::{in_addr_S_un, IN_ADDR as in_addr}; +#[cfg(windows)] use winapi::shared::ws2def::{ ADDRESS_FAMILY as sa_family_t, AF_INET, AF_INET6, SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in, SOCKADDR_STORAGE as sockaddr_storage, }; #[cfg(windows)] -use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6; +use winapi::shared::ws2ipdef::{SOCKADDR_IN6_LH_u, SOCKADDR_IN6_LH as sockaddr_in6}; #[cfg(windows)] use winapi::um::ws2tcpip::socklen_t; @@ -43,17 +47,17 @@ impl fmt::Debug for SockAddr { impl SockAddr { /// Constructs a `SockAddr` from its raw components. pub unsafe fn from_raw_parts(addr: *const sockaddr, len: socklen_t) -> SockAddr { - let mut storage = MaybeUninit::::uninit(); + let mut storage = MaybeUninit::::zeroed(); ptr::copy_nonoverlapping( addr as *const _ as *const u8, - &mut storage as *mut _ as *mut u8, + storage.as_mut_ptr() as *mut u8, len as usize, ); SockAddr { // This is safe as we written the address to `storage` above. storage: storage.assume_init(), - len: len, + len, } } @@ -120,33 +124,60 @@ impl SockAddr { } } - unsafe fn as_(&self, family: sa_family_t) -> Option { - if self.storage.ss_family != family { - return None; - } - - Some(mem::transmute_copy(&self.storage)) - } - /// Returns this address as a `SocketAddrV4` if it is in the `AF_INET` /// family. pub fn as_inet(&self) -> Option { - unsafe { self.as_(AF_INET as sa_family_t) } + match self.as_std() { + Some(SocketAddr::V4(addr)) => Some(addr), + _ => None, + } } /// Returns this address as a `SocketAddrV6` if it is in the `AF_INET6` /// family. pub fn as_inet6(&self) -> Option { - unsafe { self.as_(AF_INET6 as sa_family_t) } + match self.as_std() { + Some(SocketAddr::V6(addr)) => Some(addr), + _ => None, + } } /// Returns this address as a `SocketAddr` if it is in the `AF_INET` /// or `AF_INET6` family, otherwise returns `None`. pub fn as_std(&self) -> Option { - if let Some(addr) = self.as_inet() { - Some(SocketAddr::V4(addr)) - } else if let Some(addr) = self.as_inet6() { - Some(SocketAddr::V6(addr)) + if self.storage.ss_family == AF_INET as sa_family_t { + // Safety: if the ss_family field is AF_INET then storage must be a sockaddr_in. + let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in) }; + + #[cfg(unix)] + let ip = Ipv4Addr::from(addr.sin_addr.s_addr.to_ne_bytes()); + #[cfg(windows)] + let ip = { + let ip_bytes = unsafe { addr.sin_addr.S_un.S_un_b() }; + Ipv4Addr::from([ip_bytes.s_b1, ip_bytes.s_b2, ip_bytes.s_b3, ip_bytes.s_b4]) + }; + let port = u16::from_be(addr.sin_port); + Some(SocketAddr::V4(SocketAddrV4::new(ip, port))) + } else if self.storage.ss_family == AF_INET6 as sa_family_t { + // Safety: if the ss_family field is AF_INET6 then storage must be a sockaddr_in6. + let addr = unsafe { &*(&self.storage as *const _ as *const sockaddr_in6) }; + + #[cfg(unix)] + let ip = Ipv6Addr::from(addr.sin6_addr.s6_addr); + #[cfg(windows)] + let ip = Ipv6Addr::from(*unsafe { addr.sin6_addr.u.Byte() }); + let port = u16::from_be(addr.sin6_port); + Some(SocketAddr::V6(SocketAddrV6::new( + ip, + port, + addr.sin6_flowinfo, + #[cfg(unix)] + addr.sin6_scope_id, + #[cfg(windows)] + unsafe { + *addr.u.sin6_scope_id() + }, + ))) } else { None } @@ -168,34 +199,90 @@ impl SockAddr { } } -// SocketAddrV4 and SocketAddrV6 are just wrappers around sockaddr_in and sockaddr_in6 - -// check to make sure that the sizes at least match up -fn _size_checks(v4: SocketAddrV4, v6: SocketAddrV6) { - unsafe { - mem::transmute::(v4); - mem::transmute::(v6); - } -} - impl From for SockAddr { fn from(addr: SocketAddrV4) -> SockAddr { - unsafe { - SockAddr::from_raw_parts( - &addr as *const _ as *const _, - mem::size_of::() as socklen_t, - ) + #[cfg(unix)] + let sin_addr = in_addr { + s_addr: u32::from_ne_bytes(addr.ip().octets()), + }; + #[cfg(windows)] + let sin_addr = unsafe { + let mut s_un = mem::zeroed::(); + *s_un.S_addr_mut() = u32::from_ne_bytes(addr.ip().octets()); + in_addr { S_un: s_un } + }; + + let sockaddr_in = sockaddr_in { + sin_family: AF_INET as sa_family_t, + sin_port: addr.port().to_be(), + sin_addr, + sin_zero: [0; 8], + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + sin_len: 0, + }; + let mut storage = MaybeUninit::::zeroed(); + // Safety: A `sockaddr_in` is memory compatible with a `sockaddr_storage` + unsafe { (storage.as_mut_ptr() as *mut sockaddr_in).write(sockaddr_in) }; + SockAddr { + storage: unsafe { storage.assume_init() }, + len: mem::size_of::() as socklen_t, } } } impl From for SockAddr { fn from(addr: SocketAddrV6) -> SockAddr { - unsafe { - SockAddr::from_raw_parts( - &addr as *const _ as *const _, - mem::size_of::() as socklen_t, - ) + #[cfg(unix)] + let sin6_addr = in6_addr { + s6_addr: addr.ip().octets(), + }; + #[cfg(windows)] + let sin6_addr = unsafe { + let mut u = mem::zeroed::(); + *u.Byte_mut() = addr.ip().octets(); + in6_addr { u } + }; + #[cfg(windows)] + let u = unsafe { + let mut u = mem::zeroed::(); + *u.sin6_scope_id_mut() = addr.scope_id(); + u + }; + + let sockaddr_in6 = sockaddr_in6 { + sin6_family: AF_INET6 as sa_family_t, + sin6_port: addr.port().to_be(), + sin6_addr, + sin6_flowinfo: addr.flowinfo(), + #[cfg(unix)] + sin6_scope_id: addr.scope_id(), + #[cfg(windows)] + u, + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + ))] + sin6_len: 0, + #[cfg(any(target_os = "solaris", target_os = "illumos"))] + __sin6_src_id: 0, + }; + let mut storage = MaybeUninit::::zeroed(); + // Safety: A `sockaddr_in6` is memory compatible with a `sockaddr_storage` + unsafe { (storage.as_mut_ptr() as *mut sockaddr_in6).write(sockaddr_in6) }; + SockAddr { + storage: unsafe { storage.assume_init() }, + len: mem::size_of::() as socklen_t, } } } From 73d54bb3366474aa011a7760b186d3d799347ca1 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Wed, 11 Nov 2020 13:44:19 +0100 Subject: [PATCH 43/51] Release v0.3.16 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c8bf0d96..1b6dd7fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "socket2" -version = "0.3.15" +version = "0.3.16" authors = ["Alex Crichton "] license = "MIT/Apache-2.0" readme = "README.md" From 06a25107c7fc6797370e990d213ffb28fa4992af Mon Sep 17 00:00:00 2001 From: Marc-Antoine Perennou Date: Thu, 12 Nov 2020 09:08:21 +0100 Subject: [PATCH 44/51] [0.3] Update cfg-if to 1.0 Signed-off-by: Marc-Antoine Perennou --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1b6dd7fd..685fcac7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ version = "0.3.3" features = ["handleapi", "ws2def", "ws2ipdef", "ws2tcpip", "minwindef"] [target."cfg(any(unix, target_os = \"redox\"))".dependencies] -cfg-if = "0.1.6" +cfg-if = "1.0" libc = { version = "0.2.66", features = ["align"] } [target."cfg(target_os = \"redox\")".dependencies] From 930c9a9803df565a6733f4c6b5b1b198282c7b33 Mon Sep 17 00:00:00 2001 From: Ammar Zuberi Date: Tue, 17 Nov 2020 00:10:44 -0800 Subject: [PATCH 45/51] Additional Linux socket options Added support for setting/getting value of: * TCP Maximum Segment Size (TCP_MAXSEG) * Socket Mark (SO_MARK) Signed-off-by: Ammar Zuberi --- src/socket.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ src/sys/unix.rs | 24 ++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/src/socket.rs b/src/socket.rs index 95eb31d6..b8b48cfd 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -369,6 +369,49 @@ impl Socket { self.inner.set_ttl(ttl) } + /// Gets the value of the `TCP_MAXSEG` option on this socket. + /// + /// The `TCP_MAXSEG` option denotes the TCP Maximum Segment + /// Size and is only available on TCP sockets. + #[cfg(unix)] + pub fn mss(&self) -> io::Result { + self.inner.mss() + } + + /// Sets the value of the `TCP_MAXSEG` option on this socket. + /// + /// The `TCP_MAXSEG` option denotes the TCP Maximum Segment + /// Size and is only available on TCP sockets. + #[cfg(unix)] + pub fn set_mss(&self, mss: u32) -> io::Result<()> { + self.inner.set_mss(mss) + } + + /// Gets the value for the `SO_MARK` option on this socket. + /// + /// This value gets the socket mark field for each packet sent through + /// this socket. + /// + /// This function is only available on Linux and requires the + /// `CAP_NET_ADMIN` capability. + #[cfg(target_os = "linux")] + pub fn mark(&self) -> io::Result { + self.inner.mark() + } + + /// Sets the value for the `SO_MARK` option on this socket. + /// + /// This value sets the socket mark field for each packet sent through + /// this socket. Changing the mark can be used for mark-based routing + /// without netfilter or for packet filtering. + /// + /// This function is only available on Linux and requires the + /// `CAP_NET_ADMIN` capability. + #[cfg(target_os = "linux")] + pub fn set_mark(&self, mark: u32) -> io::Result<()> { + self.inner.set_mark(mark) + } + /// Gets the value of the `IPV6_UNICAST_HOPS` option for this socket. /// /// Specifies the hop limit for ipv6 unicast packets diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 5e55fa81..784187c5 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -534,6 +534,30 @@ impl Socket { unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int) } } + pub fn mss(&self) -> io::Result { + unsafe { + let raw: c_int = self.getsockopt(libc::IPPROTO_TCP, libc::TCP_MAXSEG)?; + Ok(raw as u32) + } + } + + pub fn set_mss(&self, mss: u32) -> io::Result<()> { + unsafe { self.setsockopt(libc::IPPROTO_TCP, libc::TCP_MAXSEG, mss as c_int) } + } + + #[cfg(target_os = "linux")] + pub fn mark(&self) -> io::Result { + unsafe { + let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_MARK)?; + Ok(raw as u32) + } + } + + #[cfg(target_os = "linux")] + pub fn set_mark(&self, mark: u32) -> io::Result<()> { + unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_MARK, mark as c_int) } + } + pub fn unicast_hops_v6(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS)?; From 7312f81e94c22bb90fbe1acd76b294fc5e91e6ec Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Sat, 21 Nov 2020 11:49:15 +0100 Subject: [PATCH 46/51] Release v0.3.17 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 685fcac7..7258c62c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "socket2" -version = "0.3.16" +version = "0.3.17" authors = ["Alex Crichton "] license = "MIT/Apache-2.0" readme = "README.md" From 3b4214da98dd344db97f1a7d5d48da18e14d2aba Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sun, 29 Nov 2020 13:34:53 +0100 Subject: [PATCH 47/51] Fix compilation on Haiku MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sin_len and sin6_len are apparently required on all BSD-like systems, from which Haiku probably inherits its network stack. sin_zero has been changed from 8 bytes to 24 bytes in hrev9079 in order to stay compatible with BeOS. --- src/sockaddr.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sockaddr.rs b/src/sockaddr.rs index 434163fe..dd8ffc01 100644 --- a/src/sockaddr.rs +++ b/src/sockaddr.rs @@ -216,10 +216,11 @@ impl From for SockAddr { sin_family: AF_INET as sa_family_t, sin_port: addr.port().to_be(), sin_addr, - sin_zero: [0; 8], + sin_zero: Default::default(), #[cfg(any( target_os = "dragonfly", target_os = "freebsd", + target_os = "haiku", target_os = "ios", target_os = "macos", target_os = "netbsd", @@ -268,6 +269,7 @@ impl From for SockAddr { #[cfg(any( target_os = "dragonfly", target_os = "freebsd", + target_os = "haiku", target_os = "ios", target_os = "macos", target_os = "netbsd", From a0053b522c363a07972935cbd6cb36b6b824638b Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Tue, 8 Dec 2020 10:06:24 -0600 Subject: [PATCH 48/51] Backport redox compilation to 0.3 --- Cargo.toml | 5 +---- src/socket.rs | 4 ++-- src/sys/unix.rs | 9 +++++++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7258c62c..e2d49fe4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,13 +19,10 @@ all-features = true version = "0.3.3" features = ["handleapi", "ws2def", "ws2ipdef", "ws2tcpip", "minwindef"] -[target."cfg(any(unix, target_os = \"redox\"))".dependencies] +[target."cfg(unix)".dependencies] cfg-if = "1.0" libc = { version = "0.2.66", features = ["align"] } -[target."cfg(target_os = \"redox\")".dependencies] -redox_syscall = "0.1.38" - [dev-dependencies] tempdir = "0.3" diff --git a/src/socket.rs b/src/socket.rs index b8b48cfd..c69262ca 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -373,7 +373,7 @@ impl Socket { /// /// The `TCP_MAXSEG` option denotes the TCP Maximum Segment /// Size and is only available on TCP sockets. - #[cfg(unix)] + #[cfg(all(unix, not(target_os = "redox")))] pub fn mss(&self) -> io::Result { self.inner.mss() } @@ -382,7 +382,7 @@ impl Socket { /// /// The `TCP_MAXSEG` option denotes the TCP Maximum Segment /// Size and is only available on TCP sockets. - #[cfg(unix)] + #[cfg(all(unix, not(target_os = "redox")))] pub fn set_mss(&self, mss: u32) -> io::Result<()> { self.inner.set_mss(mss) } diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 784187c5..5f3c27c9 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -31,7 +31,9 @@ pub use libc::c_int; // Used in `Domain`. pub(crate) use libc::{AF_INET, AF_INET6}; // Used in `Type`. -pub(crate) use libc::{SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET, SOCK_STREAM}; +#[cfg(not(target_os = "redox"))] +pub(crate) use libc::SOCK_RAW; +pub(crate) use libc::{SOCK_DGRAM, SOCK_SEQPACKET, SOCK_STREAM}; // Used in `Protocol`. pub(crate) use libc::{IPPROTO_ICMP, IPPROTO_ICMPV6, IPPROTO_TCP, IPPROTO_UDP}; @@ -131,8 +133,9 @@ impl_debug!( crate::Type, libc::SOCK_STREAM, libc::SOCK_DGRAM, + #[cfg(not(target_os = "redox"))] libc::SOCK_RAW, - #[cfg(not(target_os = "haiku"))] + #[cfg(not(any(target_os = "haiku", target_os = "redox")))] libc::SOCK_RDM, libc::SOCK_SEQPACKET, /* TODO: add these optional bit OR-ed flags: @@ -534,6 +537,7 @@ impl Socket { unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int) } } + #[cfg(not(target_os = "redox"))] pub fn mss(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(libc::IPPROTO_TCP, libc::TCP_MAXSEG)?; @@ -541,6 +545,7 @@ impl Socket { } } + #[cfg(not(target_os = "redox"))] pub fn set_mss(&self, mss: u32) -> io::Result<()> { unsafe { self.setsockopt(libc::IPPROTO_TCP, libc::TCP_MAXSEG, mss as c_int) } } From beeebd01b8ff5c73924df09cd78bea5c47b1acd0 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Wed, 16 Dec 2020 16:31:28 +0100 Subject: [PATCH 49/51] Release v0.3.18 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e2d49fe4..391dc805 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "socket2" -version = "0.3.17" +version = "0.3.18" authors = ["Alex Crichton "] license = "MIT/Apache-2.0" readme = "README.md" From 1dfd15d8f3626eb91ff6238155d3bfbfaed59cf5 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Mon, 21 Dec 2020 12:18:07 +0100 Subject: [PATCH 50/51] Add Socket::(bind_)device Backport of commit 3851430dec41c204d6219a84c47ca6885622a98e. --- src/socket.rs | 26 ++++++++++++++++++++ src/sys/unix.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/src/socket.rs b/src/socket.rs index c69262ca..1f1fcc92 100644 --- a/src/socket.rs +++ b/src/socket.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[cfg(target_os = "linux")] +use std::ffi::{CStr, CString}; use std::fmt; use std::io::{self, Read, Write}; use std::net::{self, Ipv4Addr, Ipv6Addr, Shutdown}; @@ -412,6 +414,30 @@ impl Socket { self.inner.set_mark(mark) } + /// Gets the value for the `SO_BINDTODEVICE` option on this socket. + /// + /// This value gets the socket binded device's interface name. + /// + /// This function is only available on Linux. + #[cfg(target_os = "linux")] + pub fn device(&self) -> io::Result> { + self.inner.device() + } + + /// Sets the value for the `SO_BINDTODEVICE` option on this socket. + /// + /// If a socket is bound to an interface, only packets received from that + /// particular interface are processed by the socket. Note that this only + /// works for some socket types, particularly `AF_INET` sockets. + /// + /// If `interface` is `None` or an empty string it removes the binding. + /// + /// This function is only available on Linux. + #[cfg(target_os = "linux")] + pub fn bind_device(&self, interface: Option<&CStr>) -> io::Result<()> { + self.inner.bind_device(interface) + } + /// Gets the value of the `IPV6_UNICAST_HOPS` option for this socket. /// /// Specifies the hop limit for ipv6 unicast packets diff --git a/src/sys/unix.rs b/src/sys/unix.rs index 5f3c27c9..87794002 100644 --- a/src/sys/unix.rs +++ b/src/sys/unix.rs @@ -9,16 +9,24 @@ // except according to those terms. use std::cmp; +#[cfg(target_os = "linux")] +use std::ffi::{CStr, CString}; use std::fmt; use std::io; use std::io::{ErrorKind, Read, Write}; use std::mem; +#[cfg(target_os = "linux")] +use std::mem::MaybeUninit; use std::net::Shutdown; use std::net::{self, Ipv4Addr, Ipv6Addr}; use std::ops::Neg; #[cfg(feature = "unix")] use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; use std::os::unix::prelude::*; +#[cfg(target_os = "linux")] +use std::ptr; +#[cfg(target_os = "linux")] +use std::slice; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{Duration, Instant}; @@ -563,6 +571,62 @@ impl Socket { unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_MARK, mark as c_int) } } + #[cfg(target_os = "linux")] + pub fn device(&self) -> io::Result> { + // TODO: replace with `MaybeUninit::uninit_array` once stable. + let mut buf: [MaybeUninit; libc::IFNAMSIZ] = + unsafe { MaybeUninit::<[MaybeUninit; libc::IFNAMSIZ]>::uninit().assume_init() }; + let mut len = buf.len() as libc::socklen_t; + let len = unsafe { + cvt(libc::getsockopt( + self.fd, + libc::SOL_SOCKET, + libc::SO_BINDTODEVICE, + buf.as_mut_ptr().cast(), + &mut len, + ))? + }; + if len == 0 { + Ok(None) + } else { + // Allocate a buffer for `CString` with the length including the + // null terminator. + let len = len as usize; + let mut name = Vec::with_capacity(len); + + // TODO: use `MaybeUninit::slice_assume_init_ref` once stable. + // Safety: `len` bytes are writen by the OS, this includes a null + // terminator. However we don't copy the null terminator because + // `CString::from_vec_unchecked` adds its own null terminator. + let buf = unsafe { slice::from_raw_parts(buf.as_ptr().cast(), len - 1) }; + name.extend_from_slice(buf); + + // Safety: the OS initialised the string for us, which shouldn't + // include any null bytes. + Ok(Some(unsafe { CString::from_vec_unchecked(name) })) + } + } + + #[cfg(target_os = "linux")] + pub fn bind_device(&self, interface: Option<&CStr>) -> io::Result<()> { + let (value, len) = if let Some(interface) = interface { + (interface.as_ptr(), interface.to_bytes_with_nul().len()) + } else { + (ptr::null(), 0) + }; + + unsafe { + cvt(libc::setsockopt( + self.fd, + libc::SOL_SOCKET, + libc::SO_BINDTODEVICE, + value.cast(), + len as libc::socklen_t, + )) + .map(|_| ()) + } + } + pub fn unicast_hops_v6(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS)?; From c991f802642525dcf063c253b6fcaa5d6f4c8cb6 Mon Sep 17 00:00:00 2001 From: Thomas de Zeeuw Date: Mon, 21 Dec 2020 12:18:45 +0100 Subject: [PATCH 51/51] Release v0.3.19 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 391dc805..d8629b65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "socket2" -version = "0.3.18" +version = "0.3.19" authors = ["Alex Crichton "] license = "MIT/Apache-2.0" readme = "README.md"