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