socket2-0.3.11/.appveyor.yml010066400017500001750000000007011346407126700140470ustar0000000000000000environment: 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 socket2-0.3.11/.gitignore010066400017500001750000000000501346407126700133660ustar0000000000000000target/ **/*.rs.bk Cargo.lock .vscode/ socket2-0.3.11/.travis.yml010066400017500001750000000013111346407327400135100ustar0000000000000000language: 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 socket2-0.3.11/Cargo.toml.orig010066400017500001750000000015041352255504200142630ustar0000000000000000[package] name = "socket2" version = "0.3.11" authors = ["Alex Crichton "] license = "MIT/Apache-2.0" readme = "README.md" repository = "https://github.com/alexcrichton/socket2-rs" homepage = "https://github.com/alexcrichton/socket2-rs" description = """ Utilities for handling networking sockets with a maximal amount of configuration possible intended. """ edition = "2018" [package.metadata.docs.rs] all-features = true [target."cfg(windows)".dependencies.winapi] version = "0.3.3" features = ["handleapi", "ws2def", "ws2ipdef", "ws2tcpip", "minwindef"] [target."cfg(any(unix, target_os = \"redox\"))".dependencies] cfg-if = "0.1" libc = "0.2.42" [target."cfg(target_os = \"redox\")".dependencies] redox_syscall = "0.1.38" [dev-dependencies] tempdir = "0.3" [features] reuseport = [] pair = [] unix = [] socket2-0.3.11/Cargo.toml0000644000000026500000000000000105300ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "socket2" version = "0.3.11" authors = ["Alex Crichton "] description = "Utilities for handling networking sockets with a maximal amount of configuration\npossible intended.\n" homepage = "https://github.com/alexcrichton/socket2-rs" readme = "README.md" license = "MIT/Apache-2.0" repository = "https://github.com/alexcrichton/socket2-rs" [package.metadata.docs.rs] all-features = true [dev-dependencies.tempdir] version = "0.3" [features] pair = [] reuseport = [] unix = [] [target."cfg(any(unix, target_os = \"redox\"))".dependencies.cfg-if] version = "0.1" [target."cfg(any(unix, target_os = \"redox\"))".dependencies.libc] version = "0.2.42" [target."cfg(target_os = \"redox\")".dependencies.redox_syscall] version = "0.1.38" [target."cfg(windows)".dependencies.winapi] version = "0.3.3" features = ["handleapi", "ws2def", "ws2ipdef", "ws2tcpip", "minwindef"] socket2-0.3.11/LICENSE-APACHE010066400017500001750000000251371346407126700133370ustar0000000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. socket2-0.3.11/LICENSE-MIT010066400017500001750000000020411346407126700130340ustar0000000000000000Copyright (c) 2014 Alex Crichton Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. socket2-0.3.11/README.md010066400017500001750000000015321346407126700126630ustar0000000000000000# 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 This project is licensed under either of * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. socket2-0.3.11/src/lib.rs010066400017500001750000000111711346407317500133070ustar0000000000000000// 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. //! Utilities for handling sockets //! //! This crate is sort of an evolution of the `net2` crate after seeing the //! issues on it over time. The intention of this crate is to provide as direct //! as possible access to the system's functionality for sockets as possible. No //! extra fluff (e.g. multiple syscalls or builders) provided in this crate. As //! a result using this crate can be a little wordy, but it should give you //! maximal flexibility over configuration of sockets. //! //! # Examples //! //! ```no_run //! use std::net::SocketAddr; //! use socket2::{Socket, Domain, Type}; //! //! // create a TCP listener bound to two addresses //! let socket = Socket::new(Domain::ipv6(), Type::stream(), None).unwrap(); //! //! socket.bind(&"[::1]:12345".parse::().unwrap().into()).unwrap(); //! socket.set_only_v6(false); //! socket.listen(128).unwrap(); //! //! let listener = socket.into_tcp_listener(); //! // ... //! ``` #![doc(html_root_url = "https://docs.rs/socket2/0.3")] #![deny(missing_docs)] 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; #[cfg(unix)] #[path = "sys/unix.rs"] 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. /// /// 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, } /// Specification of the communication domain for a socket. /// /// This is a newtype wrapper around an integer which provides a nicer API in /// addition to an injection point for documentation. Convenience constructors /// 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 /// value needs to be provided. #[derive(Copy, Clone)] pub struct Domain(i32); /// Specification of communication semantics on a socket. /// /// This is a newtype wrapper around an integer which provides a nicer API in /// addition to an injection point for documentation. Convenience constructors /// 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 /// value needs to be provided. #[derive(Copy, Clone)] pub struct Type(i32); /// Protocol specification used for creating sockets via `Socket::new`. /// /// 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 /// value needs to be provided. #[derive(Copy, Clone)] pub struct Protocol(i32); fn hton(i: I) -> I { i.to_be() } #[cfg(not(target_os = "redox"))] fn ntoh(i: I) -> I { I::from_be(i) } socket2-0.3.11/src/sockaddr.rs010066400017500001750000000144241346407272400143360ustar0000000000000000use std::fmt; use std::mem; use std::net::{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, }; #[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; #[cfg(windows)] use winapi::um::ws2tcpip::socklen_t; use crate::SockAddr; impl fmt::Debug for SockAddr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("SockAddr"); builder.field("family", &self.family()); if let Some(addr) = self.as_inet() { builder.field("inet", &addr); } else if let Some(addr) = self.as_inet6() { builder.field("inet6", &addr); } builder.finish() } } 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::(); ptr::copy_nonoverlapping( addr as *const _ as *const u8, &mut storage as *mut _ as *mut u8, len as usize, ); SockAddr { storage: storage, len: len, } } /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path. /// /// This function is only available on Unix when the `unix` feature is /// enabled. /// /// # Failure /// /// Returns an error if the path is longer than `SUN_LEN`. #[cfg(all(unix, feature = "unix"))] pub fn unix

(path: P) -> ::std::io::Result 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; unsafe { let mut addr = mem::zeroed::(); addr.sun_family = AF_UNIX as sa_family_t; let bytes = path.as_ref().as_os_str().as_bytes(); match (bytes.get(0), bytes.len().cmp(&addr.sun_path.len())) { // Abstract paths don't need a null terminator (Some(&0), Ordering::Greater) => { return Err(io::Error::new( io::ErrorKind::InvalidInput, "path must be no longer than SUN_LEN", )); } (Some(&0), _) => {} (_, Ordering::Greater) | (_, Ordering::Equal) => { return Err(io::Error::new( io::ErrorKind::InvalidInput, "path must be shorter than SUN_LEN", )); } _ => {} } for (dst, src) in addr.sun_path.iter_mut().zip(bytes) { *dst = *src as c_char; } // null byte for pathname is already there since we zeroed up front let base = &addr as *const _ as usize; let path = &addr.sun_path as *const _ as usize; let sun_path_offset = path - base; let mut len = sun_path_offset + bytes.len(); match bytes.get(0) { Some(&0) | None => {} Some(_) => len += 1, } Ok(SockAddr::from_raw_parts( &addr as *const _ as *const _, len as socklen_t, )) } } 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) } } /// 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) } } /// Returns this address's family. pub fn family(&self) -> sa_family_t { self.storage.ss_family } /// Returns the size of this address in bytes. pub fn len(&self) -> socklen_t { self.len } /// Returns a raw pointer to the address. pub fn as_ptr(&self) -> *const sockaddr { &self.storage as *const _ as *const _ } } // 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, ) } } } 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, ) } } } impl From for SockAddr { fn from(addr: SocketAddr) -> SockAddr { match addr { SocketAddr::V4(addr) => addr.into(), SocketAddr::V6(addr) => addr.into(), } } } #[cfg(test)] mod test { use super::*; #[test] fn inet() { let raw = "127.0.0.1:80".parse::().unwrap(); let addr = SockAddr::from(raw); assert!(addr.as_inet6().is_none()); let addr = addr.as_inet().unwrap(); assert_eq!(raw, addr); } #[test] fn inet6() { let raw = "[2001:db8::ff00:42:8329]:80" .parse::() .unwrap(); let addr = SockAddr::from(raw); assert!(addr.as_inet().is_none()); let addr = addr.as_inet6().unwrap(); assert_eq!(raw, addr); } } socket2-0.3.11/src/socket.rs010066400017500001750000001013671352255503300140310ustar0000000000000000// 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::fmt; use std::io::{self, Read, Write}; use std::net::{self, Ipv4Addr, Ipv6Addr, Shutdown}; #[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; #[cfg(windows)] use winapi::shared::ws2def as c; use crate::sys; use crate::{Domain, Protocol, SockAddr, Socket, Type}; impl Socket { /// Creates a new socket ready to be configured. /// /// This function corresponds to `socket(2)` and simply creates a new /// socket, no other configuration is done and further functions must be /// invoked to configure this socket. pub fn new(domain: Domain, type_: Type, protocol: Option) -> io::Result { let protocol = protocol.map(|p| p.0).unwrap_or(0); Ok(Socket { inner: sys::Socket::new(domain.0, type_.0, protocol)?, }) } /// Creates a pair of sockets which are connected to each other. /// /// This function corresponds to `socketpair(2)`. /// /// This function is only available on Unix when the `pair` feature is /// enabled. #[cfg(all(unix, feature = "pair"))] pub fn pair( domain: Domain, type_: Type, protocol: Option, ) -> io::Result<(Socket, Socket)> { let protocol = protocol.map(|p| p.0).unwrap_or(0); let sockets = sys::Socket::pair(domain.0, type_.0, protocol)?; Ok((Socket { inner: sockets.0 }, Socket { inner: sockets.1 })) } /// Consumes this `Socket`, converting it to a `TcpStream`. pub fn into_tcp_stream(self) -> net::TcpStream { self.into() } /// Consumes this `Socket`, converting it to a `TcpListener`. pub fn into_tcp_listener(self) -> net::TcpListener { self.into() } /// Consumes this `Socket`, converting it to a `UdpSocket`. pub fn into_udp_socket(self) -> net::UdpSocket { self.into() } /// Consumes this `Socket`, converting it into a `UnixStream`. /// /// This function is only available on Unix when the `unix` feature is /// enabled. #[cfg(all(unix, feature = "unix"))] pub fn into_unix_stream(self) -> UnixStream { self.into() } /// Consumes this `Socket`, converting it into a `UnixListener`. /// /// This function is only available on Unix when the `unix` feature is /// enabled. #[cfg(all(unix, feature = "unix"))] pub fn into_unix_listener(self) -> UnixListener { self.into() } /// Consumes this `Socket`, converting it into a `UnixDatagram`. /// /// This function is only available on Unix when the `unix` feature is /// enabled. #[cfg(all(unix, feature = "unix"))] pub fn into_unix_datagram(self) -> UnixDatagram { self.into() } /// Initiate a connection on this socket to the specified address. /// /// This function directly corresponds to the connect(2) function on Windows /// and Unix. /// /// An error will be returned if `listen` or `connect` has already been /// called on this builder. pub fn connect(&self, addr: &SockAddr) -> io::Result<()> { self.inner.connect(addr) } /// Initiate a connection on this socket to the specified address, only /// only waiting for a certain period of time for the connection to be /// established. /// /// Unlike many other methods on `Socket`, this does *not* correspond to a /// single C function. It sets the socket to nonblocking mode, connects via /// connect(2), and then waits for the connection to complete with poll(2) /// on Unix and select on Windows. When the connection is complete, the /// socket is set back to blocking mode. On Unix, this will loop over /// `EINTR` errors. /// /// # Warnings /// /// The nonblocking state of the socket is overridden by this function - /// it will be returned in blocking mode on success, and in an indeterminate /// state on failure. /// /// If the connection request times out, it may still be processing in the /// background - a second call to `connect` or `connect_timeout` may fail. pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> { self.inner.connect_timeout(addr, timeout) } /// Binds this socket to the specified address. /// /// This function directly corresponds to the bind(2) function on Windows /// and Unix. pub fn bind(&self, addr: &SockAddr) -> io::Result<()> { self.inner.bind(addr) } /// Mark a socket as ready to accept incoming connection requests using /// accept() /// /// This function directly corresponds to the listen(2) function on Windows /// and Unix. /// /// An error will be returned if `listen` or `connect` has already been /// called on this builder. pub fn listen(&self, backlog: i32) -> io::Result<()> { self.inner.listen(backlog) } /// Accept a new incoming connection from this listener. /// /// This function will block the calling thread until a new connection is /// established. When established, the corresponding `Socket` and the /// remote peer's address will be returned. pub fn accept(&self) -> io::Result<(Socket, SockAddr)> { self.inner .accept() .map(|(socket, addr)| (Socket { inner: socket }, addr)) } /// Returns the socket address of the local half of this TCP connection. pub fn local_addr(&self) -> io::Result { self.inner.local_addr() } /// Returns the socket address of the remote peer of this TCP connection. pub fn peer_addr(&self) -> io::Result { self.inner.peer_addr() } /// Creates a new independently owned handle to the underlying socket. /// /// The returned `TcpStream` is a reference to the same stream that this /// object references. Both handles will read and write the same stream of /// data, and options set on one stream will be propagated to the other /// stream. pub fn try_clone(&self) -> io::Result { self.inner.try_clone().map(|s| Socket { inner: s }) } /// Get the value of the `SO_ERROR` option on this socket. /// /// This will retrieve the stored error in the underlying socket, clearing /// the field in the process. This can be useful for checking errors between /// calls. pub fn take_error(&self) -> io::Result> { self.inner.take_error() } /// Moves this TCP stream into or out of nonblocking mode. /// /// On Unix this corresponds to calling fcntl, and on Windows this /// corresponds to calling ioctlsocket. pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.inner.set_nonblocking(nonblocking) } /// Shuts down the read, write, or both halves of this connection. /// /// This function will cause all pending and future I/O on the specified /// portions to return immediately with an appropriate value. pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { self.inner.shutdown(how) } /// Receives data on the socket from the remote address to which it is /// connected. /// /// The [`connect`] method will connect this socket to a remote address. This /// method will fail if the socket is not connected. /// /// [`connect`]: #method.connect pub fn recv(&self, buf: &mut [u8]) -> io::Result { self.inner.recv(buf) } /// Receives data on the socket from the remote adress to which it is /// connected, without removing that data from the queue. On success, /// returns the number of bytes peeked. /// /// Successive calls return the same data. This is accomplished by passing /// `MSG_PEEK` as a flag to the underlying `recv` system call. pub fn peek(&self, buf: &mut [u8]) -> io::Result { self.inner.peek(buf) } /// 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) } /// Receives data from the socket, without removing it from the queue. /// /// Successive calls return the same data. This is accomplished by passing /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. /// /// On success, returns the number of bytes peeked and the address from /// whence the data came. pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> { self.inner.peek_from(buf) } /// Sends data on the socket to a connected peer. /// /// This is typically used on TCP sockets or datagram sockets which have /// been connected. /// /// On success returns the number of bytes that were sent. pub fn send(&self, buf: &[u8]) -> io::Result { self.inner.send(buf) } /// Sends data on the socket to the given address. On success, returns the /// number of bytes written. /// /// 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) } // ================================================ /// Gets the value of the `IP_TTL` option for this socket. /// /// For more information about this option, see [`set_ttl`][link]. /// /// [link]: #method.set_ttl pub fn ttl(&self) -> io::Result { self.inner.ttl() } /// Sets the value for the `IP_TTL` option on this socket. /// /// This value sets the time-to-live field that is used in every packet sent /// from this socket. pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { self.inner.set_ttl(ttl) } /// Gets the value of the `IPV6_UNICAST_HOPS` option for this socket. /// /// Specifies the hop limit for ipv6 unicast packets pub fn unicast_hops_v6(&self) -> io::Result { self.inner.unicast_hops_v6() } /// Sets the value for the `IPV6_UNICAST_HOPS` option on this socket. /// /// Specifies the hop limit for ipv6 unicast packets pub fn set_unicast_hops_v6(&self, ttl: u32) -> io::Result<()> { self.inner.set_unicast_hops_v6(ttl) } /// Gets the value of the `IPV6_V6ONLY` option for this socket. /// /// For more information about this option, see [`set_only_v6`][link]. /// /// [link]: #method.set_only_v6 pub fn only_v6(&self) -> io::Result { self.inner.only_v6() } /// Sets the value for the `IPV6_V6ONLY` option on this socket. /// /// If this is set to `true` then the socket is restricted to sending and /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications /// can bind the same port at the same time. /// /// If this is set to `false` then the socket can be used to send and /// receive packets from an IPv4-mapped IPv6 address. pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { self.inner.set_only_v6(only_v6) } /// Returns the read timeout of this socket. /// /// If the timeout is `None`, then `read` calls will block indefinitely. pub fn read_timeout(&self) -> io::Result> { self.inner.read_timeout() } /// Sets the read timeout to the timeout specified. /// /// If the value specified is `None`, then `read` calls will block /// indefinitely. It is an error to pass the zero `Duration` to this /// method. pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { self.inner.set_read_timeout(dur) } /// Returns the write timeout of this socket. /// /// If the timeout is `None`, then `write` calls will block indefinitely. pub fn write_timeout(&self) -> io::Result> { self.inner.write_timeout() } /// Sets the write timeout to the timeout specified. /// /// If the value specified is `None`, then `write` calls will block /// indefinitely. It is an error to pass the zero `Duration` to this /// method. pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { self.inner.set_write_timeout(dur) } /// Gets the value of the `TCP_NODELAY` option on this socket. /// /// For more information about this option, see [`set_nodelay`][link]. /// /// [link]: #method.set_nodelay pub fn nodelay(&self) -> io::Result { self.inner.nodelay() } /// Sets the value of the `TCP_NODELAY` option on this socket. /// /// If set, this option disables the Nagle algorithm. This means that /// segments are always sent as soon as possible, even if there is only a /// small amount of data. When not set, data is buffered until there is a /// sufficient amount to send out, thereby avoiding the frequent sending of /// small packets. pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { self.inner.set_nodelay(nodelay) } /// Sets the value of the `SO_BROADCAST` option for this socket. /// /// When enabled, this socket is allowed to send packets to a broadcast /// address. pub fn broadcast(&self) -> io::Result { self.inner.broadcast() } /// Gets the value of the `SO_BROADCAST` option for this socket. /// /// For more information about this option, see /// [`set_broadcast`][link]. /// /// [link]: #method.set_broadcast pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { self.inner.set_broadcast(broadcast) } /// Gets the value of the `IP_MULTICAST_LOOP` option for this socket. /// /// For more information about this option, see /// [`set_multicast_loop_v4`][link]. /// /// [link]: #method.set_multicast_loop_v4 pub fn multicast_loop_v4(&self) -> io::Result { self.inner.multicast_loop_v4() } /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket. /// /// If enabled, multicast packets will be looped back to the local socket. /// Note that this may not have any affect on IPv6 sockets. pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { self.inner.set_multicast_loop_v4(multicast_loop_v4) } /// Gets the value of the `IP_MULTICAST_TTL` option for this socket. /// /// For more information about this option, see /// [`set_multicast_ttl_v4`][link]. /// /// [link]: #method.set_multicast_ttl_v4 pub fn multicast_ttl_v4(&self) -> io::Result { self.inner.multicast_ttl_v4() } /// Sets the value of the `IP_MULTICAST_TTL` option for this socket. /// /// Indicates the time-to-live value of outgoing multicast packets for /// this socket. The default value is 1 which means that multicast packets /// don't leave the local network unless explicitly requested. /// /// Note that this may not have any affect on IPv6 sockets. pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { self.inner.set_multicast_ttl_v4(multicast_ttl_v4) } /// Gets the value of the `IPV6_MULTICAST_HOPS` option for this socket /// /// For more information about this option, see /// [`set_multicast_hops_v6`][link]. /// /// [link]: #method.set_multicast_hops_v6 pub fn multicast_hops_v6(&self) -> io::Result { self.inner.multicast_hops_v6() } /// Sets the value of the `IPV6_MULTICAST_HOPS` option for this socket /// /// Indicates the number of "routers" multicast packets will transit for /// this socket. The default value is 1 which means that multicast packets /// don't leave the local network unless explicitly requested. pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> { self.inner.set_multicast_hops_v6(hops) } /// Gets the value of the `IP_MULTICAST_IF` option for this socket. /// /// For more information about this option, see /// [`set_multicast_if_v4`][link]. /// /// [link]: #method.set_multicast_if_v4 /// /// Returns the interface to use for routing multicast packets. pub fn multicast_if_v4(&self) -> io::Result { self.inner.multicast_if_v4() } /// Sets the value of the `IP_MULTICAST_IF` option for this socket. /// /// Specifies the interface to use for routing multicast packets. pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> { self.inner.set_multicast_if_v4(interface) } /// Gets the value of the `IPV6_MULTICAST_IF` option for this socket. /// /// For more information about this option, see /// [`set_multicast_if_v6`][link]. /// /// [link]: #method.set_multicast_if_v6 /// /// Returns the interface to use for routing multicast packets. pub fn multicast_if_v6(&self) -> io::Result { self.inner.multicast_if_v6() } /// Sets the value of the `IPV6_MULTICAST_IF` option for this socket. /// /// Specifies the interface to use for routing multicast packets. Unlike ipv4, this /// is generally required in ipv6 contexts where network routing prefixes may /// overlap. pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> { self.inner.set_multicast_if_v6(interface) } /// Gets the value of the `IPV6_MULTICAST_LOOP` option for this socket. /// /// For more information about this option, see /// [`set_multicast_loop_v6`][link]. /// /// [link]: #method.set_multicast_loop_v6 pub fn multicast_loop_v6(&self) -> io::Result { self.inner.multicast_loop_v6() } /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket. /// /// Controls whether this socket sees the multicast packets it sends itself. /// Note that this may not have any affect on IPv4 sockets. pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { self.inner.set_multicast_loop_v6(multicast_loop_v6) } /// Executes an operation of the `IP_ADD_MEMBERSHIP` type. /// /// This function specifies a new multicast group for this socket to join. /// The address must be a valid multicast address, and `interface` is the /// address of the local interface with which the system should join the /// multicast group. If it's equal to `INADDR_ANY` then an appropriate /// interface is chosen by the system. pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { self.inner.join_multicast_v4(multiaddr, interface) } /// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type. /// /// This function specifies a new multicast group for this socket to join. /// The address must be a valid multicast address, and `interface` is the /// index of the interface to join/leave (or 0 to indicate any interface). pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { self.inner.join_multicast_v6(multiaddr, interface) } /// Executes an operation of the `IP_DROP_MEMBERSHIP` type. /// /// For more information about this option, see /// [`join_multicast_v4`][link]. /// /// [link]: #method.join_multicast_v4 pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { self.inner.leave_multicast_v4(multiaddr, interface) } /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type. /// /// For more information about this option, see /// [`join_multicast_v6`][link]. /// /// [link]: #method.join_multicast_v6 pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { self.inner.leave_multicast_v6(multiaddr, interface) } /// Reads the linger duration for this socket by getting the SO_LINGER /// option pub fn linger(&self) -> io::Result> { self.inner.linger() } /// Sets the linger duration of this socket by setting the SO_LINGER option pub fn set_linger(&self, dur: Option) -> io::Result<()> { self.inner.set_linger(dur) } /// Check the `SO_REUSEADDR` option on this socket. pub fn reuse_address(&self) -> io::Result { self.inner.reuse_address() } /// Set value for the `SO_REUSEADDR` option on this socket. /// /// This indicates that futher 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. pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> { self.inner.set_reuse_address(reuse) } /// Gets the value of the `SO_RCVBUF` option on this socket. /// /// For more information about this option, see /// [`set_recv_buffer_size`][link]. /// /// [link]: #method.set_recv_buffer_size pub fn recv_buffer_size(&self) -> io::Result { self.inner.recv_buffer_size() } /// Sets the value of the `SO_RCVBUF` option on this socket. /// /// Changes the size of the operating system's receive buffer associated /// with the socket. pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { self.inner.set_recv_buffer_size(size) } /// Gets the value of the `SO_SNDBUF` option on this socket. /// /// For more information about this option, see [`set_send_buffer`][link]. /// /// [link]: #method.set_send_buffer pub fn send_buffer_size(&self) -> io::Result { self.inner.send_buffer_size() } /// Sets the value of the `SO_SNDBUF` option on this socket. /// /// Changes the size of the operating system's send buffer associated with /// the socket. pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { self.inner.set_send_buffer_size(size) } /// Returns whether keepalive messages are enabled on this socket, and if so /// the duration of time between them. /// /// For more information about this option, see [`set_keepalive`][link]. /// /// [link]: #method.set_keepalive pub fn keepalive(&self) -> io::Result> { self.inner.keepalive() } /// Sets whether keepalive messages are enabled to be sent on this socket. /// /// On Unix, this option will set the `SO_KEEPALIVE` as well as the /// `TCP_KEEPALIVE` or `TCP_KEEPIDLE` option (depending on your platform). /// On Windows, this will set the `SIO_KEEPALIVE_VALS` option. /// /// If `None` is specified then keepalive messages are disabled, otherwise /// the duration specified will be the time to remain idle before sending a /// TCP keepalive probe. /// /// Some platforms specify this value in seconds, so sub-second /// specifications may be omitted. pub fn set_keepalive(&self, keepalive: Option) -> io::Result<()> { self.inner.set_keepalive(keepalive) } /// Check the value of the `SO_REUSEPORT` option on this socket. /// /// This function is only available on Unix when the `reuseport` feature is /// enabled. #[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 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, not(target_os = "solaris"), feature = "reuseport"))] pub fn set_reuse_port(&self, reuse: bool) -> io::Result<()> { self.inner.set_reuse_port(reuse) } } impl Read for Socket { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } } impl<'a> Read for &'a Socket { fn read(&mut self, buf: &mut [u8]) -> io::Result { (&self.inner).read(buf) } } impl Write for Socket { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.write(buf) } fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } impl<'a> Write for &'a Socket { fn write(&mut self, buf: &[u8]) -> io::Result { (&self.inner).write(buf) } fn flush(&mut self) -> io::Result<()> { (&self.inner).flush() } } impl fmt::Debug for Socket { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.inner.fmt(f) } } impl From for Socket { fn from(socket: net::TcpStream) -> Socket { Socket { inner: socket.into(), } } } impl From for Socket { fn from(socket: net::TcpListener) -> Socket { Socket { inner: socket.into(), } } } impl From for Socket { fn from(socket: net::UdpSocket) -> Socket { Socket { inner: socket.into(), } } } #[cfg(all(unix, feature = "unix"))] impl From for Socket { fn from(socket: UnixStream) -> Socket { Socket { inner: socket.into(), } } } #[cfg(all(unix, feature = "unix"))] impl From for Socket { fn from(socket: UnixListener) -> Socket { Socket { inner: socket.into(), } } } #[cfg(all(unix, feature = "unix"))] impl From for Socket { fn from(socket: UnixDatagram) -> Socket { Socket { inner: socket.into(), } } } impl From for net::TcpStream { fn from(socket: Socket) -> net::TcpStream { socket.inner.into() } } impl From for net::TcpListener { fn from(socket: Socket) -> net::TcpListener { socket.inner.into() } } impl From for net::UdpSocket { fn from(socket: Socket) -> net::UdpSocket { socket.inner.into() } } #[cfg(all(unix, feature = "unix"))] impl From for UnixStream { fn from(socket: Socket) -> UnixStream { socket.inner.into() } } #[cfg(all(unix, feature = "unix"))] impl From for UnixListener { fn from(socket: Socket) -> UnixListener { socket.inner.into() } } #[cfg(all(unix, feature = "unix"))] impl From for UnixDatagram { fn from(socket: Socket) -> UnixDatagram { socket.inner.into() } } 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) } } 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` /// /// 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 { 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 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) } } impl From for i32 { fn from(a: Protocol) -> i32 { a.0 } } #[cfg(test)] mod test { use std::net::SocketAddr; use super::*; #[test] fn connect_timeout_unrouteable() { // this IP is unroutable, so connections should always time out let addr = "10.255.255.1:80".parse::().unwrap().into(); let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); match socket.connect_timeout(&addr, Duration::from_millis(250)) { Ok(_) => panic!("unexpected success"), Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {} Err(e) => panic!("unexpected error {}", e), } } #[test] fn connect_timeout_unbound() { // bind and drop a socket to track down a "probably unassigned" port let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); let addr = "127.0.0.1:0".parse::().unwrap().into(); socket.bind(&addr).unwrap(); let addr = socket.local_addr().unwrap(); drop(socket); let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); match socket.connect_timeout(&addr, Duration::from_millis(250)) { Ok(_) => panic!("unexpected success"), Err(ref e) if e.kind() == io::ErrorKind::ConnectionRefused || e.kind() == io::ErrorKind::TimedOut => {} Err(e) => panic!("unexpected error {}", e), } } #[test] fn connect_timeout_valid() { let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); socket .bind(&"127.0.0.1:0".parse::().unwrap().into()) .unwrap(); socket.listen(128).unwrap(); let addr = socket.local_addr().unwrap(); let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); socket .connect_timeout(&addr, Duration::from_millis(250)) .unwrap(); } #[test] #[cfg(all(unix, feature = "pair", feature = "unix"))] fn pair() { let (mut a, mut b) = Socket::pair(Domain::unix(), Type::stream(), None).unwrap(); a.write_all(b"hello world").unwrap(); let mut buf = [0; 11]; b.read_exact(&mut buf).unwrap(); assert_eq!(buf, &b"hello world"[..]); } #[test] #[cfg(all(unix, feature = "unix"))] fn unix() { use tempdir::TempDir; let dir = TempDir::new("unix").unwrap(); let addr = SockAddr::unix(dir.path().join("sock")).unwrap(); let listener = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); listener.bind(&addr).unwrap(); listener.listen(10).unwrap(); let mut a = Socket::new(Domain::unix(), Type::stream(), None).unwrap(); a.connect(&addr).unwrap(); let mut b = listener.accept().unwrap().0; a.write_all(b"hello world").unwrap(); let mut buf = [0; 11]; b.read_exact(&mut buf).unwrap(); assert_eq!(buf, &b"hello world"[..]); } #[test] fn keepalive() { let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap(); socket.set_keepalive(Some(Duration::from_secs(7))).unwrap(); // socket.keepalive() doesn't work on Windows #24 #[cfg(unix)] assert_eq!(socket.keepalive().unwrap(), Some(Duration::from_secs(7))); socket.set_keepalive(None).unwrap(); #[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()); } } socket2-0.3.11/src/sys/redox/mod.rs010066400017500001750000000603431346407306300152600ustar0000000000000000// 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))); } socket2-0.3.11/src/sys/unix.rs010066400017500001750000001030001352255503300143240ustar0000000000000000// 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::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}; use libc::{self, c_int, c_void, socklen_t, ssize_t}; 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"))] { use libc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; use libc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; } else { use libc::IPV6_ADD_MEMBERSHIP; use libc::IPV6_DROP_MEMBERSHIP; } } 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"))] { use libc::TCP_KEEPALIVE as KEEPALIVE_OPTION; } else if #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "haiku"))] { use libc::SO_KEEPALIVE as KEEPALIVE_OPTION; } else { use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION; } } 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; pub const SOCK_SEQPACKET: i32 = libc::SOCK_SEQPACKET; pub const SOCK_RAW: i32 = libc::SOCK_RAW; pub struct Socket { fd: c_int, } impl Socket { pub fn new(family: c_int, ty: c_int, protocol: c_int) -> io::Result { unsafe { // On linux we first attempt to pass the SOCK_CLOEXEC flag to // atomically create the socket and set it as CLOEXEC. Support for // this option, however, was added in 2.6.27, and we still support // 2.6.18 as a kernel, so if the returned error is EINVAL we // fallthrough to the fallback. #[cfg(target_os = "linux")] { match cvt(libc::socket(family, ty | libc::SOCK_CLOEXEC, protocol)) { Ok(fd) => return Ok(Socket::from_raw_fd(fd)), Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {} Err(e) => return Err(e), } } 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")] { fd.setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; } Ok(fd) } } pub fn pair(family: c_int, ty: c_int, protocol: c_int) -> io::Result<(Socket, Socket)> { unsafe { let mut fds = [0, 0]; cvt(libc::socketpair(family, ty, protocol, fds.as_mut_ptr()))?; 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")] { fds.0 .setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; fds.1 .setsockopt(libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32)?; } Ok(fds) } } 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<()> { self.set_nonblocking(true)?; let r = self.connect(addr); self.set_nonblocking(false)?; match r { Ok(()) => return Ok(()), // there's no io::ErrorKind conversion registered for EINPROGRESS :( Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {} Err(e) => return Err(e), } let mut pollfd = libc::pollfd { fd: self.fd, events: libc::POLLOUT, revents: 0, }; if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { return Err(io::Error::new( io::ErrorKind::InvalidInput, "cannot set a 0 duration timeout", )); } let start = Instant::now(); loop { let elapsed = start.elapsed(); if elapsed >= timeout { return Err(io::Error::new( io::ErrorKind::TimedOut, "connection timed out", )); } let timeout = timeout - elapsed; let mut timeout = timeout .as_secs() .saturating_mul(1_000) .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000); if timeout == 0 { timeout = 1; } let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int; match unsafe { libc::poll(&mut pollfd, 1, timeout) } { -1 => { let err = io::Error::last_os_error(); if err.kind() != io::ErrorKind::Interrupted { return Err(err); } } 0 => { return Err(io::Error::new( io::ErrorKind::TimedOut, "connection timed out", )) } _ => { // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look // for POLLHUP rather than read readiness if pollfd.revents & libc::POLLHUP != 0 { let e = self.take_error()?.unwrap_or_else(|| { io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP") }); return Err(e); } return 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, )) } } pub fn try_clone(&self) -> io::Result { // implementation lifted from libstd #[cfg(any(target_os = "android", target_os = "haiku"))] use libc::F_DUPFD as F_DUPFD_CLOEXEC; #[cfg(not(any(target_os = "android", target_os = "haiku")))] use libc::F_DUPFD_CLOEXEC; static CLOEXEC_FAILED: AtomicBool = AtomicBool::new(false); unsafe { if !CLOEXEC_FAILED.load(Ordering::Relaxed) { match cvt(libc::fcntl(self.fd, F_DUPFD_CLOEXEC, 0)) { Ok(fd) => { let fd = Socket::from_raw_fd(fd); if cfg!(target_os = "linux") { set_cloexec(fd.as_raw_fd())?; } return Ok(fd); } Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => { CLOEXEC_FAILED.store(true, Ordering::Relaxed); } Err(e) => return Err(e), } } let fd = cvt(libc::fcntl(self.fd, libc::F_DUPFD, 0))?; let fd = Socket::from_raw_fd(fd); set_cloexec(fd.as_raw_fd())?; Ok(fd) } } #[allow(unused_mut)] pub fn accept(&self) -> io::Result<(Socket, SockAddr)> { let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; let mut len = mem::size_of_val(&storage) as socklen_t; let mut socket = None; #[cfg(target_os = "linux")] { let res = cvt_r(|| unsafe { libc::syscall( libc::SYS_accept4, self.fd as libc::c_long, &mut storage as *mut _ as libc::c_long, &mut len, 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), } } let socket = match socket { Some(socket) => socket, None => unsafe { let fd = cvt_r(|| libc::accept(self.fd, &mut storage as *mut _ as *mut _, &mut len))?; let fd = Socket::from_raw_fd(fd); set_cloexec(fd.as_raw_fd())?; fd }, }; let addr = unsafe { SockAddr::from_raw_parts(&storage as *const _ as *const _, len) }; Ok((socket, addr)) } 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<()> { let how = match how { Shutdown::Write => libc::SHUT_WR, Shutdown::Read => libc::SHUT_RD, Shutdown::Both => libc::SHUT_RDWR, }; cvt(unsafe { libc::shutdown(self.fd, how) })?; Ok(()) } 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 { unsafe { let n = cvt({ libc::recv( self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), max_len()), libc::MSG_PEEK, ) })?; Ok(n as usize) } } 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) } 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 { unsafe { let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_UNICAST_HOPS)?; Ok(raw as u32) } } pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> { unsafe { self.setsockopt( libc::IPPROTO_IPV6 as c_int, libc::IPV6_UNICAST_HOPS, hops as c_int, ) } } 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 { unsafe { let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_HOPS)?; Ok(raw as u32) } } pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> { unsafe { self.setsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_HOPS, hops as c_int) } } pub fn multicast_if_v4(&self) -> io::Result { unsafe { let imr_interface: libc::in_addr = self.getsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_IF)?; Ok(from_s_addr(imr_interface.s_addr)) } } pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> { let interface = to_s_addr(interface); let imr_interface = libc::in_addr { s_addr: interface }; unsafe { self.setsockopt(libc::IPPROTO_IP, libc::IP_MULTICAST_IF, imr_interface) } } pub fn multicast_if_v6(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_IF)?; Ok(raw as u32) } } pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> { unsafe { self.setsockopt( libc::IPPROTO_IPV6, libc::IPV6_MULTICAST_IF, interface as c_int, ) } } 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(()) } } #[cfg(all(unix, not(target_os = "solaris"), feature = "reuseport"))] pub fn reuse_port(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT)?; Ok(raw != 0) } } #[cfg(all(unix, not(target_os = "solaris"), 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) } } 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) -> c_int { self.fd } } impl IntoRawFd for Socket { fn into_raw_fd(self) -> c_int { let fd = self.fd; mem::forget(self); return fd; } } impl FromRawFd for Socket { unsafe fn from_raw_fd(fd: c_int) -> Socket { Socket { fd: fd } } } impl AsRawFd for crate::Socket { fn as_raw_fd(&self) -> c_int { self.inner.as_raw_fd() } } impl IntoRawFd for crate::Socket { fn into_raw_fd(self) -> c_int { self.inner.into_raw_fd() } } impl FromRawFd for crate::Socket { unsafe fn from_raw_fd(fd: c_int) -> 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()) } } } #[cfg(all(unix, feature = "unix"))] impl From for UnixStream { fn from(socket: Socket) -> UnixStream { unsafe { UnixStream::from_raw_fd(socket.into_raw_fd()) } } } #[cfg(all(unix, feature = "unix"))] impl From for UnixListener { fn from(socket: Socket) -> UnixListener { unsafe { UnixListener::from_raw_fd(socket.into_raw_fd()) } } } #[cfg(all(unix, feature = "unix"))] impl From for UnixDatagram { fn from(socket: Socket) -> UnixDatagram { unsafe { UnixDatagram::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()) } } } #[cfg(all(unix, feature = "unix"))] impl From for Socket { fn from(socket: UnixStream) -> Socket { unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } } } #[cfg(all(unix, feature = "unix"))] impl From for Socket { fn from(socket: UnixListener) -> Socket { unsafe { Socket::from_raw_fd(socket.into_raw_fd()) } } } #[cfg(all(unix, feature = "unix"))] impl From for Socket { fn from(socket: UnixDatagram) -> 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". // // On macOS, however, apparently the 64-bit libc is either buggy or // intentionally showing odd behavior by rejecting any read with a size // larger than or equal to INT_MAX. To handle both of these the read // size is capped on both platforms. if cfg!(target_os = "macos") { ::max_value() as usize - 1 } else { ::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 cvt_r(mut f: F) -> io::Result where F: FnMut() -> T, T: One + PartialEq + Neg, { loop { match cvt(f()) { Err(ref e) if e.kind() == ErrorKind::Interrupted => {} other => return other, } } } fn set_cloexec(fd: c_int) -> io::Result<()> { unsafe { let previous = cvt(libc::fcntl(fd, libc::F_GETFD))?; let new = previous | libc::FD_CLOEXEC; 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( io::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 from_s_addr(in_addr: libc::in_addr_t) -> Ipv4Addr { let h_addr = crate::ntoh(in_addr); let a: u8 = (h_addr >> 24) as u8; let b: u8 = (h_addr >> 16) as u8; let c: u8 = (h_addr >> 8) as u8; let d: u8 = (h_addr >> 0) as u8; Ipv4Addr::new(a, b, c, d) } 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; } #[cfg(target_os = "android")] fn to_ipv6mr_interface(value: u32) -> c_int { value as c_int } #[cfg(not(target_os = "android"))] 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))); } socket2-0.3.11/src/sys/windows.rs010066400017500001750000000721461346407274400150630ustar0000000000000000// 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::io; use std::io::{Read, Write}; use std::mem; 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::time::Duration; use winapi::ctypes::{c_char, c_int, c_long, c_ulong}; 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; use winapi::um::processthreadsapi::GetCurrentProcessId; use winapi::um::winbase::INFINITE; use winapi::um::winsock2 as sock; use crate::SockAddr; const HANDLE_FLAG_INHERIT: DWORD = 0x00000001; const MSG_PEEK: c_int = 0x2; const SD_BOTH: c_int = 2; const SD_RECEIVE: c_int = 0; 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 const SOCK_SEQPACKET: i32 = ws2def::SOCK_SEQPACKET as i32; pub const SOCK_RAW: i32 = ws2def::SOCK_RAW as i32; #[repr(C)] struct tcp_keepalive { onoff: c_ulong, keepalivetime: c_ulong, keepaliveinterval: c_ulong, } fn init() { static INIT: Once = ONCE_INIT; INIT.call_once(|| { // Initialize winsock through the standard library by just creating a // dummy socket. Whether this is successful or not we drop the result as // libstd will be sure to have initialized winsock. let _ = net::UdpSocket::bind("127.0.0.1:34254"); }); } fn last_error() -> io::Error { io::Error::from_raw_os_error(unsafe { sock::WSAGetLastError() }) } pub struct Socket { socket: sock::SOCKET, } impl Socket { pub fn new(family: c_int, ty: c_int, protocol: c_int) -> io::Result { init(); unsafe { let socket = match sock::WSASocketW( family, ty, protocol, ptr::null_mut(), 0, WSA_FLAG_OVERLAPPED, ) { sock::INVALID_SOCKET => return Err(last_error()), socket => socket, }; let socket = Socket::from_raw_socket(socket as RawSocket); socket.set_no_inherit()?; Ok(socket) } } pub fn bind(&self, addr: &SockAddr) -> io::Result<()> { unsafe { if sock::bind(self.socket, addr.as_ptr(), addr.len()) == 0 { Ok(()) } else { Err(last_error()) } } } pub fn listen(&self, backlog: i32) -> io::Result<()> { unsafe { if sock::listen(self.socket, backlog) == 0 { Ok(()) } else { Err(last_error()) } } } pub fn connect(&self, addr: &SockAddr) -> io::Result<()> { unsafe { if sock::connect(self.socket, addr.as_ptr(), addr.len()) == 0 { Ok(()) } else { Err(last_error()) } } } pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> { self.set_nonblocking(true)?; let r = self.connect(addr); self.set_nonblocking(false)?; match r { Ok(()) => return Ok(()), Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {} Err(e) => return Err(e), } if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { return Err(io::Error::new( io::ErrorKind::InvalidInput, "cannot set a 0 duration timeout", )); } let mut timeout = sock::timeval { tv_sec: timeout.as_secs() as c_long, tv_usec: (timeout.subsec_nanos() / 1000) as c_long, }; if timeout.tv_sec == 0 && timeout.tv_usec == 0 { timeout.tv_usec = 1; } let fds = unsafe { let mut fds = mem::zeroed::(); fds.fd_count = 1; fds.fd_array[0] = self.socket; fds }; let mut writefds = fds; let mut errorfds = fds; match unsafe { sock::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout) } { sock::SOCKET_ERROR => return Err(io::Error::last_os_error()), 0 => { return Err(io::Error::new( io::ErrorKind::TimedOut, "connection timed out", )) } _ => { if writefds.fd_count != 1 { if let Some(e) = self.take_error()? { return Err(e); } } Ok(()) } } } pub fn local_addr(&self) -> io::Result { unsafe { let mut storage: SOCKADDR_STORAGE = mem::zeroed(); let mut len = mem::size_of_val(&storage) as c_int; if sock::getsockname(self.socket, &mut storage as *mut _ as *mut _, &mut len) != 0 { return Err(last_error()); } Ok(SockAddr::from_raw_parts( &storage as *const _ as *const _, len, )) } } pub fn peer_addr(&self) -> io::Result { unsafe { let mut storage: SOCKADDR_STORAGE = mem::zeroed(); let mut len = mem::size_of_val(&storage) as c_int; if sock::getpeername(self.socket, &mut storage as *mut _ as *mut _, &mut len) != 0 { return Err(last_error()); } Ok(SockAddr::from_raw_parts( &storage as *const _ as *const _, len, )) } } pub fn try_clone(&self) -> io::Result { unsafe { let mut info: sock::WSAPROTOCOL_INFOW = mem::zeroed(); let r = sock::WSADuplicateSocketW(self.socket, GetCurrentProcessId(), &mut info); if r != 0 { return Err(io::Error::last_os_error()); } let socket = sock::WSASocketW( info.iAddressFamily, info.iSocketType, info.iProtocol, &mut info, 0, WSA_FLAG_OVERLAPPED, ); let socket = match socket { sock::INVALID_SOCKET => return Err(last_error()), n => Socket::from_raw_socket(n as RawSocket), }; socket.set_no_inherit()?; Ok(socket) } } pub fn accept(&self) -> io::Result<(Socket, SockAddr)> { unsafe { let mut storage: SOCKADDR_STORAGE = mem::zeroed(); let mut len = mem::size_of_val(&storage) as c_int; let socket = { sock::accept(self.socket, &mut storage as *mut _ as *mut _, &mut len) }; let socket = match socket { sock::INVALID_SOCKET => return Err(last_error()), socket => Socket::from_raw_socket(socket as RawSocket), }; socket.set_no_inherit()?; let addr = SockAddr::from_raw_parts(&storage as *const _ as *const _, len); Ok((socket, addr)) } } pub fn take_error(&self) -> io::Result> { unsafe { let raw: c_int = self.getsockopt(SOL_SOCKET, 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 mut nonblocking = nonblocking as c_ulong; let r = sock::ioctlsocket(self.socket, sock::FIONBIO as c_int, &mut nonblocking); if r == 0 { Ok(()) } else { Err(io::Error::last_os_error()) } } } pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { let how = match how { Shutdown::Write => SD_SEND, Shutdown::Read => SD_RECEIVE, Shutdown::Both => SD_BOTH, }; if unsafe { sock::shutdown(self.socket, how) == 0 } { Ok(()) } else { Err(last_error()) } } pub fn recv(&self, buf: &mut [u8]) -> io::Result { unsafe { let n = { sock::recv( self.socket, buf.as_mut_ptr() as *mut c_char, clamp(buf.len()), 0, ) }; match n { sock::SOCKET_ERROR if sock::WSAGetLastError() == sock::WSAESHUTDOWN as i32 => Ok(0), sock::SOCKET_ERROR => Err(last_error()), n => Ok(n as usize), } } } pub fn peek(&self, buf: &mut [u8]) -> io::Result { unsafe { let n = { sock::recv( self.socket, buf.as_mut_ptr() as *mut c_char, clamp(buf.len()), MSG_PEEK, ) }; match n { sock::SOCKET_ERROR if sock::WSAGetLastError() == sock::WSAESHUTDOWN as i32 => Ok(0), sock::SOCKET_ERROR => Err(last_error()), n => Ok(n as usize), } } } 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) } fn recvfrom(&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; let n = { sock::recvfrom( self.socket, buf.as_mut_ptr() as *mut c_char, clamp(buf.len()), flags, &mut storage as *mut _ as *mut _, &mut addrlen, ) }; let n = match n { sock::SOCKET_ERROR if sock::WSAGetLastError() == sock::WSAESHUTDOWN as i32 => 0, sock::SOCKET_ERROR => return Err(last_error()), n => n as usize, }; let addr = SockAddr::from_raw_parts(&storage as *const _ as *const _, addrlen); Ok((n, addr)) } } pub fn send(&self, buf: &[u8]) -> io::Result { unsafe { let n = { sock::send( self.socket, buf.as_ptr() as *const c_char, clamp(buf.len()), 0, ) }; if n == sock::SOCKET_ERROR { Err(last_error()) } else { Ok(n as usize) } } } pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result { unsafe { let n = { sock::sendto( self.socket, buf.as_ptr() as *const c_char, clamp(buf.len()), 0, addr.as_ptr(), addr.len(), ) }; if n == sock::SOCKET_ERROR { Err(last_error()) } else { Ok(n as usize) } } } // ================================================ pub fn ttl(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(IPPROTO_IP, IP_TTL)?; Ok(raw as u32) } } pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { unsafe { self.setsockopt(IPPROTO_IP, IP_TTL, ttl as c_int) } } pub fn unicast_hops_v6(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(IPPROTO_IPV6 as c_int, IPV6_UNICAST_HOPS)?; Ok(raw as u32) } } pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> { unsafe { self.setsockopt(IPPROTO_IPV6 as c_int, IPV6_UNICAST_HOPS, hops as c_int) } } pub fn only_v6(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(IPPROTO_IPV6 as c_int, IPV6_V6ONLY)?; Ok(raw != 0) } } pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { unsafe { self.setsockopt(IPPROTO_IPV6 as c_int, IPV6_V6ONLY, only_v6 as c_int) } } pub fn read_timeout(&self) -> io::Result> { unsafe { Ok(ms2dur(self.getsockopt(SOL_SOCKET, SO_RCVTIMEO)?)) } } pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { unsafe { self.setsockopt(SOL_SOCKET, SO_RCVTIMEO, dur2ms(dur)?) } } pub fn write_timeout(&self) -> io::Result> { unsafe { Ok(ms2dur(self.getsockopt(SOL_SOCKET, SO_SNDTIMEO)?)) } } pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { unsafe { self.setsockopt(SOL_SOCKET, SO_SNDTIMEO, dur2ms(dur)?) } } pub fn nodelay(&self) -> io::Result { unsafe { 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_char) } } pub fn broadcast(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(SOL_SOCKET, SO_BROADCAST)?; Ok(raw != 0) } } pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { unsafe { self.setsockopt(SOL_SOCKET, SO_BROADCAST, broadcast as c_int) } } pub fn multicast_loop_v4(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(IPPROTO_IP, IP_MULTICAST_LOOP)?; Ok(raw != 0) } } pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { unsafe { self.setsockopt(IPPROTO_IP, IP_MULTICAST_LOOP, multicast_loop_v4 as c_int) } } pub fn multicast_ttl_v4(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(IPPROTO_IP, IP_MULTICAST_TTL)?; Ok(raw as u32) } } pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { unsafe { self.setsockopt(IPPROTO_IP, IP_MULTICAST_TTL, multicast_ttl_v4 as c_int) } } pub fn multicast_hops_v6(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(IPPROTO_IPV6 as c_int, IPV6_MULTICAST_HOPS)?; Ok(raw as u32) } } pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> { unsafe { self.setsockopt(IPPROTO_IPV6 as c_int, IPV6_MULTICAST_HOPS, hops as c_int) } } pub fn multicast_if_v4(&self) -> io::Result { unsafe { let imr_interface: IN_ADDR = self.getsockopt(IPPROTO_IP, IP_MULTICAST_IF)?; Ok(from_s_addr(imr_interface.S_un)) } } pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> { let interface = to_s_addr(interface); let imr_interface = IN_ADDR { S_un: interface }; unsafe { self.setsockopt(IPPROTO_IP, IP_MULTICAST_IF, imr_interface) } } pub fn multicast_if_v6(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(IPPROTO_IPV6 as c_int, IPV6_MULTICAST_IF)?; Ok(raw as u32) } } pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> { unsafe { self.setsockopt(IPPROTO_IPV6 as c_int, IPV6_MULTICAST_IF, interface as c_int) } } pub fn multicast_loop_v6(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(IPPROTO_IPV6 as c_int, IPV6_MULTICAST_LOOP)?; Ok(raw != 0) } } pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { unsafe { self.setsockopt( IPPROTO_IPV6 as c_int, 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 = IP_MREQ { imr_multiaddr: IN_ADDR { S_un: multiaddr }, imr_interface: IN_ADDR { S_un: interface }, }; unsafe { self.setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, mreq) } } pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { let multiaddr = to_in6_addr(multiaddr); let mreq = IPV6_MREQ { ipv6mr_multiaddr: multiaddr, ipv6mr_interface: interface, }; unsafe { self.setsockopt(IPPROTO_IP, 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 = IP_MREQ { imr_multiaddr: IN_ADDR { S_un: multiaddr }, imr_interface: IN_ADDR { S_un: interface }, }; unsafe { self.setsockopt(IPPROTO_IP, IP_DROP_MEMBERSHIP, mreq) } } pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> { let multiaddr = to_in6_addr(multiaddr); let mreq = IPV6_MREQ { ipv6mr_multiaddr: multiaddr, ipv6mr_interface: interface, }; unsafe { self.setsockopt(IPPROTO_IP, IPV6_DROP_MEMBERSHIP, mreq) } } pub fn linger(&self) -> io::Result> { unsafe { Ok(linger2dur(self.getsockopt(SOL_SOCKET, SO_LINGER)?)) } } pub fn set_linger(&self, dur: Option) -> io::Result<()> { unsafe { self.setsockopt(SOL_SOCKET, SO_LINGER, dur2linger(dur)) } } pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> { unsafe { self.setsockopt(SOL_SOCKET, SO_REUSEADDR, reuse as c_int) } } pub fn reuse_address(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(SOL_SOCKET, SO_REUSEADDR)?; Ok(raw != 0) } } pub fn recv_buffer_size(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(SOL_SOCKET, 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(SOL_SOCKET, SO_RCVBUF, size as c_int) } } pub fn send_buffer_size(&self) -> io::Result { unsafe { let raw: c_int = self.getsockopt(SOL_SOCKET, 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(SOL_SOCKET, SO_SNDBUF, size as c_int) } } pub fn keepalive(&self) -> io::Result> { let mut ka = tcp_keepalive { onoff: 0, keepalivetime: 0, keepaliveinterval: 0, }; let n = unsafe { sock::WSAIoctl( self.socket, SIO_KEEPALIVE_VALS, 0 as *mut _, 0, &mut ka as *mut _ as *mut _, mem::size_of_val(&ka) as DWORD, 0 as *mut _, 0 as *mut _, None, ) }; if n == 0 { Ok(if ka.onoff == 0 { None } else if ka.keepaliveinterval == 0 { None } else { let seconds = ka.keepaliveinterval / 1000; let nanos = (ka.keepaliveinterval % 1000) * 1_000_000; Some(Duration::new(seconds as u64, nanos as u32)) }) } else { Err(last_error()) } } pub fn set_keepalive(&self, keepalive: Option) -> io::Result<()> { let ms = dur2ms(keepalive)?; // TODO: checked casts here let ka = tcp_keepalive { onoff: keepalive.is_some() as c_ulong, keepalivetime: ms as c_ulong, keepaliveinterval: ms as c_ulong, }; let mut out = 0; let n = unsafe { sock::WSAIoctl( self.socket, SIO_KEEPALIVE_VALS, &ka as *const _ as *mut _, mem::size_of_val(&ka) as DWORD, 0 as *mut _, 0, &mut out, 0 as *mut _, None, ) }; if n == 0 { Ok(()) } else { Err(last_error()) } } 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_char; if sock::setsockopt(self.socket, opt, val, payload, mem::size_of::() as c_int) == 0 { Ok(()) } else { Err(last_error()) } } 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 c_int; if sock::getsockopt( self.socket, opt, val, &mut slot as *mut _ as *mut _, &mut len, ) == 0 { assert_eq!(len as usize, mem::size_of::()); Ok(slot) } else { Err(last_error()) } } fn set_no_inherit(&self) -> io::Result<()> { unsafe { let r = SetHandleInformation(self.socket as HANDLE, HANDLE_FLAG_INHERIT, 0); if r == 0 { Err(io::Error::last_os_error()) } else { Ok(()) } } } } 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 { self.recv(buf) } } 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("socket", &self.socket); 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 AsRawSocket for Socket { fn as_raw_socket(&self) -> RawSocket { self.socket as RawSocket } } impl IntoRawSocket for Socket { fn into_raw_socket(self) -> RawSocket { let socket = self.socket; mem::forget(self); socket as RawSocket } } impl FromRawSocket for Socket { unsafe fn from_raw_socket(socket: RawSocket) -> Socket { Socket { socket: socket as sock::SOCKET, } } } impl AsRawSocket for crate::Socket { fn as_raw_socket(&self) -> RawSocket { self.inner.as_raw_socket() } } impl IntoRawSocket for crate::Socket { fn into_raw_socket(self) -> RawSocket { self.inner.into_raw_socket() } } impl FromRawSocket for crate::Socket { unsafe fn from_raw_socket(socket: RawSocket) -> crate::Socket { crate::Socket { inner: Socket::from_raw_socket(socket), } } } impl Drop for Socket { fn drop(&mut self) { unsafe { let _ = sock::closesocket(self.socket); } } } impl From for net::TcpStream { fn from(socket: Socket) -> net::TcpStream { unsafe { net::TcpStream::from_raw_socket(socket.into_raw_socket()) } } } impl From for net::TcpListener { fn from(socket: Socket) -> net::TcpListener { unsafe { net::TcpListener::from_raw_socket(socket.into_raw_socket()) } } } impl From for net::UdpSocket { fn from(socket: Socket) -> net::UdpSocket { unsafe { net::UdpSocket::from_raw_socket(socket.into_raw_socket()) } } } impl From for Socket { fn from(socket: net::TcpStream) -> Socket { unsafe { Socket::from_raw_socket(socket.into_raw_socket()) } } } impl From for Socket { fn from(socket: net::TcpListener) -> Socket { unsafe { Socket::from_raw_socket(socket.into_raw_socket()) } } } impl From for Socket { fn from(socket: net::UdpSocket) -> Socket { unsafe { Socket::from_raw_socket(socket.into_raw_socket()) } } } fn clamp(input: usize) -> c_int { cmp::min(input, ::max_value() as usize) as c_int } fn dur2ms(dur: Option) -> io::Result { match dur { Some(dur) => { // Note that a duration is a (u64, u32) (seconds, nanoseconds) // pair, and the timeouts in windows APIs are typically u32 // milliseconds. To translate, we have two pieces to take care of: // // * 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() .checked_mul(1000) .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000)) .and_then(|ms| { ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 }) }) .map(|ms| { if ms > ::max_value() as u64 { INFINITE } else { ms as DWORD } }) .unwrap_or(INFINITE); if ms == 0 { return Err(io::Error::new( io::ErrorKind::InvalidInput, "cannot set a 0 duration timeout", )); } Ok(ms) } None => Ok(0), } } fn ms2dur(raw: DWORD) -> Option { if raw == 0 { None } else { let secs = raw / 1000; let nsec = (raw % 1000) * 1000000; Some(Duration::new(secs as u64, nsec as u32)) } } fn to_s_addr(addr: &Ipv4Addr) -> in_addr_S_un { let octets = addr.octets(); let res = crate::hton( ((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() }; unsafe { *(new_addr.S_addr_mut()) = res }; new_addr } fn from_s_addr(in_addr: in_addr_S_un) -> Ipv4Addr { 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; let c: u8 = (h_addr >> 8) as u8; let d: u8 = (h_addr >> 0) as u8; Ipv4Addr::new(a, b, c, d) } fn to_in6_addr(addr: &Ipv6Addr) -> in6_addr { let mut ret_addr: in6_addr_u = unsafe { mem::zeroed() }; unsafe { *(ret_addr.Byte_mut()) = addr.octets() }; let mut ret: in6_addr = unsafe { mem::zeroed() }; ret.u = ret_addr; ret } fn linger2dur(linger_opt: sock::linger) -> Option { if linger_opt.l_onoff == 0 { None } else { Some(Duration::from_secs(linger_opt.l_linger as u64)) } } fn dur2linger(dur: Option) -> sock::linger { match dur { Some(d) => sock::linger { l_onoff: 1, l_linger: d.as_secs() as u16, }, None => sock::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))); } socket2-0.3.11/src/utils.rs010066400017500001750000000023261346407126700137030ustar0000000000000000// 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. #[doc(hidden)] pub trait NetInt { fn from_be(i: Self) -> Self; fn to_be(&self) -> Self; } macro_rules! doit { ($($t:ident)*) => ($(impl NetInt for $t { fn from_be(i: Self) -> Self { <$t>::from_be(i) } fn to_be(&self) -> Self { <$t>::to_be(*self) } })*) } doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } #[doc(hidden)] pub trait One { fn one() -> Self; } macro_rules! one { ($($t:ident)*) => ($( impl One for $t { fn one() -> $t { 1 } } )*) } one! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } #[doc(hidden)] pub trait Zero { fn zero() -> Self; } macro_rules! zero { ($($t:ident)*) => ($( impl Zero for $t { fn zero() -> $t { 0 } } )*) } zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } socket2-0.3.11/.cargo_vcs_info.json0000644000000001120000000000000125210ustar00{ "git": { "sha1": "ffe02a037b2b1c851f17b666fe47de889152de0b" } }