From 5dc8a80f4075f4eb6e976c42359d21d2842806a6 Mon Sep 17 00:00:00 2001 From: Anthony Baire Date: Mon, 22 Aug 2022 01:23:45 +0200 Subject: [PATCH] do not assume SocketAddr can be casted from/to sockaddr upcoming stdlib 1.64 will switch to pure rust types https://github.com/rust-lang/rust/pull/78802 fix #3 --- README.md | 7 +++--- src/lib.rs | 68 +++++++++++++++++++++++++++++++++++------------------- 2 files changed, 47 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 5805aa5..882933c 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,9 @@ This crate provides a type that can act as a platform-native socket address ## Motivation -The std crate provides `SocketAddr` for managing socket addresses. Its `V4` variant -encapsulates `libc::sockaddr_in` and its `V6` variant encapsulates `libc::sockaddr_in6`. -However there is no easy way to convert `SocketAddr` from/into a `libc::sockaddr` because -`SocketAddr` is a rust enum. +The std crate provides `SocketAddr` for managing socket addresses. However there is no easy way to +convert `SocketAddr` from/into a `libc::sockaddr` because `SocketAddr` has a different internal +layout. This crate provides `OsSocketAddr` which holds a `libc::sockaddr` (containing an IPv4 or IPv6 address) and the conversion functions from/into `SocketAddr`. diff --git a/src/lib.rs b/src/lib.rs index 4095cd3..0f348e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,10 +3,10 @@ //! //! # Motivation //! -//! The std crate provides [SocketAddr] for managing socket addresses. Its `V4` variant -//! encapsulates [libc::sockaddr_in] and its `V6` variant encapsulates [libc::sockaddr_in6]. -//! However there is no easy way to convert `SocketAddr` from/into a `libc::sockaddr` because -//! `SocketAddr` is a rust enum. +//! The std crate provides [SocketAddr] for managing socket addresses. However there is no easy way +//! to convert `SocketAddr` from/into a `libc::sockaddr` because `SocketAddr` has a different +//! internal layout. + //! //! This crate provides [OsSocketAddr] which holds a `libc::sockaddr` (containing an IPv4 or IPv6 //! address) and the conversion functions from/into `SocketAddr`. @@ -95,15 +95,16 @@ extern crate libc; use std::convert::TryInto; -use std::net::SocketAddr; +use std::net::{Ipv4Addr,Ipv6Addr,SocketAddr,SocketAddrV4,SocketAddrV6}; #[cfg(target_family = "unix")] -use libc::{sockaddr, sockaddr_in, sockaddr_in6, socklen_t, AF_INET, AF_INET6}; +use libc::{sockaddr, sockaddr_in, sockaddr_in6, socklen_t, AF_INET, AF_INET6, in_addr, in6_addr}; #[cfg(target_family = "windows")] use winapi::{ shared::{ - ws2def::{AF_INET, AF_INET6, SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in}, + ws2def::{AF_INET, AF_INET6, SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in, + IN_ADDR as in_addr, IN6_ADDR as in6_addr }, ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6, }, um::ws2tcpip::socklen_t, @@ -120,7 +121,9 @@ use winapi::{ /// See [crate] level documentation. /// #[derive(Copy, Clone)] -pub struct OsSocketAddr { +#[repr(C)] +pub union OsSocketAddr { + sa4: sockaddr_in, sa6: sockaddr_in6, } @@ -169,7 +172,7 @@ impl OsSocketAddr { /// * `AF_INET6` -> the size of [sockaddr_in6] /// * *other* -> 0 pub fn len(&self) -> socklen_t { - (match self.sa6.sin6_family as i32 { + (match unsafe { self.sa6.sin6_family } as i32 { AF_INET => std::mem::size_of::(), AF_INET6 => std::mem::size_of::(), _ => 0, @@ -183,12 +186,12 @@ impl OsSocketAddr { /// Get a pointer to the internal buffer pub fn as_ptr(&self) -> *const sockaddr { - &self.sa6 as *const _ as *const _ + unsafe { &self.sa6 as *const _ as *const _ } } /// Get a mutable pointer to the internal buffer pub fn as_mut_ptr(&mut self) -> *mut sockaddr { - &mut self.sa6 as *mut _ as *mut _ + unsafe { &mut self.sa6 as *mut _ as *mut _ } } } @@ -243,8 +246,16 @@ impl TryInto for OsSocketAddr { fn try_into(self) -> Result { unsafe { match self.sa6.sin6_family as i32 { - AF_INET => Ok(SocketAddr::V4(*(self.as_ptr() as *const _))), - AF_INET6 => Ok(SocketAddr::V6(*(self.as_ptr() as *const _))), + AF_INET => Ok(SocketAddr::V4(SocketAddrV4::new( + Ipv4Addr::from(u32::from_be(self.sa4.sin_addr.s_addr)), + u16::from_be(self.sa4.sin_port), + ))), + AF_INET6 => Ok(SocketAddr::V6(SocketAddrV6::new( + Ipv6Addr::from(u128::from_be_bytes(self.sa6.sin6_addr.s6_addr)), + u16::from_be(self.sa6.sin6_port), + self.sa6.sin6_flowinfo, + self.sa6.sin6_scope_id, + ))), f => Err(BadFamilyError(f)), } } @@ -266,17 +277,26 @@ impl std::fmt::Display for BadFamilyError { impl From for OsSocketAddr { fn from(addr: SocketAddr) -> Self { - OsSocketAddr { - sa6: unsafe { - match addr { - SocketAddr::V4(addr) => { - let mut sa6 = std::mem::zeroed(); - *(&mut sa6 as *mut _ as *mut _) = addr; - sa6 - } - SocketAddr::V6(addr) => *(&addr as *const _ as *const _), - } - }, + match addr { + SocketAddr::V4(addr) => Self{ sa4: sockaddr_in{ + #[cfg(target_os = "macos")] + sin_len: std::mem::size_of::() as u8, + + sin_family: AF_INET as u16, + sin_port: u16::to_be(addr.port()), + sin_addr: in_addr{ s_addr: u32::to_be((*addr.ip()).into()) }, + sin_zero: [0; 8], + }}, + SocketAddr::V6(addr) => Self{ sa6: sockaddr_in6{ + #[cfg(target_os = "macos")] + sin_len: std::mem::size_of::() as u8, + + sin6_family: AF_INET6 as u16, + sin6_port: u16::to_be(addr.port()), + sin6_flowinfo: addr.flowinfo(), + sin6_addr: in6_addr{ s6_addr: u128::to_be_bytes((*addr.ip()).into()) }, + sin6_scope_id: addr.scope_id(), + }} } } }