(index<- )        ./librustuv/addrinfo.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2013 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 ai = std::io::net::addrinfo;
  12  use std::cast;
  13  use libc;
  14  use libc::c_int;
  15  use std::ptr::null;
  16  use std::rt::task::BlockedTask;
  17  
  18  use net;
  19  use super::{Loop, UvError, Request, wait_until_woken_after, wakeup};
  20  use uvll;
  21  
  22  struct Addrinfo {
  23      handle: *libc::addrinfo,
  24  }
  25  
  26  struct Ctx {
  27      slot: Option<BlockedTask>,
  28      status: c_int,
  29      addrinfo: Option<Addrinfo>,
  30  }
  31  
  32  pub struct GetAddrInfoRequest;
  33  
  34  impl GetAddrInfoRequest {
  35      pub fn run(loop_&Loop, nodeOption<&str>, serviceOption<&str>,
  36                 hintsOption<ai::Hint>) -> Result<Vec<ai::Info>, UvError> {
  37          assert!(node.is_some() || service.is_some());
  38          let (_c_node, c_node_ptr) = match node {
  39              Some(n) => {
  40                  let c_node = n.to_c_str();
  41                  let c_node_ptr = c_node.with_ref(|r| r);
  42                  (Some(c_node), c_node_ptr)
  43              }
  44              None => (None, null())
  45          };
  46  
  47          let (_c_service, c_service_ptr) = match service {
  48              Some(s) => {
  49                  let c_service = s.to_c_str();
  50                  let c_service_ptr = c_service.with_ref(|r| r);
  51                  (Some(c_service), c_service_ptr)
  52              }
  53              None => (None, null())
  54          };
  55  
  56          let hint = hints.map(|hint| {
  57              let mut flags = 0;
  58              each_ai_flag(|cval, aival| {
  59                  if hint.flags & (aival as uint) != 0 {
  60                      flags |= cval as i32;
  61                  }
  62              });
  63              let socktype = 0;
  64              let protocol = 0;
  65  
  66              libc::addrinfo {
  67                  ai_flags: flags,
  68                  ai_family: hint.family as c_int,
  69                  ai_socktype: socktype,
  70                  ai_protocol: protocol,
  71                  ai_addrlen: 0,
  72                  ai_canonname: null(),
  73                  ai_addr: null(),
  74                  ai_next: null(),
  75              }
  76          });
  77          let hint_ptr = hint.as_ref().map_or(null(), |x| x as *libc::addrinfo);
  78          let mut req = Request::new(uvll::UV_GETADDRINFO);
  79  
  80          return match unsafe {
  81              uvll::uv_getaddrinfo(loop_.handle, req.handle,
  82                                   getaddrinfo_cb, c_node_ptr, c_service_ptr,
  83                                   hint_ptr)
  84          } {
  85              0 => {
  86                  req.defuse(); // uv callback now owns this request
  87                  let mut cx = Ctx { slot: None, status: 0, addrinfo: None };
  88  
  89                  wait_until_woken_after(&mut cx.slot, loop_, || {
  90                      req.set_data(&cx);
  91                  });
  92  
  93                  match cx.status {
  94                      0 => Ok(accum_addrinfo(cx.addrinfo.get_ref())),
  95                      n => Err(UvError(n))
  96                  }
  97              }
  98              n => Err(UvError(n))
  99          };
 100  
 101  
 102          extern fn getaddrinfo_cb(req*uvll::uv_getaddrinfo_t,
 103                                   statusc_int,
 104                                   res*libc::addrinfo) {
 105              let req = Request::wrap(req);
 106              assert!(status != uvll::ECANCELED);
 107              let cx&mut Ctx = unsafe { req.get_data() };
 108              cx.status = status;
 109              cx.addrinfo = Some(Addrinfo { handle: res });
 110  
 111              wakeup(&mut cx.slot);
 112          }
 113      }
 114  }
 115  
 116  impl Drop for Addrinfo {
 117      fn drop(&mut self) {
 118          unsafe { uvll::uv_freeaddrinfo(self.handle) }
 119      }
 120  }
 121  
 122  fn each_ai_flag(_f: |c_int, ai::Flag|) {
 123      /* FIXME: do we really want to support these?
 124      unsafe {
 125          f(uvll::rust_AI_ADDRCONFIG(), ai::AddrConfig);
 126          f(uvll::rust_AI_ALL(), ai::All);
 127          f(uvll::rust_AI_CANONNAME(), ai::CanonName);
 128          f(uvll::rust_AI_NUMERICHOST(), ai::NumericHost);
 129          f(uvll::rust_AI_NUMERICSERV(), ai::NumericServ);
 130          f(uvll::rust_AI_PASSIVE(), ai::Passive);
 131          f(uvll::rust_AI_V4MAPPED(), ai::V4Mapped);
 132      }
 133      */
 134  }
 135  
 136  // Traverse the addrinfo linked list, producing a vector of Rust socket addresses
 137  pub fn accum_addrinfo(addr: &Addrinfo) -> Vec<ai::Info> {
 138      unsafe {
 139          let mut addr = addr.handle;
 140  
 141          let mut addrs = Vec::new();
 142          loop {
 143              let rustaddr = net::sockaddr_to_addr(cast::transmute((*addr).ai_addr),
 144                                                   (*addr).ai_addrlen as uint);
 145  
 146              let mut flags = 0;
 147              each_ai_flag(|cval, aival| {
 148                  if (*addr).ai_flags & cval != 0 {
 149                      flags |= aival as uint;
 150                  }
 151              });
 152  
 153              /* FIXME: do we really want to support these
 154              let protocol = match (*addr).ai_protocol {
 155                  p if p == uvll::rust_IPPROTO_UDP() => Some(ai::UDP),
 156                  p if p == uvll::rust_IPPROTO_TCP() => Some(ai::TCP),
 157                  _ => None,
 158              };
 159              let socktype = match (*addr).ai_socktype {
 160                  p if p == uvll::rust_SOCK_STREAM() => Some(ai::Stream),
 161                  p if p == uvll::rust_SOCK_DGRAM() => Some(ai::Datagram),
 162                  p if p == uvll::rust_SOCK_RAW() => Some(ai::Raw),
 163                  _ => None,
 164              };
 165              */
 166              let protocol = None;
 167              let socktype = None;
 168  
 169              addrs.push(ai::Info {
 170                  address: rustaddr,
 171                  family: (*addr).ai_family as uint,
 172                  socktype: socktype,
 173                  protocol: protocol,
 174                  flags: flags,
 175              });
 176              if (*addr).ai_next.is_not_null() {
 177                  addr = (*addr).ai_next;
 178              } else {
 179                  break;
 180              }
 181          }
 182  
 183          addrs
 184      }
 185  }