Files
RedBear-OS/src/header/netdb/mod.rs
T
2018-09-05 17:38:59 +02:00

989 lines
28 KiB
Rust

//! netdb implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/netdb.h.html
mod dns;
use core::str::FromStr;
use core::{mem, ptr, str};
use alloc::boxed::Box;
use alloc::str::SplitWhitespace;
use alloc::string::ToString;
use alloc::vec::IntoIter;
use alloc::{String, Vec};
use c_str::CString;
use platform;
use platform::c_str;
use platform::rlb::{Line, RawLineBuffer};
use platform::types::*;
use platform::{Pal, Sys};
use self::dns::{Dns, DnsQuery};
use header::arpa_inet::{htons, inet_aton};
use header::errno::*;
use header::fcntl::O_RDONLY;
use header::netinet_in::{in_addr, sockaddr_in, IPPROTO_UDP};
use header::stdlib::atoi;
use header::strings::strcasecmp;
use header::sys_socket;
use header::sys_socket::constants::{AF_INET, SOCK_DGRAM};
use header::sys_socket::{sockaddr, socklen_t};
use header::time;
use header::time::timespec;
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();
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 comment = r.find('#').unwrap_or(r.len());
let space = r[..comment].trim_right().rfind(char::is_whitespace).unwrap();
let mut serv_name = r[..space].trim().as_bytes().to_vec();
serv_name.push(b'\0');
let port_proto = &r[space..comment].trim();
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!();
}