From b3f7f758b1f3df8c1d2ded808492b452e4b0e1a0 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 4 Sep 2013 16:31:55 -0700 Subject: [PATCH 1/4] std::rt: Some I/O cleanup --- src/libstd/rt/uv/file.rs | 14 ++++++++------ src/libstd/rt/uv/mod.rs | 3 ++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index eaf70242440..440b5c395c7 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -139,15 +139,17 @@ impl NativeHandle<*uvll::uv_fs_t> for FsRequest { match self { &FsRequest(ptr) => ptr } } } - fn sync_cleanup(loop_: &Loop, result: int) - -> Result { - match status_to_maybe_uv_error_with_loop(loop_.native_handle(), result as i32) { - Some(err) => Err(err), - None => Ok(result) - } + +fn sync_cleanup(loop_: &Loop, result: int) + -> Result { + match status_to_maybe_uv_error_with_loop(loop_.native_handle(), result as i32) { + Some(err) => Err(err), + None => Ok(result) } +} pub struct FileDescriptor(c_int); + impl FileDescriptor { fn new(fd: c_int) -> FileDescriptor { FileDescriptor(fd) diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs index 75b9a5ac553..ea4562068b4 100644 --- a/src/libstd/rt/uv/mod.rs +++ b/src/libstd/rt/uv/mod.rs @@ -132,7 +132,8 @@ pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option pub type UdpSendCallback = ~fn(UdpWatcher, Option); -/// Callbacks used by StreamWatchers, set as custom data on the foreign handle +/// Callbacks used by StreamWatchers, set as custom data on the foreign handle. +/// XXX: Would be better not to have all watchers allocate room for all callback types. struct WatcherData { read_cb: Option, write_cb: Option, From c218694cece7c3018b4a809a52a35fcf3716d92e Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 4 Sep 2013 18:51:14 -0700 Subject: [PATCH 2/4] std::rt: Add libuv bindings for getaddrinfo --- src/libstd/rt/io/net/mod.rs | 21 +++++ src/libstd/rt/uv/addrinfo.rs | 178 +++++++++++++++++++++++++++++++++++ src/libstd/rt/uv/mod.rs | 1 + src/libstd/rt/uv/net.rs | 24 +++++ src/libstd/rt/uv/uvll.rs | 58 ++++++++++++ src/rt/rust_uv.cpp | 5 + src/rt/rustrt.def.in | 1 + 7 files changed, 288 insertions(+) create mode 100644 src/libstd/rt/io/net/mod.rs create mode 100644 src/libstd/rt/uv/addrinfo.rs diff --git a/src/libstd/rt/io/net/mod.rs b/src/libstd/rt/io/net/mod.rs new file mode 100644 index 00000000000..8f316364d27 --- /dev/null +++ b/src/libstd/rt/io/net/mod.rs @@ -0,0 +1,21 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rt::io::net::ip::IpAddr; + +fn get_host_addresses(host: &str) -> Option<~[IpAddr]> { + /*! + * Get the IP addresses for a given host name. + * + * Raises io_error on failure. + */ + + fail!() +} diff --git a/src/libstd/rt/uv/addrinfo.rs b/src/libstd/rt/uv/addrinfo.rs new file mode 100644 index 00000000000..00d1ab5aa9c --- /dev/null +++ b/src/libstd/rt/uv/addrinfo.rs @@ -0,0 +1,178 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cast::transmute; +use cell::Cell; +use c_str::ToCStr; +use libc::{c_int, c_void}; +use option::{Option, Some, None}; +use ptr::null; +use rt::uv::uvll; +use rt::uv::uvll::UV_GETADDRINFO; +use rt::uv::{Loop, UvError, NativeHandle}; +use rt::uv::status_to_maybe_uv_error_with_loop; +use rt::uv::net::UvAddrInfo; + +type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &UvAddrInfo, Option); + +pub struct GetAddrInfoRequest(*uvll::uv_getaddrinfo_t); + +pub struct RequestData { + getaddrinfo_cb: Option, +} + +impl GetAddrInfoRequest { + pub fn new() -> GetAddrInfoRequest { + let req = unsafe { uvll::malloc_req(UV_GETADDRINFO) }; + assert!(req.is_not_null()); + let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req); + req.install_req_data(); + return req; + } + + pub fn getaddrinfo(&mut self, loop_: &Loop, node: Option<&str>, + service: Option<&str>, hints: Option, + cb: GetAddrInfoCallback) { + + assert!(node.is_some() || service.is_some()); + + let (c_node, c_node_ptr) = match node { + Some(n) => { + let c_node = n.to_c_str(); + let c_node_ptr = c_node.with_ref(|r| r); + (Some(c_node), c_node_ptr) + } + None => (None, null()) + }; + + let (c_service, c_service_ptr) = match service { + Some(s) => { + let c_service = s.to_c_str(); + let c_service_ptr = c_service.with_ref(|r| r); + (Some(c_service), c_service_ptr) + } + None => (None, null()) + }; + + let cb = Cell::new(cb); + let wrapper_cb: GetAddrInfoCallback = |req, addrinfo, err| { + // Capture some heap values that need to stay alive for the + // getaddrinfo call + let _ = &c_node; + let _ = &c_service; + + let cb = cb.take(); + cb(req, addrinfo, err) + }; + + // XXX: Implement hints + assert!(hints.is_none()); + + self.get_req_data().getaddrinfo_cb = Some(wrapper_cb); + + unsafe { + assert!(0 == uvll::getaddrinfo(loop_.native_handle(), + self.native_handle(), + getaddrinfo_cb, + c_node_ptr, + c_service_ptr, + null())); + } + + extern "C" fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t, + status: c_int, + res: *uvll::addrinfo) { + let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req); + let loop_ = req.get_loop(); + let err = status_to_maybe_uv_error_with_loop(loop_.native_handle(), status); + let addrinfo = UvAddrInfo(res); + let data = req.get_req_data(); + (*data.getaddrinfo_cb.get_ref())(req, &addrinfo, err); + unsafe { + uvll::freeaddrinfo(res); + } + } + } + + fn get_loop(&self) -> Loop { + unsafe { + Loop { + handle: uvll::get_loop_from_fs_req(self.native_handle()) + } + } + } + + fn install_req_data(&mut self) { + let req = self.native_handle() as *uvll::uv_getaddrinfo_t; + let data = ~RequestData { + getaddrinfo_cb: None + }; + unsafe { + let data = transmute::<~RequestData, *c_void>(data); + uvll::set_data_for_req(req, data); + } + } + + fn get_req_data<'r>(&'r mut self) -> &'r mut RequestData { + unsafe { + let data = uvll::get_data_for_req(self.native_handle()); + let data = transmute::<&*c_void, &mut ~RequestData>(&data); + return &mut **data; + } + } + + fn delete(self) { + unsafe { + let data = uvll::get_data_for_req(self.native_handle()); + let _data = transmute::<*c_void, ~RequestData>(data); + uvll::set_data_for_req(self.native_handle(), null::<()>()); + uvll::free_req(self.native_handle()); + } + } +} + +impl NativeHandle<*uvll::uv_getaddrinfo_t> for GetAddrInfoRequest { + fn from_native_handle(handle: *uvll::uv_getaddrinfo_t) -> GetAddrInfoRequest { + GetAddrInfoRequest(handle) + } + fn native_handle(&self) -> *uvll::uv_getaddrinfo_t { + match self { &GetAddrInfoRequest(ptr) => ptr } + } +} + +#[cfg(test)] +mod test { + use option::{Some, None}; + use rt::uv::Loop; + use rt::uv::net::accum_sockaddrs; + use rt::io::net::ip::{SocketAddr, Ipv4Addr}; + use super::*; + + #[test] + fn getaddrinfo_test() { + let mut loop_ = Loop::new(); + let mut req = GetAddrInfoRequest::new(); + do req.getaddrinfo(&loop_, Some("localhost"), None, None) |_, addrinfo, _| { + let sockaddrs = accum_sockaddrs(addrinfo); + let mut found_local = false; + let local_addr = &SocketAddr { + ip: Ipv4Addr(127, 0, 0, 1), + port: 0 + }; + for addr in sockaddrs.iter() { + found_local = found_local || addr == local_addr; + } + assert!(found_local); + } + loop_.run(); + loop_.close(); + req.delete(); + } +} diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs index ea4562068b4..b85b223468e 100644 --- a/src/libstd/rt/uv/mod.rs +++ b/src/libstd/rt/uv/mod.rs @@ -70,6 +70,7 @@ pub mod net; pub mod idle; pub mod timer; pub mod async; +pub mod addrinfo; /// XXX: Loop(*handle) is buggy with destructors. Normal structs /// with dtors may not be destructured, but tuple structs can, diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 3ff6e90e32d..4d54483f47f 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -21,6 +21,8 @@ use vec; use str; use from_str::{FromStr}; +pub struct UvAddrInfo(*uvll::addrinfo); + pub enum UvSocketAddr { UvIpv4SocketAddr(*sockaddr_in), UvIpv6SocketAddr(*sockaddr_in6), @@ -95,6 +97,28 @@ pub fn uv_socket_addr_to_socket_addr(addr: UvSocketAddr) -> SocketAddr { uv_socket_addr_as_socket_addr(addr, util::id) } +// Traverse the addrinfo linked list, producing a vector of Rust socket addresses +pub fn accum_sockaddrs(addr: &UvAddrInfo) -> ~[SocketAddr] { + unsafe { + let &UvAddrInfo(addr) = addr; + let mut addr = addr; + + let mut addrs = ~[]; + loop { + let uvaddr = sockaddr_to_UvSocketAddr((*addr).ai_addr); + let rustaddr = uv_socket_addr_to_socket_addr(uvaddr); + addrs.push(rustaddr); + if (*addr).ai_next.is_not_null() { + addr = (*addr).ai_next; + } else { + break; + } + } + + return addrs; + } +} + #[cfg(test)] #[test] fn test_ip4_conversion() { diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index d2e3b4176f9..977eae0c269 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -72,6 +72,7 @@ pub type uv_timer_t = c_void; pub type uv_stream_t = c_void; pub type uv_fs_t = c_void; pub type uv_udp_send_t = c_void; +pub type uv_getaddrinfo_t = c_void; #[cfg(stage0)] pub type uv_idle_cb = *u8; @@ -97,6 +98,8 @@ pub type uv_connection_cb = *u8; pub type uv_timer_cb = *u8; #[cfg(stage0)] pub type uv_write_cb = *u8; +#[cfg(stage0)] +pub type uv_getaddrinfo_cb = *u8; #[cfg(not(stage0))] pub type uv_idle_cb = extern "C" fn(handle: *uv_idle_t, @@ -137,12 +140,44 @@ pub type uv_timer_cb = extern "C" fn(handle: *uv_timer_t, #[cfg(not(stage0))] pub type uv_write_cb = extern "C" fn(handle: *uv_write_t, status: c_int); +#[cfg(not(stage0))] +pub type uv_getaddrinfo_cb = extern "C" fn(req: *uv_getaddrinfo_t, + status: c_int, + res: *addrinfo); pub type sockaddr = c_void; pub type sockaddr_in = c_void; pub type sockaddr_in6 = c_void; pub type sockaddr_storage = c_void; +#[cfg(unix)] +pub type socklen_t = c_int; + +// XXX: This is a standard C type. Could probably be defined in libc +#[cfg(unix)] +pub struct addrinfo { + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: socklen_t, + ai_addr: *sockaddr, + ai_canonname: *char, + ai_next: *addrinfo +} + +#[cfg(windows)] +pub struct addrinfo { + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: size_t, + ai_canonname: *char, + ai_addr: *sockaddr, + ai_next: *addrinfo +} + #[deriving(Eq)] pub enum uv_handle_type { UV_UNKNOWN_HANDLE, @@ -666,6 +701,11 @@ pub unsafe fn get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t { rust_uv_get_loop_from_fs_req(req) } +pub unsafe fn get_loop_from_getaddrinfo_req(req: *uv_getaddrinfo_t) -> *uv_loop_t { + #[fixed_stack_segment]; #[inline(never)]; + + rust_uv_get_loop_from_getaddrinfo_req(req) +} pub unsafe fn get_loop_for_uv_handle(handle: *T) -> *c_void { #[fixed_stack_segment]; #[inline(never)]; @@ -721,6 +761,18 @@ pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> size_t { return rust_uv_get_len_from_buf(buf); } +pub unsafe fn getaddrinfo(loop_: *uv_loop_t, req: *uv_getaddrinfo_t, + getaddrinfo_cb: uv_getaddrinfo_cb, + node: *c_char, service: *c_char, + hints: *addrinfo) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + return rust_uv_getaddrinfo(loop_, req, getaddrinfo_cb, node, service, hints); +} +pub unsafe fn freeaddrinfo(ai: *addrinfo) { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_freeaddrinfo(ai); +} + pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str { let err = last_error(uv_loop); let err_ptr = ptr::to_unsafe_ptr(&err); @@ -845,6 +897,7 @@ extern { fn rust_uv_fs_req_cleanup(req: *uv_fs_t); fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> c_int; fn rust_uv_get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t; + fn rust_uv_get_loop_from_getaddrinfo_req(req: *uv_fs_t) -> *uv_loop_t; fn rust_uv_get_stream_handle_from_connect_req(connect_req: *uv_connect_t) -> *uv_stream_t; fn rust_uv_get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t; @@ -857,4 +910,9 @@ extern { fn rust_uv_set_data_for_req(req: *c_void, data: *c_void); fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8; fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> size_t; + fn rust_uv_getaddrinfo(loop_: *uv_loop_t, req: *uv_getaddrinfo_t, + getaddrinfo_cb: uv_getaddrinfo_cb, + node: *c_char, service: *c_char, + hints: *addrinfo) -> c_int; + fn rust_uv_freeaddrinfo(ai: *addrinfo); } diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 8ef4572f810..ac5ea4bb3b3 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -553,3 +553,8 @@ extern "C" uv_loop_t* rust_uv_get_loop_from_fs_req(uv_fs_t* req) { return req->loop; } + +extern "C" uv_loop_t* +rust_uv_get_loop_from_getaddrinfo_req(uv_getaddrinfo_t* req) { + return req->loop; +} diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index c1ba0524be9..45109443f06 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -192,3 +192,4 @@ rust_take_change_dir_lock rust_drop_change_dir_lock rust_get_test_int rust_get_task +rust_uv_get_loop_from_getaddrinfo_req From 0948f54e65227a95d386e429f4e1356d7dd3fba7 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 5 Sep 2013 14:16:17 -0700 Subject: [PATCH 3/4] std::rt: Add get_host_addresses function This is a very simplistic method for host name resolution. It converts a host name to a vector of IP addresses. Should be enough to get started. --- src/libstd/rt/io/mod.rs | 8 +------ src/libstd/rt/io/net/mod.rs | 45 +++++++++++++++++++++++++++++++++++-- src/libstd/rt/rtio.rs | 1 + src/libstd/rt/uv/uvio.rs | 34 +++++++++++++++++++++++++++- 4 files changed, 78 insertions(+), 10 deletions(-) diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index d1919905236..5ceea877453 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -269,13 +269,7 @@ pub use self::extensions::WriterByteConversions; pub mod file; /// Synchronous, non-blocking network I/O. -pub mod net { - pub mod tcp; - pub mod udp; - pub mod ip; - #[cfg(unix)] - pub mod unix; -} +pub mod net; /// Readers and Writers for memory buffers and strings. pub mod mem; diff --git a/src/libstd/rt/io/net/mod.rs b/src/libstd/rt/io/net/mod.rs index 8f316364d27..f44e879a63a 100644 --- a/src/libstd/rt/io/net/mod.rs +++ b/src/libstd/rt/io/net/mod.rs @@ -8,14 +8,55 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use option::{Option, Some, None}; +use result::{Ok, Err}; +use rt::io::io_error; use rt::io::net::ip::IpAddr; +use rt::rtio::{IoFactory, IoFactoryObject}; +use rt::local::Local; -fn get_host_addresses(host: &str) -> Option<~[IpAddr]> { +pub mod tcp; +pub mod udp; +pub mod ip; +#[cfg(unix)] +pub mod unix; + +/// Simplistic name resolution +pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> { /*! * Get the IP addresses for a given host name. * * Raises io_error on failure. */ - fail!() + let ipaddrs = unsafe { + let io: *mut IoFactoryObject = Local::unsafe_borrow(); + (*io).get_host_addresses(host) + }; + + match ipaddrs { + Ok(i) => Some(i), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } +} + +#[cfg(test)] +mod test { + use option::Some; + use rt::io::net::ip::Ipv4Addr; + use super::*; + + #[test] + fn dns_smoke_test() { + let ipaddrs = get_host_addresses("localhost").unwrap(); + let mut found_local = false; + let local_addr = &Ipv4Addr(127, 0, 0, 1); + for addr in ipaddrs.iter() { + found_local = found_local || addr == local_addr; + } + assert!(found_local); + } } diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 6f1b33d1e21..c9c402baaf0 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -73,6 +73,7 @@ pub trait IoFactory { fn fs_open(&mut self, path: &P, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError>; fn fs_unlink(&mut self, path: &P) -> Result<(), IoError>; + fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError>; } pub trait RtioTcpListener : RtioSocket { diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index e37dfba0cc1..b225513e94f 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -29,7 +29,8 @@ use rt::tube::Tube; use rt::task::SchedHome; use rt::uv::*; use rt::uv::idle::IdleWatcher; -use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr}; +use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr, accum_sockaddrs}; +use rt::uv::addrinfo::GetAddrInfoRequest; use unstable::sync::Exclusive; use super::super::io::support::PathLike; use libc::{lseek, off_t, O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, O_WRONLY, @@ -596,6 +597,37 @@ impl IoFactory for UvIoFactory { assert!(!result_cell.is_empty()); return result_cell.take(); } + + fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError> { + let result_cell = Cell::new_empty(); + let result_cell_ptr: *Cell> = &result_cell; + let host_ptr: *&str = &host; + let addrinfo_req = GetAddrInfoRequest::new(); + let addrinfo_req_cell = Cell::new(addrinfo_req); + do task::unkillable { // FIXME(#8674) + let scheduler: ~Scheduler = Local::take(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + let mut addrinfo_req = addrinfo_req_cell.take(); + unsafe { + do addrinfo_req.getaddrinfo(self.uv_loop(), + Some(*host_ptr), + None, None) |_, addrinfo, err| { + let res = match err { + None => Ok(accum_sockaddrs(addrinfo).map(|addr| addr.ip.clone())), + Some(err) => Err(uv_error_to_io_error(err)) + }; + (*result_cell_ptr).put_back(res); + let scheduler: ~Scheduler = Local::take(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + } + } + } + } + addrinfo_req.delete(); + assert!(!result_cell.is_empty()); + return result_cell.take(); + } } pub struct UvTcpListener { From 807408b708a11c9a96b2dc4fedd611276273574f Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 5 Sep 2013 22:15:02 -0700 Subject: [PATCH 4/4] std::rt: Fix addrinfo definition on BSD --- src/libstd/rt/uv/uvll.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 977eae0c269..08e9bc062ce 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -154,7 +154,8 @@ pub type sockaddr_storage = c_void; pub type socklen_t = c_int; // XXX: This is a standard C type. Could probably be defined in libc -#[cfg(unix)] +#[cfg(target_os = "android")] +#[cfg(target_os = "linux")] pub struct addrinfo { ai_flags: c_int, ai_family: c_int, @@ -166,6 +167,19 @@ pub struct addrinfo { ai_next: *addrinfo } +#[cfg(target_os = "macos")] +#[cfg(target_os = "freebsd")] +pub struct addrinfo { + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: socklen_t, + ai_canonname: *char, + ai_addr: *sockaddr, + ai_next: *addrinfo +} + #[cfg(windows)] pub struct addrinfo { ai_flags: c_int,