Skip to content
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
3 changes: 2 additions & 1 deletion library/std/src/net/hostname.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ use crate::ffi::OsString;
/// | Platform | System call |
/// |--------------|---------------------------------------------------------------------------------------------------------|
/// | UNIX | [`gethostname`](https://www.man7.org/linux/man-pages/man2/gethostname.2.html) |
/// | Windows (8+) | [`GetHostNameW`](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-gethostnamew) |
/// | Windows 8+ | [`GetHostNameW`](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-gethostnamew) |
/// | Windows 7 | [`gethostname`](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-gethostname) |
///
/// Note that platform-specific behavior [may change in the future][changes].
///
Expand Down
3 changes: 1 addition & 2 deletions library/std/src/sys/net/hostname/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ cfg_select! {
mod unix;
pub use unix::hostname;
}
// `GetHostNameW` is only available starting with Windows 8.
all(target_os = "windows", not(target_vendor = "win7")) => {
all(target_os = "windows") => {
mod windows;
pub use windows::hostname;
}
Expand Down
22 changes: 18 additions & 4 deletions library/std/src/sys/pal/windows/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,21 @@ compat_fn_with_fallback! {
}
}

#[cfg(target_vendor = "win7")]
compat_fn_with_fallback! {
pub static WS2_32: &CStr = c"ws2_32";

pub fn GetHostNameW(name: PWSTR, namelen: i32) -> i32 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I guess it could be nice to link the original issue somewhere around here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Left that out for now - none of the other compat functions have an issue linked to them, and the issue in question was "just" a compatibility issue.

unsafe {
crate::sys::winsock::hostname_fallback(name, namelen)
}
}
}

// Only available starting with Windows 8.
#[cfg(not(target_vendor = "win7"))]
windows_link::link!("ws2_32.dll" "system" fn GetHostNameW(name : PWSTR, namelen : i32) -> i32);

cfg_select! {
target_vendor = "uwp" => {
windows_link::link_raw_dylib!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS);
Expand All @@ -235,9 +250,8 @@ cfg_select! {
windows_link::link_raw_dylib!("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_link::link_raw_dylib!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32);
}
target_vendor = "win7" => {
windows_link::link!("ws2_32.dll" "system" fn gethostname(name : PSTR, namelen : i32) -> i32);
}
_ => {}
}

// Only available starting with Windows 8.
#[cfg(not(target_vendor = "win7"))]
windows_link::link!("ws2_32.dll" "system" fn GetHostNameW(name : PWSTR, namelen : i32) -> i32);
2 changes: 2 additions & 0 deletions library/std/src/sys/pal/windows/c/bindings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ CONSOLE_MODE
CONSOLE_READCONSOLE_CONTROL
CONTEXT
CopyFileExW
CP_ACP
CP_UTF8
CREATE_ALWAYS
CREATE_BREAKAWAY_FROM_JOB
Expand Down Expand Up @@ -2624,6 +2625,7 @@ WSAPROTOCOLCHAIN
WSARecv
WSASend
WSASERVICE_NOT_FOUND
WSASetLastError
WSASocketW
WSAStartup
WSASYSCALLFAILURE
Expand Down
2 changes: 2 additions & 0 deletions library/std/src/sys/pal/windows/c/windows_sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ windows_link::link!("ws2_32.dll" "system" fn WSADuplicateSocketW(s : SOCKET, dwp
windows_link::link!("ws2_32.dll" "system" fn WSAGetLastError() -> WSA_ERROR);
windows_link::link!("ws2_32.dll" "system" fn WSARecv(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytesrecvd : *mut u32, lpflags : *mut u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32);
windows_link::link!("ws2_32.dll" "system" fn WSASend(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytessent : *mut u32, dwflags : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32);
windows_link::link!("ws2_32.dll" "system" fn WSASetLastError(ierror : i32));
windows_link::link!("ws2_32.dll" "system" fn WSASocketW(af : i32, r#type : i32, protocol : i32, lpprotocolinfo : *const WSAPROTOCOL_INFOW, g : u32, dwflags : u32) -> SOCKET);
windows_link::link!("ws2_32.dll" "system" fn WSAStartup(wversionrequested : u16, lpwsadata : *mut WSADATA) -> i32);
windows_link::link!("kernel32.dll" "system" fn WaitForMultipleObjects(ncount : u32, lphandles : *const HANDLE, bwaitall : BOOL, dwmilliseconds : u32) -> WAIT_EVENT);
Expand Down Expand Up @@ -443,6 +444,7 @@ pub struct CONTEXT_0_0 {
pub type CONTEXT_FLAGS = u32;
pub type COPYFILE_FLAGS = u32;
pub type COPYPROGRESSROUTINE_PROGRESS = u32;
pub const CP_ACP: u32 = 0u32;
pub const CP_UTF8: u32 = 65001u32;
pub const CREATE_ALWAYS: FILE_CREATION_DISPOSITION = 2u32;
pub const CREATE_BREAKAWAY_FROM_JOB: PROCESS_CREATION_FLAGS = 16777216u32;
Expand Down
62 changes: 62 additions & 0 deletions library/std/src/sys/pal/windows/winsock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,65 @@ where
{
cvt(f())
}

#[cfg(target_vendor = "win7")]
pub unsafe fn hostname_fallback(name: c::PWSTR, namelen: i32) -> i32 {
// The buffer needs to have space for at least the null byte.
if namelen < 1 {
// SAFETY: SetLastError is always safe to call.
unsafe {
c::WSASetLastError(c::WSAEFAULT);
}

return c::SOCKET_ERROR;
}

// The documentation of gethostname says that a buffer size of 256 is
// always enough.
let mut buffer = [const { mem::MaybeUninit::<u8>::uninit() }; 256];

// SAFETY: these parameters specify a valid, writable region of memory.
unsafe {
if c::gethostname(buffer.as_mut_ptr().cast(), buffer.len() as i32) == c::SOCKET_ERROR {
Comment thread
Fulgen301 marked this conversation as resolved.
return c::SOCKET_ERROR;
}
Comment thread
Fulgen301 marked this conversation as resolved.
}

// Subtract one to leave space for the null terminator, as MultiByteToWideChar doesn't terminate the output buffer
// if the number of output characters is equal to the buffer length.
// SAFETY: The buffer is at least namelen characters large, thus namelen - 1 characters are always writable.
let len = unsafe {
c::MultiByteToWideChar(
c::CP_ACP,
c::MB_ERR_INVALID_CHARS,
buffer.as_mut_ptr().cast(),
-1,
name,
namelen - 1,
)
};

if len == 0 {
// GetHostNameW reports WSAEFAULT if the buffer is too small, and WSAENETDOWN on internal errors.
// SAFETY: GetLastError and SetLastError are always safe to call.
unsafe {
if c::WSAGetLastError() == c::ERROR_INSUFFICIENT_BUFFER as _ {
c::WSASetLastError(c::WSAEFAULT);
} else {
c::WSASetLastError(c::WSAENETDOWN);
}
}
return c::SOCKET_ERROR;
}

// Ensure the output is always null terminated.
// If MultiByteToWideChar has already written a null terminator, that null terminator will be included in len
// and this will add a second one, but writing a zero is cheap enough to omit the length comparison.
// SAFETY: len is always less than namelen as MultiByteToWideChar only writes namelen - 1 characters.
unsafe {
name.add(len as _).write(0);
}

// Success
0
}
Loading