Paul Sajna 6 년 전
부모
커밋
07eb658a8a

+ 1 - 0
src/header/mod.rs

@@ -10,6 +10,7 @@ pub mod fnmatch;
 pub mod grp;
 pub mod inttypes;
 pub mod locale;
+pub mod netdb;
 pub mod netinet_in;
 //pub mod pthread;
 pub mod pwd;

+ 7 - 0
src/header/netdb/cbindgen.toml

@@ -0,0 +1,7 @@
+sys_includes = ["sys/socket.h", "netinet/in.h"]
+include_guard = "_NETDB_H"
+language = "C"
+style = "Tag"
+
+[enum]
+prefix_with_name = true

+ 22 - 0
src/header/netdb/dns/answer.rs

@@ -0,0 +1,22 @@
+// Copyright 2016 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use alloc::String;
+use alloc::Vec;
+
+#[derive(Clone, Debug)]
+pub struct DnsAnswer {
+    pub name: String,
+    pub a_type: u16,
+    pub a_class: u16,
+    pub ttl_a: u16,
+    pub ttl_b: u16,
+    pub data: Vec<u8>
+}

+ 209 - 0
src/header/netdb/dns/mod.rs

@@ -0,0 +1,209 @@
+// Copyright 2016 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use self::answer::DnsAnswer;
+pub use self::query::DnsQuery;
+
+use core::slice;
+use core::u16;
+use alloc::String;
+use alloc::Vec;
+
+mod answer;
+mod query;
+
+#[allow(non_camel_case_types)]
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(packed)]
+pub struct n16 {
+    inner: u16
+}
+
+impl n16 {
+    pub fn as_bytes(&self) -> &[u8] {
+        unsafe { slice::from_raw_parts((&self.inner as *const u16) as *const u8, 2) }
+    }
+
+    pub fn from_bytes(bytes: &[u8]) -> Self {
+        n16 {
+            inner: unsafe { slice::from_raw_parts(bytes.as_ptr() as *const u16, bytes.len()/2)[0] }
+        }
+    }
+}
+
+impl From<u16> for n16 {
+    fn from(value: u16) -> Self {
+        n16 {
+            inner: value.to_be()
+        }
+    }
+}
+
+impl From<n16> for u16 {
+    fn from(value: n16) -> Self {
+        u16::from_be(value.inner)
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct Dns {
+    pub transaction_id: u16,
+    pub flags: u16,
+    pub queries: Vec<DnsQuery>,
+    pub answers: Vec<DnsAnswer>
+}
+
+impl Dns {
+    pub fn compile(&self) -> Vec<u8> {
+        let mut data = Vec::new();
+
+        macro_rules! push_u8 {
+            ($value:expr) => {
+                data.push($value);
+            };
+        };
+
+        macro_rules! push_n16 {
+            ($value:expr) => {
+                data.extend_from_slice(n16::from($value).as_bytes());
+            };
+        };
+
+        push_n16!(self.transaction_id);
+        push_n16!(self.flags);
+        push_n16!(self.queries.len() as u16);
+        push_n16!(self.answers.len() as u16);
+        push_n16!(0);
+        push_n16!(0);
+
+        for query in self.queries.iter() {
+            for part in query.name.split('.') {
+                push_u8!(part.len() as u8);
+                data.extend_from_slice(part.as_bytes());
+            }
+            push_u8!(0);
+            push_n16!(query.q_type);
+            push_n16!(query.q_class);
+        }
+        data
+    }
+
+    pub fn parse(data: &[u8]) -> Result<Self, String> {
+        let name_ind = 0b11000000;
+        let mut i = 0;
+
+        macro_rules! pop_u8 {
+            () => {
+                {
+                    i += 1;
+                    if i > data.len() {
+                        return Err(format!("{}: {}: pop_u8", file!(), line!()));
+                    }
+                    data[i - 1]
+                }
+            };
+        };
+
+        macro_rules! pop_n16 {
+            () => {
+                {
+                    i += 2;
+                    if i > data.len() {
+                        return Err(format!("{}: {}: pop_n16", file!(), line!()));
+                    }
+                    u16::from(n16::from_bytes(&data[i - 2 .. i]))
+                }
+            };
+        };
+
+        macro_rules! pop_data {
+            () => {
+                {
+                    let mut data = Vec::new();
+
+                    let data_len = pop_n16!();
+                    for _data_i in 0..data_len {
+                        data.push(pop_u8!());
+                    }
+
+                    data
+                }
+            };
+        };
+
+        macro_rules! pop_name {
+            () => {
+                {
+                    let mut name = String::new();
+                    let old_i = i;
+
+                    loop {
+                        let name_len = pop_u8!();
+                        if name_len & name_ind == name_ind {
+                            i -= 1;
+                            i = (pop_n16!() - ((name_ind as u16) << 8)) as usize;
+                            continue;
+                        }
+                        if name_len == 0 {
+                            break;
+                        }
+                        if ! name.is_empty() {
+                            name.push('.');
+                        }
+                        for _name_i in 0..name_len {
+                            name.push(pop_u8!() as char);
+                        }
+                    }
+
+                    if i <= old_i {
+                        i = old_i + 2;
+                    }
+
+                    name
+                }
+            };
+        };
+
+        let transaction_id = pop_n16!();
+        let flags = pop_n16!();
+        let queries_len = pop_n16!();
+        let answers_len = pop_n16!();
+        pop_n16!();
+        pop_n16!();
+
+        let mut queries = Vec::new();
+        for _query_i in 0..queries_len {
+            queries.push(DnsQuery {
+                name: pop_name!(),
+                q_type: pop_n16!(),
+                q_class: pop_n16!()
+            });
+        }
+
+        let mut answers = Vec::new();
+        for _answer_i in 0..answers_len {
+            answers.push(DnsAnswer {
+                name: pop_name!(),
+                a_type: pop_n16!(),
+                a_class: pop_n16!(),
+                ttl_a: pop_n16!(),
+                ttl_b: pop_n16!(),
+                data: pop_data!()
+            });
+        }
+
+        Ok(Dns {
+            transaction_id: transaction_id,
+            flags: flags,
+            queries: queries,
+            answers: answers,
+        })
+    }
+}

+ 18 - 0
src/header/netdb/dns/query.rs

@@ -0,0 +1,18 @@
+// Copyright 2016 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use alloc::String;
+
+#[derive(Clone, Debug)]
+pub struct DnsQuery {
+    pub name: String,
+    pub q_type: u16,
+    pub q_class: u16
+}

+ 22 - 0
src/header/netdb/linux.rs

@@ -0,0 +1,22 @@
+use alloc::string::String;
+use platform::rawfile::RawFile;
+use platform::Line;
+use platform::rlb::RawLineBuffer;
+use c_str::CString;
+
+pub fn get_dns_server() -> String {
+    let fd = match RawFile::open(&CString::new("/etc/resolv.conf").unwrap(), 0, 0) {
+        Ok(fd) => fd,
+        Err(_) => return String::new() // TODO: better error handling
+    };
+
+    let mut rlb = RawLineBuffer::new(*fd);
+    while let Line::Some(line) = rlb.next() {
+        if line.starts_with(b"nameserver ") {
+            return String::from_utf8(line[11..].to_vec()).unwrap_or_default();
+        }
+    }
+
+    // TODO: better error handling
+    String::new()
+}

+ 944 - 0
src/header/netdb/mod.rs

@@ -0,0 +1,944 @@
+//! netdb implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/netdb.h.html
+
+mod dns;
+
+use core::{mem, str, ptr};
+use core::str::FromStr;
+
+use alloc::{Vec, String};
+use alloc::str::SplitWhitespace;
+use alloc::string::ToString;
+use alloc::vec::IntoIter;
+use alloc::boxed::Box;
+
+use c_str::CString;
+
+use platform;
+use platform::{Pal, Sys};
+use platform::types::*;
+use platform::rlb::{Line, RawLineBuffer};
+use platform::c_str;
+
+use self::dns::{Dns, DnsQuery};
+
+use header::arpa_inet::{htons, ntohs, inet_aton};
+use header::errno::*;
+use header::fcntl::O_RDONLY;
+use header::netinet_in::{in_addr, IPPROTO_UDP, sockaddr_in};
+use header::stdlib::atoi;
+use header::strings::strcasecmp;
+use header::sys_socket;
+use header::sys_socket::{sockaddr, socklen_t};
+use header::sys_socket::constants::{SOCK_DGRAM, AF_INET};
+use header::time;
+use header::unistd::SEEK_SET;
+
+#[cfg(target_os = "linux")]
+#[path = "linux.rs"]
+pub mod sys;
+
+#[cfg(target_os = "redox")]
+#[path = "redox.rs"]
+pub mod sys;
+
+const MAXADDRS: usize = 35;
+const MAXALIASES: usize = 35;
+
+struct LookupHost(IntoIter<in_addr>);
+
+impl Iterator for LookupHost {
+    type Item = in_addr;
+    fn next (&mut self) -> Option<Self::Item> {
+        self.0.next()
+    }
+}
+
+#[repr(C)]
+pub struct hostent {
+    h_name: *mut c_char,
+    h_aliases: *mut *mut c_char,
+    h_addrtype: c_int,
+    h_length: c_int,
+    h_addr_list: *mut *mut c_char,
+}
+
+#[repr(C)]
+pub struct netent {
+    n_name: *mut c_char, /* official name of net */
+    n_aliases: *mut *mut c_char, /* alias list */
+    n_addrtype: c_int, /* net address type */
+    n_net: c_ulong, /* network # */
+}
+
+#[repr(C)]
+pub struct servent {
+    s_name: *mut c_char, /* official service name */
+    s_aliases: *mut *mut c_char, /* alias list */
+    s_port: c_int, /* port # */
+    s_proto: *mut c_char, /* protocol to use */
+}
+
+#[repr(C)]
+pub struct protoent {
+    p_name: *mut c_char, /* official protocol name */
+    p_aliases: *mut *mut c_char, /* alias list */
+    p_proto: c_int, /* protocol # */
+}
+
+#[repr(C)]
+pub struct addrinfo {
+    ai_flags: c_int, /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
+    ai_family: c_int, /* PF_xxx */
+    ai_socktype: c_int, /* SOCK_xxx */
+    ai_protocol: c_int, /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+    ai_addrlen: size_t, /* length of ai_addr */
+    ai_canonname: *mut c_char, /* canonical name for hostname */
+    ai_addr: *mut sockaddr, /* binary address */
+    ai_next: *mut addrinfo, /* next structure in linked list */
+}
+
+static mut NETDB: c_int = 0;
+static mut NET_ENTRY: netent = netent {
+    n_name: ptr::null_mut(),
+    n_aliases: ptr::null_mut(),
+    n_addrtype: 0,
+    n_net: 0,
+};
+static mut NET_NAME: Option<Vec<u8>> = None;
+static mut NET_ALIASES: [*const c_char; MAXALIASES] = [ptr::null(); MAXALIASES];
+static mut NET_NUM: Option<u64> = None;
+static mut N_POS: usize = 0;
+static mut NET_STAYOPEN: c_int = 0;
+
+static mut HOSTDB: c_int = 0;
+static mut HOST_ENTRY: hostent = hostent {
+    h_name: ptr::null_mut(),
+    h_aliases: ptr::null_mut(), 
+    h_addrtype: 0,
+    h_length: 0,
+    h_addr_list: ptr::null_mut(), 
+};
+static mut HOST_NAME: Option<Vec<u8>> = None;
+static mut HOST_ALIASES: Option<Vec<Vec<u8>>> = None;
+static mut HOST_ADDR: Option<in_addr> = None;
+static mut HOST_ADDR_LIST: [*mut c_char; 2] = [ptr::null_mut(); 2];
+static mut _HOST_ADDR_LIST: [u8;4] = [0u8;4];
+static mut H_POS: usize = 0;
+static mut HOST_STAYOPEN: c_int = 0;
+
+#[allow(non_upper_case_globals)]
+#[no_mangle]
+pub static mut h_errno: c_int = 0;
+pub const HOST_NOT_FOUND: c_int = 1;
+pub const NO_DATA: c_int = 2;
+pub const NO_RECOVERY: c_int = 3;
+pub const TRY_AGAIN: c_int = 4;
+
+static mut PROTODB: c_int = 0;
+static mut PROTO_ENTRY: protoent = protoent {
+    p_name: ptr::null_mut(),
+    p_aliases: ptr::null_mut(),
+    p_proto: 0 as c_int,
+};
+static mut PROTO_NAME: Option<Vec<u8>> = None;
+static mut PROTO_ALIASES: Option<Vec<Vec<u8>>> = None;
+static mut PROTO_NUM: Option<c_int> = None;
+static mut P_POS: usize = 0; 
+static mut PROTO_STAYOPEN: c_int = 0;
+
+static mut SERVDB: c_int = 0;
+static mut SERV_ENTRY: servent = servent {
+    s_name: ptr::null_mut(),
+    s_aliases: ptr::null_mut(),
+    s_port: 0 as c_int,
+    s_proto: ptr::null_mut(),
+
+};
+static mut SERV_NAME: Option<Vec<u8>> = None;
+static mut SERV_ALIASES: Option<Vec<Vec<u8>>> = None;
+static mut SERV_PORT: Option<c_int> = None;
+static mut SERV_PROTO: Option<Vec<u8>> = None;
+static mut S_POS: usize = 0;
+static mut SERV_STAYOPEN: c_int = 0;
+
+const NULL_ALIASES: [*mut c_char; 2] = [ptr::null_mut(); 2];
+
+fn bytes_to_box_str(bytes: &[u8]) -> Box<str> {
+    Box::from(core::str::from_utf8(bytes).unwrap_or(""))
+}
+
+fn lookup_host(host: &str) -> Result<LookupHost, c_int> {
+    let dns_string = sys::get_dns_server();
+
+    let dns_vec: Vec<u8> = dns_string
+        .trim()
+        .split(".")
+        .map(|octet| octet.parse::<u8>().unwrap_or(0))
+        .collect();
+
+    if dns_vec.len() == 4 {
+        let mut dns_arr =  [0u8;4];
+        for (i, octet) in dns_vec.iter().enumerate() {
+            dns_arr[i] = *octet;
+        }
+        let dns_addr = unsafe {mem::transmute::<[u8;4], u32>(dns_arr)};
+
+        let mut timespec = timespec::default();
+        Sys::clock_gettime(time::constants::CLOCK_REALTIME, &mut timespec);
+        let tid = (timespec.tv_nsec >> 16) as u16;
+
+        let packet = Dns {
+            transaction_id: tid,
+            flags: 0x0100,
+            queries: vec![
+                DnsQuery {
+                    name: host.to_string(),
+                    q_type: 0x0001,
+                    q_class: 0x0001,
+                },
+            ],
+            answers: vec![],
+        };
+
+        let packet_data = packet.compile();
+        let packet_data_len = packet_data.len();
+
+        let packet_data_box = packet_data.into_boxed_slice(); 
+        let packet_data_ptr = Box::into_raw(packet_data_box) as *mut _ as *mut c_void;
+
+        let sock = unsafe {sys_socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP as i32)};
+
+        let mut dest = sockaddr_in {
+            sin_family: AF_INET as u16,
+            sin_port: htons(53),
+            sin_addr: in_addr {
+                s_addr: dns_addr,
+            },
+            ..Default::default()
+        };
+        
+        let dest_ptr = &mut dest as *mut _ as *mut sockaddr;
+
+        unsafe {
+            if sys_socket::sendto(sock, packet_data_ptr, packet_data_len, 0, dest_ptr, 16) < 0 {
+                Box::from_raw(packet_data_ptr);
+                return Err(EIO);
+            }
+        }
+
+        unsafe {
+            Box::from_raw(packet_data_ptr);
+        }
+
+        let mut i = 0 as socklen_t;
+        let mut buf = [0u8;65536];
+        let buf_ptr = buf.as_mut_ptr() as *mut c_void;
+
+        let mut count = -1;
+
+        let mut from: sockaddr = Default::default();
+        let from_ptr = &mut from as *mut sockaddr;
+
+        unsafe {
+            count = sys_socket::recvfrom(sock, buf_ptr, 65536, 0, from_ptr, &mut i as *mut socklen_t);
+        }
+        if count < 0 {
+            return Err(EIO)
+        }
+
+        match Dns::parse(&buf[..count as usize]) {
+            Ok(response) => {
+                let mut addrs = vec![];
+                for answer in response.answers.iter() {
+                    if answer.a_type == 0x0001 && answer.a_class == 0x0001 &&
+                        answer.data.len() == 4
+                    {
+                        let addr = in_addr {
+                            s_addr: unsafe { mem::transmute::<[u8;4], u32>([
+                                answer.data[0],
+                                answer.data[1],
+                                answer.data[2],
+                                answer.data[3],
+                            ])},
+                        };
+                        addrs.push(addr);
+                    }
+                }
+                Ok(LookupHost(addrs.into_iter()))
+            }
+            Err(_err) => Err(EINVAL),
+        }
+    } else {
+        Err(EINVAL)
+    }
+}
+
+fn lookup_addr(addr: in_addr) -> Result<Vec<Vec<u8>>, c_int> {
+    let dns_string = sys::get_dns_server();
+
+    let dns_vec: Vec<u8> = dns_string
+        .trim()
+        .split(".")
+        .map(|octet| octet.parse::<u8>().unwrap_or(0))
+        .collect();
+
+    let mut dns_arr =  [0u8;4];
+
+    for (i, octet) in dns_vec.iter().enumerate() {
+        dns_arr[i] = *octet;
+    }
+
+    let mut addr_vec: Vec<u8> = unsafe { mem::transmute::<u32, [u8;4]>(addr.s_addr).to_vec() };
+    addr_vec.reverse();
+    let mut name: Vec<u8> = vec![];
+    for octet in addr_vec {
+        for ch in format!("{}", octet).as_bytes() {
+            name.push(*ch);
+        }
+        name.push(b"."[0]);
+    }
+    name.pop();
+    for ch in b".IN-ADDR.ARPA" {
+        name.push(*ch);
+    }
+
+    if dns_vec.len() == 4 {
+        let mut timespec = timespec::default();
+        Sys::clock_gettime(time::constants::CLOCK_REALTIME, &mut timespec);
+        let tid = (timespec.tv_nsec >> 16) as u16;
+
+        let packet = Dns {
+            transaction_id: tid,
+            flags: 0x0100,
+            queries: vec![
+                DnsQuery {
+                    name: String::from_utf8(name).unwrap(),
+                    q_type: 0x000C,
+                    q_class: 0x0001,
+                },
+            ],
+            answers: vec![],
+        };
+
+        let packet_data = packet.compile();
+        use core::fmt::Write;
+        let packet_data_len = packet_data.len();
+        let packet_data_box = packet_data.into_boxed_slice();
+        let packet_data_ptr = Box::into_raw(packet_data_box) as *mut _ as *mut c_void;
+
+        let sock = unsafe {sys_socket::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP as i32)};
+
+        let mut dest = sockaddr_in {
+            sin_family: AF_INET as u16,
+            sin_port: htons(53),
+            sin_addr: in_addr {
+                s_addr: unsafe { mem::transmute::<[u8;4], u32>(dns_arr) },
+            },
+            ..Default::default()
+        };
+
+        let dest_ptr = &mut dest as *mut _ as *mut sockaddr;
+
+        unsafe {
+            if sys_socket::sendto(sock, packet_data_ptr, packet_data_len, 0, dest_ptr, 16) < 0 {
+                return Err(EIO);
+            }
+        }
+
+        unsafe {
+            Box::from_raw(packet_data_ptr);
+        }
+
+        let mut i = mem::size_of::<sockaddr_in>() as socklen_t;
+        let mut buf = [0u8;65536];
+        let buf_ptr = buf.as_mut_ptr() as *mut c_void;
+
+        let mut count = -1;
+
+        unsafe {
+            count = sys_socket::recvfrom(sock, buf_ptr, 65536, 0, dest_ptr, &mut i as *mut socklen_t);
+        }
+        if count < 0 {
+            return Err(EIO)
+        }
+
+        match Dns::parse(&buf[..count as usize]) {
+            Ok(response) => {
+                let mut names = vec![];
+                for answer in response.answers.iter() {
+                    if answer.a_type == 0x000C && answer.a_class == 0x0001 {
+                        // answer.data is encoded kinda weird.
+                        // Basically length-prefixed strings for each
+                        // subsection of the domain.
+                        // We need to parse this to insert periods where
+                        // they belong (ie at the end of each string)
+                        let data = parse_revdns_answer(answer.data.clone());
+                        names.push(data);
+                    }
+                }
+                Ok(names)
+            }
+            Err(_err) => Err(EINVAL),
+        }
+    } else {
+        Err(EINVAL)
+    }
+}
+
+fn parse_revdns_answer(data: Vec<u8>) -> Vec<u8> {
+    let mut cursor = 0;
+    let mut offset = 0;
+    let mut index = 0;
+    let mut output = data.clone();
+    while index < data.len() - 1 {
+        offset = data[index] as usize;
+        index = cursor + offset + 1;
+        output[index] = '.' as u8;
+        cursor = index;
+    }
+    //we don't want an extra period at the end
+    output.pop();
+    output
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn endhostent() {
+    Sys::close(HOSTDB);
+    HOSTDB = 0;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn endnetent() {
+    Sys::close(NETDB);
+    NETDB = 0;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn endprotoent() {
+    Sys::close(PROTODB);
+    PROTODB = 0;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn endservent() {
+    Sys::close(SERVDB);
+    SERVDB = 0;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn gethostbyaddr(v: *const c_void, length: socklen_t, format:c_int) -> *const hostent {
+    let addr: in_addr = *(v as *mut in_addr);
+
+    // check the hosts file first
+    let mut p: *const hostent;
+    sethostent(HOST_STAYOPEN);
+    while { p=gethostent(); p!=ptr::null()} {
+        let mut cp = (*p).h_addr_list;
+        loop {
+            if cp.is_null() {
+                break;
+            }
+            if (*cp).is_null() {
+                break;
+            }
+            let mut cp_slice: [i8;4] = [0i8;4];
+            (*cp).copy_to(cp_slice.as_mut_ptr(), 4);
+            let cp_s_addr = mem::transmute::<[i8;4], u32>(cp_slice);
+            if cp_s_addr == addr.s_addr {
+                sethostent(HOST_STAYOPEN);
+                return p;
+            }
+            cp = cp.offset(1);
+        }
+    }
+
+    //TODO actually get aliases
+    let mut _host_aliases: Vec<Vec<u8>> = Vec::new();
+    _host_aliases.push(vec![b'\0']);
+    let mut host_aliases: Vec<*mut i8> = Vec::new(); 
+    host_aliases.push(ptr::null_mut());
+    HOST_ALIASES = Some(_host_aliases);
+
+
+    match lookup_addr(addr) {
+        Ok(s) => {
+            _HOST_ADDR_LIST = mem::transmute::<u32, [u8;4]>(addr.s_addr);
+            HOST_ADDR_LIST = [_HOST_ADDR_LIST.as_mut_ptr() as *mut c_char, ptr::null_mut()];
+            let mut host_name = s[0].to_vec();
+            HOST_NAME = Some(host_name);
+            HOST_ENTRY = hostent {
+                h_name: HOST_NAME.as_mut().unwrap().as_mut_ptr() as *mut c_char,
+                h_aliases: host_aliases.as_mut_slice().as_mut_ptr() as *mut *mut i8, 
+                h_addrtype: format,
+                h_length: length as i32,
+                h_addr_list: HOST_ADDR_LIST.as_mut_ptr()
+            };
+            &HOST_ENTRY
+        }
+        Err(e) => { platform::errno = e; return ptr::null(); }
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn gethostbyname(name: *const c_char) -> *const hostent {
+
+    // check if some idiot gave us an address instead of a name
+    let mut octets = str::from_utf8_unchecked(c_str(name)).split('.');
+    let mut s_addr = [0u8;4];
+    let mut is_addr = true; 
+    for i in 0..4 {
+        if let Some(n) = octets.next().and_then(|x| u8::from_str(x).ok()) {
+            s_addr[i] = n;
+        } else {
+            is_addr = false;
+        }
+    }
+    if octets.next() != None {
+        is_addr = false;
+    }
+
+    if is_addr == true {
+        let addr = in_addr {
+            s_addr: mem::transmute::<[u8;4], u32>(s_addr),
+        };
+        return gethostbyaddr(&addr as *const _ as *const c_void, 4, AF_INET);
+    }
+
+    // check the hosts file first
+    let mut p: *const hostent;
+    sethostent(HOST_STAYOPEN);
+    while { p = gethostent(); p!=ptr::null() } {
+        if strcasecmp((*p).h_name, name) == 0 {
+            sethostent(HOST_STAYOPEN);
+            return p;
+        }
+        let mut cp = (*p).h_aliases;
+        loop {
+            if cp.is_null() {
+                break;
+            }
+            if (*cp).is_null() {
+                break;
+            }
+            if strcasecmp(*cp, name) == 0 {
+                sethostent(HOST_STAYOPEN);
+                return p;
+            }
+            cp = cp.offset(1);
+        }
+    }
+
+    let mut host = match lookup_host(str::from_utf8_unchecked(c_str(name))) {
+        Ok(lookuphost) => lookuphost,
+        Err(e) => { platform::errno = e; return ptr::null() }
+    };
+    let host_addr = match host.next() {
+        Some(result) => result,
+        None => { platform::errno = ENOENT; return ptr::null() }
+    };
+
+    let host_name: Vec<u8> = c_str(name).to_vec();
+    HOST_NAME = Some(host_name);
+    _HOST_ADDR_LIST = mem::transmute::<u32, [u8;4]>(host_addr.s_addr);
+    HOST_ADDR_LIST = [_HOST_ADDR_LIST.as_mut_ptr() as *mut c_char, ptr::null_mut()];
+    HOST_ADDR = Some(host_addr);
+
+    //TODO actually get aliases
+    let mut _host_aliases: Vec<Vec<u8>> = Vec::new();
+    _host_aliases.push(vec![b'\0']);
+    let mut host_aliases: Vec<*mut i8> = Vec::new(); 
+    host_aliases.push(ptr::null_mut());
+    host_aliases.push(ptr::null_mut());
+    HOST_ALIASES = Some(_host_aliases);
+
+    HOST_ENTRY = hostent {
+        h_name: HOST_NAME.as_mut().unwrap().as_mut_ptr() as *mut c_char,
+        h_aliases: host_aliases.as_mut_slice().as_mut_ptr() as *mut *mut i8, 
+        h_addrtype: AF_INET,
+        h_length: 4,
+        h_addr_list: HOST_ADDR_LIST.as_mut_ptr()
+    };
+    sethostent(HOST_STAYOPEN);
+    &HOST_ENTRY as *const hostent
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn gethostent() -> *const hostent {
+    if HOSTDB == 0 {
+        HOSTDB = Sys::open(&CString::new("/etc/hosts").unwrap(), O_RDONLY, 0);
+    }
+    let mut rlb = RawLineBuffer::new(HOSTDB);
+    rlb.seek(H_POS);
+
+    let mut r: Box<str> = Box::default();
+    while r.is_empty() || r.split_whitespace().next() == None || r.starts_with("#") {
+        r = match rlb.next() {
+            Line::Some(s) => bytes_to_box_str(s),
+            _ => {
+                if HOST_STAYOPEN == 0 { endhostent(); }
+                return ptr::null();
+            }
+        };
+    }
+    rlb.next();
+    H_POS = rlb.line_pos();
+
+    let mut iter: SplitWhitespace = r.split_whitespace();
+
+    let mut addr_vec = iter.next().unwrap().as_bytes().to_vec();
+    addr_vec.push(b'\0');
+    let addr_cstr = addr_vec.as_slice().as_ptr() as *const i8;
+    let mut addr = mem::uninitialized();
+    inet_aton(addr_cstr, &mut addr);
+
+    _HOST_ADDR_LIST = mem::transmute::<u32, [u8;4]>(addr.s_addr);
+    HOST_ADDR_LIST = [_HOST_ADDR_LIST.as_mut_ptr() as *mut c_char, ptr::null_mut()];
+
+    HOST_ADDR = Some(addr);
+
+    let mut host_name = iter.next().unwrap().as_bytes().to_vec();
+    host_name.push(b'\0');
+
+    let mut _host_aliases: Vec<Vec<u8>> = Vec::new();
+
+    loop {
+        let mut alias = match iter.next() {
+            Some(s) => s.as_bytes().to_vec(),
+            _ => break
+        };
+        alias.push(b'\0');
+        _host_aliases.push(alias);
+    }
+    HOST_ALIASES = Some(_host_aliases);
+
+    let mut host_aliases: Vec<*mut i8> = HOST_ALIASES.as_mut().unwrap().iter_mut().map(|x| x.as_mut_ptr() as *mut i8).collect();
+    host_aliases.push(ptr::null_mut());
+    host_aliases.push(ptr::null_mut());
+
+    HOST_NAME = Some(host_name);
+
+    HOST_ENTRY = hostent {
+        h_name: HOST_NAME.as_mut().unwrap().as_mut_ptr() as *mut c_char,
+        h_aliases: host_aliases.as_mut_slice().as_mut_ptr() as *mut *mut i8,
+        h_addrtype: AF_INET,
+        h_length: 4,
+        h_addr_list: HOST_ADDR_LIST.as_mut_ptr()
+    };
+        if HOST_STAYOPEN == 0 { 
+            endhostent(); 
+        }
+        &HOST_ENTRY as *const hostent
+}
+
+pub unsafe extern "C" fn getnetbyaddr(net: u32, net_type: c_int) -> *const netent {
+    unimplemented!();
+}
+
+pub unsafe extern "C" fn getnetbyname(name: *const c_char) -> *const netent {
+    unimplemented!();
+}
+
+pub unsafe extern "C" fn getnetent() -> *const netent {
+    unimplemented!();
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn getprotobyname(name: *const c_char) -> *const protoent {
+    let mut p: *const protoent;
+    setprotoent(PROTO_STAYOPEN);
+    while {p=getprotoent();
+           p!=ptr::null()} {
+        if strcasecmp((*p).p_name, name) == 0 {
+            setprotoent(PROTO_STAYOPEN);
+            return p;
+        }
+
+        let mut cp = (*p).p_aliases;
+        loop {
+            if cp == ptr::null_mut() {
+                setprotoent(PROTO_STAYOPEN);
+                break;
+            }
+            if (*cp) == ptr::null_mut() {
+                setprotoent(PROTO_STAYOPEN);
+                break;
+            }
+			if strcasecmp(*cp, name) == 0 {
+                setprotoent(PROTO_STAYOPEN);
+			    return p;
+			}
+			cp = cp.offset(1);
+	    }
+    }
+    setprotoent(PROTO_STAYOPEN);
+    
+    platform::errno = ENOENT;
+    ptr::null() as *const protoent
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn getprotobynumber(number: c_int) -> *const protoent {
+    setprotoent(PROTO_STAYOPEN);
+    let mut p: *const protoent;
+    while {p=getprotoent();
+           p!=ptr::null()} {
+        if (*p).p_proto == number {
+            setprotoent(PROTO_STAYOPEN);
+            return p;
+        }
+    }
+    setprotoent(PROTO_STAYOPEN);
+    platform::errno = ENOENT;
+    ptr::null() as *const protoent
+ }
+
+#[no_mangle]
+pub unsafe extern "C" fn getprotoent() -> *const protoent {
+    if PROTODB == 0 {
+        PROTODB = Sys::open(&CString::new("/etc/protocols").unwrap(), O_RDONLY, 0);
+    }
+
+    let mut rlb = RawLineBuffer::new(PROTODB);
+    rlb.seek(P_POS);
+
+    let mut r: Box<str> = Box::default();
+    while r.is_empty() || r.split_whitespace().next() == None || r.starts_with("#") {
+        r = match rlb.next() {
+            Line::Some(s) => bytes_to_box_str(s),
+            _ => {
+                if PROTO_STAYOPEN == 0 { endprotoent(); }
+                return ptr::null();
+            },
+        };
+    }
+    rlb.next();
+    P_POS = rlb.line_pos();
+
+    let mut iter: SplitWhitespace = r.split_whitespace();
+
+    let mut proto_name: Vec<u8> = iter.next().unwrap().as_bytes().to_vec();
+    proto_name.push(b'\0');
+
+    let mut num = iter.next().unwrap().as_bytes().to_vec();
+    num.push(b'\0');
+    PROTO_NUM = Some(atoi(num.as_mut_slice().as_mut_ptr() as *mut i8));
+
+    let mut _proto_aliases: Vec<Vec<u8>> = Vec::new();
+    loop {
+        let mut alias = match iter.next() {
+            Some(s) => s.as_bytes().to_vec(),
+            None => break
+        };
+        alias.push(b'\0');
+        _proto_aliases.push(alias);
+    }
+    let mut proto_aliases: Vec<*mut i8> = _proto_aliases.iter_mut().map(|x| x.as_mut_ptr() as *mut i8).collect();
+    proto_aliases.push(ptr::null_mut());
+
+    PROTO_ALIASES = Some(_proto_aliases);
+    PROTO_NAME = Some(proto_name);
+
+
+    PROTO_ENTRY = protoent { 
+        p_name: PROTO_NAME.as_mut().unwrap().as_mut_slice().as_mut_ptr() as *mut c_char,
+        p_aliases: proto_aliases.as_mut_slice().as_mut_ptr() as *mut *mut i8,
+        p_proto: PROTO_NUM.unwrap()           
+    };
+        if PROTO_STAYOPEN == 0 { endprotoent(); }
+        &PROTO_ENTRY as *const protoent
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn getservbyname(
+    name: *const c_char,
+    proto: *const c_char)
+-> *const servent {
+    setservent(SERV_STAYOPEN);
+    let mut p: *const servent;
+    if proto.is_null() {
+        while { p = getservent(); p!=ptr::null() } {
+            if strcasecmp((*p).s_name, name) == 0 {
+                setservent(SERV_STAYOPEN);
+                return p;
+            }
+        }
+    } else {
+        while { p = getservent(); p!=ptr::null() } {
+            if strcasecmp((*p).s_name, name) == 0 && strcasecmp((*p).s_proto, proto) == 0 {
+                setservent(SERV_STAYOPEN);
+                return p;
+            }
+        }
+    }
+    setservent(SERV_STAYOPEN);
+    platform::errno = ENOENT;
+    ptr::null() as *const servent
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn getservbyport(
+    port: c_int,
+    proto: *const c_char)
+-> *const servent {
+    setservent(SERV_STAYOPEN);
+    let mut p: *const servent;
+    if proto.is_null() {
+        while { p=getservent(); p!=ptr::null()} {
+                if (*p).s_port == port {
+                    setservent(SERV_STAYOPEN);
+                    return p;
+                }
+        }
+    } else {
+        while { p=getservent(); p!=ptr::null()} {
+            if (*p).s_port == port && strcasecmp((*p).s_proto, proto) == 0 {
+                setservent(SERV_STAYOPEN);
+                return p;
+            }
+        }
+    }
+    setservent(SERV_STAYOPEN);
+    platform::errno = ENOENT;
+    ptr::null()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn getservent() -> *const servent {
+    if SERVDB == 0 {
+        SERVDB = Sys::open(&CString::new("/etc/services").unwrap(), O_RDONLY, 0);
+    }
+    let mut rlb = RawLineBuffer::new(SERVDB);
+    rlb.seek(S_POS);
+
+    let mut r: Box<str> = Box::default();
+    while r.is_empty() || r.split_whitespace().next() == None || r.starts_with("#") {
+        r = match rlb.next() {
+            Line::Some(s) => bytes_to_box_str(s),
+            _ => {
+                if SERV_STAYOPEN == 0 { endservent(); }
+                return ptr::null();
+            }
+        };
+    }
+
+    rlb.next();
+    S_POS = rlb.line_pos(); 
+
+    let mut iter: SplitWhitespace = r.split_whitespace();
+    let mut serv_name: Vec<u8> = iter.next().unwrap().as_bytes().to_vec();
+    serv_name.push(b'\0');
+    let port_proto = iter.next().unwrap();
+    let mut split = port_proto.split("/");
+    let mut port = split.next().unwrap().as_bytes().to_vec();
+    port.push(b'\0');
+    SERV_PORT = Some(htons(atoi(port.as_mut_slice().as_mut_ptr() as *mut i8) as u16) as u32 as i32);
+    let mut proto = split.next().unwrap().as_bytes().to_vec();
+    proto.push(b'\0');
+
+    /*
+     *let mut _serv_aliases: Vec<Vec<u8>> = Vec::new();
+     *loop {
+     *    let mut alias = match iter.next() {
+     *        Some(s) => s.as_bytes().to_vec(),
+     *        _ => break
+     *    };
+     *    alias.push(b'\0');
+     *    _serv_aliases.push(alias);
+     *}
+     *let mut serv_aliases: Vec<*mut i8> = _serv_aliases.iter_mut().map(|x| x.as_mut_ptr() as *mut i8).collect();
+     *serv_aliases.push(ptr::null_mut());
+     * 
+     */
+    let mut _serv_aliases: Vec<Vec<u8>> = Vec::new();
+    _serv_aliases.push(vec![b'\0']);
+    let mut serv_aliases: Vec<*mut i8> = Vec::new(); 
+    serv_aliases.push(ptr::null_mut());
+    serv_aliases.push(ptr::null_mut());
+    
+    SERV_ALIASES = Some(_serv_aliases);
+    SERV_NAME = Some(serv_name);
+    SERV_PROTO = Some(proto);
+
+    SERV_ENTRY = servent {
+        s_name: SERV_NAME.as_mut().unwrap().as_mut_slice().as_mut_ptr() as *mut c_char,
+        s_aliases: serv_aliases.as_mut_slice().as_mut_ptr() as *mut *mut i8, 
+        s_port: SERV_PORT.unwrap(),
+        s_proto: SERV_PROTO.as_mut().unwrap().as_mut_slice().as_mut_ptr() as *mut c_char
+    };
+
+    if SERV_STAYOPEN == 0 { endservent(); }
+    &SERV_ENTRY as *const servent
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn sethostent(stayopen: c_int) {
+    HOST_STAYOPEN = stayopen;
+    if HOSTDB == 0 {
+        HOSTDB = Sys::open(&CString::new("/etc/hosts").unwrap(), O_RDONLY, 0)
+    } else {
+       Sys::lseek(HOSTDB, 0, SEEK_SET);
+    }
+    H_POS = 0;
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn setnetent(stayopen: c_int) {
+    NET_STAYOPEN = stayopen;
+    if NETDB == 0 {
+        NETDB = Sys::open(&CString::new("/etc/networks").unwrap(), O_RDONLY, 0)
+    } else {
+       Sys::lseek(NETDB, 0, SEEK_SET);
+       N_POS = 0;
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn setprotoent(stayopen: c_int) {
+    PROTO_STAYOPEN = stayopen;
+    if PROTODB == 0 {
+        PROTODB = Sys::open(&CString::new("/etc/protocols").unwrap(), O_RDONLY, 0)
+    } else {
+       Sys::lseek(PROTODB, 0, SEEK_SET);
+       P_POS = 0;
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn setservent(stayopen: c_int) {
+    SERV_STAYOPEN = stayopen;
+    if SERVDB == 0 {
+        SERVDB = Sys::open(&CString::new("/etc/services").unwrap(), O_RDONLY, 0)
+    } else {
+       Sys::lseek(SERVDB, 0, SEEK_SET);
+       S_POS = 0;
+    }
+}
+
+pub unsafe extern "C" fn getaddrinfo(
+    node: *const c_char,
+    service: *const c_char,
+    hints: *const addrinfo,
+    res: *mut *mut addrinfo)
+-> c_int {
+    unimplemented!();
+}
+
+pub unsafe extern "C" fn getnameinfo(
+    addr: *const sockaddr,
+    addrlen: socklen_t,
+    host: *mut c_char,
+    hostlen: socklen_t,
+    serv: *mut c_char,
+    servlen: socklen_t,
+    flags: c_int)
+-> c_int {
+    unimplemented!();
+}
+
+pub extern "C" fn freeaddrinfo(res: *mut addrinfo) {
+    unimplemented!();
+}
+
+pub extern "C" fn gai_strerror(errcode: c_int) -> *const c_char {
+    unimplemented!();
+}

+ 7 - 0
src/header/netdb/redox.rs

@@ -0,0 +1,7 @@
+use alloc::string::String;
+use c_str::CString;
+use platform::rawfile::file_read_all;
+
+pub fn get_dns_server() -> String {
+    String::from_utf8(file_read_all(&CString::new("/etc/net/dns").unwrap()).unwrap()).unwrap()
+}

+ 3 - 1
src/header/netinet_in/mod.rs

@@ -7,7 +7,7 @@ pub type in_addr_t = u32;
 pub type in_port_t = u16;
 
 #[repr(C)]
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, Default)]
 pub struct in_addr {
     pub s_addr: in_addr_t,
 }
@@ -18,10 +18,12 @@ pub struct in6_addr {
 }
 
 #[repr(C)]
+#[derive(Debug, Default)]
 pub struct sockaddr_in {
     pub sin_family: sa_family_t,
     pub sin_port: in_port_t,
     pub sin_addr: in_addr,
+    pub _pad: [c_char; 8],
 }
 
 #[repr(C)]

+ 7 - 45
src/header/pwd/mod.rs

@@ -7,7 +7,7 @@ use c_str::CStr;
 use header::{errno, fcntl};
 use platform;
 use platform::types::*;
-use platform::RawFile;
+use platform::{Line, RawFile, RawLineBuffer};
 use platform::{Pal, Sys};
 
 #[repr(C)]
@@ -56,54 +56,16 @@ where
         Err(_) => return OptionPasswd::Error,
     };
 
-    let mut buf = Vec::new();
-    let mut newline = None;
+    let mut rlb = RawLineBuffer::new(*file);
 
     loop {
-        // TODO when nll becomes a thing:
-        // let mut newline;
-
-        // WORKAROUND:
-        if let Some(newline) = newline {
-            buf.drain(..newline + 1);
-        }
-
-        // Read until newline
-        loop {
-            newline = buf.iter().position(|b| *b == b'\n');
-
-            if newline.is_some() {
-                break;
-            }
-
-            let len = buf.len();
-
-            if len >= buf.capacity() {
-                buf.reserve(1024);
-            }
-
-            unsafe {
-                let capacity = buf.capacity();
-                buf.set_len(capacity);
-            }
-
-            let read = Sys::read(*file, &mut buf[len..]);
-
-            unsafe {
-                buf.set_len(len + read as usize);
-            }
-
-            if read == 0 {
-                return OptionPasswd::NotFound;
-            }
-            if read < 0 {
-                return OptionPasswd::Error;
-            }
-        }
+        let line = match rlb.next() {
+            Line::Error => return OptionPasswd::Error,
+            Line::EOF => return OptionPasswd::NotFound,
+            Line::Some(line) => line
+        };
 
         // Parse into passwd
-        let newline = newline.unwrap(); // safe because it doesn't break the loop otherwise
-        let line = &buf[..newline];
         let mut parts: [&[u8]; 7] = [&[]; 7];
         for (i, part) in line.splitn(7, |b| *b == b':').enumerate() {
             parts[i] = part;

+ 6 - 3
src/header/stdio/printf.rs

@@ -1,5 +1,5 @@
 use core::fmt::Write as CoreWrite;
-use core::{slice, str};
+use core::{slice, str, ptr};
 
 use platform::types::*;
 use platform::{self, Write};
@@ -61,8 +61,11 @@ pub unsafe fn printf<W: Write>(w: W, format: *const c_char, mut ap: VaList) -> c
                     let a = ap.get::<*const c_char>();
 
                     found_percent = false;
-
-                    w.write_str(str::from_utf8_unchecked(platform::c_str(a)))
+                    if a != ptr::null() {
+                        w.write_str(str::from_utf8_unchecked(platform::c_str(a)))
+                    } else {
+                        w.write_str("NULL")
+                    }
                 }
                 'u' => {
                     let a = ap.get::<c_uint>();

+ 1 - 0
src/header/strings/mod.rs

@@ -109,6 +109,7 @@ pub unsafe extern "C" fn strcasecmp(mut first: *const c_char, mut second: *const
     }
     0
 }
+
 #[no_mangle]
 pub unsafe extern "C" fn strncasecmp(
     mut first: *const c_char,

+ 1 - 1
src/header/sys_socket/cbindgen.toml

@@ -1,6 +1,6 @@
 sys_includes = ["stddef.h", "stdint.h", "sys/types.h"]
 include_guard = "_SYS_SOCKET_H"
-style = "Tag"
+style = "Both"
 language = "C"
 
 [defines]

+ 1 - 0
src/header/sys_socket/mod.rs

@@ -14,6 +14,7 @@ pub type sa_family_t = u16;
 pub type socklen_t = u32;
 
 #[repr(C)]
+#[derive(Default)]
 pub struct sockaddr {
     pub sa_family: sa_family_t,
     data: [c_char; 14],

+ 1 - 1
src/header/time/constants.rs

@@ -44,7 +44,7 @@ pub(crate) const MON_NAMES: [&str; 12] = [
     "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
 ];
 
-pub(crate) const CLOCK_REALTIME: clockid_t = 0;
+pub const CLOCK_REALTIME: clockid_t = 0;
 pub const CLOCK_MONOTONIC: clockid_t = 1;
 pub(crate) const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2;
 

+ 3 - 0
src/platform/mod.rs

@@ -29,6 +29,9 @@ pub use self::rawfile::RawFile;
 
 pub mod rawfile;
 
+pub use self::rlb::{Line, RawLineBuffer};
+pub mod rlb;
+
 use self::types::*;
 pub mod types;
 

+ 32 - 0
src/platform/rawfile.rs

@@ -1,3 +1,4 @@
+use alloc::Vec;
 use core::ops::Deref;
 
 use super::{types::*, Pal, Sys};
@@ -46,3 +47,34 @@ impl Deref for RawFile {
         &self.0
     }
 }
+
+pub fn file_read_all(path: &CStr) -> Result<Vec<u8>, ()> {
+    let file = RawFile::open(path, 0, 0o644)?;
+
+    let mut buf = Vec::new();
+    let mut len = 0;
+
+    loop {
+        if len >= buf.capacity() {
+            buf.reserve(32);
+
+            unsafe {
+                let capacity = buf.capacity();
+                buf.set_len(capacity);
+            }
+        }
+
+        let read = Sys::read(*file, &mut buf[len..]);
+
+        len += read as usize;
+
+        if read == 0 {
+            unsafe { buf.set_len(len); }
+            return Ok(buf);
+        }
+        if read < 0 {
+            unsafe { buf.set_len(len); }
+            return Err(());
+        }
+    }
+}

+ 97 - 0
src/platform/rlb.rs

@@ -0,0 +1,97 @@
+use alloc::vec::Vec;
+
+use platform::{Pal, Sys};
+use platform::types::*;
+
+use header::unistd::{lseek, SEEK_SET};
+/// Implements an `Iterator` which returns on either newline or EOF.
+#[derive(Clone)]
+pub struct RawLineBuffer {
+    pub fd: c_int,
+    buf: Vec<u8>,
+    newline: Option<usize>,
+    read: usize
+}
+
+#[derive(PartialEq)]
+pub enum Line<'a> {
+    Error,
+    EOF,
+    Some(&'a [u8])
+}
+
+impl RawLineBuffer {
+    pub const fn new(fd: c_int) -> Self {
+        Self {
+            fd: fd,
+            buf: Vec::new(),
+            newline: None,
+            read: 0
+        }
+    }
+
+    // Can't use iterators because we want to return a reference.
+    // See https://stackoverflow.com/a/30422716/5069285
+    pub fn next(&mut self) -> Line {
+        // Remove last line
+        if let Some(newline) = self.newline {
+            self.buf.drain(..newline + 1);
+        }
+
+        loop {
+            // Exit if newline was read already
+            self.newline = self.buf.iter().position(|b| *b == b'\n');
+
+            if self.newline.is_some() {
+                break;
+            }
+
+            let len = self.buf.len();
+
+            if len >= self.buf.capacity() {
+                self.buf.reserve(1024);
+            }
+
+            // Create buffer of what's left in the vector, uninitialized memory
+            unsafe {
+                let capacity = self.buf.capacity();
+                self.buf.set_len(capacity);
+            }
+
+            let read = Sys::read(self.fd, &mut self.buf[len..]);
+
+            let read_usize = read.max(0) as usize;
+
+            // Remove all uninitialized memory that wasn't read
+            unsafe {
+                self.buf.set_len(len + read_usize);
+            }
+
+            self.read += read_usize;
+
+            if read == 0 {
+                return Line::EOF;
+            }
+            if read < 0 {
+                return Line::Error;
+            }
+        }
+
+        let newline = self.newline.unwrap(); // safe because it doesn't break the loop otherwise
+        Line::Some(&self.buf[..newline])
+    }
+
+    /// Return the byte position of the start of the line
+    pub fn line_pos(&self) -> usize {
+        self.read - self.buf.len()
+    }
+
+    /// Seek to a byte position in the file
+    pub fn seek(&mut self, pos: usize) -> off_t {
+        let ret = lseek(self.fd, pos as i64, SEEK_SET);
+        if ret != !0 {
+            self.read = pos;
+        }
+        ret
+    }
+}

+ 1 - 0
src/platform/types.rs

@@ -107,6 +107,7 @@ impl<'a> From<&'a timespec> for redox_timespec {
 }
 
 #[repr(C)]
+#[derive(Default)]
 pub struct stat {
     pub st_dev: dev_t,
     pub st_ino: ino_t,

+ 2 - 1
tests/Makefile

@@ -10,17 +10,18 @@ EXPECT_BINS=\
 	fnmatch \
 	locale \
 	math \
+	netdb \
 	select \
 	setjmp \
 	signal \
 	stdio/all \
-	stdio/setvbuf \
 	stdio/freopen \
 	stdio/fwrite \
 	stdio/getc_unget \
 	stdio/printf \
 	stdio/rename \
 	stdio/scanf \
+	stdio/setvbuf \
 	stdio/sprintf \
 	stdlib/a64l \
 	stdlib/atof \

+ 0 - 0
tests/expected/netdb.stderr


+ 1 - 0
tests/expected/netdb.stdout

@@ -0,0 +1 @@
+No visible errors occurred!

+ 230 - 0
tests/netdb.c

@@ -0,0 +1,230 @@
+/* Copyright (C) 1998-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Andreas Jaeger <[email protected]>, 1998.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+/*
+  Testing of some network related lookup functions.
+  The system databases looked up are:
+  - /etc/services
+  - /etc/hosts
+  - /etc/networks
+  - /etc/protocols
+  The tests try to be fairly generic and simple so that they work on
+  every possible setup (and might therefore not detect some possible
+  errors).
+*/
+
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+
+int error_count;
+static void
+output_servent (const char *call, struct servent *sptr)
+{
+  char **pptr;
+  if (sptr == NULL)
+    printf ("Call: %s returned NULL\n", call);
+  else
+    {
+      printf ("Call: %s, returned: s_name: %s, s_port: %d, s_proto: %s\n",
+              call, sptr->s_name, ntohs(sptr->s_port), sptr->s_proto);
+      for (pptr = sptr->s_aliases; *pptr != NULL; pptr++)
+        printf ("  alias: %s\n", *pptr);
+    }
+}
+static void
+test_services (void)
+{
+  struct servent *sptr;
+  sptr = getservbyname ("domain", "tcp");
+  // output_servent ("getservbyname (\"domain\", \"tcp\")", sptr);
+  sptr = getservbyname ("domain", "udp");
+  // output_servent ("getservbyname (\"domain\", \"udp\")", sptr);
+  sptr = getservbyname ("domain", NULL);
+  // output_servent ("getservbyname (\"domain\", NULL)", sptr);
+  sptr = getservbyname ("not-existant", NULL);
+  // output_servent ("getservbyname (\"not-existant\", NULL)", sptr);
+  /* This shouldn't return anything.  */
+  sptr = getservbyname ("", "");
+  // output_servent ("getservbyname (\"\", \"\")", sptr);
+  sptr = getservbyname ("", "tcp");
+  // output_servent ("getservbyname (\"\", \"tcp\")", sptr);
+  sptr = getservbyport (htons(53), "tcp");
+  // output_servent ("getservbyport (htons(53), \"tcp\")", sptr);
+  sptr = getservbyport (htons(53), NULL);
+  // output_servent ("getservbyport (htons(53), NULL)", sptr);
+  sptr = getservbyport (htons(1), "udp"); /* shouldn't exist */
+  // output_servent ("getservbyport (htons(1), \"udp\")", sptr);
+  setservent (0);
+  do
+    {
+      sptr = getservent ();
+      //output_servent ("getservent ()", sptr);
+    }
+  while (sptr != NULL);
+  endservent ();
+}
+static void
+output_hostent (const char *call, struct hostent *hptr)
+{
+  char **pptr;
+  char buf[INET6_ADDRSTRLEN];
+  if (hptr == NULL)
+    printf ("Call: %s returned NULL\n", call);
+  else
+    {
+      printf ("Call: %s returned: name: %s, addr_type: %d\n",
+              call, hptr->h_name, hptr->h_addrtype);
+      if (hptr->h_aliases)
+        for (pptr = hptr->h_aliases; *pptr != NULL; pptr++)
+          printf ("  alias: %s\n", *pptr);
+      for (pptr = hptr->h_addr_list; *pptr != NULL; pptr++)
+        printf ("  ip: %s\n",
+                inet_ntop (hptr->h_addrtype, *pptr, buf, sizeof (buf)));
+    }
+}
+static void
+test_hosts (void)
+{
+  struct hostent *hptr1, *hptr2;
+  char *name = NULL;
+  size_t namelen = 0;
+  struct in_addr ip;
+  hptr1 = gethostbyname ("localhost");
+  hptr2 = gethostbyname ("LocalHost");
+  if (hptr1 != NULL || hptr2 != NULL)
+    {
+      if (hptr1 == NULL)
+        {
+          printf ("localhost not found - but LocalHost found:-(\n");
+          ++error_count;
+        }
+      else if (hptr2 == NULL)
+        {
+          printf ("LocalHost not found - but localhost found:-(\n");
+          ++error_count;
+        }
+      else if (strcmp (hptr1->h_name, hptr2->h_name) != 0)
+        {
+          printf ("localhost and LocalHost have different canoncial name\n");
+          printf ("gethostbyname (\"localhost\")->%s\n", hptr1->h_name);
+          printf ("gethostbyname (\"LocalHost\")->%s\n", hptr2->h_name);
+          ++error_count;
+        }
+       //else
+       //  output_hostent ("gethostbyname(\"localhost\")", hptr1);
+    }
+  hptr1 = gethostbyname ("127.0.0.1");
+  //output_hostent ("gethostbyname (\"127.0.0.1\")", hptr1);
+  while (gethostname (name, namelen) < 0 && errno == ENAMETOOLONG)
+    {
+      namelen += 2;                /* tiny increments to test a lot */
+      name = realloc (name, namelen);
+    }
+  if (gethostname (name, namelen) == 0)
+    {
+      // printf ("Hostname: %s\n", name);
+      if (name != NULL)
+        {
+          hptr1 = gethostbyname (name);
+        //  output_hostent ("gethostbyname (gethostname(...))", hptr1);
+        }
+    }
+  ip.s_addr = htonl (INADDR_LOOPBACK);
+
+  hptr1 = gethostbyaddr ((char *) &ip, sizeof(ip), AF_INET);
+  if (hptr1 != NULL)
+    {
+     // printf ("official name of 127.0.0.1: %s\n", hptr1->h_name);
+    }
+  sethostent (0);
+  do
+    {
+      hptr1 = gethostent ();
+      //output_hostent ("gethostent ()", hptr1);
+    }
+  while (hptr1 != NULL);
+  endhostent ();
+  struct hostent* redox = gethostbyname("redox-os.org");
+  if (redox == NULL) {
+      ++error_count;
+  }
+  //output_hostent("gethostbyname(\"redox-os.org\")", redox);
+  struct in_addr el_goog;
+  inet_aton("8.8.4.4", &el_goog);
+  struct hostent* google = gethostbyaddr(&el_goog, 4, AF_INET);
+  if (google == NULL) {
+      ++error_count;
+  }
+  //output_hostent("gethostbyaddr(\"8.8.4.4\")",google);
+}
+
+static void
+output_protoent (const char *call, struct protoent *prptr)
+{
+  char **pptr;
+  if (prptr == NULL)
+    printf ("Call: %s returned NULL\n", call);
+  else
+    {
+      printf ("Call: %s, returned: p_name: %s, p_proto: %d\n",
+              call, prptr->p_name, prptr->p_proto);
+      for (pptr = prptr->p_aliases; *pptr != NULL; pptr++)
+        printf ("  alias: %s\n", *pptr);
+    }
+}
+static void
+test_protocols (void)
+{
+  struct protoent *prptr;
+  prptr = getprotobyname ("ICMP");
+ // output_protoent ("getprotobyname (\"ICMP\")", prptr);
+  prptr = getprotobynumber (1);
+ // output_protoent ("getprotobynumber (1)", prptr);
+  setprotoent (0);
+  do
+    {
+      prptr = getprotoent ();
+     // output_protoent ("getprotoent ()", prptr);
+    }
+  while (prptr != NULL);
+  endprotoent ();
+}
+static int
+do_test (void)
+{
+  /*
+    setdb ("db");
+  */
+  test_hosts ();
+  //test_network ();
+  test_protocols ();
+  test_services ();
+  if (error_count)
+    printf ("\n %d errors occurred!\n", error_count);
+  else
+    printf ("No visible errors occurred!\n");
+  return (error_count != 0);
+}
+
+int main() {
+    do_test();
+}