Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std: net: Add function to return the system hostname #135141

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions library/std/src/net/hostname.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use crate::ffi::OsString;

/// Returns the system hostname.
///
/// This can error out in platform-specific error cases;
/// for example, uefi and wasm, where hostnames aren't
/// supported.
///
/// # Underlying system calls
///
/// | Platform | System call |
/// |----------|---------------------------------------------------------------------------------------------------------|
/// | UNIX | [`gethostname`](https://www.man7.org/linux/man-pages/man2/gethostname.2.html) |
/// | Windows | [`GetHostNameW`](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-gethostnamew) |
///
/// Note that platform-specific behavior [may change in the future][changes].
///
/// [changes]: crate::io#platform-specific-behavior
#[unstable(feature = "gethostname", issue = "135142")]
pub fn hostname() -> crate::io::Result<OsString> {
crate::sys::net::gethostname()
}
6 changes: 5 additions & 1 deletion library/std/src/net/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! Networking primitives for TCP/UDP communication.
//!
//! This module provides networking functionality for the Transmission Control and User
//! Datagram Protocols, as well as types for IP and socket addresses.
//! Datagram Protocols, as well as types for IP and socket addresses, and functions related
//! to network properties.
//!
//! # Organization
//!
Expand All @@ -24,6 +25,8 @@
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::net::AddrParseError;

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

mod hostname;
mod ip_addr;
mod socket_addr;
mod tcp;
Expand Down
31 changes: 30 additions & 1 deletion library/std/src/sys/pal/unix/net.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use libc::{MSG_PEEK, c_int, c_void, size_t, sockaddr, socklen_t};

use crate::ffi::CStr;
use crate::ffi::{CStr, OsString};
use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
use crate::net::{Shutdown, SocketAddr};
use crate::os::unix::ffi::OsStringExt;
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
use crate::sys::fd::FileDesc;
use crate::sys::pal::unix::IsMinusOne;
Expand Down Expand Up @@ -649,3 +650,31 @@ fn on_resolver_failure() {

#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
fn on_resolver_failure() {}

pub fn gethostname() -> io::Result<OsString> {
// 255 bytes is the maximum allowable length for a hostname (as per the DNS spec),
// so we shouldn't ever have problems with this. I (@orowith2os) considered using a constant
// and letting the platform set the length, but it was determined after some discussion that
// this could break things if the platform changes their length. Possible alternative is to
// read the sysconf setting for the max hostname length, but that might be a bit too much work.
// The 256 byte length is to allow for the NUL terminator.
let mut temp_buffer = [0; 256];

// SAFETY: we're passing in a valid (0-initialized) buffer, and the length of said buffer.
unsafe {
cvt(libc::gethostname(temp_buffer.as_mut_ptr() as _, temp_buffer.len() as _))?;
}

// Unfortunately, the UNIX specification says that the name will be truncated
// if it does not fit in the buffer, without returning. As additionally, the
// truncated name may still be null-terminated, there is no reliable way to
// detect truncation. Fortunately, most platforms ignore what the specication
// says and return an error (mostly ENAMETOOLONG). Should that not be the case,
// the following detects truncation if the null-terminator was omitted. Note
// that this check does not impact performance at all as we need to find the
// length of the string anyways.
match CStr::from_bytes_until_nul(&temp_buffer) {
Ok(bytes) => Ok(OsString::from_vec(bytes.to_bytes().to_vec())),
Err(_) => Err(io::Error::from_raw_os_error(libc::ENAMETOOLONG)),
}
}
5 changes: 5 additions & 0 deletions library/std/src/sys/pal/unsupported/net.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
use crate::ffi::OsString;
use crate::fmt;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use crate::sys::unsupported;
use crate::time::Duration;

pub fn gethostname() -> crate::io::Result<OsString> {
unsupported()
}

pub struct TcpStream(!);

impl TcpStream {
Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/pal/windows/c/bindings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1978,6 +1978,7 @@ Windows.Win32.Networking.WinSock.FD_SET
Windows.Win32.Networking.WinSock.FIONBIO
Windows.Win32.Networking.WinSock.freeaddrinfo
Windows.Win32.Networking.WinSock.getaddrinfo
Windows.Win32.Networking.WinSock.GetHostNameW
Windows.Win32.Networking.WinSock.getpeername
Windows.Win32.Networking.WinSock.getsockname
Windows.Win32.Networking.WinSock.getsockopt
Expand Down
1 change: 1 addition & 0 deletions library/std/src/sys/pal/windows/c/windows_sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ windows_targets::link!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, e
windows_targets::link!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
windows_targets::link!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32);
windows_targets::link!("userenv.dll" "system" fn GetUserProfileDirectoryW(htoken : HANDLE, lpprofiledir : PWSTR, lpcchsize : *mut u32) -> BOOL);
windows_targets::link!("ws2_32.dll" "system" fn GetHostNameW(name : PWSTR, namelen : i32) -> i32);
windows_targets::link!("ws2_32.dll" "system" fn WSACleanup() -> i32);
windows_targets::link!("ws2_32.dll" "system" fn WSADuplicateSocketW(s : SOCKET, dwprocessid : u32, lpprotocolinfo : *mut WSAPROTOCOL_INFOW) -> i32);
windows_targets::link!("ws2_32.dll" "system" fn WSAGetLastError() -> WSA_ERROR);
Expand Down
21 changes: 21 additions & 0 deletions library/std/src/sys/pal/windows/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

use core::ffi::{c_int, c_long, c_ulong, c_ushort};

use crate::ffi::OsString;
use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut, Read};
use crate::net::{Shutdown, SocketAddr};
use crate::os::windows::ffi::OsStringExt;
use crate::os::windows::io::{
AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket,
};
Expand Down Expand Up @@ -572,3 +574,22 @@ impl FromRawSocket for Socket {
unsafe { Self(FromRawSocket::from_raw_socket(raw_socket)) }
}
}

pub fn gethostname() -> io::Result<OsString> {
init();

// The documentation of GetHostNameW says that a buffer size of 256 is
// always enough.
let mut buffer = [0; 256];
// SAFETY: these parameters specify a valid, writable region of memory.
let ret = unsafe { c::GetHostNameW(buffer.as_mut_ptr(), buffer.len() as i32) };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess my one nitpick is that maybe the max buffer len could be a constant instead of using as i32, which is often a code smell but in this case it's narrowly scoped enough that I don't feel strongly about it.

if ret == 0 {
let len = buffer
.iter()
.position(|&w| w == 0)
.expect("GetHostNameW failed to return a null-terminated name");
Ok(OsString::from_wide(&buffer[..len]))
} else {
Err(io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }))
}
}
Loading