2014-02-10 08:36:31 -06:00
|
|
|
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
2013-12-27 19:50:16 -06:00
|
|
|
// 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.
|
|
|
|
|
2014-04-18 15:23:56 -05:00
|
|
|
use libc;
|
2013-12-27 19:50:16 -06:00
|
|
|
use std::io::net::ip;
|
|
|
|
use std::io;
|
|
|
|
use std::mem;
|
|
|
|
use std::rt::rtio;
|
2014-01-22 21:32:16 -06:00
|
|
|
use std::sync::arc::UnsafeArc;
|
2014-04-25 22:50:22 -05:00
|
|
|
use std::unstable::mutex;
|
2013-12-27 19:50:16 -06:00
|
|
|
|
2014-02-26 14:57:00 -06:00
|
|
|
use super::{IoResult, retry, keep_going};
|
2014-04-18 15:23:56 -05:00
|
|
|
use super::c;
|
2014-04-22 20:38:59 -05:00
|
|
|
use super::util;
|
2013-12-27 19:50:16 -06:00
|
|
|
|
2013-12-28 18:40:15 -06:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// sockaddr and misc bindings
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2013-12-27 19:50:16 -06:00
|
|
|
#[cfg(windows)] pub type sock_t = libc::SOCKET;
|
|
|
|
#[cfg(unix)] pub type sock_t = super::file::fd_t;
|
|
|
|
|
|
|
|
pub fn htons(u: u16) -> u16 {
|
2014-04-14 05:04:14 -05:00
|
|
|
mem::to_be16(u)
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
pub fn ntohs(u: u16) -> u16 {
|
2014-04-14 05:04:14 -05:00
|
|
|
mem::from_be16(u)
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
|
2013-12-28 18:40:15 -06:00
|
|
|
enum InAddr {
|
|
|
|
InAddr(libc::in_addr),
|
|
|
|
In6Addr(libc::in6_addr),
|
|
|
|
}
|
|
|
|
|
|
|
|
fn ip_to_inaddr(ip: ip::IpAddr) -> InAddr {
|
|
|
|
match ip {
|
|
|
|
ip::Ipv4Addr(a, b, c, d) => {
|
|
|
|
InAddr(libc::in_addr {
|
|
|
|
s_addr: (d as u32 << 24) |
|
|
|
|
(c as u32 << 16) |
|
|
|
|
(b as u32 << 8) |
|
|
|
|
(a as u32 << 0)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
ip::Ipv6Addr(a, b, c, d, e, f, g, h) => {
|
|
|
|
In6Addr(libc::in6_addr {
|
|
|
|
s6_addr: [
|
|
|
|
htons(a),
|
|
|
|
htons(b),
|
|
|
|
htons(c),
|
|
|
|
htons(d),
|
|
|
|
htons(e),
|
|
|
|
htons(f),
|
|
|
|
htons(g),
|
|
|
|
htons(h),
|
|
|
|
]
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-27 19:50:16 -06:00
|
|
|
fn addr_to_sockaddr(addr: ip::SocketAddr) -> (libc::sockaddr_storage, uint) {
|
|
|
|
unsafe {
|
2014-02-08 04:46:55 -06:00
|
|
|
let storage: libc::sockaddr_storage = mem::init();
|
2013-12-28 18:40:15 -06:00
|
|
|
let len = match ip_to_inaddr(addr.ip) {
|
|
|
|
InAddr(inaddr) => {
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 12:34:51 -05:00
|
|
|
let storage: *mut libc::sockaddr_in = mem::transmute(&storage);
|
2013-12-27 19:50:16 -06:00
|
|
|
(*storage).sin_family = libc::AF_INET as libc::sa_family_t;
|
|
|
|
(*storage).sin_port = htons(addr.port);
|
2013-12-28 18:40:15 -06:00
|
|
|
(*storage).sin_addr = inaddr;
|
2013-12-27 19:50:16 -06:00
|
|
|
mem::size_of::<libc::sockaddr_in>()
|
|
|
|
}
|
2013-12-28 18:40:15 -06:00
|
|
|
In6Addr(inaddr) => {
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 12:34:51 -05:00
|
|
|
let storage: *mut libc::sockaddr_in6 = mem::transmute(&storage);
|
2013-12-27 19:50:16 -06:00
|
|
|
(*storage).sin6_family = libc::AF_INET6 as libc::sa_family_t;
|
|
|
|
(*storage).sin6_port = htons(addr.port);
|
2013-12-28 18:40:15 -06:00
|
|
|
(*storage).sin6_addr = inaddr;
|
2013-12-27 19:50:16 -06:00
|
|
|
mem::size_of::<libc::sockaddr_in6>()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
return (storage, len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-28 18:40:15 -06:00
|
|
|
fn socket(addr: ip::SocketAddr, ty: libc::c_int) -> IoResult<sock_t> {
|
2013-12-27 19:50:16 -06:00
|
|
|
unsafe {
|
|
|
|
let fam = match addr.ip {
|
|
|
|
ip::Ipv4Addr(..) => libc::AF_INET,
|
|
|
|
ip::Ipv6Addr(..) => libc::AF_INET6,
|
|
|
|
};
|
2013-12-28 18:40:15 -06:00
|
|
|
match libc::socket(fam, ty, 0) {
|
2013-12-27 19:50:16 -06:00
|
|
|
-1 => Err(super::last_error()),
|
|
|
|
fd => Ok(fd),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-28 18:40:15 -06:00
|
|
|
fn setsockopt<T>(fd: sock_t, opt: libc::c_int, val: libc::c_int,
|
|
|
|
payload: T) -> IoResult<()> {
|
|
|
|
unsafe {
|
|
|
|
let payload = &payload as *T as *libc::c_void;
|
|
|
|
let ret = libc::setsockopt(fd, opt, val,
|
|
|
|
payload,
|
|
|
|
mem::size_of::<T>() as libc::socklen_t);
|
2014-01-22 21:32:16 -06:00
|
|
|
if ret != 0 {
|
|
|
|
Err(last_error())
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
2013-12-28 18:40:15 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-22 20:38:59 -05:00
|
|
|
pub fn getsockopt<T: Copy>(fd: sock_t, opt: libc::c_int,
|
|
|
|
val: libc::c_int) -> IoResult<T> {
|
2014-04-18 15:23:56 -05:00
|
|
|
unsafe {
|
|
|
|
let mut slot: T = mem::init();
|
|
|
|
let mut len = mem::size_of::<T>() as libc::socklen_t;
|
|
|
|
let ret = c::getsockopt(fd, opt, val,
|
|
|
|
&mut slot as *mut _ as *mut _,
|
|
|
|
&mut len);
|
|
|
|
if ret != 0 {
|
|
|
|
Err(last_error())
|
|
|
|
} else {
|
|
|
|
assert!(len as uint == mem::size_of::<T>());
|
|
|
|
Ok(slot)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-22 21:32:16 -06:00
|
|
|
#[cfg(windows)]
|
|
|
|
fn last_error() -> io::IoError {
|
2014-04-18 15:23:56 -05:00
|
|
|
io::IoError::from_errno(unsafe { c::WSAGetLastError() } as uint, true)
|
2014-01-22 21:32:16 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
fn last_error() -> io::IoError {
|
|
|
|
super::last_error()
|
|
|
|
}
|
|
|
|
|
2014-01-30 16:28:28 -06:00
|
|
|
#[cfg(windows)] unsafe fn close(sock: sock_t) { let _ = libc::closesocket(sock); }
|
|
|
|
#[cfg(unix)] unsafe fn close(sock: sock_t) { let _ = libc::close(sock); }
|
2013-12-28 18:40:15 -06:00
|
|
|
|
2013-12-27 19:50:16 -06:00
|
|
|
fn sockname(fd: sock_t,
|
2014-05-09 18:30:57 -05:00
|
|
|
f: unsafe extern "system" fn(sock_t, *mut libc::sockaddr,
|
2013-12-27 19:50:16 -06:00
|
|
|
*mut libc::socklen_t) -> libc::c_int)
|
|
|
|
-> IoResult<ip::SocketAddr>
|
|
|
|
{
|
2014-02-08 04:46:55 -06:00
|
|
|
let mut storage: libc::sockaddr_storage = unsafe { mem::init() };
|
2013-12-27 19:50:16 -06:00
|
|
|
let mut len = mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
|
|
|
|
unsafe {
|
|
|
|
let storage = &mut storage as *mut libc::sockaddr_storage;
|
|
|
|
let ret = f(fd,
|
|
|
|
storage as *mut libc::sockaddr,
|
|
|
|
&mut len as *mut libc::socklen_t);
|
|
|
|
if ret != 0 {
|
2014-01-22 21:32:16 -06:00
|
|
|
return Err(last_error())
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
}
|
2013-12-28 18:40:15 -06:00
|
|
|
return sockaddr_to_addr(&storage, len as uint);
|
|
|
|
}
|
|
|
|
|
2014-01-22 14:38:19 -06:00
|
|
|
pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage,
|
|
|
|
len: uint) -> IoResult<ip::SocketAddr> {
|
2013-12-27 19:50:16 -06:00
|
|
|
match storage.ss_family as libc::c_int {
|
|
|
|
libc::AF_INET => {
|
|
|
|
assert!(len as uint >= mem::size_of::<libc::sockaddr_in>());
|
2013-12-28 18:40:15 -06:00
|
|
|
let storage: &libc::sockaddr_in = unsafe {
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 12:34:51 -05:00
|
|
|
mem::transmute(storage)
|
2013-12-27 19:50:16 -06:00
|
|
|
};
|
|
|
|
let addr = storage.sin_addr.s_addr as u32;
|
|
|
|
let a = (addr >> 0) as u8;
|
|
|
|
let b = (addr >> 8) as u8;
|
|
|
|
let c = (addr >> 16) as u8;
|
|
|
|
let d = (addr >> 24) as u8;
|
|
|
|
Ok(ip::SocketAddr {
|
|
|
|
ip: ip::Ipv4Addr(a, b, c, d),
|
|
|
|
port: ntohs(storage.sin_port),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
libc::AF_INET6 => {
|
|
|
|
assert!(len as uint >= mem::size_of::<libc::sockaddr_in6>());
|
2013-12-28 18:40:15 -06:00
|
|
|
let storage: &libc::sockaddr_in6 = unsafe {
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 12:34:51 -05:00
|
|
|
mem::transmute(storage)
|
2013-12-27 19:50:16 -06:00
|
|
|
};
|
|
|
|
let a = ntohs(storage.sin6_addr.s6_addr[0]);
|
|
|
|
let b = ntohs(storage.sin6_addr.s6_addr[1]);
|
|
|
|
let c = ntohs(storage.sin6_addr.s6_addr[2]);
|
|
|
|
let d = ntohs(storage.sin6_addr.s6_addr[3]);
|
|
|
|
let e = ntohs(storage.sin6_addr.s6_addr[4]);
|
|
|
|
let f = ntohs(storage.sin6_addr.s6_addr[5]);
|
|
|
|
let g = ntohs(storage.sin6_addr.s6_addr[6]);
|
|
|
|
let h = ntohs(storage.sin6_addr.s6_addr[7]);
|
|
|
|
Ok(ip::SocketAddr {
|
|
|
|
ip: ip::Ipv6Addr(a, b, c, d, e, f, g, h),
|
|
|
|
port: ntohs(storage.sin6_port),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
Err(io::standard_error(io::OtherIoError))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
pub fn init() {}
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
pub fn init() {
|
|
|
|
|
|
|
|
unsafe {
|
2014-02-14 18:18:49 -06:00
|
|
|
use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
|
2014-01-16 21:57:59 -06:00
|
|
|
static mut INITIALIZED: bool = false;
|
2014-02-14 18:18:49 -06:00
|
|
|
static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
|
2014-01-28 00:41:25 -06:00
|
|
|
|
2014-02-13 00:17:50 -06:00
|
|
|
let _guard = LOCK.lock();
|
2014-01-28 00:41:25 -06:00
|
|
|
if !INITIALIZED {
|
2014-04-18 15:23:56 -05:00
|
|
|
let mut data: c::WSADATA = mem::init();
|
|
|
|
let ret = c::WSAStartup(0x202, // version 2.2
|
|
|
|
&mut data);
|
2014-01-28 00:41:25 -06:00
|
|
|
assert_eq!(ret, 0);
|
|
|
|
INITIALIZED = true;
|
2014-01-16 21:57:59 -06:00
|
|
|
}
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-28 18:40:15 -06:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// TCP streams
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
pub struct TcpStream {
|
2014-03-27 17:10:28 -05:00
|
|
|
inner: UnsafeArc<Inner>,
|
2014-04-25 22:50:22 -05:00
|
|
|
read_deadline: u64,
|
|
|
|
write_deadline: u64,
|
2014-01-22 21:32:16 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
struct Inner {
|
|
|
|
fd: sock_t,
|
2014-04-25 22:50:22 -05:00
|
|
|
lock: mutex::NativeMutex,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Guard<'a> {
|
|
|
|
pub fd: sock_t,
|
|
|
|
pub guard: mutex::LockGuard<'a>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Inner {
|
|
|
|
fn new(fd: sock_t) -> Inner {
|
|
|
|
Inner { fd: fd, lock: unsafe { mutex::NativeMutex::new() } }
|
|
|
|
}
|
2013-12-28 18:40:15 -06:00
|
|
|
}
|
|
|
|
|
2013-12-27 19:50:16 -06:00
|
|
|
impl TcpStream {
|
2014-04-18 15:23:56 -05:00
|
|
|
pub fn connect(addr: ip::SocketAddr,
|
|
|
|
timeout: Option<u64>) -> IoResult<TcpStream> {
|
|
|
|
let fd = try!(socket(addr, libc::SOCK_STREAM));
|
2014-04-25 22:50:22 -05:00
|
|
|
let ret = TcpStream::new(Inner::new(fd));
|
2014-04-18 15:23:56 -05:00
|
|
|
|
2014-04-25 22:50:22 -05:00
|
|
|
let (addr, len) = addr_to_sockaddr(addr);
|
2014-04-18 15:23:56 -05:00
|
|
|
let addrp = &addr as *_ as *libc::sockaddr;
|
2014-04-25 22:50:22 -05:00
|
|
|
let len = len as libc::socklen_t;
|
|
|
|
|
2014-04-18 15:23:56 -05:00
|
|
|
match timeout {
|
|
|
|
Some(timeout) => {
|
2014-04-22 20:38:59 -05:00
|
|
|
try!(util::connect_timeout(fd, addrp, len, timeout));
|
2014-04-18 15:23:56 -05:00
|
|
|
Ok(ret)
|
|
|
|
},
|
|
|
|
None => {
|
|
|
|
match retry(|| unsafe { libc::connect(fd, addrp, len) }) {
|
2014-01-22 21:32:16 -06:00
|
|
|
-1 => Err(last_error()),
|
2013-12-27 19:50:16 -06:00
|
|
|
_ => Ok(ret),
|
|
|
|
}
|
2014-04-18 15:23:56 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-25 22:50:22 -05:00
|
|
|
fn new(inner: Inner) -> TcpStream {
|
|
|
|
TcpStream {
|
|
|
|
inner: UnsafeArc::new(inner),
|
|
|
|
read_deadline: 0,
|
|
|
|
write_deadline: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-22 21:32:16 -06:00
|
|
|
pub fn fd(&self) -> sock_t {
|
|
|
|
// This unsafety is fine because it's just a read-only arc
|
|
|
|
unsafe { (*self.inner.get()).fd }
|
|
|
|
}
|
2013-12-27 19:50:16 -06:00
|
|
|
|
|
|
|
fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> {
|
2014-01-22 21:32:16 -06:00
|
|
|
setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_NODELAY,
|
2013-12-28 18:40:15 -06:00
|
|
|
nodelay as libc::c_int)
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fn set_keepalive(&mut self, seconds: Option<uint>) -> IoResult<()> {
|
2014-01-22 21:32:16 -06:00
|
|
|
let ret = setsockopt(self.fd(), libc::SOL_SOCKET, libc::SO_KEEPALIVE,
|
2013-12-28 18:40:15 -06:00
|
|
|
seconds.is_some() as libc::c_int);
|
|
|
|
match seconds {
|
|
|
|
Some(n) => ret.and_then(|()| self.set_tcp_keepalive(n)),
|
|
|
|
None => ret,
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "macos")]
|
2013-12-28 18:40:15 -06:00
|
|
|
fn set_tcp_keepalive(&mut self, seconds: uint) -> IoResult<()> {
|
2014-01-22 21:32:16 -06:00
|
|
|
setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_KEEPALIVE,
|
2013-12-28 18:40:15 -06:00
|
|
|
seconds as libc::c_int)
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
#[cfg(target_os = "freebsd")]
|
2013-12-28 18:40:15 -06:00
|
|
|
fn set_tcp_keepalive(&mut self, seconds: uint) -> IoResult<()> {
|
2014-01-22 21:32:16 -06:00
|
|
|
setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_KEEPIDLE,
|
2013-12-28 18:40:15 -06:00
|
|
|
seconds as libc::c_int)
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
#[cfg(not(target_os = "macos"), not(target_os = "freebsd"))]
|
2013-12-28 18:40:15 -06:00
|
|
|
fn set_tcp_keepalive(&mut self, _seconds: uint) -> IoResult<()> {
|
2013-12-27 19:50:16 -06:00
|
|
|
Ok(())
|
|
|
|
}
|
2014-04-25 22:50:22 -05:00
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
fn lock_nonblocking(&self) {}
|
|
|
|
|
|
|
|
#[cfg(not(target_os = "linux"))]
|
|
|
|
fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
|
|
|
|
let ret = Guard {
|
|
|
|
fd: self.fd(),
|
|
|
|
guard: unsafe { (*self.inner.get()).lock.lock() },
|
|
|
|
};
|
|
|
|
assert!(util::set_nonblocking(self.fd(), true).is_ok());
|
|
|
|
ret
|
|
|
|
}
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(windows)] type wrlen = libc::c_int;
|
|
|
|
#[cfg(not(windows))] type wrlen = libc::size_t;
|
|
|
|
|
|
|
|
impl rtio::RtioTcpStream for TcpStream {
|
|
|
|
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
|
2014-04-25 22:50:22 -05:00
|
|
|
let fd = self.fd();
|
|
|
|
let dolock = || self.lock_nonblocking();
|
|
|
|
let doread = |nb| unsafe {
|
|
|
|
let flags = if nb {c::MSG_DONTWAIT} else {0};
|
|
|
|
libc::recv(fd,
|
|
|
|
buf.as_mut_ptr() as *mut libc::c_void,
|
|
|
|
buf.len() as wrlen,
|
|
|
|
flags) as libc::c_int
|
|
|
|
};
|
|
|
|
read(fd, self.read_deadline, dolock, doread)
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
2014-04-25 22:50:22 -05:00
|
|
|
|
2013-12-27 19:50:16 -06:00
|
|
|
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
|
2014-04-25 22:50:22 -05:00
|
|
|
let fd = self.fd();
|
|
|
|
let dolock = || self.lock_nonblocking();
|
|
|
|
let dowrite = |nb: bool, buf: *u8, len: uint| unsafe {
|
|
|
|
let flags = if nb {c::MSG_DONTWAIT} else {0};
|
|
|
|
libc::send(fd,
|
2014-02-26 14:57:00 -06:00
|
|
|
buf as *mut libc::c_void,
|
|
|
|
len as wrlen,
|
2014-04-25 22:50:22 -05:00
|
|
|
flags) as i64
|
|
|
|
};
|
|
|
|
match write(fd, self.write_deadline, buf, true, dolock, dowrite) {
|
|
|
|
Ok(_) => Ok(()),
|
|
|
|
Err(e) => Err(e)
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
fn peer_name(&mut self) -> IoResult<ip::SocketAddr> {
|
2014-01-22 21:32:16 -06:00
|
|
|
sockname(self.fd(), libc::getpeername)
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
fn control_congestion(&mut self) -> IoResult<()> {
|
|
|
|
self.set_nodelay(false)
|
|
|
|
}
|
|
|
|
fn nodelay(&mut self) -> IoResult<()> {
|
|
|
|
self.set_nodelay(true)
|
|
|
|
}
|
|
|
|
fn keepalive(&mut self, delay_in_seconds: uint) -> IoResult<()> {
|
|
|
|
self.set_keepalive(Some(delay_in_seconds))
|
|
|
|
}
|
|
|
|
fn letdie(&mut self) -> IoResult<()> {
|
|
|
|
self.set_keepalive(None)
|
|
|
|
}
|
2014-01-22 21:32:16 -06:00
|
|
|
|
2014-05-05 20:56:44 -05:00
|
|
|
fn clone(&self) -> Box<rtio::RtioTcpStream:Send> {
|
|
|
|
box TcpStream {
|
|
|
|
inner: self.inner.clone(),
|
2014-04-25 22:50:22 -05:00
|
|
|
read_deadline: 0,
|
|
|
|
write_deadline: 0,
|
2014-05-05 20:56:44 -05:00
|
|
|
} as Box<rtio::RtioTcpStream:Send>
|
2014-01-22 21:32:16 -06:00
|
|
|
}
|
2014-04-25 22:50:22 -05:00
|
|
|
|
2014-03-12 19:04:34 -05:00
|
|
|
fn close_write(&mut self) -> IoResult<()> {
|
2014-04-24 20:48:21 -05:00
|
|
|
super::mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_WR) })
|
|
|
|
}
|
|
|
|
fn close_read(&mut self) -> IoResult<()> {
|
|
|
|
super::mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_RD) })
|
2014-03-12 19:04:34 -05:00
|
|
|
}
|
2014-04-25 22:50:22 -05:00
|
|
|
|
|
|
|
fn set_timeout(&mut self, timeout: Option<u64>) {
|
|
|
|
let deadline = timeout.map(|a| ::io::timer::now() + a).unwrap_or(0);
|
|
|
|
self.read_deadline = deadline;
|
|
|
|
self.write_deadline = deadline;
|
|
|
|
}
|
|
|
|
fn set_read_timeout(&mut self, timeout: Option<u64>) {
|
|
|
|
self.read_deadline = timeout.map(|a| ::io::timer::now() + a).unwrap_or(0);
|
|
|
|
}
|
|
|
|
fn set_write_timeout(&mut self, timeout: Option<u64>) {
|
|
|
|
self.write_deadline = timeout.map(|a| ::io::timer::now() + a).unwrap_or(0);
|
|
|
|
}
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl rtio::RtioSocket for TcpStream {
|
|
|
|
fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
|
2014-01-22 21:32:16 -06:00
|
|
|
sockname(self.fd(), libc::getsockname)
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-22 21:32:16 -06:00
|
|
|
impl Drop for Inner {
|
2013-12-28 18:40:15 -06:00
|
|
|
fn drop(&mut self) { unsafe { close(self.fd); } }
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
|
2014-04-25 22:50:22 -05:00
|
|
|
#[unsafe_destructor]
|
|
|
|
impl<'a> Drop for Guard<'a> {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
assert!(util::set_nonblocking(self.fd, false).is_ok());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-28 18:40:15 -06:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// TCP listeners
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2013-12-27 19:50:16 -06:00
|
|
|
pub struct TcpListener {
|
2014-04-21 22:30:07 -05:00
|
|
|
inner: Inner,
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TcpListener {
|
|
|
|
pub fn bind(addr: ip::SocketAddr) -> IoResult<TcpListener> {
|
2014-04-25 22:50:22 -05:00
|
|
|
let fd = try!(socket(addr, libc::SOCK_STREAM));
|
|
|
|
let ret = TcpListener { inner: Inner::new(fd) };
|
|
|
|
|
|
|
|
let (addr, len) = addr_to_sockaddr(addr);
|
|
|
|
let addrp = &addr as *_ as *libc::sockaddr;
|
|
|
|
let len = len as libc::socklen_t;
|
|
|
|
|
|
|
|
// On platforms with Berkeley-derived sockets, this allows
|
|
|
|
// to quickly rebind a socket, without needing to wait for
|
|
|
|
// the OS to clean up the previous one.
|
|
|
|
if cfg!(unix) {
|
|
|
|
try!(setsockopt(fd, libc::SOL_SOCKET, libc::SO_REUSEADDR,
|
|
|
|
1 as libc::c_int));
|
|
|
|
}
|
|
|
|
|
|
|
|
match unsafe { libc::bind(fd, addrp, len) } {
|
|
|
|
-1 => Err(last_error()),
|
|
|
|
_ => Ok(ret),
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-21 22:30:07 -05:00
|
|
|
pub fn fd(&self) -> sock_t { self.inner.fd }
|
2013-12-27 19:50:16 -06:00
|
|
|
|
|
|
|
pub fn native_listen(self, backlog: int) -> IoResult<TcpAcceptor> {
|
2014-01-22 21:32:16 -06:00
|
|
|
match unsafe { libc::listen(self.fd(), backlog as libc::c_int) } {
|
|
|
|
-1 => Err(last_error()),
|
2014-04-21 22:30:07 -05:00
|
|
|
_ => Ok(TcpAcceptor { listener: self, deadline: 0 })
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl rtio::RtioTcpListener for TcpListener {
|
2014-05-05 20:56:44 -05:00
|
|
|
fn listen(~self) -> IoResult<Box<rtio::RtioTcpAcceptor:Send>> {
|
|
|
|
self.native_listen(128).map(|a| {
|
|
|
|
box a as Box<rtio::RtioTcpAcceptor:Send>
|
|
|
|
})
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl rtio::RtioSocket for TcpListener {
|
|
|
|
fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
|
2014-01-22 21:32:16 -06:00
|
|
|
sockname(self.fd(), libc::getsockname)
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct TcpAcceptor {
|
2014-03-27 17:10:28 -05:00
|
|
|
listener: TcpListener,
|
2014-04-21 22:30:07 -05:00
|
|
|
deadline: u64,
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TcpAcceptor {
|
2014-01-22 21:32:16 -06:00
|
|
|
pub fn fd(&self) -> sock_t { self.listener.fd() }
|
2013-12-27 19:50:16 -06:00
|
|
|
|
|
|
|
pub fn native_accept(&mut self) -> IoResult<TcpStream> {
|
2014-04-21 22:30:07 -05:00
|
|
|
if self.deadline != 0 {
|
2014-04-25 22:50:22 -05:00
|
|
|
try!(util::await(self.fd(), Some(self.deadline), util::Readable));
|
2014-04-21 22:30:07 -05:00
|
|
|
}
|
2013-12-27 19:50:16 -06:00
|
|
|
unsafe {
|
2014-02-08 04:46:55 -06:00
|
|
|
let mut storage: libc::sockaddr_storage = mem::init();
|
2013-12-27 19:50:16 -06:00
|
|
|
let storagep = &mut storage as *mut libc::sockaddr_storage;
|
|
|
|
let size = mem::size_of::<libc::sockaddr_storage>();
|
|
|
|
let mut size = size as libc::socklen_t;
|
2014-01-04 01:49:56 -06:00
|
|
|
match retry(|| {
|
|
|
|
libc::accept(self.fd(),
|
|
|
|
storagep as *mut libc::sockaddr,
|
|
|
|
&mut size as *mut libc::socklen_t) as libc::c_int
|
|
|
|
}) as sock_t {
|
2014-01-22 21:32:16 -06:00
|
|
|
-1 => Err(last_error()),
|
2014-04-25 22:50:22 -05:00
|
|
|
fd => Ok(TcpStream::new(Inner::new(fd))),
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl rtio::RtioSocket for TcpAcceptor {
|
|
|
|
fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
|
2013-12-28 18:40:15 -06:00
|
|
|
sockname(self.fd(), libc::getsockname)
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl rtio::RtioTcpAcceptor for TcpAcceptor {
|
2014-05-05 20:56:44 -05:00
|
|
|
fn accept(&mut self) -> IoResult<Box<rtio::RtioTcpStream:Send>> {
|
|
|
|
self.native_accept().map(|s| box s as Box<rtio::RtioTcpStream:Send>)
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fn accept_simultaneously(&mut self) -> IoResult<()> { Ok(()) }
|
|
|
|
fn dont_accept_simultaneously(&mut self) -> IoResult<()> { Ok(()) }
|
2014-04-21 22:30:07 -05:00
|
|
|
fn set_timeout(&mut self, timeout: Option<u64>) {
|
2014-04-22 20:38:59 -05:00
|
|
|
self.deadline = timeout.map(|a| ::io::timer::now() + a).unwrap_or(0);
|
2014-04-21 22:30:07 -05:00
|
|
|
}
|
2013-12-27 19:50:16 -06:00
|
|
|
}
|
2013-12-28 18:40:15 -06:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// UDP
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
pub struct UdpSocket {
|
2014-03-27 17:10:28 -05:00
|
|
|
inner: UnsafeArc<Inner>,
|
2014-04-25 22:50:22 -05:00
|
|
|
read_deadline: u64,
|
|
|
|
write_deadline: u64,
|
2013-12-28 18:40:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl UdpSocket {
|
|
|
|
pub fn bind(addr: ip::SocketAddr) -> IoResult<UdpSocket> {
|
2014-04-25 22:50:22 -05:00
|
|
|
let fd = try!(socket(addr, libc::SOCK_DGRAM));
|
|
|
|
let ret = UdpSocket {
|
|
|
|
inner: UnsafeArc::new(Inner::new(fd)),
|
|
|
|
read_deadline: 0,
|
|
|
|
write_deadline: 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
let (addr, len) = addr_to_sockaddr(addr);
|
|
|
|
let addrp = &addr as *_ as *libc::sockaddr;
|
|
|
|
let len = len as libc::socklen_t;
|
|
|
|
|
|
|
|
match unsafe { libc::bind(fd, addrp, len) } {
|
|
|
|
-1 => Err(last_error()),
|
|
|
|
_ => Ok(ret),
|
2013-12-28 18:40:15 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-22 21:32:16 -06:00
|
|
|
pub fn fd(&self) -> sock_t {
|
|
|
|
// unsafety is fine because it's just a read-only arc
|
|
|
|
unsafe { (*self.inner.get()).fd }
|
|
|
|
}
|
2013-12-28 18:40:15 -06:00
|
|
|
|
|
|
|
pub fn set_broadcast(&mut self, on: bool) -> IoResult<()> {
|
2014-01-22 21:32:16 -06:00
|
|
|
setsockopt(self.fd(), libc::SOL_SOCKET, libc::SO_BROADCAST,
|
2013-12-28 18:40:15 -06:00
|
|
|
on as libc::c_int)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_multicast_loop(&mut self, on: bool) -> IoResult<()> {
|
2014-01-22 21:32:16 -06:00
|
|
|
setsockopt(self.fd(), libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP,
|
2013-12-28 18:40:15 -06:00
|
|
|
on as libc::c_int)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_membership(&mut self, addr: ip::IpAddr,
|
|
|
|
opt: libc::c_int) -> IoResult<()> {
|
|
|
|
match ip_to_inaddr(addr) {
|
|
|
|
InAddr(addr) => {
|
|
|
|
let mreq = libc::ip_mreq {
|
|
|
|
imr_multiaddr: addr,
|
|
|
|
// interface == INADDR_ANY
|
|
|
|
imr_interface: libc::in_addr { s_addr: 0x0 },
|
|
|
|
};
|
2014-01-22 21:32:16 -06:00
|
|
|
setsockopt(self.fd(), libc::IPPROTO_IP, opt, mreq)
|
2013-12-28 18:40:15 -06:00
|
|
|
}
|
|
|
|
In6Addr(addr) => {
|
|
|
|
let mreq = libc::ip6_mreq {
|
|
|
|
ipv6mr_multiaddr: addr,
|
|
|
|
ipv6mr_interface: 0,
|
|
|
|
};
|
2014-01-22 21:32:16 -06:00
|
|
|
setsockopt(self.fd(), libc::IPPROTO_IPV6, opt, mreq)
|
2013-12-28 18:40:15 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-04-25 22:50:22 -05:00
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
fn lock_nonblocking(&self) {}
|
|
|
|
|
|
|
|
#[cfg(not(target_os = "linux"))]
|
|
|
|
fn lock_nonblocking<'a>(&'a self) -> Guard<'a> {
|
|
|
|
let ret = Guard {
|
|
|
|
fd: self.fd(),
|
|
|
|
guard: unsafe { (*self.inner.get()).lock.lock() },
|
|
|
|
};
|
|
|
|
assert!(util::set_nonblocking(self.fd(), true).is_ok());
|
|
|
|
ret
|
|
|
|
}
|
2013-12-28 18:40:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl rtio::RtioSocket for UdpSocket {
|
|
|
|
fn socket_name(&mut self) -> IoResult<ip::SocketAddr> {
|
|
|
|
sockname(self.fd(), libc::getsockname)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(windows)] type msglen_t = libc::c_int;
|
|
|
|
#[cfg(unix)] type msglen_t = libc::size_t;
|
|
|
|
|
|
|
|
impl rtio::RtioUdpSocket for UdpSocket {
|
|
|
|
fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, ip::SocketAddr)> {
|
2014-04-25 22:50:22 -05:00
|
|
|
let fd = self.fd();
|
|
|
|
let mut storage: libc::sockaddr_storage = unsafe { mem::init() };
|
|
|
|
let storagep = &mut storage as *mut _ as *mut libc::sockaddr;
|
|
|
|
let mut addrlen: libc::socklen_t =
|
|
|
|
mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
|
|
|
|
|
|
|
|
let dolock = || self.lock_nonblocking();
|
|
|
|
let doread = |nb| unsafe {
|
|
|
|
let flags = if nb {c::MSG_DONTWAIT} else {0};
|
|
|
|
libc::recvfrom(fd,
|
|
|
|
buf.as_mut_ptr() as *mut libc::c_void,
|
|
|
|
buf.len() as msglen_t,
|
|
|
|
flags,
|
|
|
|
storagep,
|
|
|
|
&mut addrlen) as libc::c_int
|
|
|
|
};
|
|
|
|
let n = try!(read(fd, self.read_deadline, dolock, doread));
|
|
|
|
sockaddr_to_addr(&storage, addrlen as uint).and_then(|addr| {
|
|
|
|
Ok((n as uint, addr))
|
|
|
|
})
|
2013-12-28 18:40:15 -06:00
|
|
|
}
|
2014-04-25 22:50:22 -05:00
|
|
|
|
2013-12-28 18:40:15 -06:00
|
|
|
fn sendto(&mut self, buf: &[u8], dst: ip::SocketAddr) -> IoResult<()> {
|
2014-04-25 22:50:22 -05:00
|
|
|
let (dst, dstlen) = addr_to_sockaddr(dst);
|
|
|
|
let dstp = &dst as *_ as *libc::sockaddr;
|
|
|
|
let dstlen = dstlen as libc::socklen_t;
|
|
|
|
|
|
|
|
let fd = self.fd();
|
|
|
|
let dolock = || self.lock_nonblocking();
|
|
|
|
let dowrite = |nb, buf: *u8, len: uint| unsafe {
|
|
|
|
let flags = if nb {c::MSG_DONTWAIT} else {0};
|
|
|
|
libc::sendto(fd,
|
|
|
|
buf as *libc::c_void,
|
|
|
|
len as msglen_t,
|
|
|
|
flags,
|
|
|
|
dstp,
|
|
|
|
dstlen) as i64
|
|
|
|
};
|
|
|
|
|
|
|
|
let n = try!(write(fd, self.write_deadline, buf, false, dolock, dowrite));
|
|
|
|
if n != buf.len() {
|
|
|
|
Err(io::IoError {
|
|
|
|
kind: io::ShortWrite(n),
|
|
|
|
desc: "couldn't send entire packet at once",
|
|
|
|
detail: None,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
Ok(())
|
2013-12-28 18:40:15 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn join_multicast(&mut self, multi: ip::IpAddr) -> IoResult<()> {
|
|
|
|
match multi {
|
|
|
|
ip::Ipv4Addr(..) => {
|
|
|
|
self.set_membership(multi, libc::IP_ADD_MEMBERSHIP)
|
|
|
|
}
|
|
|
|
ip::Ipv6Addr(..) => {
|
|
|
|
self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn leave_multicast(&mut self, multi: ip::IpAddr) -> IoResult<()> {
|
|
|
|
match multi {
|
|
|
|
ip::Ipv4Addr(..) => {
|
|
|
|
self.set_membership(multi, libc::IP_DROP_MEMBERSHIP)
|
|
|
|
}
|
|
|
|
ip::Ipv6Addr(..) => {
|
|
|
|
self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn loop_multicast_locally(&mut self) -> IoResult<()> {
|
|
|
|
self.set_multicast_loop(true)
|
|
|
|
}
|
|
|
|
fn dont_loop_multicast_locally(&mut self) -> IoResult<()> {
|
|
|
|
self.set_multicast_loop(false)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn multicast_time_to_live(&mut self, ttl: int) -> IoResult<()> {
|
2014-01-22 21:32:16 -06:00
|
|
|
setsockopt(self.fd(), libc::IPPROTO_IP, libc::IP_MULTICAST_TTL,
|
2013-12-28 18:40:15 -06:00
|
|
|
ttl as libc::c_int)
|
|
|
|
}
|
|
|
|
fn time_to_live(&mut self, ttl: int) -> IoResult<()> {
|
2014-01-22 21:32:16 -06:00
|
|
|
setsockopt(self.fd(), libc::IPPROTO_IP, libc::IP_TTL, ttl as libc::c_int)
|
2013-12-28 18:40:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fn hear_broadcasts(&mut self) -> IoResult<()> {
|
|
|
|
self.set_broadcast(true)
|
|
|
|
}
|
|
|
|
fn ignore_broadcasts(&mut self) -> IoResult<()> {
|
|
|
|
self.set_broadcast(false)
|
|
|
|
}
|
|
|
|
|
2014-05-05 20:56:44 -05:00
|
|
|
fn clone(&self) -> Box<rtio::RtioUdpSocket:Send> {
|
|
|
|
box UdpSocket {
|
|
|
|
inner: self.inner.clone(),
|
2014-04-25 22:50:22 -05:00
|
|
|
read_deadline: 0,
|
|
|
|
write_deadline: 0,
|
2014-05-05 20:56:44 -05:00
|
|
|
} as Box<rtio::RtioUdpSocket:Send>
|
2014-01-22 21:32:16 -06:00
|
|
|
}
|
2014-04-25 22:50:22 -05:00
|
|
|
|
|
|
|
fn set_timeout(&mut self, timeout: Option<u64>) {
|
|
|
|
let deadline = timeout.map(|a| ::io::timer::now() + a).unwrap_or(0);
|
|
|
|
self.read_deadline = deadline;
|
|
|
|
self.write_deadline = deadline;
|
|
|
|
}
|
|
|
|
fn set_read_timeout(&mut self, timeout: Option<u64>) {
|
|
|
|
self.read_deadline = timeout.map(|a| ::io::timer::now() + a).unwrap_or(0);
|
|
|
|
}
|
|
|
|
fn set_write_timeout(&mut self, timeout: Option<u64>) {
|
|
|
|
self.write_deadline = timeout.map(|a| ::io::timer::now() + a).unwrap_or(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Timeout helpers
|
|
|
|
//
|
|
|
|
// The read/write functions below are the helpers for reading/writing a socket
|
|
|
|
// with a possible deadline specified. This is generally viewed as a timed out
|
|
|
|
// I/O operation.
|
|
|
|
//
|
|
|
|
// From the application's perspective, timeouts apply to the I/O object, not to
|
|
|
|
// the underlying file descriptor (it's one timeout per object). This means that
|
|
|
|
// we can't use the SO_RCVTIMEO and corresponding send timeout option.
|
|
|
|
//
|
|
|
|
// The next idea to implement timeouts would be to use nonblocking I/O. An
|
|
|
|
// invocation of select() would wait (with a timeout) for a socket to be ready.
|
|
|
|
// Once its ready, we can perform the operation. Note that the operation *must*
|
|
|
|
// be nonblocking, even though select() says the socket is ready. This is
|
|
|
|
// because some other thread could have come and stolen our data (handles can be
|
|
|
|
// cloned).
|
|
|
|
//
|
|
|
|
// To implement nonblocking I/O, the first option we have is to use the
|
|
|
|
// O_NONBLOCK flag. Remember though that this is a global setting, affecting all
|
|
|
|
// I/O objects, so this was initially viewed as unwise.
|
|
|
|
//
|
|
|
|
// It turns out that there's this nifty MSG_DONTWAIT flag which can be passed to
|
|
|
|
// send/recv, but the niftiness wears off once you realize it only works well on
|
|
|
|
// linux [1] [2]. This means that it's pretty easy to get a nonblocking
|
|
|
|
// operation on linux (no flag fidding, no affecting other objects), but not on
|
|
|
|
// other platforms.
|
|
|
|
//
|
|
|
|
// To work around this constraint on other platforms, we end up using the
|
|
|
|
// original strategy of flipping the O_NONBLOCK flag. As mentioned before, this
|
|
|
|
// could cause other objects' blocking operations to suddenly become
|
|
|
|
// nonblocking. To get around this, a "blocking operation" which returns EAGAIN
|
|
|
|
// falls back to using the same code path as nonblocking operations, but with an
|
|
|
|
// infinite timeout (select + send/recv). This helps emulate blocking
|
|
|
|
// reads/writes despite the underlying descriptor being nonblocking, as well as
|
|
|
|
// optimizing the fast path of just hitting one syscall in the good case.
|
|
|
|
//
|
|
|
|
// As a final caveat, this implementation uses a mutex so only one thread is
|
|
|
|
// doing a nonblocking operation at at time. This is the operation that comes
|
|
|
|
// after the select() (at which point we think the socket is ready). This is
|
|
|
|
// done for sanity to ensure that the state of the O_NONBLOCK flag is what we
|
|
|
|
// expect (wouldn't want someone turning it on when it should be off!). All
|
|
|
|
// operations performed in the lock are *nonblocking* to avoid holding the mutex
|
|
|
|
// forever.
|
|
|
|
//
|
|
|
|
// So, in summary, linux uses MSG_DONTWAIT and doesn't need mutexes, everyone
|
|
|
|
// else uses O_NONBLOCK and mutexes with some trickery to make sure blocking
|
|
|
|
// reads/writes are still blocking.
|
|
|
|
//
|
|
|
|
// Fun, fun!
|
|
|
|
//
|
|
|
|
// [1] http://twistedmatrix.com/pipermail/twisted-commits/2012-April/034692.html
|
|
|
|
// [2] http://stackoverflow.com/questions/19819198/does-send-msg-dontwait
|
|
|
|
|
|
|
|
pub fn read<T>(fd: sock_t,
|
|
|
|
deadline: u64,
|
|
|
|
lock: || -> T,
|
|
|
|
read: |bool| -> libc::c_int) -> IoResult<uint> {
|
|
|
|
let mut ret = -1;
|
|
|
|
if deadline == 0 {
|
|
|
|
ret = retry(|| read(false));
|
|
|
|
}
|
|
|
|
|
|
|
|
if deadline != 0 || (ret == -1 && util::wouldblock()) {
|
|
|
|
let deadline = match deadline {
|
|
|
|
0 => None,
|
|
|
|
n => Some(n),
|
|
|
|
};
|
|
|
|
loop {
|
|
|
|
// With a timeout, first we wait for the socket to become
|
|
|
|
// readable using select(), specifying the relevant timeout for
|
|
|
|
// our previously set deadline.
|
|
|
|
try!(util::await(fd, deadline, util::Readable));
|
|
|
|
|
|
|
|
// At this point, we're still within the timeout, and we've
|
|
|
|
// determined that the socket is readable (as returned by
|
|
|
|
// select). We must still read the socket in *nonblocking* mode
|
|
|
|
// because some other thread could come steal our data. If we
|
|
|
|
// fail to read some data, we retry (hence the outer loop) and
|
|
|
|
// wait for the socket to become readable again.
|
|
|
|
let _guard = lock();
|
|
|
|
match retry(|| read(deadline.is_some())) {
|
|
|
|
-1 if util::wouldblock() => { assert!(deadline.is_some()); }
|
|
|
|
-1 => return Err(last_error()),
|
|
|
|
n => { ret = n; break }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
match ret {
|
|
|
|
0 => Err(io::standard_error(io::EndOfFile)),
|
|
|
|
n if n < 0 => Err(last_error()),
|
|
|
|
n => Ok(n as uint)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn write<T>(fd: sock_t,
|
|
|
|
deadline: u64,
|
|
|
|
buf: &[u8],
|
|
|
|
write_everything: bool,
|
|
|
|
lock: || -> T,
|
|
|
|
write: |bool, *u8, uint| -> i64) -> IoResult<uint> {
|
|
|
|
let mut ret = -1;
|
|
|
|
let mut written = 0;
|
|
|
|
if deadline == 0 {
|
|
|
|
if write_everything {
|
|
|
|
ret = keep_going(buf, |inner, len| {
|
|
|
|
written = buf.len() - len;
|
|
|
|
write(false, inner, len)
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
ret = retry(|| {
|
|
|
|
write(false, buf.as_ptr(), buf.len()) as libc::c_int
|
|
|
|
}) as i64;
|
|
|
|
if ret > 0 { written = ret as uint; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if deadline != 0 || (ret == -1 && util::wouldblock()) {
|
|
|
|
let deadline = match deadline {
|
|
|
|
0 => None,
|
|
|
|
n => Some(n),
|
|
|
|
};
|
|
|
|
while written < buf.len() && (write_everything || written == 0) {
|
|
|
|
// As with read(), first wait for the socket to be ready for
|
|
|
|
// the I/O operation.
|
|
|
|
match util::await(fd, deadline, util::Writable) {
|
|
|
|
Err(ref e) if e.kind == io::TimedOut && written > 0 => {
|
|
|
|
assert!(deadline.is_some());
|
|
|
|
return Err(io::IoError {
|
|
|
|
kind: io::ShortWrite(written),
|
|
|
|
desc: "short write",
|
|
|
|
detail: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
Err(e) => return Err(e),
|
|
|
|
Ok(()) => {}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Also as with read(), we use MSG_DONTWAIT to guard ourselves
|
|
|
|
// against unforseen circumstances.
|
|
|
|
let _guard = lock();
|
|
|
|
let ptr = buf.slice_from(written).as_ptr();
|
|
|
|
let len = buf.len() - written;
|
|
|
|
match retry(|| write(deadline.is_some(), ptr, len) as libc::c_int) {
|
|
|
|
-1 if util::wouldblock() => {}
|
|
|
|
-1 => return Err(last_error()),
|
|
|
|
n => { written += n as uint; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
if ret < 0 {
|
|
|
|
Err(last_error())
|
|
|
|
} else {
|
|
|
|
Ok(written)
|
|
|
|
}
|
2013-12-28 18:40:15 -06:00
|
|
|
}
|