Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 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
53 changes: 53 additions & 0 deletions library/std/src/os/unix/net/datagram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use libc::MSG_NOSIGNAL;
#[cfg(any(doc, target_os = "android", target_os = "linux"))]
use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
use super::{sockaddr_un, SocketAddr};
#[cfg(any(doc, target_os = "linux", target_os = "haiku", target_os = "vxworks",))]
use crate::ffi::CString;
#[cfg(any(doc, target_os = "android", target_os = "linux"))]
use crate::io::{IoSlice, IoSliceMut};
use crate::net::Shutdown;
Expand Down Expand Up @@ -836,6 +838,57 @@ impl UnixDatagram {
self.0.set_mark(mark)
}

/// Bind the socket to an interface
///
#[cfg_attr(
any(target_os = "linux", target_os = "haiku", target_os = "vxworks"),
doc = "```no_run"
)]
#[cfg_attr(
not(any(target_os = "linux", target_os = "haiku", target_os = "vxworks")),
doc = "```ignore"
)]
/// #![feature(unix_set_device)]
/// use std::os::unix::net::UnixDatagram;
///
/// fn main() -> std::io::Result<()> {
/// let socket = UnixDatagram::unbound()?;
/// socket.set_device("eth0")?;
/// Ok(())
/// }
/// ```
#[cfg(any(doc, target_os = "linux", target_os = "haiku", target_os = "vxworks",))]
#[unstable(feature = "unix_set_device", issue = "129182")]
pub fn set_device(&self, ifrname: &str) -> io::Result<()> {
self.0.set_device(ifrname)
}

/// Get the interface this socket is bound to
///
#[cfg_attr(
any(target_os = "linux", target_os = "haiku", target_os = "vxworks"),
doc = "```no_run"
)]
#[cfg_attr(
not(any(target_os = "linux", target_os = "haiku", target_os = "vxworks")),
doc = "```ignore"
)]
/// #![feature(unix_set_device)]
/// use std::os::unix::net::UnixDatagram;
///
/// fn main() -> std::io::Result<()> {
/// let socket = UnixDatagram::unbound()?;
/// socket.set_device("eth0")?;
/// let name = socket.device()?;
/// assert_eq!(Ok("eth0"), name.to_str());

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.

Something seems odd here.

#![feature(unix_set_todevice)]
use std::os::unix::net::UnixDatagram;
    ///
fn main() -> std::io::Result<()> {
    let socket = UnixDatagram::unbound()?;
    socket.set_todevice(c"eno1")?;
    let name = socket.todevice()?;
    assert_eq!(Ok("eno1"), name.to_str());
    Ok(())
}

The assertion fails.

thread 'main' panicked at test_case.rs:8:5:
assertion `left == right` failed
  left: Ok("eno1")
 right: Ok("�
�")
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

/// Ok(())
/// }
/// ```
#[cfg(any(doc, target_os = "linux", target_os = "haiku", target_os = "vxworks",))]
#[unstable(feature = "unix_set_device", issue = "129182")]
pub fn device(&self) -> io::Result<CString> {
self.0.device()
}
/// Returns the value of the `SO_ERROR` option.
///
/// # Examples
Expand Down
54 changes: 54 additions & 0 deletions library/std/src/os/unix/net/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use super::{peer_cred, UCred};
#[cfg(any(doc, target_os = "android", target_os = "linux"))]
use super::{recv_vectored_with_ancillary_from, send_vectored_with_ancillary_to, SocketAncillary};
use super::{sockaddr_un, SocketAddr};
#[cfg(any(doc, target_os = "linux", target_os = "haiku", target_os = "vxworks",))]
use crate::ffi::CString;
use crate::fmt;
use crate::io::{self, IoSlice, IoSliceMut};
use crate::net::Shutdown;
Expand Down Expand Up @@ -405,6 +407,58 @@ impl UnixStream {
self.0.set_mark(mark)
}

/// Bind the socket to an interface
///
#[cfg_attr(
any(target_os = "linux", target_os = "haiku", target_os = "vxworks"),
doc = "```no_run"
)]
#[cfg_attr(
not(any(target_os = "linux", target_os = "haiku", target_os = "vxworks")),
doc = "```ignore"
)]
/// #![feature(unix_set_device)]
/// use std::os::unix::net::UnixStream;
///
/// fn main() -> std::io::Result<()> {
/// let socket = UnixStream::connect("/tmp/sock")?;

@joshtriplett joshtriplett Aug 27, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why is this using UnixStream? That...shouldn't work.

The examples should be things expected to work.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Wait, it looks like these are being added to UNIX sockets? Shouldn't these be for TCP/UDP, not UNIX?

/// socket.set_device("eth0")?;
/// Ok(())
/// }
/// ```
#[cfg(any(doc, target_os = "linux", target_os = "haiku", target_os = "vxworks",))]
#[unstable(feature = "unix_set_device", issue = "129182")]
pub fn set_device(&self, ifrname: &str) -> io::Result<()> {
self.0.set_device(ifrname)
}

/// Get the interface this socket is bound to
///
#[cfg_attr(
any(target_os = "linux", target_os = "haiku", target_os = "vxworks"),
doc = "```no_run"
)]
#[cfg_attr(
not(any(target_os = "linux", target_os = "haiku", target_os = "vxworks")),
doc = "```ignore"
)]
/// #![feature(unix_set_device)]
/// use std::os::unix::net::UnixStream;
///
/// fn main() -> std::io::Result<()> {
/// let socket = UnixStream::connect("/tmp/sock")?;
/// socket.set_device("eth0")?;
/// let name = socket.device()?;
/// assert_eq!(Ok("eth0"), name.to_str());
/// Ok(())
/// }
/// ```
#[cfg(any(doc, target_os = "linux", target_os = "haiku", target_os = "vxworks",))]
#[unstable(feature = "unix_set_device", issue = "129182")]
pub fn device(&self) -> io::Result<CString> {
self.0.device()
}

/// Returns the value of the `SO_ERROR` option.
///
/// # Examples
Expand Down
24 changes: 24 additions & 0 deletions library/std/src/sys/pal/unix/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,30 @@ impl Socket {
setsockopt(self, libc::SOL_SOCKET, option, mark as libc::c_int)
}

#[cfg(any(target_os = "linux", target_os = "haiku", target_os = "vxworks"))]
pub fn device(&self) -> io::Result<crate::ffi::CString> {
let buf: [libc::c_char; libc::IFNAMSIZ] =
getsockopt(self, libc::SOL_SOCKET, libc::SO_BINDTODEVICE)?;
let s: &[u8] = unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len()) };
let name = CStr::from_bytes_until_nul(s).unwrap();
Ok(crate::ffi::CString::new(name.to_bytes()).unwrap())
}
Comment thread
kennytm marked this conversation as resolved.

#[cfg(any(target_os = "linux", target_os = "haiku", target_os = "vxworks"))]
pub fn set_device(&self, ifrname: &str) -> io::Result<()> {
let istr = ifrname.as_bytes();

if istr.len() >= libc::IFNAMSIZ {
return Err(io::Error::from_raw_os_error(libc::ENAMETOOLONG));
}

let mut buf = [0; libc::IFNAMSIZ];
for (src, dst) in istr.iter().zip(&mut buf[..libc::IFNAMSIZ - 1]) {
*dst = *src as libc::c_char;
}
setsockopt(self, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, buf)
}

pub fn take_error(&self) -> io::Result<Option<io::Error>> {
let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?;
if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
Expand Down