(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(fdnet::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(fdnet::sock_t,
  74                         addrp: *libc::sockaddr,
  75                         lenlibc::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 setc::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 errlibc::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(fdnet::sock_t, set&mut c::fd_set,
 119               timeoutu64) -> 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(fdnet::sock_t, deadlineOption<u64>,
 139               statusSocketStatus) -> IoResult<()> {
 140      let mut setc::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 tvlibc::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:- 2
libnative/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:- 4
libnative/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:- 4
libnative/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:- 3
113:     // 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:- 2
164:         -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:- 2
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() };


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:- 2
155:                 let ms = if deadline < now {0} else {deadline - now};
156:                 tv = ms_to_timeval(ms);
157:                 &tv as *_