1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
15 use std::rt::rtio::{IoResult, IoError};
19 use super::{retry, last_error};
22 pub enum SocketStatus {
27 pub fn timeout(desc: &'static str) -> IoError {
28 #[cfg(unix)] use ERROR = libc::ETIMEDOUT;
29 #[cfg(windows)] use ERROR = libc::ERROR_OPERATION_ABORTED;
33 detail: Some(desc.to_str()),
37 pub fn short_write(n: uint, desc: &'static str) -> IoError {
38 #[cfg(unix)] use ERROR = libc::EAGAIN;
39 #[cfg(windows)] use ERROR = libc::ERROR_OPERATION_ABORTED;
43 detail: Some(desc.to_str()),
47 pub fn eof() -> IoError {
49 code: libc::EOF as uint,
55 pub fn ms_to_timeval(ms: u64) -> libc::timeval {
57 tv_sec: (ms / 1000) as libc::time_t,
58 tv_usec: ((ms % 1000) * 1000) as libc::suseconds_t,
63 pub fn wouldblock() -> bool {
64 let err = os::errno();
65 err == libc::EWOULDBLOCK as int || err == libc::EAGAIN as int
69 pub fn wouldblock() -> bool {
70 let err = os::errno();
71 err == libc::WSAEWOULDBLOCK as uint
75 pub fn set_nonblocking(fd: net::sock_t, nb: bool) -> IoResult<()> {
76 let set = nb as libc::c_int;
77 super::mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) }))
81 pub fn set_nonblocking(fd: net::sock_t, nb: bool) -> IoResult<()> {
82 let mut set = nb as libc::c_ulong;
83 if unsafe { c::ioctlsocket(fd, c::FIONBIO, &mut set) != 0 } {
90 // See http://developerweb.net/viewtopic.php?id=3196 for where this is
92 pub fn connect_timeout(fd: net::sock_t,
93 addrp: *const libc::sockaddr,
95 timeout_ms: u64) -> IoResult<()> {
97 #[cfg(unix)] use INPROGRESS = libc::EINPROGRESS;
98 #[cfg(windows)] use INPROGRESS = libc::WSAEINPROGRESS;
99 #[cfg(unix)] use WOULDBLOCK = libc::EWOULDBLOCK;
100 #[cfg(windows)] use WOULDBLOCK = libc::WSAEWOULDBLOCK;
102 // Make sure the call to connect() doesn't block
103 try!(set_nonblocking(fd, true));
105 let ret = match unsafe { libc::connect(fd, addrp, len) } {
106 // If the connection is in progress, then we need to wait for it to
107 // finish (with a timeout). The current strategy for doing this is
108 // to use select() with a timeout.
109 -1 if os::errno() as int == INPROGRESS as int ||
110 os::errno() as int == WOULDBLOCK as int => {
111 let mut set: c::fd_set = unsafe { mem::zeroed() };
112 c::fd_set(&mut set, fd);
113 match await(fd, &mut set, timeout_ms) {
114 0 => Err(timeout("connection timed out")),
115 -1 => Err(last_error()),
117 let err: libc::c_int = try!(
118 net::getsockopt(fd, libc::SOL_SOCKET, libc::SO_ERROR));
125 detail: Some(os::error_string(err as uint)),
132 -1 => Err(last_error()),
136 // be sure to turn blocking I/O back on
137 try!(set_nonblocking(fd, false));
141 fn await(fd: net::sock_t, set: &mut c::fd_set,
142 timeout: u64) -> libc::c_int {
143 let start = ::io::timer::now();
145 // Recalculate the timeout each iteration (it is generally
146 // undefined what the value of the 'tv' is after select
148 let mut tv = ms_to_timeval(timeout - (::io::timer::now() - start));
149 c::select(fd + 1, ptr::mut_null(), set as *mut _,
150 ptr::mut_null(), &mut tv)
154 fn await(_fd: net::sock_t, set: &mut c::fd_set,
155 timeout: u64) -> libc::c_int {
156 let mut tv = ms_to_timeval(timeout);
157 unsafe { c::select(1, ptr::mut_null(), set, ptr::mut_null(), &mut tv) }
161 pub fn await(fd: net::sock_t, deadline: Option<u64>,
162 status: SocketStatus) -> IoResult<()> {
163 let mut set: c::fd_set = unsafe { mem::zeroed() };
164 c::fd_set(&mut set, fd);
165 let (read, write) = match status {
166 Readable => (&mut set as *mut _, ptr::mut_null()),
167 Writable => (ptr::mut_null(), &mut set as *mut _),
169 let mut tv: libc::timeval = unsafe { mem::zeroed() };
172 let now = ::io::timer::now();
173 let tvp = match deadline {
174 None => ptr::mut_null(),
176 // If we're past the deadline, then pass a 0 timeout to
177 // select() so we can poll the status
178 let ms = if deadline < now {0} else {deadline - now};
179 tv = ms_to_timeval(ms);
183 let n = if cfg!(windows) {1} else {fd as libc::c_int + 1};
184 let r = unsafe { c::select(n, read, write, ptr::mut_null(), tvp) };
187 -1 => Err(last_error()),
188 0 => Err(timeout("timed out")),