1use socket2::SockAddr;
2use std::ffi::CStr;
3use std::io;
4use std::net::SocketAddr;
5use std::os::raw::c_char;
6use std::str;
7
8#[cfg(unix)]
9use libc::{c_char as libc_c_char, getnameinfo as c_getnameinfo};
10
11#[cfg(windows)]
12#[allow(non_camel_case_types)]
13type libc_c_char = u8;
14#[cfg(windows)]
15use windows_sys::Win32::Networking::WinSock::getnameinfo as c_getnameinfo;
16
17use crate::err::LookupError;
18
19pub fn getnameinfo(sock: &SocketAddr, flags: i32) -> Result<(String, String), LookupError> {
30 let sock: SockAddr = (*sock).into();
32 let c_sock = sock.as_ptr();
33 let c_sock_len = sock.len();
34
35 let mut c_host = [0 as u8; 1024_usize];
39 let mut c_service = [0 as u8; 32_usize];
41
42 #[cfg(windows)]
44 crate::win::init_winsock();
45
46 unsafe {
47 LookupError::match_gai_error(c_getnameinfo(
48 c_sock as *const _,
49 c_sock_len,
50 c_host.as_mut_ptr() as *mut libc_c_char,
51 c_host.len() as _,
52 c_service.as_mut_ptr() as *mut libc_c_char,
53 c_service.len() as _,
54 flags,
55 ))?;
56 }
57
58 let host = unsafe { CStr::from_ptr(c_host.as_ptr() as *const c_char) };
59 let service = unsafe { CStr::from_ptr(c_service.as_ptr() as *const c_char) };
60
61 let host = match str::from_utf8(host.to_bytes()) {
62 Ok(name) => Ok(name.to_owned()),
63 Err(_) => Err(io::Error::new(
64 io::ErrorKind::Other,
65 "Host UTF8 parsing failed",
66 )),
67 }?;
68
69 let service = match str::from_utf8(service.to_bytes()) {
70 Ok(service) => Ok(service.to_owned()),
71 Err(_) => Err(io::Error::new(
72 io::ErrorKind::Other,
73 "Service UTF8 parsing failed",
74 )),
75 }?;
76
77 Ok((host, service))
78}
79
80#[test]
81fn test_getnameinfo() {
82 use std::net::{IpAddr, SocketAddr};
83
84 let ip: IpAddr = "127.0.0.1".parse().unwrap();
85 let port = 22;
86 let socket: SocketAddr = (ip, port).into();
87
88 let (name, service) = match getnameinfo(&socket, 0) {
89 Ok((n, s)) => (n, s),
90 Err(e) => panic!("Failed to lookup socket {:?}", e),
91 };
92
93 assert_eq!(service, "ssh");
94
95 #[cfg(unix)]
96 {
97 assert_eq!(name, "localhost");
98 }
99
100 #[cfg(windows)]
101 {
102 let hostname = crate::hostname::get_hostname().unwrap();
103 assert_eq!(name, hostname);
104 }
105}