diff --git a/Cargo.toml b/Cargo.toml index 6e42523..927e249 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ abstractions. winapi = "0.2" kernel32-sys = "0.2" ws2_32-sys = "0.2" -net2 = { version = "0.2.5", default-features = false } +net2 = { version = "0.2.36", default-features = false } [dev-dependencies] rand = "0.3" diff --git a/src/net.rs b/src/net.rs index f3d1930..5c6eb45 100644 --- a/src/net.rs +++ b/src/net.rs @@ -13,6 +13,9 @@ use std::os::windows::prelude::*; use net2::TcpBuilder; use winapi::*; +use winapi::inaddr::IN_ADDR; +use winapi::ws2def::SOCKADDR_IN; +use winapi::ws2ipdef::{in6_addr, sockaddr_in6}; use ws2_32::*; /// A type to represent a buffer in which a socket address will be stored. @@ -478,13 +481,46 @@ fn cvt(i: c_int, size: DWORD) -> io::Result> { } } -fn socket_addr_to_ptrs(addr: &SocketAddr) -> (*const SOCKADDR, c_int) { +/// A type with the same memory layout as `SOCKADDR`. Used in converting Rust level +/// SocketAddr* types into their system representation. The benefit of this specific +/// type over using `SOCKADDR_STORAGE` is that this type is exactly as large as it +/// needs to be and not a lot larger. And it can be initialized cleaner from Rust. +#[repr(C)] +pub(crate) union SocketAddrCRepr { + v4: SOCKADDR_IN, + v6: sockaddr_in6, +} + +impl SocketAddrCRepr { + pub(crate) fn as_ptr(&self) -> *const SOCKADDR { + self as *const _ as *const SOCKADDR + } +} + +fn socket_addr_to_ptrs(addr: &SocketAddr) -> (SocketAddrCRepr, c_int) { match *addr { SocketAddr::V4(ref a) => { - (a as *const _ as *const _, mem::size_of::() as c_int) + let sockaddr_in = SOCKADDR_IN { + sin_family: AF_INET as ADDRESS_FAMILY, + sin_port: a.port().to_be(), + sin_addr: IN_ADDR { S_un: u32::from(*a.ip()).to_be() }, + sin_zero: [0; 8], + }; + + let sockaddr = SocketAddrCRepr { v4: sockaddr_in }; + (sockaddr, mem::size_of::() as c_int) } SocketAddr::V6(ref a) => { - (a as *const _ as *const _, mem::size_of::() as c_int) + let sockaddr_in6 = sockaddr_in6 { + sin6_family: AF_INET6 as i16, + sin6_port: a.port().to_be(), + sin6_addr: in6_addr { s6_addr: a.ip().octets() }, + sin6_flowinfo: a.flowinfo(), + sin6_scope_id: a.scope_id(), + }; + + let sockaddr = SocketAddrCRepr { v6: sockaddr_in6 }; + (sockaddr, mem::size_of::() as c_int) } } } @@ -643,7 +679,7 @@ unsafe fn connect_overlapped(socket: SOCKET, let (addr_buf, addr_len) = socket_addr_to_ptrs(addr); let mut bytes_sent: DWORD = 0; - let r = connect_ex(socket, addr_buf, addr_len, + let r = connect_ex(socket, addr_buf.as_ptr(), addr_len, buf.as_ptr() as *mut _, buf.len() as u32, &mut bytes_sent, overlapped); @@ -694,7 +730,7 @@ impl UdpSocketExt for UdpSocket { let mut sent_bytes = 0; let r = WSASendTo(self.as_raw_socket(), &mut buf, 1, &mut sent_bytes, 0, - addr_buf as *const _, addr_len, + addr_buf.as_ptr() as *const _, addr_len, overlapped, None); cvt(r, sent_bytes) }