(index<- ) ./libnative/io/util.rs
git branch: * master 5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
modified: Fri May 9 13:02:28 2014
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.
4 //
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.
10
11 use libc;
12 use std::io::IoResult;
13 use std::io;
14 use std::mem;
15 use std::os;
16 use std::ptr;
17
18 use super::c;
19 use super::net;
20 use super::{retry, last_error};
21
22 #[deriving(Show)]
23 pub enum SocketStatus {
24 Readable,
25 Writable,
26 }
27
28 pub fn timeout(desc: &'static str) -> io::IoError {
29 io::IoError {
30 kind: io::TimedOut,
31 desc: desc,
32 detail: None,
33 }
34 }
35
36 pub fn ms_to_timeval(ms: u64) -> libc::timeval {
37 libc::timeval {
38 tv_sec: (ms / 1000) as libc::time_t,
39 tv_usec: ((ms % 1000) * 1000) as libc::suseconds_t,
40 }
41 }
42
43 #[cfg(unix)]
44 pub fn wouldblock() -> bool {
45 let err = os::errno();
46 err == libc::EWOULDBLOCK as int || err == libc::EAGAIN as int
47 }
48
49 #[cfg(windows)]
50 pub fn wouldblock() -> bool {
51 let err = os::errno();
52 err == libc::WSAEWOULDBLOCK as uint
53 }
54
55 #[cfg(unix)]
56 pub fn set_nonblocking(fd: net::sock_t, nb: bool) -> IoResult<()> {
57 let set = nb as libc::c_int;
58 super::mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) }))
59 }
60
61 #[cfg(windows)]
62 pub fn set_nonblocking(fd: net::sock_t, nb: bool) -> IoResult<()> {
63 let mut set = nb as libc::c_ulong;
64 if unsafe { c::ioctlsocket(fd, c::FIONBIO, &mut set) != 0 } {
65 Err(last_error())
66 } else {
67 Ok(())
68 }
69 }
70
71 // See http://developerweb.net/viewtopic.php?id=3196 for where this is
72 // derived from.
73 pub fn connect_timeout(fd: net::sock_t,
74 addrp: *libc::sockaddr,
75 len: libc::socklen_t,
76 timeout_ms: u64) -> IoResult<()> {
77 use std::os;
78 #[cfg(unix)] use INPROGRESS = libc::EINPROGRESS;
79 #[cfg(windows)] use INPROGRESS = libc::WSAEINPROGRESS;
80 #[cfg(unix)] use WOULDBLOCK = libc::EWOULDBLOCK;
81 #[cfg(windows)] use WOULDBLOCK = libc::WSAEWOULDBLOCK;
82
83 // Make sure the call to connect() doesn't block
84 try!(set_nonblocking(fd, true));
85
86 let ret = match unsafe { libc::connect(fd, addrp, len) } {
87 // If the connection is in progress, then we need to wait for it to
88 // finish (with a timeout). The current strategy for doing this is
89 // to use select() with a timeout.
90 -1 if os::errno() as int == INPROGRESS as int ||
91 os::errno() as int == WOULDBLOCK as int => {
92 let mut set: c::fd_set = unsafe { mem::init() };
93 c::fd_set(&mut set, fd);
94 match await(fd, &mut set, timeout_ms) {
95 0 => Err(timeout("connection timed out")),
96 -1 => Err(last_error()),
97 _ => {
98 let err: libc::c_int = try!(
99 net::getsockopt(fd, libc::SOL_SOCKET, libc::SO_ERROR));
100 if err == 0 {
101 Ok(())
102 } else {
103 Err(io::IoError::from_errno(err as uint, true))
104 }
105 }
106 }
107 }
108
109 -1 => Err(last_error()),
110 _ => Ok(()),
111 };
112
113 // be sure to turn blocking I/O back on
114 try!(set_nonblocking(fd, false));
115 return ret;
116
117 #[cfg(unix)]
118 fn await(fd: net::sock_t, set: &mut c::fd_set,
119 timeout: u64) -> libc::c_int {
120 let start = ::io::timer::now();
121 retry(|| unsafe {
122 // Recalculate the timeout each iteration (it is generally
123 // undefined what the value of the 'tv' is after select
124 // returns EINTR).
125 let tv = ms_to_timeval(timeout - (::io::timer::now() - start));
126 c::select(fd + 1, ptr::null(), set as *mut _ as *_,
127 ptr::null(), &tv)
128 })
129 }
130 #[cfg(windows)]
131 fn await(_fd: net::sock_t, set: &mut c::fd_set,
132 timeout: u64) -> libc::c_int {
133 let tv = ms_to_timeval(timeout);
134 unsafe { c::select(1, ptr::null(), &*set, ptr::null(), &tv) }
135 }
136 }
137
138 pub fn await(fd: net::sock_t, deadline: Option<u64>,
139 status: SocketStatus) -> IoResult<()> {
140 let mut set: c::fd_set = unsafe { mem::init() };
141 c::fd_set(&mut set, fd);
142 let (read, write) = match status {
143 Readable => (&set as *_, ptr::null()),
144 Writable => (ptr::null(), &set as *_),
145 };
146 let mut tv: libc::timeval = unsafe { mem::init() };
147
148 match retry(|| {
149 let now = ::io::timer::now();
150 let tvp = match deadline {
151 None => ptr::null(),
152 Some(deadline) => {
153 // If we're past the deadline, then pass a 0 timeout to
154 // select() so we can poll the status
155 let ms = if deadline < now {0} else {deadline - now};
156 tv = ms_to_timeval(ms);
157 &tv as *_
158 }
159 };
160 let n = if cfg!(windows) {1} else {fd as libc::c_int + 1};
161 let r = unsafe { c::select(n, read, write, ptr::null(), tvp) };
162 r
163 }) {
164 -1 => Err(last_error()),
165 0 => Err(timeout("timed out")),
166 _ => Ok(()),
167 }
168 }
libnative/io/util.rs:72:17-72:17 -fn- definition:
// derived from.
pub fn connect_timeout(fd: net::sock_t,
addrp: *libc::sockaddr,
references:- 2libnative/io/pipe_unix.rs:
88: Some(timeout_ms) => {
89: try!(util::connect_timeout(inner.fd, addrp, len, timeout_ms));
90: Ok(inner)
libnative/io/net.rs:
271: Some(timeout) => {
272: try!(util::connect_timeout(fd, addrp, len, timeout));
273: Ok(ret)
libnative/io/util.rs:137:1-137:1 -fn- definition:
pub fn await(fd: net::sock_t, deadline: Option<u64>,
status: SocketStatus) -> IoResult<()> {
let mut set: c::fd_set = unsafe { mem::init() };
references:- 4libnative/io/pipe_unix.rs:
245: if self.deadline != 0 {
246: try!(util::await(self.fd(), Some(self.deadline), util::Readable));
247: }
libnative/io/net.rs:
811: // our previously set deadline.
812: try!(util::await(fd, deadline, util::Readable));
--
865: // the I/O operation.
866: match util::await(fd, deadline, util::Writable) {
867: Err(ref e) if e.kind == io::TimedOut && written > 0 => {
libnative/io/util.rs:43:13-43:13 -fn- definition:
pub fn wouldblock() -> bool {
let err = os::errno();
err == libc::EWOULDBLOCK as int || err == libc::EAGAIN as int
references:- 4libnative/io/net.rs:
858: if deadline != 0 || (ret == -1 && util::wouldblock()) {
859: let deadline = match deadline {
--
884: match retry(|| write(deadline.is_some(), ptr, len) as libc::c_int) {
885: -1 if util::wouldblock() => {}
886: -1 => return Err(last_error()),
libnative/io/util.rs:55:13-55:13 -fn- definition:
pub fn set_nonblocking(fd: net::sock_t, nb: bool) -> IoResult<()> {
let set = nb as libc::c_int;
super::mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) }))
references:- 3113: // be sure to turn blocking I/O back on
114: try!(set_nonblocking(fd, false));
115: return ret;
libnative/io/net.rs:
428: fn drop(&mut self) {
429: assert!(util::set_nonblocking(self.fd, false).is_ok());
430: }
libnative/io/util.rs:27:1-27:1 -fn- definition:
pub fn timeout(desc: &'static str) -> io::IoError {
io::IoError {
kind: io::TimedOut,
references:- 2164: -1 => Err(last_error()),
165: 0 => Err(timeout("timed out")),
166: _ => Ok(()),
libnative/io/util.rs:22:18-22:18 -enum- definition:
pub enum SocketStatus {
Readable,
Writable,
references:- 2138: pub fn await(fd: net::sock_t, deadline: Option<u64>,
139: status: SocketStatus) -> IoResult<()> {
140: let mut set: c::fd_set = unsafe { mem::init() };
libnative/io/util.rs:35:1-35:1 -fn- definition:
pub fn ms_to_timeval(ms: u64) -> libc::timeval {
libc::timeval {
tv_sec: (ms / 1000) as libc::time_t,
references:- 2155: let ms = if deadline < now {0} else {deadline - now};
156: tv = ms_to_timeval(ms);
157: &tv as *_