-
Notifications
You must be signed in to change notification settings - Fork 222
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from sfackler/sockaddr
Add a SockAddr type
- Loading branch information
Showing
5 changed files
with
219 additions
and
177 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
use std::net::{SocketAddrV4, SocketAddrV6, SocketAddr}; | ||
use std::mem; | ||
use std::ptr; | ||
use std::fmt; | ||
|
||
#[cfg(unix)] | ||
use libc::{sockaddr, sockaddr_storage, sockaddr_in, sockaddr_in6, sa_family_t, socklen_t, AF_INET, | ||
AF_INET6}; | ||
#[cfg(windows)] | ||
use winapi::{SOCKADDR as sockaddr, SOCKADDR_STORAGE as sockaddr_storage, | ||
SOCKADDR_IN as sockaddr_in, SOCKADDR_IN6 as sockaddr_in6, | ||
ADDRESS_FAMILY as sa_family_t, socklen_t, AF_INET, AF_INET6}; | ||
|
||
use SockAddr; | ||
|
||
impl fmt::Debug for SockAddr { | ||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
let mut builder = fmt.debug_struct("SockAddr"); | ||
builder.field("family", &self.family()); | ||
if let Some(addr) = self.as_inet() { | ||
builder.field("inet", &addr); | ||
} else if let Some(addr) = self.as_inet6() { | ||
builder.field("inet6", &addr); | ||
} | ||
builder.finish() | ||
} | ||
} | ||
|
||
impl SockAddr { | ||
/// Constructs a `SockAddr` from its raw components. | ||
pub unsafe fn from_raw_parts(addr: *const sockaddr, len: socklen_t) -> SockAddr { | ||
let mut storage = mem::uninitialized::<sockaddr_storage>(); | ||
ptr::copy_nonoverlapping(addr as *const _ as *const u8, | ||
&mut storage as *mut _ as *mut u8, | ||
len as usize); | ||
|
||
SockAddr { | ||
storage: storage, | ||
len: len, | ||
} | ||
} | ||
|
||
unsafe fn as_<T>(&self, family: sa_family_t) -> Option<T> { | ||
if self.storage.ss_family != family { | ||
return None; | ||
} | ||
|
||
Some(mem::transmute_copy(&self.storage)) | ||
} | ||
|
||
/// Returns this address as a `SocketAddrV4` if it is in the `AF_INET` | ||
/// family. | ||
pub fn as_inet(&self) -> Option<SocketAddrV4> { | ||
unsafe { self.as_(AF_INET as sa_family_t) } | ||
} | ||
|
||
/// Returns this address as a `SocketAddrV4` if it is in the `AF_INET6` | ||
/// family. | ||
pub fn as_inet6(&self) -> Option<SocketAddrV6> { | ||
unsafe { self.as_(AF_INET6 as sa_family_t) } | ||
} | ||
|
||
/// Returns this address's family. | ||
pub fn family(&self) -> sa_family_t { | ||
self.storage.ss_family | ||
} | ||
|
||
/// Returns the size of this address in bytes. | ||
pub fn len(&self) -> socklen_t { | ||
self.len | ||
} | ||
|
||
/// Returns a raw pointer to the address. | ||
pub fn as_ptr(&self) -> *const sockaddr { | ||
&self.storage as *const _ as *const _ | ||
} | ||
} | ||
|
||
// SocketAddrV4 and SocketAddrV6 are just wrappers around sockaddr_in and sockaddr_in6 | ||
|
||
// check to make sure that the sizes at least match up | ||
fn _size_checks(v4: SocketAddrV4, v6: SocketAddrV6) { | ||
unsafe { | ||
mem::transmute::<SocketAddrV4, sockaddr_in>(v4); | ||
mem::transmute::<SocketAddrV6, sockaddr_in6>(v6); | ||
} | ||
} | ||
|
||
impl From<SocketAddrV4> for SockAddr { | ||
fn from(addr: SocketAddrV4) -> SockAddr { | ||
unsafe { | ||
SockAddr::from_raw_parts(&addr as *const _ as *const _, | ||
mem::size_of::<SocketAddrV4>() as socklen_t) | ||
} | ||
} | ||
} | ||
|
||
impl From<SocketAddrV6> for SockAddr { | ||
fn from(addr: SocketAddrV6) -> SockAddr { | ||
unsafe { | ||
SockAddr::from_raw_parts(&addr as *const _ as *const _, | ||
mem::size_of::<SocketAddrV6>() as socklen_t) | ||
} | ||
} | ||
} | ||
|
||
impl From<SocketAddr> for SockAddr { | ||
fn from(addr: SocketAddr) -> SockAddr { | ||
match addr { | ||
SocketAddr::V4(addr) => addr.into(), | ||
SocketAddr::V6(addr) => addr.into(), | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use super::*; | ||
|
||
#[test] | ||
fn inet() { | ||
let raw = "127.0.0.1:80".parse::<SocketAddrV4>().unwrap(); | ||
let addr = SockAddr::from(raw); | ||
assert!(addr.as_inet6().is_none()); | ||
let addr = addr.as_inet().unwrap(); | ||
assert_eq!(raw, addr); | ||
} | ||
|
||
#[test] | ||
fn inet6() { | ||
let raw = "[2001:db8::ff00:42:8329]:80" | ||
.parse::<SocketAddrV6>() | ||
.unwrap(); | ||
let addr = SockAddr::from(raw); | ||
assert!(addr.as_inet().is_none()); | ||
let addr = addr.as_inet6().unwrap(); | ||
assert_eq!(raw, addr); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.