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