summaryrefslogtreecommitdiffstats
path: root/third_party/rust/net2/src/socket.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/net2/src/socket.rs')
-rw-r--r--third_party/rust/net2/src/socket.rs260
1 files changed, 260 insertions, 0 deletions
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")),
+ }
+}