xref: /drstd/dlibc/src/unix/header/netdb/mod.rs (revision 9670759b785600bf6315e4173e46a602f16add7a)
1 //! netdb implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xns/netdb.h.html
2 
3 mod dns;
4 
5 use core::{
6     mem, ptr, slice,
7     str::{self, FromStr},
8 };
9 
10 use alloc::{borrow::ToOwned, boxed::Box, str::SplitWhitespace, vec::Vec};
11 use crate::unix::header::{
12     arpa_inet::{htons, inet_aton, ntohl},
13     errno::*,
14     fcntl::O_RDONLY,
15     netinet_in::{in_addr, sockaddr_in, sockaddr_in6},
16     stdlib::atoi,
17     strings::strcasecmp,
18     sys_socket::{constants::AF_INET, sa_family_t, socklen_t},
19     unistd::SEEK_SET,
20 };
21 
22 use sockaddr;
23 
24 use crate::unix::{
25     c_str::{CStr, CString},
26     platform::{
27         self,
28         rlb::{Line, RawLineBuffer},
29     },
30 };
31 
32 #[cfg(target_os = "linux")]
33 #[path = "linux.rs"]
34 pub mod sys;
35 
36 #[cfg(target_os = "dragonos")]
37 #[path = "dragonos.rs"]
38 pub mod sys;
39 
40 #[cfg(target_os = "redox")]
41 #[path = "redox.rs"]
42 pub mod sys;
43 
44 pub use self::host::*;
45 pub mod host;
46 
47 pub use self::lookup::*;
48 pub mod lookup;
49 
50 #[repr(C)]
51 pub struct hostent {
52     h_name: *mut ::c_char,
53     h_aliases: *mut *mut ::c_char,
54     h_addrtype: ::c_int,
55     h_length: ::c_int,
56     h_addr_list: *mut *mut ::c_char,
57 }
58 
59 #[repr(C)]
60 pub struct netent {
61     n_name: *mut ::c_char,         /* official name of net */
62     n_aliases: *mut *mut ::c_char, /* alias list */
63     n_addrtype: ::c_int,           /* net address type */
64     n_net: ::c_ulong,              /* network # */
65 }
66 
67 #[repr(C)]
68 pub struct protoent {
69     p_name: *mut ::c_char,         /* official protocol name */
70     p_aliases: *mut *mut ::c_char, /* alias list */
71     p_proto: ::c_int,              /* protocol # */
72 }
73 
74 #[repr(C)]
75 pub struct servent {
76     s_name: *mut ::c_char,         /* official service name */
77     s_aliases: *mut *mut ::c_char, /* alias list */
78     s_port: ::c_int,               /* port # */
79     s_proto: *mut ::c_char,        /* protocol to use */
80 }
81 
82 #[repr(C)]
83 #[derive(Debug)]
84 pub struct addrinfo {
85     ai_flags: ::c_int,           /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
86     ai_family: ::c_int,          /* PF_xxx */
87     ai_socktype: ::c_int,        /* SOCK_xxx */
88     ai_protocol: ::c_int,        /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
89     ai_addrlen: ::size_t,        /* length of ai_addr */
90     ai_canonname: *mut ::c_char, /* canonical name for hostname */
91     ai_addr: *mut sockaddr,    /* binary address */
92     ai_next: *mut addrinfo,    /* next structure in linked list */
93 }
94 
95 pub const AI_PASSIVE: ::c_int = 0x0001;
96 pub const AI_CANONNAME: ::c_int = 0x0002;
97 pub const AI_NUMERICHOST: ::c_int = 0x0004;
98 pub const AI_V4MAPPED: ::c_int = 0x0008;
99 pub const AI_ALL: ::c_int = 0x0010;
100 pub const AI_ADDRCONFIG: ::c_int = 0x0020;
101 pub const AI_NUMERICSERV: ::c_int = 0x0400;
102 
103 pub const EAI_BADFLAGS: ::c_int = -1;
104 pub const EAI_NONAME: ::c_int = -2;
105 pub const EAI_AGAIN: ::c_int = -3;
106 pub const EAI_FAIL: ::c_int = -4;
107 pub const EAI_NODATA: ::c_int = -5;
108 pub const EAI_FAMILY: ::c_int = -6;
109 pub const EAI_SOCKTYPE: ::c_int = -7;
110 pub const EAI_SERVICE: ::c_int = -8;
111 pub const EAI_ADDRFAMILY: ::c_int = -9;
112 pub const EAI_MEMORY: ::c_int = -10;
113 pub const EAI_SYSTEM: ::c_int = -11;
114 pub const EAI_OVERFLOW: ::c_int = -12;
115 
116 pub const NI_MAXHOST: ::c_int = 1025;
117 pub const NI_MAXSERV: ::c_int = 32;
118 
119 pub const NI_NUMERICHOST: ::c_int = 0x0001;
120 pub const NI_NUMERICSERV: ::c_int = 0x0002;
121 pub const NI_NOFQDN: ::c_int = 0x0004;
122 pub const NI_NAMEREQD: ::c_int = 0x0008;
123 pub const NI_DGRAM: ::c_int = 0x0010;
124 
125 static mut NETDB: ::c_int = 0;
126 pub static mut NET_ENTRY: netent = netent {
127     n_name: ptr::null_mut(),
128     n_aliases: ptr::null_mut(),
129     n_addrtype: 0,
130     n_net: 0,
131 };
132 pub static mut NET_NAME: Option<Vec<u8>> = None;
133 pub static mut NET_ALIASES: Option<Vec<Vec<u8>>> = None;
134 pub static mut NET_ADDR: Option<u32> = None;
135 static mut N_POS: usize = 0;
136 static mut NET_STAYOPEN: ::c_int = 0;
137 
138 #[allow(non_upper_case_globals)]
139 #[no_mangle]
140 pub static mut h_errno: ::c_int = 0;
141 pub const HOST_NOT_FOUND: ::c_int = 1;
142 pub const NO_DATA: ::c_int = 2;
143 pub const NO_RECOVERY: ::c_int = 3;
144 pub const TRY_AGAIN: ::c_int = 4;
145 
146 static mut PROTODB: ::c_int = 0;
147 static mut PROTO_ENTRY: protoent = protoent {
148     p_name: ptr::null_mut(),
149     p_aliases: ptr::null_mut(),
150     p_proto: 0 as ::c_int,
151 };
152 static mut PROTO_NAME: Option<Vec<u8>> = None;
153 static mut PROTO_ALIASES: Option<Vec<Vec<u8>>> = None;
154 static mut PROTO_NUM: Option<::c_int> = None;
155 static mut P_POS: usize = 0;
156 static mut PROTO_STAYOPEN: ::c_int = 0;
157 
158 static mut SERVDB: ::c_int = 0;
159 static mut SERV_ENTRY: servent = servent {
160     s_name: ptr::null_mut(),
161     s_aliases: ptr::null_mut(),
162     s_port: 0 as ::c_int,
163     s_proto: ptr::null_mut(),
164 };
165 static mut SERV_NAME: Option<Vec<u8>> = None;
166 static mut SERV_ALIASES: Option<Vec<Vec<u8>>> = None;
167 static mut SERV_PORT: Option<::c_int> = None;
168 static mut SERV_PROTO: Option<Vec<u8>> = None;
169 static mut S_POS: usize = 0;
170 static mut SERV_STAYOPEN: ::c_int = 0;
171 
172 fn bytes_to_box_str(bytes: &[u8]) -> Box<str> {
173     Box::from(core::str::from_utf8(bytes).unwrap_or(""))
174 }
175 
176 #[no_mangle]
177 pub unsafe extern "C" fn endnetent() {
178     platform::pal::close(NETDB);
179     NETDB = 0;
180 }
181 
182 #[no_mangle]
183 pub unsafe extern "C" fn endprotoent() {
184     platform::pal::close(PROTODB);
185     PROTODB = 0;
186 }
187 
188 #[no_mangle]
189 pub unsafe extern "C" fn endservent() {
190     platform::pal::close(SERVDB);
191     SERVDB = 0;
192 }
193 
194 #[no_mangle]
195 pub unsafe extern "C" fn gethostbyaddr(
196     v: *const ::c_void,
197     length: socklen_t,
198     format: ::c_int,
199 ) -> *mut hostent {
200     let addr: in_addr = *(v as *mut in_addr);
201 
202     // check the hosts file first
203     let mut p: *mut hostent;
204     sethostent(HOST_STAYOPEN);
205     while {
206         p = gethostent();
207         !p.is_null()
208     } {
209         let mut cp = (*p).h_addr_list;
210         loop {
211             if cp.is_null() {
212                 break;
213             }
214             if (*cp).is_null() {
215                 break;
216             }
217             let mut cp_slice: [i8; 4] = [0i8; 4];
218             (*cp).copy_to(cp_slice.as_mut_ptr(), 4);
219             let cp_s_addr = mem::transmute::<[i8; 4], u32>(cp_slice);
220             if cp_s_addr == addr.s_addr {
221                 sethostent(HOST_STAYOPEN);
222                 return p;
223             }
224             cp = cp.offset(1);
225         }
226     }
227 
228     //TODO actually get aliases
229     let mut _host_aliases: Vec<Vec<u8>> = Vec::new();
230     _host_aliases.push(vec![b'\0']);
231     let mut host_aliases: Vec<*mut i8> = Vec::new();
232     host_aliases.push(ptr::null_mut());
233     HOST_ALIASES = Some(_host_aliases);
234 
235     match lookup_addr(addr) {
236         Ok(s) => {
237             _HOST_ADDR_LIST = mem::transmute::<u32, [u8; 4]>(addr.s_addr);
238             HOST_ADDR_LIST = [_HOST_ADDR_LIST.as_mut_ptr() as *mut ::c_char, ptr::null_mut()];
239             let host_name = s[0].to_vec();
240             HOST_NAME = Some(host_name);
241             HOST_ENTRY = hostent {
242                 h_name: HOST_NAME.as_mut().unwrap().as_mut_ptr() as *mut ::c_char,
243                 h_aliases: host_aliases.as_mut_slice().as_mut_ptr() as *mut *mut i8,
244                 h_addrtype: format,
245                 h_length: length as i32,
246                 h_addr_list: HOST_ADDR_LIST.as_mut_ptr(),
247             };
248             &mut HOST_ENTRY
249         }
250         Err(e) => {
251             platform::errno = e;
252             ptr::null_mut()
253         }
254     }
255 }
256 
257 #[no_mangle]
258 pub unsafe extern "C" fn gethostbyname(name: *const ::c_char) -> *mut hostent {
259     // check if some idiot gave us an address instead of a name
260     let name_cstr = CStr::from_ptr(name);
261     let mut octets = str::from_utf8_unchecked(name_cstr.to_bytes()).split('.');
262     let mut s_addr = [0u8; 4];
263     let mut is_addr = true;
264     for item in &mut s_addr {
265         if let Some(n) = octets.next().and_then(|x| u8::from_str(x).ok()) {
266             *item = n;
267         } else {
268             is_addr = false;
269         }
270     }
271     if octets.next() != None {
272         is_addr = false;
273     }
274 
275     if is_addr {
276         let addr = in_addr {
277             s_addr: mem::transmute::<[u8; 4], u32>(s_addr),
278         };
279         return gethostbyaddr(&addr as *const _ as *const ::c_void, 4, AF_INET);
280     }
281 
282     // check the hosts file first
283     let mut p: *mut hostent;
284     sethostent(HOST_STAYOPEN);
285     while {
286         p = gethostent();
287         !p.is_null()
288     } {
289         if strcasecmp((*p).h_name, name) == 0 {
290             sethostent(HOST_STAYOPEN);
291             return p;
292         }
293         let mut cp = (*p).h_aliases;
294         loop {
295             if cp.is_null() {
296                 break;
297             }
298             if (*cp).is_null() {
299                 break;
300             }
301             if strcasecmp(*cp, name) == 0 {
302                 sethostent(HOST_STAYOPEN);
303                 return p;
304             }
305             cp = cp.offset(1);
306         }
307     }
308 
309     let name_cstr = CStr::from_ptr(name);
310 
311     let mut host = match lookup_host(str::from_utf8_unchecked(name_cstr.to_bytes())) {
312         Ok(lookuphost) => lookuphost,
313         Err(e) => {
314             platform::errno = e;
315             return ptr::null_mut();
316         }
317     };
318     let host_addr = match host.next() {
319         Some(result) => result,
320         None => {
321             platform::errno = ENOENT;
322             return ptr::null_mut();
323         }
324     };
325 
326     let host_name: Vec<u8> = name_cstr.to_bytes().to_vec();
327     HOST_NAME = Some(host_name);
328     _HOST_ADDR_LIST = mem::transmute::<u32, [u8; 4]>(host_addr.s_addr);
329     HOST_ADDR_LIST = [_HOST_ADDR_LIST.as_mut_ptr() as *mut ::c_char, ptr::null_mut()];
330     HOST_ADDR = Some(host_addr);
331 
332     //TODO actually get aliases
333     let mut _host_aliases: Vec<Vec<u8>> = Vec::new();
334     _host_aliases.push(vec![b'\0']);
335     let mut host_aliases: Vec<*mut i8> = Vec::new();
336     host_aliases.push(ptr::null_mut());
337     host_aliases.push(ptr::null_mut());
338     HOST_ALIASES = Some(_host_aliases);
339 
340     HOST_ENTRY = hostent {
341         h_name: HOST_NAME.as_mut().unwrap().as_mut_ptr() as *mut ::c_char,
342         h_aliases: host_aliases.as_mut_slice().as_mut_ptr() as *mut *mut i8,
343         h_addrtype: AF_INET,
344         h_length: 4,
345         h_addr_list: HOST_ADDR_LIST.as_mut_ptr(),
346     };
347     sethostent(HOST_STAYOPEN);
348     &mut HOST_ENTRY as *mut hostent
349 }
350 
351 pub unsafe extern "C" fn getnetbyaddr(net: u32, net_type: ::c_int) -> *mut netent {
352     unimplemented!();
353 }
354 
355 #[no_mangle]
356 pub unsafe extern "C" fn getnetbyname(name: *const ::c_char) -> *mut netent {
357     let mut n: *mut netent;
358     setnetent(NET_STAYOPEN);
359     while {
360         n = getnetent();
361         !n.is_null()
362     } {
363         if strcasecmp((*n).n_name, name) == 0 {
364             setnetent(NET_STAYOPEN);
365             return n;
366         }
367     }
368     setnetent(NET_STAYOPEN);
369 
370     platform::errno = ENOENT;
371     ptr::null_mut() as *mut netent
372 }
373 
374 #[no_mangle]
375 pub unsafe extern "C" fn getnetent() -> *mut netent {
376     if NETDB == 0 {
377         NETDB = platform::pal::open("/etc/networks".as_ptr() as *const i8, O_RDONLY, 0);
378     }
379 
380     let mut rlb = RawLineBuffer::new(NETDB);
381     rlb.seek(N_POS);
382 
383     let mut r: Box<str> = Box::default();
384     while r.is_empty() || r.split_whitespace().next() == None || r.starts_with('#') {
385         r = match rlb.next() {
386             Line::Some(s) => bytes_to_box_str(s),
387             _ => {
388                 if NET_STAYOPEN == 0 {
389                     endnetent();
390                 }
391                 return ptr::null_mut();
392             }
393         };
394     }
395     rlb.next();
396     N_POS = rlb.line_pos();
397 
398     let mut iter: SplitWhitespace = r.split_whitespace();
399 
400     let mut net_name = iter.next().unwrap().as_bytes().to_vec();
401     net_name.push(b'\0');
402     NET_NAME = Some(net_name);
403 
404     let mut addr_vec = iter.next().unwrap().as_bytes().to_vec();
405     addr_vec.push(b'\0');
406     let addr_cstr = addr_vec.as_slice().as_ptr() as *const i8;
407     let mut addr = mem::MaybeUninit::uninit();
408     inet_aton(addr_cstr, addr.as_mut_ptr());
409     let addr = addr.assume_init();
410     NET_ADDR = Some(ntohl(addr.s_addr));
411 
412     let mut _net_aliases: Vec<Vec<u8>> = Vec::new();
413     for s in iter {
414         let mut alias = s.as_bytes().to_vec();
415         alias.push(b'\0');
416         _net_aliases.push(alias);
417     }
418     let mut net_aliases: Vec<*mut i8> = _net_aliases
419         .iter_mut()
420         .map(|x| x.as_mut_ptr() as *mut i8)
421         .collect();
422     net_aliases.push(ptr::null_mut());
423     NET_ALIASES = Some(_net_aliases);
424 
425     NET_ENTRY = netent {
426         n_name: NET_NAME.as_mut().unwrap().as_mut_ptr() as *mut ::c_char,
427         n_aliases: net_aliases.as_mut_slice().as_mut_ptr() as *mut *mut i8,
428         n_addrtype: AF_INET,
429         n_net: NET_ADDR.unwrap() as ::c_ulong,
430     };
431     &mut NET_ENTRY as *mut netent
432 }
433 
434 #[no_mangle]
435 pub unsafe extern "C" fn getprotobyname(name: *const ::c_char) -> *mut protoent {
436     let mut p: *mut protoent;
437     setprotoent(PROTO_STAYOPEN);
438     while {
439         p = getprotoent();
440         !p.is_null()
441     } {
442         if strcasecmp((*p).p_name, name) == 0 {
443             setprotoent(PROTO_STAYOPEN);
444             return p;
445         }
446 
447         let mut cp = (*p).p_aliases;
448         loop {
449             if cp.is_null() {
450                 setprotoent(PROTO_STAYOPEN);
451                 break;
452             }
453             if (*cp).is_null() {
454                 setprotoent(PROTO_STAYOPEN);
455                 break;
456             }
457             if strcasecmp(*cp, name) == 0 {
458                 setprotoent(PROTO_STAYOPEN);
459                 return p;
460             }
461             cp = cp.offset(1);
462         }
463     }
464     setprotoent(PROTO_STAYOPEN);
465 
466     platform::errno = ENOENT;
467     ptr::null_mut() as *mut protoent
468 }
469 
470 #[no_mangle]
471 pub unsafe extern "C" fn getprotobynumber(number: ::c_int) -> *mut protoent {
472     setprotoent(PROTO_STAYOPEN);
473     let mut p: *mut protoent;
474     while {
475         p = getprotoent();
476         !p.is_null()
477     } {
478         if (*p).p_proto == number {
479             setprotoent(PROTO_STAYOPEN);
480             return p;
481         }
482     }
483     setprotoent(PROTO_STAYOPEN);
484     platform::errno = ENOENT;
485     ptr::null_mut() as *mut protoent
486 }
487 
488 #[no_mangle]
489 pub unsafe extern "C" fn getprotoent() -> *mut protoent {
490     if PROTODB == 0 {
491         PROTODB = platform::pal::open("/etc/protocols".as_ptr() as *const i8, O_RDONLY, 0);
492     }
493 
494     let mut rlb = RawLineBuffer::new(PROTODB);
495     rlb.seek(P_POS);
496 
497     let mut r: Box<str> = Box::default();
498     while r.is_empty() || r.split_whitespace().next() == None || r.starts_with('#') {
499         r = match rlb.next() {
500             Line::Some(s) => bytes_to_box_str(s),
501             _ => {
502                 if PROTO_STAYOPEN == 0 {
503                     endprotoent();
504                 }
505                 return ptr::null_mut();
506             }
507         };
508     }
509     rlb.next();
510     P_POS = rlb.line_pos();
511 
512     let mut iter: SplitWhitespace = r.split_whitespace();
513 
514     let mut proto_name: Vec<u8> = iter.next().unwrap().as_bytes().to_vec();
515     proto_name.push(b'\0');
516 
517     let mut num = iter.next().unwrap().as_bytes().to_vec();
518     num.push(b'\0');
519     PROTO_NUM = Some(atoi(num.as_mut_slice().as_mut_ptr() as *mut i8));
520 
521     let mut _proto_aliases: Vec<Vec<u8>> = Vec::new();
522     for s in iter {
523         let mut alias = s.as_bytes().to_vec();
524         alias.push(b'\0');
525         _proto_aliases.push(alias);
526     }
527     let mut proto_aliases: Vec<*mut i8> = _proto_aliases
528         .iter_mut()
529         .map(|x| x.as_mut_ptr() as *mut i8)
530         .collect();
531     proto_aliases.push(ptr::null_mut());
532 
533     PROTO_ALIASES = Some(_proto_aliases);
534     PROTO_NAME = Some(proto_name);
535 
536     PROTO_ENTRY = protoent {
537         p_name: PROTO_NAME.as_mut().unwrap().as_mut_slice().as_mut_ptr() as *mut ::c_char,
538         p_aliases: proto_aliases.as_mut_slice().as_mut_ptr() as *mut *mut i8,
539         p_proto: PROTO_NUM.unwrap(),
540     };
541     if PROTO_STAYOPEN == 0 {
542         endprotoent();
543     }
544     &mut PROTO_ENTRY as *mut protoent
545 }
546 
547 #[no_mangle]
548 pub unsafe extern "C" fn getservbyname(name: *const ::c_char, proto: *const ::c_char) -> *mut servent {
549     setservent(SERV_STAYOPEN);
550     let mut p: *mut servent;
551     if proto.is_null() {
552         while {
553             p = getservent();
554             !p.is_null()
555         } {
556             if strcasecmp((*p).s_name, name) == 0 {
557                 setservent(SERV_STAYOPEN);
558                 return p;
559             }
560         }
561     } else {
562         while {
563             p = getservent();
564             !p.is_null()
565         } {
566             if strcasecmp((*p).s_name, name) == 0 && strcasecmp((*p).s_proto, proto) == 0 {
567                 setservent(SERV_STAYOPEN);
568                 return p;
569             }
570         }
571     }
572     setservent(SERV_STAYOPEN);
573     platform::errno = ENOENT;
574     ptr::null_mut() as *mut servent
575 }
576 
577 #[no_mangle]
578 pub unsafe extern "C" fn getservbyport(port: ::c_int, proto: *const ::c_char) -> *mut servent {
579     setservent(SERV_STAYOPEN);
580     let mut p: *mut servent;
581     if proto.is_null() {
582         while {
583             p = getservent();
584             !p.is_null()
585         } {
586             if (*p).s_port == port {
587                 setservent(SERV_STAYOPEN);
588                 return p;
589             }
590         }
591     } else {
592         while {
593             p = getservent();
594             !p.is_null()
595         } {
596             if (*p).s_port == port && strcasecmp((*p).s_proto, proto) == 0 {
597                 setservent(SERV_STAYOPEN);
598                 return p;
599             }
600         }
601     }
602     setservent(SERV_STAYOPEN);
603     platform::errno = ENOENT;
604     ptr::null_mut()
605 }
606 
607 #[no_mangle]
608 pub unsafe extern "C" fn getservent() -> *mut servent {
609     if SERVDB == 0 {
610         SERVDB = platform::pal::open("/etc/services".as_ptr() as *const i8, O_RDONLY, 0);
611     }
612     let mut rlb = RawLineBuffer::new(SERVDB);
613     rlb.seek(S_POS);
614 
615     let r: Box<str> = Box::default();
616 
617     loop {
618         let r = match rlb.next() {
619             Line::Some(s) => bytes_to_box_str(s),
620             _ => {
621                 if SERV_STAYOPEN == 0 {
622                     endservent();
623                 }
624                 return ptr::null_mut();
625             }
626         };
627 
628         let mut iter = r.split_whitespace();
629         let mut serv_name = match iter.next() {
630             Some(serv_name) => serv_name.as_bytes().to_vec(),
631             None => continue,
632         };
633         serv_name.push(b'\0');
634         let port_proto = match iter.next() {
635             Some(port_proto) => port_proto,
636             None => continue,
637         };
638         let mut split = port_proto.split('/');
639         let mut port = match split.next() {
640             Some(port) => port.as_bytes().to_vec(),
641             None => continue,
642         };
643         port.push(b'\0');
644         SERV_PORT =
645             Some(htons(atoi(port.as_mut_slice().as_mut_ptr() as *mut i8) as u16) as u32 as i32);
646         let mut proto = match split.next() {
647             Some(proto) => proto.as_bytes().to_vec(),
648             None => continue,
649         };
650         proto.push(b'\0');
651 
652         rlb.next();
653         S_POS = rlb.line_pos();
654 
655         /*
656          *let mut _serv_aliases: Vec<Vec<u8>> = Vec::new();
657          *loop {
658          *    let mut alias = match iter.next() {
659          *        Some(s) => s.as_bytes().to_vec(),
660          *        _ => break
661          *    };
662          *    alias.push(b'\0');
663          *    _serv_aliases.push(alias);
664          *}
665          *let mut serv_aliases: Vec<*mut i8> = _serv_aliases.iter_mut().map(|x| x.as_mut_ptr() as *mut i8).collect();
666          *serv_aliases.push(ptr::null_mut());
667          *
668          */
669         let mut _serv_aliases: Vec<Vec<u8>> = Vec::new();
670         _serv_aliases.push(vec![b'\0']);
671         let mut serv_aliases: Vec<*mut i8> = Vec::new();
672         serv_aliases.push(ptr::null_mut());
673         serv_aliases.push(ptr::null_mut());
674 
675         SERV_ALIASES = Some(_serv_aliases);
676         SERV_NAME = Some(serv_name);
677         SERV_PROTO = Some(proto);
678 
679         SERV_ENTRY = servent {
680             s_name: SERV_NAME.as_mut().unwrap().as_mut_slice().as_mut_ptr() as *mut ::c_char,
681             s_aliases: serv_aliases.as_mut_slice().as_mut_ptr() as *mut *mut i8,
682             s_port: SERV_PORT.unwrap(),
683             s_proto: SERV_PROTO.as_mut().unwrap().as_mut_slice().as_mut_ptr() as *mut ::c_char,
684         };
685 
686         if SERV_STAYOPEN == 0 {
687             endservent();
688         }
689         break &mut SERV_ENTRY as *mut servent;
690     }
691 }
692 
693 #[no_mangle]
694 pub unsafe extern "C" fn setnetent(stayopen: ::c_int) {
695     NET_STAYOPEN = stayopen;
696     if NETDB == 0 {
697         NETDB = platform::pal::open("/etc/networks".as_ptr() as *const i8, O_RDONLY, 0)
698     } else {
699         platform::pal::lseek(NETDB, 0, SEEK_SET);
700         N_POS = 0;
701     }
702 }
703 
704 #[no_mangle]
705 pub unsafe extern "C" fn setprotoent(stayopen: ::c_int) {
706     PROTO_STAYOPEN = stayopen;
707     if PROTODB == 0 {
708         PROTODB = platform::pal::open("/etc/protocols".as_ptr() as *const i8, O_RDONLY, 0)
709     } else {
710         platform::pal::lseek(PROTODB, 0, SEEK_SET);
711         P_POS = 0;
712     }
713 }
714 
715 #[no_mangle]
716 pub unsafe extern "C" fn setservent(stayopen: ::c_int) {
717     SERV_STAYOPEN = stayopen;
718     if SERVDB == 0 {
719         SERVDB = platform::pal::open("/etc/services".as_ptr() as *const i8, O_RDONLY, 0)
720     } else {
721         platform::pal::lseek(SERVDB, 0, SEEK_SET);
722         S_POS = 0;
723     }
724 }
725 
726 #[no_mangle]
727 pub unsafe extern "C" fn getaddrinfo(
728     node: *const ::c_char,
729     service: *const ::c_char,
730     hints: *const addrinfo,
731     res: *mut *mut addrinfo,
732 ) -> ::c_int {
733     //TODO: getaddrinfo
734     let node_opt = if node.is_null() {
735         None
736     } else {
737         Some(CStr::from_ptr(node))
738     };
739 
740     let service_opt = if service.is_null() {
741         None
742     } else {
743         Some(CStr::from_ptr(service))
744     };
745 
746     let hints_opt = if hints.is_null() { None } else { Some(&*hints) };
747 
748     trace!(
749         "getaddrinfo({:?}, {:?}, {:?})",
750         node_opt.map(|c| str::from_utf8_unchecked(c.to_bytes())),
751         service_opt.map(|c| str::from_utf8_unchecked(c.to_bytes())),
752         hints_opt
753     );
754 
755     //TODO: Use hints
756     let mut ai_flags = hints_opt.map_or(0, |hints| hints.ai_flags);
757     let mut ai_family; // = hints_opt.map_or(AF_UNSPEC, |hints| hints.ai_family);
758     let ai_socktype = hints_opt.map_or(0, |hints| hints.ai_socktype);
759     let mut ai_protocol; // = hints_opt.map_or(0, |hints| hints.ai_protocol);
760 
761     *res = ptr::null_mut();
762 
763     let mut port = 0;
764     if let Some(service) = service_opt {
765         //TODO: Support other service definitions as well as AI_NUMERICSERV
766         match str::from_utf8_unchecked(service.to_bytes()).parse::<u16>() {
767             Ok(ok) => port = ok,
768             Err(_err) => (),
769         }
770     }
771 
772     //TODO: Check hosts file
773     if let Some(node) = node_opt {
774         //TODO: Support AI_NUMERICHOST
775         let lookuphost = match lookup_host(str::from_utf8_unchecked(node.to_bytes())) {
776             Ok(lookuphost) => lookuphost,
777             Err(e) => {
778                 platform::errno = e;
779                 return EAI_SYSTEM;
780             }
781         };
782 
783         for in_addr in lookuphost {
784             ai_family = AF_INET;
785             ai_protocol = 0;
786 
787             let ai_addr = Box::into_raw(Box::new(sockaddr_in {
788                 sin_family: ai_family as sa_family_t,
789                 sin_port: htons(port),
790                 sin_addr: in_addr,
791                 sin_zero: [0; 8],
792             })) as *mut sockaddr;
793 
794             let ai_addrlen = mem::size_of::<sockaddr_in>();
795 
796             let ai_canonname = if ai_flags & AI_CANONNAME > 0 {
797                 ai_flags &= !AI_CANONNAME;
798                 node.to_owned().into_raw()
799             } else {
800                 ptr::null_mut()
801             };
802 
803             let addrinfo = Box::new(addrinfo {
804                 ai_flags: 0,
805                 ai_family,
806                 ai_socktype,
807                 ai_protocol,
808                 ai_addrlen,
809                 ai_canonname,
810                 ai_addr,
811                 ai_next: ptr::null_mut(),
812             });
813 
814             let mut indirect = res;
815             while !(*indirect).is_null() {
816                 indirect = &mut (**indirect).ai_next;
817             }
818             *indirect = Box::into_raw(addrinfo);
819         }
820     }
821 
822     0
823 }
824 
825 #[no_mangle]
826 pub unsafe extern "C" fn getnameinfo(
827     addr: *const sockaddr,
828     addrlen: socklen_t,
829     host: *mut ::c_char,
830     hostlen: socklen_t,
831     serv: *mut ::c_char,
832     servlen: socklen_t,
833     flags: ::c_int,
834 ) -> ::c_int {
835     //TODO: getnameinfo
836     if addrlen as usize != mem::size_of::<sockaddr_in>() {
837         return EAI_FAMILY;
838     }
839 
840     let addr = &*(addr as *const sockaddr_in);
841 
842     let host_opt = if host.is_null() {
843         None
844     } else {
845         Some(slice::from_raw_parts_mut(host, hostlen as usize))
846     };
847 
848     let serv_opt = if serv.is_null() {
849         None
850     } else {
851         Some(slice::from_raw_parts_mut(serv, servlen as usize))
852     };
853 
854     eprintln!("getnameinfo({:p}, {}, {:#x})", addr, addrlen, flags);
855 
856     platform::errno = ENOSYS;
857     EAI_SYSTEM
858 }
859 
860 #[no_mangle]
861 pub unsafe extern "C" fn freeaddrinfo(res: *mut addrinfo) {
862     let mut ai = res;
863     while !ai.is_null() {
864         let bai = Box::from_raw(ai);
865         if !bai.ai_canonname.is_null() {
866             CString::from_raw(bai.ai_canonname);
867         }
868         if !bai.ai_addr.is_null() {
869             if bai.ai_addrlen == mem::size_of::<sockaddr_in>() {
870                 Box::from_raw(bai.ai_addr as *mut sockaddr_in);
871             } else if bai.ai_addrlen == mem::size_of::<sockaddr_in6>() {
872                 Box::from_raw(bai.ai_addr as *mut sockaddr_in6);
873             } else {
874                 eprintln!("freeaddrinfo: unknown ai_addrlen {}", bai.ai_addrlen);
875             }
876         }
877         ai = bai.ai_next;
878     }
879 }
880 
881 #[no_mangle]
882 pub extern "C" fn gai_strerror(errcode: ::c_int) -> *const ::c_char {
883     match errcode {
884         EAI_BADFLAGS => c_str!("Invalid flags"),
885         EAI_NONAME => c_str!("Name does not resolve"),
886         EAI_AGAIN => c_str!("Try again"),
887         EAI_FAIL => c_str!("Non-recoverable error"),
888         EAI_NODATA => c_str!("Unknown error"),
889         EAI_FAMILY => c_str!("Unrecognized address family or invalid length"),
890         EAI_SOCKTYPE => c_str!("Unrecognized socket type"),
891         EAI_SERVICE => c_str!("Unrecognized service"),
892         EAI_ADDRFAMILY => c_str!("Address family for name not supported"),
893         EAI_MEMORY => c_str!("Out of memory"),
894         EAI_SYSTEM => c_str!("System error"),
895         EAI_OVERFLOW => c_str!("Overflow"),
896         _ => c_str!("Unknown error"),
897     }
898     .as_ptr()
899 }
900 
901 #[no_mangle]
902 pub extern "C" fn hstrerror(errcode: ::c_int) -> *const ::c_char {
903     match errcode {
904         HOST_NOT_FOUND => c_str!("Unknown hostname"),
905         NO_DATA => c_str!("No address for hostname"),
906         NO_RECOVERY => c_str!("Unknown server error"),
907         TRY_AGAIN => c_str!("Hostname lookup failure"),
908         _ => c_str!("Unknown error"),
909     }
910     .as_ptr()
911 }
912