diff --git a/Cargo.toml b/Cargo.toml index d42592f7ff4f90a51fd3aed80089fc98e2dd9c2e..da451427fa2299cb249a4025cef64a3225e6af49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ redox_syscall = "0.1" spin = "0.4.10" [features] -#default = ["trace"] +default = [] trace = [] [profile.dev] diff --git a/src/header/netdb/mod.rs b/src/header/netdb/mod.rs index f40d128d16f3df12d955ea210d418737c8f8e84f..8ad831ff4b4e1bb49153a7642f28b9fa8503d752 100644 --- a/src/header/netdb/mod.rs +++ b/src/header/netdb/mod.rs @@ -5,6 +5,7 @@ mod dns; use core::str::FromStr; use core::{mem, ptr, slice, str}; +use alloc::borrow::ToOwned; use alloc::boxed::Box; use alloc::str::SplitWhitespace; use alloc::vec::Vec; @@ -13,11 +14,11 @@ use c_str::{CStr, CString}; use header::arpa_inet::htons; use header::errno::*; use header::fcntl::O_RDONLY; -use header::netinet_in::{in_addr, sockaddr_in}; +use header::netinet_in::{in_addr, sockaddr_in, sockaddr_in6}; use header::stdlib::atoi; use header::strings::strcasecmp; use header::sys_socket::constants::{AF_UNSPEC, AF_INET}; -use header::sys_socket::{sockaddr, socklen_t}; +use header::sys_socket::{sa_family_t, sockaddr, socklen_t}; use header::unistd::SEEK_SET; use platform; use platform::rlb::{Line, RawLineBuffer}; @@ -670,15 +671,72 @@ pub unsafe extern "C" fn getaddrinfo( let hints_opt = if hints.is_null() { None } else { Some(&*hints) }; - eprintln!( + trace!( "getaddrinfo({:?}, {:?}, {:?})", node_opt.map(|c| str::from_utf8_unchecked(c.to_bytes())), service_opt.map(|c| str::from_utf8_unchecked(c.to_bytes())), hints_opt ); - platform::errno = ENOSYS; - EAI_SYSTEM + //TODO: Use hints + let mut ai_flags = hints_opt.map_or(0, |hints| hints.ai_flags); + let mut ai_family = hints_opt.map_or(AF_UNSPEC, |hints| hints.ai_family); + let mut ai_socktype = hints_opt.map_or(0, |hints| hints.ai_socktype); + let mut ai_protocol = hints_opt.map_or(0, |hints| hints.ai_protocol); + + *res = ptr::null_mut(); + + //TODO: Check hosts file + if let Some(node) = node_opt { + let lookuphost = match lookup_host(str::from_utf8_unchecked(node.to_bytes())) { + Ok(lookuphost) => lookuphost, + Err(e) => { + platform::errno = e; + return EAI_SYSTEM; + } + }; + + for in_addr in lookuphost { + ai_family = AF_INET; + ai_socktype = AF_UNSPEC; + ai_protocol = 0; + + let ai_addr = Box::into_raw(Box::new(sockaddr_in { + sin_family: AF_INET as sa_family_t, + sin_port: 0, + sin_addr: in_addr, + sin_zero: [0; 8] + })) as *mut sockaddr; + + let ai_addrlen = mem::size_of::<sockaddr_in>(); + + let ai_canonname = if ai_flags & AI_CANONNAME > 0 { + ai_flags &= !AI_CANONNAME; + node.to_owned().into_raw() + } else { + ptr::null_mut() + }; + + let addrinfo = Box::new(addrinfo { + ai_flags: 0, + ai_family, + ai_socktype, + ai_protocol, + ai_addrlen, + ai_canonname, + ai_addr, + ai_next: ptr::null_mut(), + }); + + let mut indirect = res; + while !(*indirect).is_null() { + indirect=&mut (**indirect).ai_next; + } + *indirect = Box::into_raw(addrinfo); + } + } + + 0 } #[no_mangle] @@ -721,8 +779,19 @@ pub unsafe extern "C" fn freeaddrinfo(res: *mut addrinfo) { let mut ai = res; while !ai.is_null() { let bai = Box::from_raw(ai); - ai = (*ai).ai_next; - drop(bai); + if !bai.ai_canonname.is_null() { + CString::from_raw(bai.ai_canonname); + } + if !bai.ai_addr.is_null() { + if bai.ai_addrlen == mem::size_of::<sockaddr_in>() { + Box::from_raw(bai.ai_addr as *mut sockaddr_in); + } else if bai.ai_addrlen == mem::size_of::<sockaddr_in6>() { + Box::from_raw(bai.ai_addr as *mut sockaddr_in6); + } else { + eprintln!("freeaddrinfo: unknown ai_addrlen {}", bai.ai_addrlen); + } + } + ai = bai.ai_next; } } diff --git a/src/header/sys_socket/mod.rs b/src/header/sys_socket/mod.rs index 3a6f187325f71afb4b751396cbdf9a1fe4f8c0a4..b6a50b5907e2d2731c3fc4707c5a5617e3fa932a 100644 --- a/src/header/sys_socket/mod.rs +++ b/src/header/sys_socket/mod.rs @@ -14,7 +14,7 @@ pub type socklen_t = u32; #[derive(Default)] pub struct sockaddr { pub sa_family: sa_family_t, - pub data: [c_char; 14], + pub sa_data: [c_char; 14], } #[no_mangle] diff --git a/tests/Makefile b/tests/Makefile index 2c4983fa0911e743182ba55860508f4707007333..669b8001288ebe2c02c5ff26668469a0180928b9 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -15,7 +15,8 @@ EXPECT_BINS=\ libgen \ locale \ math \ - netdb \ + netdb/netdb \ + netdb/getaddrinfo \ regex \ select \ setjmp \ @@ -112,7 +113,6 @@ BINS=\ .PHONY: all $(BINS) clean run expected verify all: $(BINS) -expect: $(EXPECT_BINS) $(BINS): %: bins/% @@ -126,7 +126,7 @@ run: | ../sysroot all "bins/$${bin}" test args || exit $$?; \ done -expected: | ../sysroot expect +expected: | ../sysroot $(EXPECT_BINS) rm -rf expected mkdir -p expected for bin in $(EXPECT_BINS); \ @@ -136,7 +136,7 @@ expected: | ../sysroot expect "bins/$${bin}" test args > "expected/$${bin}.stdout" 2> "expected/$${bin}.stderr" || exit $$?; \ done -verify: | ../sysroot expect +verify: | ../sysroot $(EXPECT_BINS) rm -rf gen mkdir -p gen for bin in $(EXPECT_BINS); \ @@ -151,6 +151,7 @@ verify: | ../sysroot expect CFLAGS=\ -fno-builtin \ -fno-stack-protector \ + -static \ -Wall \ -g \ -nostdinc \ diff --git a/tests/expected/netdb.stderr b/tests/expected/netdb/getaddrinfo.stderr similarity index 100% rename from tests/expected/netdb.stderr rename to tests/expected/netdb/getaddrinfo.stderr diff --git a/tests/expected/netdb/getaddrinfo.stdout b/tests/expected/netdb/getaddrinfo.stdout new file mode 100644 index 0000000000000000000000000000000000000000..6bc12bb59ba8f7f23d53ec13bf10a6a31a0df2e6 --- /dev/null +++ b/tests/expected/netdb/getaddrinfo.stdout @@ -0,0 +1 @@ +IPv4 address: 23.21.162.66 (www.redox-os.org) diff --git a/tests/expected/netdb/netdb.stderr b/tests/expected/netdb/netdb.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/netdb.stdout b/tests/expected/netdb/netdb.stdout similarity index 100% rename from tests/expected/netdb.stdout rename to tests/expected/netdb/netdb.stdout diff --git a/tests/netdb/getaddrinfo.c b/tests/netdb/getaddrinfo.c new file mode 100644 index 0000000000000000000000000000000000000000..3864d0d9903b788b4c3c49a6d5c440187b2d4b94 --- /dev/null +++ b/tests/netdb/getaddrinfo.c @@ -0,0 +1,50 @@ +// Adapted from https://gist.github.com/jirihnidek/bf7a2363e480491da72301b228b35d5d + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <netdb.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> + +int main(void) { + struct addrinfo hints, *res; + int errcode; + char addrstr[INET6_ADDRSTRLEN]; + void *ptr; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags |= AI_CANONNAME; + + errcode = getaddrinfo("www.redox-os.org", NULL, &hints, &res); + if (errcode != 0) { + perror("getaddrinfo"); + return -1; + } + + while (res) { + switch (res->ai_family) { + case AF_INET: + ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr; + break; + case AF_INET6: + ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; + break; + } + inet_ntop(res->ai_family, ptr, addrstr, INET6_ADDRSTRLEN); + + printf( + "IPv%d address: %s (%s)\n", + res->ai_family == PF_INET6 ? 6 : 4, + addrstr, + res->ai_canonname + ); + + res = res->ai_next; + } + + return 0; +} diff --git a/tests/netdb.c b/tests/netdb/netdb.c similarity index 100% rename from tests/netdb.c rename to tests/netdb/netdb.c