Skip to content

Commit 316a42e

Browse files
committed
std: net: Add function to get the system hostname
1 parent b3b368a commit 316a42e

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

library/std/src/net/hostname.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#[cfg(not(target_family = "windows"))]
2+
use libc::gethostname;
3+
4+
use crate::ffi::{CStr, OsString};
5+
use crate::os::raw::c_char;
6+
7+
/// Returns the system hostname.
8+
///
9+
/// The returned result will, on success, return the same result [`libc::gethostname`] would return
10+
/// (as it is implemented using the very same function), and on error, what `errno` contains, also
11+
/// set by [`libc::gethostname`].
12+
#[unstable(feature = "gethostname", issue = "135142")]
13+
pub fn hostname() -> crate::io::Result<OsString> {
14+
// 255 bytes is the maximum allowable length for a hostname (as per the DNS spec),
15+
// so we shouldn't ever have problems with this. I (@orowith2os) considered using a constant
16+
// and letting the platform set the length, but it was determined after some discussion that
17+
// this could break things if the platform changes their length. Possible alternative is to
18+
// read the sysconf setting for the max hostname length, but that might be a bit too much work.
19+
// The 256 byte length is to allow for the NUL terminator.
20+
let mut temp_buffer: [c_char; 256] = [0; 256];
21+
// 0 = no problem, and there isn't any other relevant error code to check for. Only stuff for
22+
// sethostname, and ENAMETOOLONG, which is only relevant for glibc 2.1 or newer. With the
23+
// previous information given in mind, we shouldn't ever encounter any error other than the
24+
// fact that the system *somehow* failed to get the hostname.
25+
// SAFETY: should never be unsafe, as we're passing in a valid (0-initialized) buffer, and the
26+
// length of said buffer.
27+
#[cfg(not(target_family = "windows"))]
28+
let gethostname_result = unsafe { gethostname(&mut temp_buffer as _, temp_buffer.len()) };
29+
#[cfg(target_family = "windows")]
30+
let gethostname_result = {
31+
println!(
32+
"gethostname impl for the Rust stdlib isn't done on Windows yet, so here's an error instead!"
33+
);
34+
-1
35+
};
36+
37+
match gethostname_result {
38+
0 => {
39+
// SAFETY: we already know the pointer here is valid, we made it from safe Rust earlier.
40+
let cstring = unsafe { CStr::from_ptr(&mut temp_buffer as _) };
41+
return Ok(OsString::from(cstring.to_string_lossy().as_ref()));
42+
}
43+
_ => Err(crate::io::Error::last_os_error()),
44+
}
45+
}

library/std/src/net/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//! Networking primitives for TCP/UDP communication.
22
//!
33
//! This module provides networking functionality for the Transmission Control and User
4-
//! Datagram Protocols, as well as types for IP and socket addresses.
4+
//! Datagram Protocols, as well as types for IP and socket addresses, and functions related
5+
//! to network properties.
56
//!
67
//! # Organization
78
//!
@@ -24,6 +25,8 @@
2425
#[stable(feature = "rust1", since = "1.0.0")]
2526
pub use core::net::AddrParseError;
2627

28+
#[unstable(feature = "gethostname", issue = "135142")]
29+
pub use self::hostname::hostname;
2730
#[stable(feature = "rust1", since = "1.0.0")]
2831
pub use self::ip_addr::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
2932
#[stable(feature = "rust1", since = "1.0.0")]
@@ -36,6 +39,7 @@ pub use self::tcp::{Incoming, TcpListener, TcpStream};
3639
pub use self::udp::UdpSocket;
3740
use crate::io::{self, ErrorKind};
3841

42+
mod hostname;
3943
mod ip_addr;
4044
mod socket_addr;
4145
mod tcp;

0 commit comments

Comments
 (0)