diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/net2 | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/net2')
-rw-r--r-- | third_party/rust/net2/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/net2/Cargo.toml | 51 | ||||
-rw-r--r-- | third_party/rust/net2/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | third_party/rust/net2/LICENSE-MIT | 25 | ||||
-rw-r--r-- | third_party/rust/net2/README.md | 31 | ||||
-rw-r--r-- | third_party/rust/net2/src/ext.rs | 1466 | ||||
-rw-r--r-- | third_party/rust/net2/src/lib.rs | 126 | ||||
-rw-r--r-- | third_party/rust/net2/src/socket.rs | 260 | ||||
-rw-r--r-- | third_party/rust/net2/src/sys/unix/impls.rs | 44 | ||||
-rw-r--r-- | third_party/rust/net2/src/sys/unix/mod.rs | 104 | ||||
-rw-r--r-- | third_party/rust/net2/src/sys/wasi/impls.rs | 33 | ||||
-rw-r--r-- | third_party/rust/net2/src/sys/wasi/mod.rs | 185 | ||||
-rw-r--r-- | third_party/rust/net2/src/sys/windows/impls.rs | 44 | ||||
-rw-r--r-- | third_party/rust/net2/src/sys/windows/mod.rs | 125 | ||||
-rw-r--r-- | third_party/rust/net2/src/tcp.rs | 161 | ||||
-rw-r--r-- | third_party/rust/net2/src/udp.rs | 89 | ||||
-rw-r--r-- | third_party/rust/net2/src/unix.rs | 57 | ||||
-rw-r--r-- | third_party/rust/net2/src/utils.rs | 51 |
18 files changed, 3054 insertions, 0 deletions
diff --git a/third_party/rust/net2/.cargo-checksum.json b/third_party/rust/net2/.cargo-checksum.json new file mode 100644 index 0000000000..0605e787bc --- /dev/null +++ b/third_party/rust/net2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"fd3b1aa06b845c62754d8eaf1ca8a4cc07126b2fb76ed822a470a8881240f3db","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"a99cb0401bd49e68c945f6a249175dd5c4a5117b2c8cc5d5fb7dea369002574e","src/ext.rs":"08e78272ef677efcb4c029489214055ddb392f3163a931f260fccbd8a824eb51","src/lib.rs":"2f20b711078a365240f2c7683d9c34cac7c09bfd4756d89bf099bff56fb0de72","src/socket.rs":"f544539c94ccf8fc8710edbbf170d706a6037319e562b7d253aff2e1a75b7c48","src/sys/unix/impls.rs":"05f123226e8fe7559317d50864021650b2455d25d01a9aff1c65c01ae26cf4ef","src/sys/unix/mod.rs":"e06b26bad48c815b9a2af4509d1873333e2aad0031980f6d2625f72542698d56","src/sys/wasi/impls.rs":"da4e95a27a765b64fbbebce55b860020ac891456085ed706d5f8f391e0d1cddf","src/sys/wasi/mod.rs":"e88b02f4d5e0ae558f093d49cc0bb1b3cdf86ede625d00ed9231f0ab414e483f","src/sys/windows/impls.rs":"bee70b7cd45055c4eaa1967f7aad7ec46639de458c71ed6f3e97a2f7b2c49281","src/sys/windows/mod.rs":"31a73007ea65a4905e93395f86105d2ef9fb84d3d795511c6cfdc8cba595cb0c","src/tcp.rs":"0bebf5cca75714151de30c8f2d7697ca519c57da065e93ba81796bce04673f8d","src/udp.rs":"8af5a55a4ae5e4120ffe18dcc4dc24072e18da34bf3591a02b18653e5d3e8ac8","src/unix.rs":"1156707694cb1f002a2eb2144bf205a73412e1661fd196a8a2a7bc8ea5aaad2d","src/utils.rs":"d31de5333a6fa2f5c99b64cc937be596888d9863264632e6bc6b36b30197fa5b"},"package":"74d0df99cfcd2530b2e694f6e17e7f37b8e26bb23983ac530c0c97408837c631"}
\ No newline at end of file diff --git a/third_party/rust/net2/Cargo.toml b/third_party/rust/net2/Cargo.toml new file mode 100644 index 0000000000..702ee35475 --- /dev/null +++ b/third_party/rust/net2/Cargo.toml @@ -0,0 +1,51 @@ +# 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 are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +name = "net2" +version = "0.2.38" +authors = ["Alex Crichton <alex@alexcrichton.com>"] +include = [ + "Cargo.toml", + "LICENSE-APACHE", + "LICENSE-MIT", + "README.md", + "src/**/*.rs", +] +description = """ +Extensions to the standard library's networking types as proposed in RFC 1158. +""" +homepage = "https://github.com/deprecrated/net2-rs" +documentation = "https://docs.rs/net2/~0.2" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/deprecrated/net2-rs" + +[dependencies.cfg-if] +version = "0.1" + +[features] +default = ["duration"] +duration = [] +nightly = [] + +[target."cfg(any(unix, target_os=\"wasi\"))".dependencies.libc] +version = "0.2.54" + +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = [ + "handleapi", + "winsock2", + "ws2def", + "ws2ipdef", + "ws2tcpip", +] diff --git a/third_party/rust/net2/LICENSE-APACHE b/third_party/rust/net2/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/net2/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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. diff --git a/third_party/rust/net2/LICENSE-MIT b/third_party/rust/net2/LICENSE-MIT new file mode 100644 index 0000000000..39d4bdb5ac --- /dev/null +++ b/third_party/rust/net2/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +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. diff --git a/third_party/rust/net2/README.md b/third_party/rust/net2/README.md new file mode 100644 index 0000000000..9818422220 --- /dev/null +++ b/third_party/rust/net2/README.md @@ -0,0 +1,31 @@ +# net2 + +Extensions to the standard library's networking types, proposed in [RFC 1158][rfc]. + +[rfc]: https://github.com/alexcrichton/rfcs/blob/net2.1/text/0000-io-net-2.1.md + +[![Build Status](https://github.com/deprecrated/net2-rs/workflows/CI/badge.svg)](https://github.com/deprecrated/net2-rs/actions?query=workflow%3ACI+branch%3Amaster) +[![Documentation](https://docs.rs/net2/badge.svg?version=0.2)](https://docs.rs/net2/~0.2) + +# net2 is Deprecated + +Prospective and existing consumers are encouraged to consider +[socket2](https://crates.io/crates/socket2) instead. + + +# 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 Serde by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/third_party/rust/net2/src/ext.rs b/third_party/rust/net2/src/ext.rs new file mode 100644 index 0000000000..76e58d9b79 --- /dev/null +++ b/third_party/rust/net2/src/ext.rs @@ -0,0 +1,1466 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style, dead_code)] + +use std::io; +use std::mem; +use std::net::{TcpStream, TcpListener, UdpSocket, Ipv4Addr, Ipv6Addr}; +use std::net::ToSocketAddrs; + +use {TcpBuilder, UdpBuilder, FromInner}; +use sys; +use sys::c; +use socket; + +cfg_if! { + if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "illumos", + target_env = "uclibc"))] { + use libc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; + use libc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; + } else { + // ... + } +} + +use std::time::Duration; + +#[cfg(any(unix, target_os = "wasi"))] use libc::*; +#[cfg(any(unix))] use std::os::unix::prelude::*; +#[cfg(target_os = "wasi")] use std::os::wasi::prelude::*; +#[cfg(unix)] pub type Socket = c_int; +#[cfg(target_os = "wasi")] pub type Socket = std::os::wasi::io::RawFd; +#[cfg(windows)] pub type Socket = SOCKET; +#[cfg(windows)] use std::os::windows::prelude::*; +#[cfg(any(windows, target_os = "wasi"))] use sys::c::*; + +#[cfg(windows)] const SIO_KEEPALIVE_VALS: DWORD = 0x98000004; +#[cfg(windows)] +#[repr(C)] +struct tcp_keepalive { + onoff: c_ulong, + keepalivetime: c_ulong, + keepaliveinterval: c_ulong, +} + +#[cfg(any(unix, target_os = "wasi"))] fn v(opt: c_int) -> c_int { opt } +#[cfg(windows)] fn v(opt: IPPROTO) -> c_int { opt as c_int } + +#[cfg(target_os = "wasi")] +pub fn set_opt<T: Copy>(_sock: Socket, _opt: c_int, _val: c_int, + _payload: T) -> io::Result<()> { + Ok(()) +} + +#[cfg(not(target_os = "wasi"))] +pub fn set_opt<T: Copy>(sock: Socket, opt: c_int, val: c_int, + payload: T) -> io::Result<()> { + unsafe { + let payload = &payload as *const T as *const c_void; + try!(::cvt(setsockopt(sock, opt, val, payload as *const _, + mem::size_of::<T>() as socklen_t))); + } + Ok(()) +} + +#[cfg(target_os = "wasi")] +pub fn get_opt<T: Copy>(_sock: Socket, _opt: c_int, _val: c_int) -> io::Result<T> { + unimplemented!() +} +#[cfg(not(target_os = "wasi"))] +pub fn get_opt<T: Copy>(sock: Socket, opt: c_int, val: c_int) -> io::Result<T> { + unsafe { + let mut slot: T = mem::zeroed(); + let mut len = mem::size_of::<T>() as socklen_t; + try!(::cvt(getsockopt(sock, opt, val, + &mut slot as *mut _ as *mut _, + &mut len))); + assert_eq!(len as usize, mem::size_of::<T>()); + Ok(slot) + } +} + +/// Extension methods for the standard [`TcpStream` type][link] in `std::net`. +/// +/// [link]: https://doc.rust-lang.org/std/net/struct.TcpStream.html +pub trait TcpStreamExt { + /// 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. + fn set_nodelay(&self, nodelay: bool) -> io::Result<()>; + + /// Gets the value of the `TCP_NODELAY` option on this socket. + /// + /// For more information about this option, see [`set_nodelay`][link]. + /// + /// [link]: #tymethod.set_nodelay + fn nodelay(&self) -> io::Result<bool>; + + /// 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. + fn set_recv_buffer_size(&self, size: usize) -> io::Result<()>; + + /// Gets the value of the `SO_RCVBUF` option on this socket. + /// + /// For more information about this option, see [`set_recv_buffer_size`][link]. + /// + /// [link]: #tymethod.set_recv_buffer_size + fn recv_buffer_size(&self) -> io::Result<usize>; + + /// 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. + fn set_send_buffer_size(&self, size: usize) -> io::Result<()>; + + /// Gets the value of the `SO_SNDBUF` option on this socket. + /// + /// For more information about this option, see [`set_send_buffer`][link]. + /// + /// [link]: #tymethod.set_send_buffer + fn send_buffer_size(&self) -> io::Result<usize>; + + /// 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 number of milliseconds specified will be the time to remain idle + /// before sending a TCP keepalive probe. + /// + /// Some platforms specify this value in seconds, so sub-second millisecond + /// specifications may be omitted. + fn set_keepalive_ms(&self, keepalive: Option<u32>) -> io::Result<()>; + + /// Returns whether keepalive messages are enabled on this socket, and if so + /// the amount of milliseconds between them. + /// + /// For more information about this option, see [`set_keepalive_ms`][link]. + /// + /// [link]: #tymethod.set_keepalive_ms + fn keepalive_ms(&self) -> io::Result<Option<u32>>; + + /// 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. + fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()>; + + /// 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]: #tymethod.set_keepalive + fn keepalive(&self) -> io::Result<Option<Duration>>; + + /// Sets the `SO_RCVTIMEO` option for this socket. + /// + /// This option specifies the timeout, in milliseconds, of how long calls to + /// this socket's `read` function will wait before returning a timeout. A + /// value of `None` means that no read timeout should be specified and + /// otherwise `Some` indicates the number of milliseconds for the timeout. + fn set_read_timeout_ms(&self, val: Option<u32>) -> io::Result<()>; + + /// Sets the `SO_RCVTIMEO` option for this socket. + /// + /// This option specifies the timeout of how long calls to this socket's + /// `read` function will wait before returning a timeout. A value of `None` + /// means that no read timeout should be specified and otherwise `Some` + /// indicates the number of duration of the timeout. + fn set_read_timeout(&self, val: Option<Duration>) -> io::Result<()>; + + /// Gets the value of the `SO_RCVTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_read_timeout_ms`][link]. + /// + /// [link]: #tymethod.set_read_timeout_ms + fn read_timeout_ms(&self) -> io::Result<Option<u32>>; + + /// Gets the value of the `SO_RCVTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_read_timeout`][link]. + /// + /// [link]: #tymethod.set_read_timeout + fn read_timeout(&self) -> io::Result<Option<Duration>>; + + /// Sets the `SO_SNDTIMEO` option for this socket. + /// + /// This option specifies the timeout, in milliseconds, of how long calls to + /// this socket's `write` function will wait before returning a timeout. A + /// value of `None` means that no read timeout should be specified and + /// otherwise `Some` indicates the number of milliseconds for the timeout. + fn set_write_timeout_ms(&self, val: Option<u32>) -> io::Result<()>; + + /// Sets the `SO_SNDTIMEO` option for this socket. + /// + /// This option specifies the timeout of how long calls to this socket's + /// `write` function will wait before returning a timeout. A value of `None` + /// means that no read timeout should be specified and otherwise `Some` + /// indicates the duration of the timeout. + fn set_write_timeout(&self, val: Option<Duration>) -> io::Result<()>; + + /// Gets the value of the `SO_SNDTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_write_timeout_ms`][link]. + /// + /// [link]: #tymethod.set_write_timeout_ms + fn write_timeout_ms(&self) -> io::Result<Option<u32>>; + + /// Gets the value of the `SO_SNDTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_write_timeout`][link]. + /// + /// [link]: #tymethod.set_write_timeout + fn write_timeout(&self) -> io::Result<Option<Duration>>; + + /// 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. + fn set_ttl(&self, ttl: u32) -> io::Result<()>; + + /// Gets the value of the `IP_TTL` option for this socket. + /// + /// For more information about this option, see [`set_ttl`][link]. + /// + /// [link]: #tymethod.set_ttl + fn ttl(&self) -> io::Result<u32>; + + /// 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. + fn set_only_v6(&self, only_v6: bool) -> io::Result<()>; + + /// Gets the value of the `IPV6_V6ONLY` option for this socket. + /// + /// For more information about this option, see [`set_only_v6`][link]. + /// + /// [link]: #tymethod.set_only_v6 + fn only_v6(&self) -> io::Result<bool>; + + /// Executes a `connect` operation on this socket, establishing a connection + /// to the host specified by `addr`. + /// + /// Note that this normally does not need to be called on a `TcpStream`, + /// it's typically automatically done as part of a normal + /// `TcpStream::connect` function call or `TcpBuilder::connect` method call. + /// + /// This should only be necessary if an unconnected socket was extracted + /// from a `TcpBuilder` and then needs to be connected. + fn connect<T: ToSocketAddrs>(&self, addr: T) -> io::Result<()>; + + /// 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. + fn take_error(&self) -> io::Result<Option<io::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. + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()>; + + /// Sets the linger duration of this socket by setting the SO_LINGER option + fn set_linger(&self, dur: Option<Duration>) -> io::Result<()>; + + /// reads the linger duration for this socket by getting the SO_LINGER option + fn linger(&self) -> io::Result<Option<Duration>>; +} + +/// Extension methods for the standard [`TcpListener` type][link] in `std::net`. +/// +/// [link]: https://doc.rust-lang.org/std/net/struct.TcpListener.html +pub trait TcpListenerExt { + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This is the same as [`TcpStreamExt::set_ttl`][other]. + /// + /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl + fn set_ttl(&self, ttl: u32) -> io::Result<()>; + + /// Gets the value of the `IP_TTL` option for this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_ttl`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_ttl + fn ttl(&self) -> io::Result<u32>; + + /// Sets the value for the `IPV6_V6ONLY` option on this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_only_v6`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6 + fn set_only_v6(&self, only_v6: bool) -> io::Result<()>; + + /// Gets the value of the `IPV6_V6ONLY` option for this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_only_v6`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6 + fn only_v6(&self) -> io::Result<bool>; + + /// 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. + fn take_error(&self) -> io::Result<Option<io::Error>>; + + /// Moves this TCP listener into or out of nonblocking mode. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_nonblocking`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_nonblocking + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()>; + + /// Sets the linger duration of this socket by setting the SO_LINGER option + fn set_linger(&self, dur: Option<Duration>) -> io::Result<()>; + + /// reads the linger duration for this socket by getting the SO_LINGER option + fn linger(&self) -> io::Result<Option<Duration>>; +} + +/// Extension methods for the standard [`UdpSocket` type][link] in `std::net`. +/// +/// [link]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html +pub trait UdpSocketExt { + /// 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. + fn set_recv_buffer_size(&self, size: usize) -> io::Result<()>; + + /// Gets the value of the `SO_RCVBUF` option on this socket. + /// + /// For more information about this option, see [`set_recv_buffer_size`][link]. + /// + /// [link]: #tymethod.set_recv_buffer_size + fn recv_buffer_size(&self) -> io::Result<usize>; + + /// 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. + fn set_send_buffer_size(&self, size: usize) -> io::Result<()>; + + /// Gets the value of the `SO_SNDBUF` option on this socket. + /// + /// For more information about this option, see [`set_send_buffer`][link]. + /// + /// [link]: #tymethod.set_send_buffer + fn send_buffer_size(&self) -> io::Result<usize>; + + /// Sets the value of the `SO_BROADCAST` option for this socket. + /// + /// When enabled, this socket is allowed to send packets to a broadcast + /// address. + fn set_broadcast(&self, broadcast: bool) -> io::Result<()>; + + /// Gets the value of the `SO_BROADCAST` option for this socket. + /// + /// For more information about this option, see + /// [`set_broadcast`][link]. + /// + /// [link]: #tymethod.set_broadcast + fn broadcast(&self) -> io::Result<bool>; + + /// 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. + fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()>; + + /// 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]: #tymethod.set_multicast_loop_v4 + fn multicast_loop_v4(&self) -> io::Result<bool>; + + /// 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. + fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()>; + + /// 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]: #tymethod.set_multicast_ttl_v4 + fn multicast_ttl_v4(&self) -> io::Result<u32>; + + /// Sets the value of the `IPV6_MULTICAST_HOPS` option for this socket + fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()>; + + /// Gets the value of the `IPV6_MULTICAST_HOPS` option for this socket + fn multicast_hops_v6(&self) -> io::Result<u32>; + + /// 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. + fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()>; + + /// 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]: #tymethod.set_multicast_loop_v6 + fn multicast_loop_v6(&self) -> io::Result<bool>; + + /// Sets the value of the `IP_MULTICAST_IF` option for this socket. + /// + /// Specifies the interface to use for routing multicast packets. + fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()>; + + /// Gets the value of the `IP_MULTICAST_IF` option for this socket. + /// + /// Returns the interface to use for routing multicast packets. + fn multicast_if_v4(&self) -> io::Result<Ipv4Addr>; + + + /// Sets the value of the `IPV6_MULTICAST_IF` option for this socket. + /// + /// Specifies the interface to use for routing multicast packets. + fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()>; + + /// Gets the value of the `IPV6_MULTICAST_IF` option for this socket. + /// + /// Returns the interface to use for routing multicast packets. + fn multicast_if_v6(&self) -> io::Result<u32>; + + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This is the same as [`TcpStreamExt::set_ttl`][other]. + /// + /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl + fn set_ttl(&self, ttl: u32) -> io::Result<()>; + + /// Gets the value of the `IP_TTL` option for this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_ttl`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_ttl + fn ttl(&self) -> io::Result<u32>; + + /// Sets the value for the `IPV6_UNICAST_HOPS` option on this socket. + /// + /// Specifies the hop limit for ipv6 unicast packets + fn set_unicast_hops_v6(&self, ttl: u32) -> io::Result<()>; + + /// Gets the value of the `IPV6_UNICAST_HOPS` option for this socket. + /// + /// Specifies the hop limit for ipv6 unicast packets + fn unicast_hops_v6(&self) -> io::Result<u32>; + + /// Sets the value for the `IPV6_V6ONLY` option on this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_only_v6`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6 + fn set_only_v6(&self, only_v6: bool) -> io::Result<()>; + + /// Gets the value of the `IPV6_V6ONLY` option for this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_only_v6`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6 + fn only_v6(&self) -> io::Result<bool>; + + /// 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. + fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) + -> io::Result<()>; + + /// 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). + fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) + -> io::Result<()>; + + /// Executes an operation of the `IP_DROP_MEMBERSHIP` type. + /// + /// For more information about this option, see + /// [`join_multicast_v4`][link]. + /// + /// [link]: #tymethod.join_multicast_v4 + fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) + -> io::Result<()>; + + /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type. + /// + /// For more information about this option, see + /// [`join_multicast_v6`][link]. + /// + /// [link]: #tymethod.join_multicast_v6 + fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) + -> io::Result<()>; + + /// Sets the `SO_RCVTIMEO` option for this socket. + /// + /// This option specifies the timeout, in milliseconds, of how long calls to + /// this socket's `read` function will wait before returning a timeout. A + /// value of `None` means that no read timeout should be specified and + /// otherwise `Some` indicates the number of milliseconds for the timeout. + fn set_read_timeout_ms(&self, val: Option<u32>) -> io::Result<()>; + + /// Sets the `SO_RCVTIMEO` option for this socket. + /// + /// This option specifies the timeout of how long calls to this socket's + /// `read` function will wait before returning a timeout. A value of `None` + /// means that no read timeout should be specified and otherwise `Some` + /// indicates the number of duration of the timeout. + fn set_read_timeout(&self, val: Option<Duration>) -> io::Result<()>; + + /// Gets the value of the `SO_RCVTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_read_timeout_ms`][link]. + /// + /// [link]: #tymethod.set_read_timeout_ms + fn read_timeout_ms(&self) -> io::Result<Option<u32>>; + + /// Gets the value of the `SO_RCVTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_read_timeout`][link]. + /// + /// [link]: #tymethod.set_read_timeout + fn read_timeout(&self) -> io::Result<Option<Duration>>; + + /// Sets the `SO_SNDTIMEO` option for this socket. + /// + /// This option specifies the timeout, in milliseconds, of how long calls to + /// this socket's `write` function will wait before returning a timeout. A + /// value of `None` means that no read timeout should be specified and + /// otherwise `Some` indicates the number of milliseconds for the timeout. + fn set_write_timeout_ms(&self, val: Option<u32>) -> io::Result<()>; + + /// Sets the `SO_SNDTIMEO` option for this socket. + /// + /// This option specifies the timeout of how long calls to this socket's + /// `write` function will wait before returning a timeout. A value of `None` + /// means that no read timeout should be specified and otherwise `Some` + /// indicates the duration of the timeout. + fn set_write_timeout(&self, val: Option<Duration>) -> io::Result<()>; + + /// Gets the value of the `SO_SNDTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_write_timeout_ms`][link]. + /// + /// [link]: #tymethod.set_write_timeout_ms + fn write_timeout_ms(&self) -> io::Result<Option<u32>>; + + /// Gets the value of the `SO_SNDTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_write_timeout`][link]. + /// + /// [link]: #tymethod.set_write_timeout + fn write_timeout(&self) -> io::Result<Option<Duration>>; + + /// 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. + fn take_error(&self) -> io::Result<Option<io::Error>>; + + /// Connects this UDP socket to a remote address, allowing the `send` and + /// `recv` syscalls to be used to send data and also applies filters to only + /// receive data from the specified address. + fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()>; + + /// Sends data on the socket to 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. + fn send(&self, buf: &[u8]) -> io::Result<usize>; + + /// 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. + fn recv(&self, buf: &mut [u8]) -> io::Result<usize>; + + /// Moves this UDP socket into or out of nonblocking mode. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_nonblocking`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_nonblocking + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()>; +} + +#[doc(hidden)] +pub trait AsSock { + fn as_sock(&self) -> Socket; +} + +#[cfg(any(unix, target_os = "wasi"))] +impl<T: AsRawFd> AsSock for T { + fn as_sock(&self) -> Socket { self.as_raw_fd() } +} +#[cfg(windows)] +impl<T: AsRawSocket> AsSock for T { + fn as_sock(&self) -> Socket { self.as_raw_socket() as Socket } +} + +cfg_if! { + if #[cfg(any(target_os = "macos", target_os = "ios"))] { + use libc::TCP_KEEPALIVE as KEEPALIVE_OPTION; + } else if #[cfg(any(target_os = "haiku", target_os = "netbsd", target_os = "openbsd"))] { + use libc::SO_KEEPALIVE as KEEPALIVE_OPTION; + } else if #[cfg(unix)] { + use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION; + } else { + // ... + } +} + +impl TcpStreamExt for TcpStream { + + fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { + // TODO: casting usize to a c_int should be a checked cast + set_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF, size as c_int) + } + + fn recv_buffer_size(&self) -> io::Result<usize> { + get_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF).map(int2usize) + } + + fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF, size as c_int) + } + + fn send_buffer_size(&self) -> io::Result<usize> { + get_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF).map(int2usize) + } + + fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_TCP), TCP_NODELAY, + nodelay as c_int) + } + fn nodelay(&self) -> io::Result<bool> { + get_opt(self.as_sock(), v(IPPROTO_TCP), TCP_NODELAY) + .map(int2bool) + } + + fn set_keepalive(&self, keepalive: Option<Duration>) -> io::Result<()> { + self.set_keepalive_ms(keepalive.map(dur2ms)) + } + + fn keepalive(&self) -> io::Result<Option<Duration>> { + self.keepalive_ms().map(|o| o.map(ms2dur)) + } + + #[cfg(unix)] + fn set_keepalive_ms(&self, keepalive: Option<u32>) -> io::Result<()> { + try!(set_opt(self.as_sock(), SOL_SOCKET, SO_KEEPALIVE, + keepalive.is_some() as c_int)); + if let Some(dur) = keepalive { + try!(set_opt(self.as_sock(), v(IPPROTO_TCP), KEEPALIVE_OPTION, + (dur / 1000) as c_int)); + } + Ok(()) + } + + #[cfg(unix)] + fn keepalive_ms(&self) -> io::Result<Option<u32>> { + let keepalive = try!(get_opt::<c_int>(self.as_sock(), SOL_SOCKET, + SO_KEEPALIVE)); + if keepalive == 0 { + return Ok(None) + } + let secs = try!(get_opt::<c_int>(self.as_sock(), v(IPPROTO_TCP), + KEEPALIVE_OPTION)); + Ok(Some((secs as u32) * 1000)) + } + + #[cfg(target_os = "wasi")] + fn set_keepalive_ms(&self, _keepalive: Option<u32>) -> io::Result<()> { + unimplemented!() + } + + #[cfg(target_os = "wasi")] + fn keepalive_ms(&self) -> io::Result<Option<u32>> { + unimplemented!() + } + + #[cfg(windows)] + fn set_keepalive_ms(&self, keepalive: Option<u32>) -> io::Result<()> { + let ms = keepalive.unwrap_or(INFINITE); + let ka = tcp_keepalive { + onoff: keepalive.is_some() as c_ulong, + keepalivetime: ms as c_ulong, + keepaliveinterval: ms as c_ulong, + }; + unsafe { + ::cvt_win(WSAIoctl(self.as_sock(), + SIO_KEEPALIVE_VALS, + &ka as *const _ as *mut _, + mem::size_of_val(&ka) as DWORD, + 0 as *mut _, + 0, + 0 as *mut _, + 0 as *mut _, + None)).map(|_| ()) + } + } + + #[cfg(windows)] + fn keepalive_ms(&self) -> io::Result<Option<u32>> { + let mut ka = tcp_keepalive { + onoff: 0, + keepalivetime: 0, + keepaliveinterval: 0, + }; + unsafe { + try!(::cvt_win(WSAIoctl(self.as_sock(), + 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))); + } + Ok({ + if ka.onoff == 0 { + None + } else { + timeout2ms(ka.keepaliveinterval as DWORD) + } + }) + } + + fn set_read_timeout_ms(&self, dur: Option<u32>) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO, + ms2timeout(dur)) + } + + fn read_timeout_ms(&self) -> io::Result<Option<u32>> { + get_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO) + .map(timeout2ms) + } + + fn set_write_timeout_ms(&self, dur: Option<u32>) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO, + ms2timeout(dur)) + } + + fn write_timeout_ms(&self) -> io::Result<Option<u32>> { + get_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO) + .map(timeout2ms) + } + + fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + self.set_read_timeout_ms(dur.map(dur2ms)) + } + + fn read_timeout(&self) -> io::Result<Option<Duration>> { + self.read_timeout_ms().map(|o| o.map(ms2dur)) + } + + fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + self.set_write_timeout_ms(dur.map(dur2ms)) + } + + fn write_timeout(&self) -> io::Result<Option<Duration>> { + self.write_timeout_ms().map(|o| o.map(ms2dur)) + } + + fn set_ttl(&self, ttl: u32) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int) + } + + fn ttl(&self) -> io::Result<u32> { + get_opt::<c_int>(self.as_sock(), IPPROTO_IP, IP_TTL) + .map(|b| b as u32) + } + + fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int) + } + + fn only_v6(&self) -> io::Result<bool> { + get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY).map(int2bool) + } + + fn connect<T: ToSocketAddrs>(&self, addr: T) -> io::Result<()> { + do_connect(self.as_sock(), addr) + } + + fn take_error(&self) -> io::Result<Option<io::Error>> { + get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err) + } + + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + set_nonblocking(self.as_sock(), nonblocking) + } + + fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_LINGER, dur2linger(dur)) + } + + fn linger(&self) -> io::Result<Option<Duration>> { + get_opt(self.as_sock(), SOL_SOCKET, SO_LINGER).map(linger2dur) + } +} + +#[cfg(any(unix, target_os = "wasi"))] +fn ms2timeout(dur: Option<u32>) -> timeval { + // TODO: be more rigorous + match dur { + Some(d) => timeval { + tv_sec: (d / 1000) as time_t, + tv_usec: (d % 1000) as suseconds_t, + }, + None => timeval { tv_sec: 0, tv_usec: 0 }, + } +} + +#[cfg(any(unix, target_os = "wasi"))] +fn timeout2ms(dur: timeval) -> Option<u32> { + if dur.tv_sec == 0 && dur.tv_usec == 0 { + None + } else { + Some(dur.tv_sec as u32 * 1000 + dur.tv_usec as u32 / 1000) + } +} + +#[cfg(windows)] +fn ms2timeout(dur: Option<u32>) -> DWORD { + dur.unwrap_or(0) +} + +#[cfg(windows)] +fn timeout2ms(dur: DWORD) -> Option<u32> { + if dur == 0 { + None + } else { + Some(dur) + } +} + +fn linger2dur(linger_opt: linger) -> Option<Duration> { + if linger_opt.l_onoff == 0 { + None + } + else { + Some(Duration::from_secs(linger_opt.l_linger as u64)) + } +} + +#[cfg(windows)] +fn dur2linger(dur: Option<Duration>) -> linger { + match dur { + Some(d) => { + linger { + l_onoff: 1, + l_linger: d.as_secs() as u16, + } + }, + None => linger { l_onoff: 0, l_linger: 0 }, + } +} + +#[cfg(any(unix, target_os = "wasi"))] +fn dur2linger(dur: Option<Duration>) -> linger { + match dur { + Some(d) => { + linger { + l_onoff: 1, + l_linger: d.as_secs() as c_int, + } + }, + None => linger { l_onoff: 0, l_linger: 0 }, + } +} + +fn ms2dur(ms: u32) -> Duration { + Duration::new((ms as u64) / 1000, (ms as u32) % 1000 * 1_000_000) +} + +fn dur2ms(dur: Duration) -> u32 { + (dur.as_secs() as u32 * 1000) + (dur.subsec_nanos() / 1_000_000) +} + +pub fn int2bool(n: c_int) -> bool { + if n == 0 {false} else {true} +} + +pub fn int2usize(n: c_int) -> usize { + // TODO: casting c_int to a usize should be a checked cast + n as usize +} + +pub fn int2err(n: c_int) -> Option<io::Error> { + if n == 0 { + None + } else { + Some(io::Error::from_raw_os_error(n as i32)) + } +} + +impl UdpSocketExt for UdpSocket { + + fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF, size as c_int) + } + + fn recv_buffer_size(&self) -> io::Result<usize> { + get_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF).map(int2usize) + } + + fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF, size as c_int) + } + + fn send_buffer_size(&self) -> io::Result<usize> { + get_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF).map(int2usize) + } + + fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_BROADCAST, + broadcast as c_int) + } + fn broadcast(&self) -> io::Result<bool> { + get_opt(self.as_sock(), SOL_SOCKET, SO_BROADCAST) + .map(int2bool) + } + fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_LOOP, + multicast_loop_v4 as c_int) + } + fn multicast_loop_v4(&self) -> io::Result<bool> { + get_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_LOOP) + .map(int2bool) + } + + fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_TTL, + multicast_ttl_v4 as c_int) + } + + fn multicast_ttl_v4(&self) -> io::Result<u32> { + get_opt::<c_int>(self.as_sock(), IPPROTO_IP, IP_MULTICAST_TTL) + .map(|b| b as u32) + } + + fn set_multicast_hops_v6(&self, _hops: u32) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_HOPS, + _hops as c_int) + } + + fn multicast_hops_v6(&self) -> io::Result<u32> { + get_opt::<c_int>(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_HOPS) + .map(|b| b as u32) + } + + fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_LOOP, + multicast_loop_v6 as c_int) + } + fn multicast_loop_v6(&self) -> io::Result<bool> { + get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_LOOP) + .map(int2bool) + } + + fn set_multicast_if_v4(&self, _interface: &Ipv4Addr) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_IF, ip2in_addr(_interface)) + } + + fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> { + get_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_IF).map(in_addr2ip) + } + + fn set_multicast_if_v6(&self, _interface: u32) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_IF, to_ipv6mr_interface(_interface)) + } + + fn multicast_if_v6(&self) -> io::Result<u32> { + get_opt::<c_int>(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_IF).map(|b| b as u32) + } + + fn set_ttl(&self, ttl: u32) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int) + } + + fn ttl(&self) -> io::Result<u32> { + get_opt::<c_int>(self.as_sock(), IPPROTO_IP, IP_TTL) + .map(|b| b as u32) + } + + fn set_unicast_hops_v6(&self, _ttl: u32) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_UNICAST_HOPS, _ttl as c_int) + } + + fn unicast_hops_v6(&self) -> io::Result<u32> { + get_opt::<c_int>(self.as_sock(), IPPROTO_IP, IPV6_UNICAST_HOPS) + .map(|b| b as u32) + } + + fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int) + } + + fn only_v6(&self) -> io::Result<bool> { + get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY).map(int2bool) + } + + fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) + -> io::Result<()> { + let mreq = ip_mreq { + imr_multiaddr: ip2in_addr(multiaddr), + imr_interface: ip2in_addr(interface), + }; + set_opt(self.as_sock(), IPPROTO_IP, IP_ADD_MEMBERSHIP, mreq) + } + + fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) + -> io::Result<()> { + let mreq = ipv6_mreq { + ipv6mr_multiaddr: ip2in6_addr(multiaddr), + ipv6mr_interface: to_ipv6mr_interface(interface), + }; + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_ADD_MEMBERSHIP, + mreq) + } + + fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) + -> io::Result<()> { + let mreq = ip_mreq { + imr_multiaddr: ip2in_addr(multiaddr), + imr_interface: ip2in_addr(interface), + }; + set_opt(self.as_sock(), IPPROTO_IP, IP_DROP_MEMBERSHIP, mreq) + } + + fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) + -> io::Result<()> { + let mreq = ipv6_mreq { + ipv6mr_multiaddr: ip2in6_addr(multiaddr), + ipv6mr_interface: to_ipv6mr_interface(interface), + }; + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_DROP_MEMBERSHIP, + mreq) + } + + fn set_read_timeout_ms(&self, dur: Option<u32>) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO, + ms2timeout(dur)) + } + + fn read_timeout_ms(&self) -> io::Result<Option<u32>> { + get_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO) + .map(timeout2ms) + } + + fn set_write_timeout_ms(&self, dur: Option<u32>) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO, + ms2timeout(dur)) + } + + fn write_timeout_ms(&self) -> io::Result<Option<u32>> { + get_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO) + .map(timeout2ms) + } + + fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + self.set_read_timeout_ms(dur.map(dur2ms)) + } + + fn read_timeout(&self) -> io::Result<Option<Duration>> { + self.read_timeout_ms().map(|o| o.map(ms2dur)) + } + + fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { + self.set_write_timeout_ms(dur.map(dur2ms)) + } + + fn write_timeout(&self) -> io::Result<Option<Duration>> { + self.write_timeout_ms().map(|o| o.map(ms2dur)) + } + + fn take_error(&self) -> io::Result<Option<io::Error>> { + get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err) + } + + fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> { + do_connect(self.as_sock(), addr) + } + + #[cfg(unix)] + fn send(&self, buf: &[u8]) -> io::Result<usize> { + unsafe { + ::cvt(send(self.as_sock() as c_int, buf.as_ptr() as *const _, buf.len(), 0)).map(|n| n as usize) + } + } + + #[cfg(target_os = "wasi")] + fn send(&self, buf: &[u8]) -> io::Result<usize> { + let _so_datalen: *mut sys::c::size_t = &mut 0; + unsafe { + let _errno = libc::__wasi_sock_send( + self.as_sock() as libc::__wasi_fd_t, + buf.as_ptr() as *const _, + buf.len(), + 0, + _so_datalen, + ); + // TODO: handle errno + Ok((*_so_datalen) as usize) + } + } + + #[cfg(windows)] + fn send(&self, buf: &[u8]) -> io::Result<usize> { + let len = ::std::cmp::min(buf.len(), c_int::max_value() as usize); + let buf = &buf[..len]; + unsafe { + ::cvt(send(self.as_sock(), buf.as_ptr() as *const _, len as c_int, 0)) + .map(|n| n as usize) + } + } + + #[cfg(unix)] + fn recv(&self, buf: &mut [u8]) -> io::Result<usize> { + unsafe { + ::cvt(recv(self.as_sock(), buf.as_mut_ptr() as *mut _, buf.len(), 0)) + .map(|n| n as usize) + } + } + + #[cfg(target_os = "wasi")] + fn recv(&self, buf: &mut [u8]) -> io::Result<usize> { + let _ro_datalen: *mut sys::c::size_t = &mut 0; + let _ro_flags: *mut sys::c::__wasi_roflags_t = &mut 0; + unsafe { + let _errno = __wasi_sock_recv( + self.as_sock(), + buf.as_mut_ptr() as *mut _, + buf.len(), + 0, + _ro_datalen, + _ro_flags, + ); + // TODO: handle errno + Ok((*_ro_datalen) as usize) + } + } + + #[cfg(windows)] + fn recv(&self, buf: &mut [u8]) -> io::Result<usize> { + let len = ::std::cmp::min(buf.len(), c_int::max_value() as usize); + let buf = &mut buf[..len]; + unsafe { + ::cvt(recv(self.as_sock(), buf.as_mut_ptr() as *mut _, buf.len() as c_int, 0)) + .map(|n| n as usize) + } + } + + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + set_nonblocking(self.as_sock(), nonblocking) + } +} + +fn do_connect<A: ToSocketAddrs>(sock: Socket, addr: A) -> io::Result<()> { + let err = io::Error::new(io::ErrorKind::Other, + "no socket addresses resolved"); + let addrs = try!(addr.to_socket_addrs()); + let sys = sys::Socket::from_inner(sock); + let sock = socket::Socket::from_inner(sys); + let ret = addrs.fold(Err(err), |prev, addr| { + prev.or_else(|_| sock.connect(&addr)) + }); + mem::forget(sock); + return ret +} + +#[cfg(unix)] +fn set_nonblocking(sock: Socket, nonblocking: bool) -> io::Result<()> { + let mut nonblocking = nonblocking as c_ulong; + ::cvt(unsafe { + ioctl(sock, FIONBIO, &mut nonblocking) + }).map(|_| ()) +} + +#[cfg(target_os = "wasi")] +fn set_nonblocking(_sock: Socket, _nonblocking: bool) -> io::Result<()> { + Ok(()) +} + +#[cfg(windows)] +fn set_nonblocking(sock: Socket, nonblocking: bool) -> io::Result<()> { + let mut nonblocking = nonblocking as c_ulong; + ::cvt(unsafe { + ioctlsocket(sock, FIONBIO as c_int, &mut nonblocking) + }).map(|_| ()) +} + +#[cfg(any(unix, target_os = "wasi"))] +fn ip2in_addr(ip: &Ipv4Addr) -> in_addr { + let oct = ip.octets(); + in_addr { + s_addr: ::hton(((oct[0] as u32) << 24) | + ((oct[1] as u32) << 16) | + ((oct[2] as u32) << 8) | + ((oct[3] as u32) << 0)), + } +} + +#[cfg(windows)] +fn ip2in_addr(ip: &Ipv4Addr) -> in_addr { + let oct = ip.octets(); + unsafe { + let mut S_un: in_addr_S_un = mem::zeroed(); + *S_un.S_addr_mut() = ::hton(((oct[0] as u32) << 24) | + ((oct[1] as u32) << 16) | + ((oct[2] as u32) << 8) | + ((oct[3] as u32) << 0)); + in_addr { + S_un: S_un, + } + } +} + +fn in_addr2ip(ip: &in_addr) -> Ipv4Addr { + let h_addr = c::in_addr_to_u32(ip); + + 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) +} + +#[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) -> c_uint { + value as c_uint +} + +fn ip2in6_addr(ip: &Ipv6Addr) -> in6_addr { + let mut ret: in6_addr = unsafe { mem::zeroed() }; + let seg = ip.segments(); + let bytes = [ + (seg[0] >> 8) as u8, + (seg[0] >> 0) as u8, + (seg[1] >> 8) as u8, + (seg[1] >> 0) as u8, + (seg[2] >> 8) as u8, + (seg[2] >> 0) as u8, + (seg[3] >> 8) as u8, + (seg[3] >> 0) as u8, + (seg[4] >> 8) as u8, + (seg[4] >> 0) as u8, + (seg[5] >> 8) as u8, + (seg[5] >> 0) as u8, + (seg[6] >> 8) as u8, + (seg[6] >> 0) as u8, + (seg[7] >> 8) as u8, + (seg[7] >> 0) as u8, + ]; + #[cfg(windows)] unsafe { *ret.u.Byte_mut() = bytes; } + #[cfg(not(windows))] { ret.s6_addr = bytes; } + + return ret +} + +impl TcpListenerExt for TcpListener { + fn set_ttl(&self, ttl: u32) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int) + } + + fn ttl(&self) -> io::Result<u32> { + get_opt::<c_int>(self.as_sock(), IPPROTO_IP, IP_TTL) + .map(|b| b as u32) + } + + fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int) + } + + fn only_v6(&self) -> io::Result<bool> { + get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY).map(int2bool) + } + + fn take_error(&self) -> io::Result<Option<io::Error>> { + get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err) + } + + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + set_nonblocking(self.as_sock(), nonblocking) + } + + fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_LINGER, dur2linger(dur)) + } + + fn linger(&self) -> io::Result<Option<Duration>> { + get_opt(self.as_sock(), SOL_SOCKET, SO_LINGER).map(linger2dur) + } +} + +impl TcpBuilder { + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This is the same as [`TcpStreamExt::set_ttl`][other]. + /// + /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl + pub fn ttl(&self, ttl: u32) -> io::Result<&Self> { + set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int) + .map(|()| self) + } + + /// Sets the value for the `IPV6_V6ONLY` option on this socket. + /// + /// This is the same as [`TcpStreamExt::set_only_v6`][other]. + /// + /// [other]: trait.TcpStreamExt.html#tymethod.set_only_v6 + pub fn only_v6(&self, only_v6: bool) -> io::Result<&Self> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int) + .map(|()| self) + } + + /// Set value for the `SO_REUSEADDR` 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. + pub fn reuse_address(&self, reuse: bool) -> io::Result<&Self> { + set_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR, + reuse as c_int).map(|()| self) + } + + /// Check the `SO_REUSEADDR` option on this socket. + pub fn get_reuse_address(&self) -> io::Result<bool> { + get_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR).map(int2bool) + } + + /// 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<Option<io::Error>> { + get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err) + } + + /// Sets the linger option for this socket + fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_LINGER, dur2linger(dur)) + } + + /// Gets the linger option for this socket + fn linger(&self) -> io::Result<Option<Duration>> { + get_opt(self.as_sock(), SOL_SOCKET, SO_LINGER).map(linger2dur) + } +} + +impl UdpBuilder { + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This is the same as [`TcpStreamExt::set_ttl`][other]. + /// + /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl + pub fn ttl(&self, ttl: u32) -> io::Result<&Self> { + set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int) + .map(|()| self) + } + + /// Sets the value for the `IPV6_V6ONLY` option on this socket. + /// + /// This is the same as [`TcpStream::only_v6`][other]. + /// + /// [other]: struct.TcpBuilder.html#method.only_v6 + pub fn only_v6(&self, only_v6: bool) -> io::Result<&Self> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int) + .map(|()| self) + } + + /// Set value for the `SO_REUSEADDR` option on this socket. + /// + /// This is the same as [`TcpBuilder::reuse_address`][other]. + /// + /// [other]: struct.TcpBuilder.html#method.reuse_address + pub fn reuse_address(&self, reuse: bool) -> io::Result<&Self> { + set_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR, + reuse as c_int).map(|()| self) + } + + /// Check the `SO_REUSEADDR` option on this socket. + pub fn get_reuse_address(&self) -> io::Result<bool> { + get_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR).map(int2bool) + } + + /// 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<Option<io::Error>> { + get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err) + } +} diff --git a/third_party/rust/net2/src/lib.rs b/third_party/rust/net2/src/lib.rs new file mode 100644 index 0000000000..a4b460e255 --- /dev/null +++ b/third_party/rust/net2/src/lib.rs @@ -0,0 +1,126 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Extensions to `std::net` networking types. +//! +//! This crate implements a number of extensions to the standard `std::net` +//! networking types, hopefully being slated for inclusion into the standard +//! library in the future. The goal of this crate is to expose all sorts of +//! cross-platform and platform-specific configuration options of UDP/TCP +//! sockets. System APIs are wrapped with as thin a layer as possible instead of +//! bundling multiple actions into one API call. +//! +//! More information about the design of this crate can be found in the +//! [associated rfc][rfc] +//! +//! [rfc]: https://github.com/rust-lang/rfcs/pull/1158 +//! +//! # Examples +//! +//! ```no_run +//! use net2::TcpBuilder; +//! +//! let tcp = TcpBuilder::new_v4().unwrap(); +//! tcp.reuse_address(true).unwrap() +//! .only_v6(false).unwrap(); +//! +//! let mut stream = tcp.connect("127.0.0.1:80").unwrap(); +//! +//! // use `stream` as a TcpStream +//! ``` + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/net2-rs")] +#![deny(missing_docs, warnings)] + +// Silence warnings about deprecated try!() usage +#![allow(deprecated)] + +#![cfg_attr(target_os = "wasi", feature(wasi_ext))] + +#[cfg(any(target_os = "wasi", unix))] extern crate libc; + +#[cfg(windows)] extern crate winapi; + +#[macro_use] extern crate cfg_if; + +use std::io; +use std::ops::Neg; +use std::net::{ToSocketAddrs, SocketAddr}; + +use utils::{One, NetInt}; + +mod tcp; +mod udp; +mod socket; +mod ext; +mod utils; + +#[cfg(unix)] #[path = "sys/unix/mod.rs"] mod sys; +#[cfg(windows)] #[path = "sys/windows/mod.rs"] mod sys; +#[cfg(target_os = "wasi")] #[path = "sys/wasi/mod.rs"] mod sys; +#[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))] pub mod unix; + +pub use tcp::TcpBuilder; +pub use udp::UdpBuilder; +pub use ext::{TcpStreamExt, TcpListenerExt, UdpSocketExt}; + +fn one_addr<T: ToSocketAddrs>(tsa: T) -> io::Result<SocketAddr> { + let mut addrs = try!(tsa.to_socket_addrs()); + let addr = match addrs.next() { + Some(addr) => addr, + None => return Err(io::Error::new(io::ErrorKind::Other, + "no socket addresses could be resolved")) + }; + if addrs.next().is_none() { + Ok(addr) + } else { + Err(io::Error::new(io::ErrorKind::Other, + "more than one address resolved")) + } +} + +fn cvt<T: One + PartialEq + Neg<Output=T>>(t: T) -> io::Result<T> { + let one: T = T::one(); + if t == -one { + Err(io::Error::last_os_error()) + } else { + Ok(t) + } +} + +#[cfg(windows)] +fn cvt_win<T: PartialEq + utils::Zero>(t: T) -> io::Result<T> { + if t == T::zero() { + Err(io::Error::last_os_error()) + } else { + Ok(t) + } +} + +fn hton<I: NetInt>(i: I) -> I { i.to_be() } + +fn ntoh<I: NetInt>(i: I) -> I { I::from_be(i) } + +trait AsInner { + type Inner; + fn as_inner(&self) -> &Self::Inner; +} + +trait FromInner { + type Inner; + fn from_inner(inner: Self::Inner) -> Self; +} + +trait IntoInner { + type Inner; + fn into_inner(self) -> Self::Inner; +} diff --git a/third_party/rust/net2/src/socket.rs b/third_party/rust/net2/src/socket.rs new file mode 100644 index 0000000000..5b0f4935a9 --- /dev/null +++ b/third_party/rust/net2/src/socket.rs @@ -0,0 +1,260 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; +use std::io; +use std::mem; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +#[cfg(any(unix, target_os = "wasi"))] +use libc::c_int; +#[cfg(windows)] +use winapi::ctypes::c_int; + +use sys; +use sys::c; + +pub struct Socket { + inner: sys::Socket, +} + +impl Socket { + pub fn new(family: c_int, ty: c_int) -> io::Result<Socket> { + Ok(Socket { inner: try!(sys::Socket::new(family, ty)) }) + } + + pub fn bind(&self, addr: &SocketAddr) -> io::Result<()> { + let (addr, len) = addr2raw(addr); + unsafe { + ::cvt(c::bind(self.inner.raw(), addr.as_ptr(), len as c::socklen_t)).map(|_| ()) + } + } + + pub fn listen(&self, backlog: i32) -> io::Result<()> { + unsafe { + ::cvt(c::listen(self.inner.raw(), backlog)).map(|_| ()) + } + } + + pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { + let (addr, len) = addr2raw(addr); + unsafe { + ::cvt(c::connect(self.inner.raw(), addr.as_ptr(), len)).map(|_| ()) + } + } + + pub fn getsockname(&self) -> io::Result<SocketAddr> { + unsafe { + let mut storage: c::sockaddr_storage = mem::zeroed(); + let mut len = mem::size_of_val(&storage) as c::socklen_t; + try!(::cvt(c::getsockname(self.inner.raw(), + &mut storage as *mut _ as *mut _, + &mut len))); + raw2addr(&storage, len) + } + } +} + +impl fmt::Debug for Socket { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.raw().fmt(f) + } +} + +impl ::AsInner for Socket { + type Inner = sys::Socket; + fn as_inner(&self) -> &sys::Socket { &self.inner } +} + +impl ::FromInner for Socket { + type Inner = sys::Socket; + fn from_inner(sock: sys::Socket) -> Socket { + Socket { inner: sock } + } +} + +impl ::IntoInner for Socket { + type Inner = sys::Socket; + fn into_inner(self) -> sys::Socket { self.inner } +} + +/// A type with the same memory layout as `c::sockaddr`. Used in converting Rust level +/// SocketAddr* types into their system representation. The benefit of this specific +/// type over using `c::sockaddr_storage` is that this type is exactly as large as it +/// needs to be and not a lot larger. +#[repr(C)] +pub(crate) union SocketAddrCRepr { + v4: c::sockaddr_in, + v6: c::sockaddr_in6, +} + +impl SocketAddrCRepr { + pub(crate) fn as_ptr(&self) -> *const c::sockaddr { + self as *const _ as *const c::sockaddr + } +} + +fn addr2raw(addr: &SocketAddr) -> (SocketAddrCRepr, c::socklen_t) { + match addr { + &SocketAddr::V4(ref v4) => addr2raw_v4(v4), + &SocketAddr::V6(ref v6) => addr2raw_v6(v6), + } +} + +#[cfg(unix)] +fn addr2raw_v4(addr: &SocketAddrV4) -> (SocketAddrCRepr, c::socklen_t) { + let sin_addr = c::in_addr { + s_addr: u32::from(*addr.ip()).to_be(), + }; + + let sockaddr = SocketAddrCRepr { + v4: c::sockaddr_in { + sin_family: c::AF_INET as c::sa_family_t, + sin_port: addr.port().to_be(), + sin_addr, + #[cfg(not(target_os = "haiku"))] + sin_zero: [0; 8], + #[cfg(target_os = "haiku")] + sin_zero: [0; 24], + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "haiku", + ))] + sin_len: 0, + }, + }; + (sockaddr, mem::size_of::<c::sockaddr_in>() as c::socklen_t) +} + +#[cfg(windows)] +fn addr2raw_v4(addr: &SocketAddrV4) -> (SocketAddrCRepr, c::socklen_t) { + let sin_addr = unsafe { + let mut s_un = mem::zeroed::<c::in_addr_S_un>(); + *s_un.S_addr_mut() = u32::from(*addr.ip()).to_be(); + c::IN_ADDR { S_un: s_un } + }; + + let sockaddr = SocketAddrCRepr { + v4: c::sockaddr_in { + sin_family: c::AF_INET as c::sa_family_t, + sin_port: addr.port().to_be(), + sin_addr, + sin_zero: [0; 8], + }, + }; + (sockaddr, mem::size_of::<c::sockaddr_in>() as c::socklen_t) +} + +#[cfg(unix)] +fn addr2raw_v6(addr: &SocketAddrV6) -> (SocketAddrCRepr, c::socklen_t) { + let sin6_addr = { + let mut sin6_addr = unsafe { mem::zeroed::<c::in6_addr>() }; + sin6_addr.s6_addr = addr.ip().octets(); + sin6_addr + }; + + let sockaddr = SocketAddrCRepr { + v6: c::sockaddr_in6 { + sin6_family: c::AF_INET6 as c::sa_family_t, + sin6_port: addr.port().to_be(), + sin6_addr, + sin6_flowinfo: addr.flowinfo(), + sin6_scope_id: addr.scope_id(), + #[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "haiku", + ))] + sin6_len: 0, + #[cfg(any(target_os = "solaris", target_os = "illumos"))] + __sin6_src_id: 0, + }, + }; + (sockaddr, mem::size_of::<c::sockaddr_in6>() as c::socklen_t) +} + +#[cfg(windows)] +fn addr2raw_v6(addr: &SocketAddrV6) -> (SocketAddrCRepr, c::socklen_t) { + let sin6_addr = unsafe { + let mut u = mem::zeroed::<c::in6_addr_u>(); + *u.Byte_mut() = addr.ip().octets(); + c::IN6_ADDR { u } + }; + let scope_id = unsafe { + let mut u = mem::zeroed::<c::SOCKADDR_IN6_LH_u>(); + *u.sin6_scope_id_mut() = addr.scope_id(); + u + }; + + let sockaddr = SocketAddrCRepr { + v6: c::sockaddr_in6 { + sin6_family: c::AF_INET6 as c::sa_family_t, + sin6_port: addr.port().to_be(), + sin6_addr, + sin6_flowinfo: addr.flowinfo(), + u: scope_id, + }, + }; + (sockaddr, mem::size_of::<c::sockaddr_in6>() as c::socklen_t) +} + +fn raw2addr(storage: &c::sockaddr_storage, len: c::socklen_t) -> io::Result<SocketAddr> { + match storage.ss_family as c_int { + c::AF_INET => { + unsafe { + assert!(len as usize >= mem::size_of::<c::sockaddr_in>()); + let sa = storage as *const _ as *const c::sockaddr_in; + let bits = c::sockaddr_in_u32(&(*sa)); + let ip = Ipv4Addr::new((bits >> 24) as u8, + (bits >> 16) as u8, + (bits >> 8) as u8, + bits as u8); + Ok(SocketAddr::V4(SocketAddrV4::new(ip, ::ntoh((*sa).sin_port)))) + } + } + c::AF_INET6 => { + unsafe { + assert!(len as usize >= mem::size_of::<c::sockaddr_in6>()); + + let sa = storage as *const _ as *const c::sockaddr_in6; + #[cfg(windows)] let arr = (*sa).sin6_addr.u.Byte(); + #[cfg(not(windows))] let arr = (*sa).sin6_addr.s6_addr; + + let ip = Ipv6Addr::new( + (arr[0] as u16) << 8 | (arr[1] as u16), + (arr[2] as u16) << 8 | (arr[3] as u16), + (arr[4] as u16) << 8 | (arr[5] as u16), + (arr[6] as u16) << 8 | (arr[7] as u16), + (arr[8] as u16) << 8 | (arr[9] as u16), + (arr[10] as u16) << 8 | (arr[11] as u16), + (arr[12] as u16) << 8 | (arr[13] as u16), + (arr[14] as u16) << 8 | (arr[15] as u16), + ); + + #[cfg(windows)] let sin6_scope_id = *(*sa).u.sin6_scope_id(); + #[cfg(not(windows))] let sin6_scope_id = (*sa).sin6_scope_id; + + Ok(SocketAddr::V6(SocketAddrV6::new(ip, + ::ntoh((*sa).sin6_port), + (*sa).sin6_flowinfo, + sin6_scope_id))) + } + } + _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid argument")), + } +} diff --git a/third_party/rust/net2/src/sys/unix/impls.rs b/third_party/rust/net2/src/sys/unix/impls.rs new file mode 100644 index 0000000000..95c2fb8081 --- /dev/null +++ b/third_party/rust/net2/src/sys/unix/impls.rs @@ -0,0 +1,44 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::unix::io::{FromRawFd, AsRawFd}; +use libc::c_int; + +use {TcpBuilder, UdpBuilder, FromInner, AsInner}; +use socket::Socket; +use sys; + +impl FromRawFd for TcpBuilder { + unsafe fn from_raw_fd(fd: c_int) -> TcpBuilder { + let sock = sys::Socket::from_inner(fd); + TcpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for TcpBuilder { + fn as_raw_fd(&self) -> c_int { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() + } +} + +impl FromRawFd for UdpBuilder { + unsafe fn from_raw_fd(fd: c_int) -> UdpBuilder { + let sock = sys::Socket::from_inner(fd); + UdpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for UdpBuilder { + fn as_raw_fd(&self) -> c_int { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() + } +} diff --git a/third_party/rust/net2/src/sys/unix/mod.rs b/third_party/rust/net2/src/sys/unix/mod.rs new file mode 100644 index 0000000000..cc8a60d01e --- /dev/null +++ b/third_party/rust/net2/src/sys/unix/mod.rs @@ -0,0 +1,104 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +use std::io; +use std::mem; +use std::net::{TcpListener, TcpStream, UdpSocket}; +use std::os::unix::io::FromRawFd; +use libc::{self, c_int}; +#[cfg(not(any(target_os = "emscripten", target_os = "haiku", target_os = "illumos", target_os = "solaris")))] +use libc::{ioctl, FIOCLEX}; + +mod impls; + +pub mod c { + pub use libc::*; + + pub fn sockaddr_in_u32(sa: &sockaddr_in) -> u32 { + ::ntoh((*sa).sin_addr.s_addr) + } + + pub fn in_addr_to_u32(addr: &in_addr) -> u32 { + ::ntoh(addr.s_addr) + } +} + +pub struct Socket { + fd: c_int, +} + +impl Socket { + #[cfg(not(any(target_os = "emscripten", target_os = "haiku", target_os = "illumos", target_os = "solaris")))] + pub fn new(family: c_int, ty: c_int) -> io::Result<Socket> { + unsafe { + // Linux >2.6.26 overloads the type argument to accept SOCK_CLOEXEC, + // avoiding a race with another thread running fork/exec between + // socket() and ioctl() + #[cfg(any(target_os = "linux", target_os = "android"))] + match ::cvt(libc::socket(family, ty | libc::SOCK_CLOEXEC, 0)) { + Ok(fd) => return Ok(Socket { fd: fd }), + // Older versions of Linux return EINVAL; fall back to ioctl + Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {} + Err(e) => return Err(e), + } + + let fd = try!(::cvt(libc::socket(family, ty, 0))); + ioctl(fd, FIOCLEX); + Ok(Socket { fd: fd }) + } + } + + // ioctl(FIOCLEX) is not supported by Solaris/illumos or emscripten, + // use fcntl(FD_CLOEXEC) instead + #[cfg(any(target_os = "emscripten", target_os = "haiku", target_os = "illumos", target_os = "solaris"))] + pub fn new(family: c_int, ty: c_int) -> io::Result<Socket> { + unsafe { + let fd = try!(::cvt(libc::socket(family, ty, 0))); + libc::fcntl(fd, libc::FD_CLOEXEC); + Ok(Socket { fd: fd }) + } + } + + pub fn raw(&self) -> c_int { self.fd } + + fn into_fd(self) -> c_int { + let fd = self.fd; + mem::forget(self); + fd + } + + pub fn into_tcp_listener(self) -> TcpListener { + unsafe { TcpListener::from_raw_fd(self.into_fd()) } + } + + pub fn into_tcp_stream(self) -> TcpStream { + unsafe { TcpStream::from_raw_fd(self.into_fd()) } + } + + pub fn into_udp_socket(self) -> UdpSocket { + unsafe { UdpSocket::from_raw_fd(self.into_fd()) } + } +} + +impl ::FromInner for Socket { + type Inner = c_int; + fn from_inner(fd: c_int) -> Socket { + Socket { fd: fd } + } +} + +impl Drop for Socket { + fn drop(&mut self) { + unsafe { + let _ = libc::close(self.fd); + } + } +} diff --git a/third_party/rust/net2/src/sys/wasi/impls.rs b/third_party/rust/net2/src/sys/wasi/impls.rs new file mode 100644 index 0000000000..eef8094b60 --- /dev/null +++ b/third_party/rust/net2/src/sys/wasi/impls.rs @@ -0,0 +1,33 @@ +use std::os::wasi::io::{FromRawFd, AsRawFd}; + +use {TcpBuilder, UdpBuilder, FromInner, AsInner}; +use socket::Socket; +use sys::{self, c::__wasi_fd_t}; + +impl FromRawFd for TcpBuilder { + unsafe fn from_raw_fd(fd: __wasi_fd_t) -> TcpBuilder { + let sock = sys::Socket::from_inner(fd); + TcpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for TcpBuilder { + fn as_raw_fd(&self) -> __wasi_fd_t { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as __wasi_fd_t + } +} + +impl FromRawFd for UdpBuilder { + unsafe fn from_raw_fd(fd: __wasi_fd_t) -> UdpBuilder { + let sock = sys::Socket::from_inner(fd); + UdpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for UdpBuilder { + fn as_raw_fd(&self) -> __wasi_fd_t { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as __wasi_fd_t + } +} diff --git a/third_party/rust/net2/src/sys/wasi/mod.rs b/third_party/rust/net2/src/sys/wasi/mod.rs new file mode 100644 index 0000000000..bbc507ed68 --- /dev/null +++ b/third_party/rust/net2/src/sys/wasi/mod.rs @@ -0,0 +1,185 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_camel_case_types)] +use libc::{self, c_int, __wasi_fd_t}; +use std::io; +use std::mem; +use std::net::{TcpListener, TcpStream, UdpSocket}; +use std::os::wasi::io::FromRawFd; + +mod impls; + +pub mod c { + pub use libc::*; + + pub type sa_family_t = u16; + pub type socklen_t = u32; + pub type in_port_t = u16; + + pub const SOCK_DGRAM: c_int = 0x00; + pub const SOL_SOCKET: c_int = 0x00; + pub const SO_RCVBUF: c_int = 0x00; + pub const SO_SNDBUF: c_int = 0x00; + pub const TCP_NODELAY: c_int = 0x00; + pub const IPPROTO_TCP: c_int = 0x00; + pub const SO_RCVTIMEO: c_int = 0x00; + pub const SO_SNDTIMEO: c_int = 0x00; + pub const IPPROTO_IP: c_int = 0x00; + pub const IP_TTL: c_int = 0x00; + pub const IPPROTO_IPV6: c_int = 0x00; + pub const IPV6_V6ONLY: c_int = 0x00; + pub const SO_ERROR: c_int = 0x00; + pub const SO_LINGER: c_int = 0x00; + pub const SO_BROADCAST: c_int = 0x00; + pub const IP_MULTICAST_LOOP: c_int = 0x00; + pub const IP_MULTICAST_TTL: c_int = 0x00; + pub const IPV6_MULTICAST_HOPS: c_int = 0x00; + pub const IPV6_MULTICAST_LOOP: c_int = 0x00; + pub const IP_MULTICAST_IF: c_int = 0x00; + pub const IPV6_MULTICAST_IF: c_int = 0x00; + pub const IPV6_UNICAST_HOPS: c_int = 0x00; + pub const IP_ADD_MEMBERSHIP: c_int = 0x00; + pub const IPV6_ADD_MEMBERSHIP: c_int = 0x00; + pub const IP_DROP_MEMBERSHIP: c_int = 0x00; + pub const IPV6_DROP_MEMBERSHIP: c_int = 0x00; + pub const SO_REUSEADDR: c_int = 0x00; + pub const SOCK_STREAM: c_int = 0x00; + pub const AF_INET: c_int = 0x00; + pub const AF_INET6: c_int = 0x01; + + #[repr(C)] + pub struct sockaddr_storage { + pub ss_family: sa_family_t, + } + #[repr(C)] + pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14], + } + + #[repr(C)] + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: in6_addr, + pub sin6_scope_id: u32, + } + + #[repr(C)] + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: in_port_t, + pub sin_addr: in_addr, + pub sin_zero: [u8; 8], + } + + #[repr(align(4))] + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + #[derive(Copy, Clone)] + pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + pub ipv6mr_interface: c_uint, + } + + pub type in_addr_t = u32; + #[derive(Copy, Clone)] + pub struct in_addr { + pub s_addr: in_addr_t, + } + + #[derive(Copy, Clone)] + pub struct linger { + pub l_onoff: c_int, + pub l_linger: c_int, + } + + #[derive(Copy, Clone)] + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub unsafe fn getsockname(_socket: __wasi_fd_t, _address: *mut sockaddr, + _address_len: *mut socklen_t) -> c_int { + unimplemented!() + } + pub unsafe fn connect(_socket: __wasi_fd_t, _address: *const sockaddr, + _len: socklen_t) -> c_int { + unimplemented!() + } + pub unsafe fn listen(_socket: __wasi_fd_t, _backlog: c_int) -> c_int { + unimplemented!() + } + pub unsafe fn bind(_socket: __wasi_fd_t, _address: *const sockaddr, + _address_len: socklen_t) -> c_int { + unimplemented!() + } + + pub fn sockaddr_in_u32(sa: &sockaddr_in) -> u32 { + ::ntoh((*sa).sin_addr.s_addr) + } + + pub fn in_addr_to_u32(addr: &in_addr) -> u32 { + ::ntoh(addr.s_addr) + } +} + +pub struct Socket { + fd: __wasi_fd_t, +} + +impl Socket { + pub fn new(_family: c_int, _ty: c_int) -> io::Result<Socket> { + unimplemented!() + } + + pub fn raw(&self) -> libc::__wasi_fd_t { + self.fd + } + + fn into_fd(self) -> libc::__wasi_fd_t { + let fd = self.fd; + mem::forget(self); + fd + } + + pub fn into_tcp_listener(self) -> TcpListener { + unsafe { TcpListener::from_raw_fd(self.into_fd()) } + } + + pub fn into_tcp_stream(self) -> TcpStream { + unsafe { TcpStream::from_raw_fd(self.into_fd()) } + } + + pub fn into_udp_socket(self) -> UdpSocket { + unsafe { UdpSocket::from_raw_fd(self.into_fd()) } + } +} + +impl ::FromInner for Socket { + type Inner = libc::__wasi_fd_t; + fn from_inner(fd: libc::__wasi_fd_t) -> Socket { + Socket { fd: fd } + } +} + +impl Drop for Socket { + fn drop(&mut self) { + // unsafe { + // let _ = libc::close(self.fd); + // } + } +}
\ No newline at end of file diff --git a/third_party/rust/net2/src/sys/windows/impls.rs b/third_party/rust/net2/src/sys/windows/impls.rs new file mode 100644 index 0000000000..48e787ca20 --- /dev/null +++ b/third_party/rust/net2/src/sys/windows/impls.rs @@ -0,0 +1,44 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::windows::io::{FromRawSocket, RawSocket, AsRawSocket}; +use winapi::um::winsock2::SOCKET; + +use {TcpBuilder, UdpBuilder, FromInner, AsInner}; +use socket::Socket; +use sys; + +impl FromRawSocket for TcpBuilder { + unsafe fn from_raw_socket(fd: RawSocket) -> TcpBuilder { + let sock = sys::Socket::from_inner(fd as SOCKET); + TcpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawSocket for TcpBuilder { + fn as_raw_socket(&self) -> RawSocket { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as RawSocket + } +} + +impl FromRawSocket for UdpBuilder { + unsafe fn from_raw_socket(fd: RawSocket) -> UdpBuilder { + let sock = sys::Socket::from_inner(fd as SOCKET); + UdpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawSocket for UdpBuilder { + fn as_raw_socket(&self) -> RawSocket { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as RawSocket + } +} diff --git a/third_party/rust/net2/src/sys/windows/mod.rs b/third_party/rust/net2/src/sys/windows/mod.rs new file mode 100644 index 0000000000..7086bec9dc --- /dev/null +++ b/third_party/rust/net2/src/sys/windows/mod.rs @@ -0,0 +1,125 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] + +use std::io; +use std::mem; +use std::net::{TcpListener, TcpStream, UdpSocket}; +use std::os::windows::io::{RawSocket, FromRawSocket}; +use std::sync::{Once, ONCE_INIT}; + +const HANDLE_FLAG_INHERIT: DWORD = 0x00000001; + +pub mod c { + pub use winapi::ctypes::*; + pub use winapi::um::handleapi::*; + pub use winapi::um::winbase::*; + pub use winapi::um::winsock2::*; + pub use winapi::um::ws2tcpip::*; + + pub use winapi::shared::inaddr::*; + pub use winapi::shared::in6addr::*; + pub use winapi::shared::minwindef::*; + pub use winapi::shared::ntdef::*; + pub use winapi::shared::ws2def::*; + pub use winapi::shared::ws2def::{SOCK_STREAM, SOCK_DGRAM}; + pub use winapi::shared::ws2def::SOCKADDR as sockaddr; + pub use winapi::shared::ws2def::SOCKADDR_STORAGE as sockaddr_storage; + pub use winapi::shared::ws2def::SOCKADDR_IN as sockaddr_in; + pub use winapi::shared::ws2def::ADDRESS_FAMILY as sa_family_t; + pub use winapi::shared::ws2ipdef::*; + pub use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6; + pub use winapi::shared::ws2ipdef::IP_MREQ as ip_mreq; + pub use winapi::shared::ws2ipdef::IPV6_MREQ as ipv6_mreq; + + pub fn sockaddr_in_u32(sa: &sockaddr_in) -> u32 { + ::ntoh(unsafe { *sa.sin_addr.S_un.S_addr() }) + } + + pub fn in_addr_to_u32(addr: &in_addr) -> u32 { + ::ntoh(unsafe { *addr.S_un.S_addr() }) + } +} + +use self::c::*; + +mod impls; + +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 _ = UdpSocket::bind("127.0.0.1:34254"); + }); +} + +pub struct Socket { + socket: SOCKET, +} + +impl Socket { + pub fn new(family: c_int, ty: c_int) -> io::Result<Socket> { + init(); + let socket = try!(unsafe { + match WSASocketW(family, ty, 0, 0 as *mut _, 0, + WSA_FLAG_OVERLAPPED) { + INVALID_SOCKET => Err(io::Error::last_os_error()), + n => Ok(Socket { socket: n }), + } + }); + try!(socket.set_no_inherit()); + Ok(socket) + } + + pub fn raw(&self) -> SOCKET { self.socket } + + fn into_socket(self) -> SOCKET { + let socket = self.socket; + mem::forget(self); + socket + } + + pub fn into_tcp_listener(self) -> TcpListener { + unsafe { TcpListener::from_raw_socket(self.into_socket() as RawSocket) } + } + + pub fn into_tcp_stream(self) -> TcpStream { + unsafe { TcpStream::from_raw_socket(self.into_socket() as RawSocket) } + } + + pub fn into_udp_socket(self) -> UdpSocket { + unsafe { UdpSocket::from_raw_socket(self.into_socket() as RawSocket) } + } + + fn set_no_inherit(&self) -> io::Result<()> { + ::cvt_win(unsafe { + SetHandleInformation(self.socket as HANDLE, HANDLE_FLAG_INHERIT, 0) + }).map(|_| ()) + } +} + +impl ::FromInner for Socket { + type Inner = SOCKET; + fn from_inner(socket: SOCKET) -> Socket { + Socket { socket: socket } + } +} + +impl Drop for Socket { + fn drop(&mut self) { + unsafe { + let _ = closesocket(self.socket); + } + } +} diff --git a/third_party/rust/net2/src/tcp.rs b/third_party/rust/net2/src/tcp.rs new file mode 100644 index 0000000000..5a535dbb5c --- /dev/null +++ b/third_party/rust/net2/src/tcp.rs @@ -0,0 +1,161 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cell::RefCell; +use std::io; +use std::net::{SocketAddr, ToSocketAddrs, TcpListener, TcpStream}; +use std::fmt; + +use IntoInner; +use socket::Socket; +use sys::c; + +/// An "in progress" TCP socket which has not yet been connected or listened. +/// +/// Allows configuration of a socket before one of these operations is executed. +pub struct TcpBuilder { + socket: RefCell<Option<Socket>>, +} + +impl TcpBuilder { + /// Constructs a new TcpBuilder with the `AF_INET` domain, the `SOCK_STREAM` + /// type, and with a protocol argument of 0. + /// + /// Note that passing other kinds of flags or arguments can be done through + /// the `FromRaw{Fd,Socket}` implementation. + pub fn new_v4() -> io::Result<TcpBuilder> { + Socket::new(c::AF_INET, c::SOCK_STREAM).map(::FromInner::from_inner) + } + + /// Constructs a new TcpBuilder with the `AF_INET6` domain, the `SOCK_STREAM` + /// type, and with a protocol argument of 0. + /// + /// Note that passing other kinds of flags or arguments can be done through + /// the `FromRaw{Fd,Socket}` implementation. + pub fn new_v6() -> io::Result<TcpBuilder> { + Socket::new(c::AF_INET6, c::SOCK_STREAM).map(::FromInner::from_inner) + } + + /// Binds this socket to the specified address. + /// + /// This function directly corresponds to the bind(2) function on Windows + /// and Unix. + pub fn bind<T>(&self, addr: T) -> io::Result<&TcpBuilder> + where T: ToSocketAddrs + { + self.with_socket(|sock| { + let addr = try!(::one_addr(addr)); + sock.bind(&addr) + }).map(|()| self) + } + + /// 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<TcpListener> { + self.with_socket(|sock| { + sock.listen(backlog) + }).and_then(|()| { + self.to_tcp_listener() + }) + } + + /// 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<T>(&self, addr: T) -> io::Result<TcpStream> + where T: ToSocketAddrs + { + self.with_socket(|sock| { + let err = io::Error::new(io::ErrorKind::Other, + "no socket addresses resolved"); + try!(addr.to_socket_addrs()).fold(Err(err), |prev, addr| { + prev.or_else(|_| sock.connect(&addr)) + }) + }).and_then(|()| { + self.to_tcp_stream() + }) + } + + /// Converts this builder into a `TcpStream` + /// + /// This function will consume the internal socket and return it re-wrapped + /// as a `TcpStream`. An error will be returned if the internal socket has + /// already been consumed from a successful call to `connect`, `listen`, + /// etc. + pub fn to_tcp_stream(&self) -> io::Result<TcpStream> { + self.socket.borrow_mut().take().map(|s| s.into_inner().into_tcp_stream()) + .ok_or(io::Error::new(io::ErrorKind::Other, + "socket has already been consumed")) + } + + /// Converts this builder into a `TcpListener` + /// + /// This function will consume the internal socket and return it re-wrapped + /// as a `TcpListener`. An error will be returned if the internal socket has + /// already been consumed from a successful call to `connect`, `listen`, + /// etc. + pub fn to_tcp_listener(&self) -> io::Result<TcpListener> { + self.socket.borrow_mut().take() + .map(|s| s.into_inner().into_tcp_listener()) + .ok_or(io::Error::new(io::ErrorKind::Other, + "socket has already been consumed")) + } + + /// Returns the address of the local half of this TCP socket. + /// + /// An error will be returned if `listen` or `connect` has already been + /// called on this builder. + pub fn local_addr(&self) -> io::Result<SocketAddr> { + match *self.socket.borrow() { + Some(ref s) => s.getsockname(), + None => Err(io::Error::new(io::ErrorKind::Other, + "builder has already finished its socket")), + } + } + + fn with_socket<F>(&self, f: F) -> io::Result<()> + where F: FnOnce(&Socket) -> io::Result<()> + { + match *self.socket.borrow() { + Some(ref s) => f(s), + None => Err(io::Error::new(io::ErrorKind::Other, + "builder has already finished its socket")), + } + } +} + +impl fmt::Debug for TcpBuilder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "TcpBuilder {{ socket: {:?} }}", + self.socket.borrow().as_ref().unwrap()) + } +} + +impl ::AsInner for TcpBuilder { + type Inner = RefCell<Option<Socket>>; + fn as_inner(&self) -> &RefCell<Option<Socket>> { &self.socket } +} + +impl ::FromInner for TcpBuilder { + type Inner = Socket; + fn from_inner(sock: Socket) -> TcpBuilder { + TcpBuilder { socket: RefCell::new(Some(sock)) } + } +} diff --git a/third_party/rust/net2/src/udp.rs b/third_party/rust/net2/src/udp.rs new file mode 100644 index 0000000000..d061ab5c6f --- /dev/null +++ b/third_party/rust/net2/src/udp.rs @@ -0,0 +1,89 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cell::RefCell; +use std::fmt; +use std::io; +use std::net::{ToSocketAddrs, UdpSocket}; + +use IntoInner; +use socket::Socket; +use sys::c; + +/// An "in progress" UDP socket which has not yet been connected. +/// +/// Allows configuration of a socket before the socket is connected. +pub struct UdpBuilder { + socket: RefCell<Option<Socket>>, +} + +impl UdpBuilder { + /// Constructs a new UdpBuilder with the `AF_INET` domain, the `SOCK_DGRAM` + /// type, and with a protocol argument of 0. + /// + /// Note that passing other kinds of flags or arguments can be done through + /// the `FromRaw{Fd,Socket}` implementation. + pub fn new_v4() -> io::Result<UdpBuilder> { + Socket::new(c::AF_INET, c::SOCK_DGRAM).map(::FromInner::from_inner) + } + + /// Constructs a new UdpBuilder with the `AF_INET6` domain, the `SOCK_DGRAM` + /// type, and with a protocol argument of 0. + /// + /// Note that passing other kinds of flags or arguments can be done through + /// the `FromRaw{Fd,Socket}` implementation. + pub fn new_v6() -> io::Result<UdpBuilder> { + Socket::new(c::AF_INET6, c::SOCK_DGRAM).map(::FromInner::from_inner) + } + + /// Binds this socket to the specified address. + /// + /// This function directly corresponds to the bind(2) function on Windows + /// and Unix. + pub fn bind<T>(&self, addr: T) -> io::Result<UdpSocket> + where T: ToSocketAddrs + { + try!(self.with_socket(|sock| { + let addr = try!(::one_addr(addr)); + sock.bind(&addr) + })); + Ok(self.socket.borrow_mut().take().unwrap().into_inner().into_udp_socket()) + } + + fn with_socket<F>(&self, f: F) -> io::Result<()> + where F: FnOnce(&Socket) -> io::Result<()> + { + match *self.socket.borrow() { + Some(ref s) => f(s), + None => Err(io::Error::new(io::ErrorKind::Other, + "builder has already finished its socket")), + } + } +} + +impl fmt::Debug for UdpBuilder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "UdpBuilder {{ socket: {:?} }}", + self.socket.borrow().as_ref().unwrap()) + } +} + +impl ::AsInner for UdpBuilder { + type Inner = RefCell<Option<Socket>>; + fn as_inner(&self) -> &RefCell<Option<Socket>> { &self.socket } +} + +impl ::FromInner for UdpBuilder { + type Inner = Socket; + fn from_inner(sock: Socket) -> UdpBuilder { + UdpBuilder { socket: RefCell::new(Some(sock)) } + } +} + diff --git a/third_party/rust/net2/src/unix.rs b/third_party/rust/net2/src/unix.rs new file mode 100644 index 0000000000..a1e1c6f5e9 --- /dev/null +++ b/third_party/rust/net2/src/unix.rs @@ -0,0 +1,57 @@ +//! Unix-specific extensions to the `std::net` types. + +use std::io; +use sys::c::{self, c_int}; + +use {TcpBuilder, UdpBuilder}; +use ext::{self, AsSock}; + +/// Unix-specific extensions for the `TcpBuilder` type in this library. +pub trait UnixTcpBuilderExt { + /// 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. + fn reuse_port(&self, reuse: bool) -> io::Result<&Self>; + + /// Check the value of the `SO_REUSEPORT` option on this socket. + fn get_reuse_port(&self) -> io::Result<bool>; +} + +impl UnixTcpBuilderExt for TcpBuilder { + fn reuse_port(&self, reuse: bool) -> io::Result<&Self> { + ext::set_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT, + reuse as c_int).map(|()| self) + } + + fn get_reuse_port(&self) -> io::Result<bool> { + ext::get_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT) + .map(ext::int2bool) + } +} + +/// Unix-specific extensions for the `UdpBuilder` type in this library. +pub trait UnixUdpBuilderExt { + /// 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. + fn reuse_port(&self, reuse: bool) -> io::Result<&Self>; + + /// Check the value of the `SO_REUSEPORT` option on this socket. + fn get_reuse_port(&self) -> io::Result<bool>; +} + +impl UnixUdpBuilderExt for UdpBuilder { + fn reuse_port(&self, reuse: bool) -> io::Result<&Self> { + ext::set_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT, + reuse as c_int).map(|()| self) + } + + fn get_reuse_port(&self) -> io::Result<bool> { + ext::get_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT) + .map(ext::int2bool) + } +} diff --git a/third_party/rust/net2/src/utils.rs b/third_party/rust/net2/src/utils.rs new file mode 100644 index 0000000000..21fe9d61fc --- /dev/null +++ b/third_party/rust/net2/src/utils.rs @@ -0,0 +1,51 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 } + |