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

UnixStream doesn't support abstract addresses #42048

Open
jethrogb opened this issue May 16, 2017 · 20 comments
Open

UnixStream doesn't support abstract addresses #42048

jethrogb opened this issue May 16, 2017 · 20 comments
Labels
C-feature-accepted Category: A feature request that has been accepted pending implementation. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@jethrogb
Copy link
Contributor

jethrogb commented May 16, 2017

From RFC 1479:

Linux's abstract namespace is not supported. Functionality may be added in the future via extension traits in std::os::linux::net.

This feature is described in the Linux unix(7) manpage.

This issue tracks the absence of (and hopefully future development of) this feature.

@sfackler
Copy link
Member

This should be pretty easy to add for anyone that's interested!

@sfackler sfackler added E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels May 17, 2017
@jethrogb
Copy link
Contributor Author

Not that easy... I'd probably want to change UnixStream::connect to take a A: Into<SocketAddr> and then impl<T: AsRef<Path>> From<T> for SocketAddr. But, that conversion is fallible (see std::sys::unix::ext::sockaddr_un). So you need TryInto. But then you can't supply a SocketAddr directly until we get impl<T, U> TryFrom<U> for T where T: From<U>, which requires !...

@sfackler
Copy link
Member

Abstract namespaces are Linux only so we'd only want to make them available through a Linux-only method. Probably something like

pub trait UnixStreamExt {
    fn connect_abstract(name: &[u8]) -> io::Result<UnixStream>;
}

pub trait SocketAddrExt {
    fn as_abstract(&self) -> Option<&[u8]>;
}

@jethrogb
Copy link
Contributor Author

That seems like a strange API, to have two different connect functions. You can have it be Linux only to have an extension trait to create a SockAddr on Linux only.

@sfackler
Copy link
Member

But then you can't supply a SocketAddr directly until we get impl<T, U> TryFrom for T where T: From, which requires !...

Why is it impossible to implement TryFrom from a type to itself without !?

@retep998
Copy link
Member

@sfackler Because we want to indicate that the TryFrom implementation will never fail, so gotta wait until ! is available.

@jethrogb
Copy link
Contributor Author

Actually that might still not work, because now you need TryFrom<Err=io::Error> for AsRef<Path> and TryFrom<Err=!> for SocketAddr...

@sfackler
Copy link
Member

@retep998

  1. ! is not the only way to indicate that. String's FromStr impl has always been infallible: https://doc.rust-lang.org/src/collections/string.rs.html#1829-1852
  2. How is that valuable in any way in practice? When have you ever said, "man, this code I'm trying to write would have been way better if some_socket_addr.to_socket_addrs() returned a Result<T, !> instead of Result<T, io::Error>"? If you're working in a concrete context you're not going to use try_from to go from a type to itself, and if you're in an generic context, you're only going use try_from if you want to deal with the failure case anyway.

@Mark-Simulacrum Mark-Simulacrum removed the E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. label Jun 23, 2017
@metux
Copy link

metux commented Jul 12, 2017

I'd advice against using that misfeature. In the past 20 years, I've never seen any practical usecase
for that, and it creates more trouble than it's actually worth it.

@jethrogb
Copy link
Contributor Author

@metux practical use-case is interoperability with other software that creates an abstract socket?

@metux
Copy link

metux commented Jul 13, 2017

Ok. Does anyone here run an application which needs that ? I don't recall any in the last two decades.

@jethrogb
Copy link
Contributor Author

Would I have opened this ticket if I didn't?

@metux
Copy link

metux commented Jul 13, 2017

Would I have opened this ticket if I didn't?

No idea, you didn't tell ;-)

@Mark-Simulacrum Mark-Simulacrum added the C-feature-request Category: A feature request, i.e: not implemented / a PR. label Jul 27, 2017
@dtolnay dtolnay added C-feature-accepted Category: A feature request that has been accepted pending implementation. and removed C-feature-request Category: A feature request, i.e: not implemented / a PR. labels Nov 17, 2017
@dtolnay
Copy link
Member

dtolnay commented Nov 17, 2017

I would love to see a PR implementing Linux-only support for abstract addresses. I believe we will be able to reach agreement in the PR without needing to draft an RFC.

@jethrogb
Copy link
Contributor Author

Now that TryFrom and never_type are close to being stabilized, I took another look at this. d47e979

There's a conflicting implementations issue, a P: AsRef<Path> might already implement Into<SocketAddr>:

error[E0119]: conflicting implementations of trait `core::convert::TryFrom<_>` for type `sys::unix::ext::net::SocketAddr`:
  --> src/libstd/sys/unix/ext/net.rs:91:1
   |
91 | impl<P: AsRef<Path>> TryFrom<P> for SocketAddr {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: conflicting implementation in crate `core`:
           - impl<T, U> core::convert::TryFrom<U> for T
             where U: core::convert::Into<T>;

@jethrogb
Copy link
Contributor Author

Here is the commit that adds SocketAddrExt c4db068. That should plug right into whatever solution we come up with for the UnixStream API.

@joshtriplett
Copy link
Member

joshtriplett commented Jan 26, 2020

I'm interested in this support.

Rather than changing the type of connect (which seems likely to produce inference errors), why not introduce a couple of new methods, bind_addr and connect_addr, which accept a concrete SocketAddr? Those methods could exist on all platforms; only the mechanism to create an abstract SocketAddr needs to be a platform-specific extension.

This would avoid dealing with TryFrom at all, and would avoid introducing potential inference and compatibility issues as well.

@vorner
Copy link
Contributor

vorner commented Jan 28, 2020

I'd like to chime in on this one. There's one neat use case of the abstract namespace and it's implementing robust lock against running in parallel. You try to bind the address and if it's already in use, some other instance is running. Furthermore, unlike the filesystem based ones, these clean up automatically and you don't have to worry about races around unlinking the old (dead) socket „file“.

@toshokan
Copy link

Sockets with abstract addresses are also often needed to interact with dbus on Linux.
See https://github.com/diwic/dbus-rs/blob/627b42597f13c8f5db3b4259271a5881439c310b/dbus-native/src/sys.rs#L8

GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this issue May 18, 2021
Add abstract namespace support for Unix domain sockets

Hello! The other day I wanted to mess around with UDS in Rust and found that abstract namespaces ([unix(7)](https://man7.org/linux/man-pages/man7/unix.7.html)) on Linux still needed development. I took the approach of adding `_addr` specific public functions to reduce conflicts.

Feature name: `unix_socket_abstract`
Tracking issue: rust-lang#85410
Further context: rust-lang#42048

## Non-platform specific additions

`UnixListener::bind_addr(&SocketAddr) -> Result<UnixListener>`

`UnixStream::connect_addr(&SocketAddr) -> Result<()>`

`UnixDatagram::bind_addr(&SocketAddr) -> Result<UnixDatagram>`

`UnixDatagram::connect_addr(&SocketAddr) -> Result<()>`

`UnixDatagram::send_to_addr(&self, &[u8], &SocketAddr) -> Result<usize>`

## Platform-specific (Linux) additions

`SocketAddr::from_abstract_namespace(&[u8]) -> SocketAddr`

`SockerAddr::as_abstract_namespace() -> Option<&[u8]>`

## Example

```rust
#![feature(unix_socket_abstract)]
use std::os::unix::net::{UnixListener, SocketAddr};

fn main() -> std::io::Result<()> {
    let addr = SocketAddr::from_abstract_namespace(b"namespace")?; // Linux only
    let listener = match UnixListener::bind_addr(&addr) {
        Ok(sock) => sock,
        Err(err) => {
            println!("Couldn't bind: {:?}", err);
            return Err(err);
        }
    };
    Ok(())
}
```

## Further Details

The main inspiration for the implementation came from the [nix-rust](https://github.com/nix-rust/nix/blob/master/src/sys/socket/addr.rs#L558) crate but there are also other [historical](rust-lang@c4db068) [attempts](https://github.com/tormol/uds/blob/master/src/addr.rs#L324) with similar approaches.

A comment I did have was with this change, we now allow a `SocketAddr` to be constructed explicitly rather than just used almost as a handle for the return of `peer_addr` and `local_addr`. We could consider adding other explicit constructors (e.g. `SocketAddr::from_pathname`, `SockerAddr::from_unnamed`).

Cheers!
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue May 18, 2021
…tt,GuillaumeGomez

Add abstract namespace support for Unix domain sockets

Hello! The other day I wanted to mess around with UDS in Rust and found that abstract namespaces ([unix(7)](https://man7.org/linux/man-pages/man7/unix.7.html)) on Linux still needed development. I took the approach of adding `_addr` specific public functions to reduce conflicts.

Feature name: `unix_socket_abstract`
Tracking issue: rust-lang#85410
Further context: rust-lang#42048

## Non-platform specific additions

`UnixListener::bind_addr(&SocketAddr) -> Result<UnixListener>`

`UnixStream::connect_addr(&SocketAddr) -> Result<()>`

`UnixDatagram::bind_addr(&SocketAddr) -> Result<UnixDatagram>`

`UnixDatagram::connect_addr(&SocketAddr) -> Result<()>`

`UnixDatagram::send_to_addr(&self, &[u8], &SocketAddr) -> Result<usize>`

## Platform-specific (Linux) additions

`SocketAddr::from_abstract_namespace(&[u8]) -> SocketAddr`

`SockerAddr::as_abstract_namespace() -> Option<&[u8]>`

## Example

```rust
#![feature(unix_socket_abstract)]
use std::os::unix::net::{UnixListener, SocketAddr};

fn main() -> std::io::Result<()> {
    let addr = SocketAddr::from_abstract_namespace(b"namespace")?; // Linux only
    let listener = match UnixListener::bind_addr(&addr) {
        Ok(sock) => sock,
        Err(err) => {
            println!("Couldn't bind: {:?}", err);
            return Err(err);
        }
    };
    Ok(())
}
```

## Further Details

The main inspiration for the implementation came from the [nix-rust](https://github.com/nix-rust/nix/blob/master/src/sys/socket/addr.rs#L558) crate but there are also other [historical](rust-lang@c4db068) [attempts](https://github.com/tormol/uds/blob/master/src/addr.rs#L324) with similar approaches.

A comment I did have was with this change, we now allow a `SocketAddr` to be constructed explicitly rather than just used almost as a handle for the return of `peer_addr` and `local_addr`. We could consider adding other explicit constructors (e.g. `SocketAddr::from_pathname`, `SockerAddr::from_unnamed`).

Cheers!
bors added a commit to rust-lang-ci/rust that referenced this issue Oct 15, 2021
Add abstract namespace support for Unix domain sockets

Hello! The other day I wanted to mess around with UDS in Rust and found that abstract namespaces ([unix(7)](https://man7.org/linux/man-pages/man7/unix.7.html)) on Linux still needed development. I took the approach of adding `_addr` specific public functions to reduce conflicts.

Feature name: `unix_socket_abstract`
Tracking issue: rust-lang#85410
Further context: rust-lang#42048

## Non-platform specific additions

`UnixListener::bind_addr(&SocketAddr) -> Result<UnixListener>`

`UnixStream::connect_addr(&SocketAddr) -> Result<()>`

`UnixDatagram::bind_addr(&SocketAddr) -> Result<UnixDatagram>`

`UnixDatagram::connect_addr(&SocketAddr) -> Result<()>`

`UnixDatagram::send_to_addr(&self, &[u8], &SocketAddr) -> Result<usize>`

## Platform-specific (Linux) additions

`SocketAddr::from_abstract_namespace(&[u8]) -> SocketAddr`

`SockerAddr::as_abstract_namespace() -> Option<&[u8]>`

## Example

```rust
#![feature(unix_socket_abstract)]
use std::os::unix::net::{UnixListener, SocketAddr};

fn main() -> std::io::Result<()> {
    let addr = SocketAddr::from_abstract_namespace(b"namespace")?; // Linux only
    let listener = match UnixListener::bind_addr(&addr) {
        Ok(sock) => sock,
        Err(err) => {
            println!("Couldn't bind: {:?}", err);
            return Err(err);
        }
    };
    Ok(())
}
```

## Further Details

The main inspiration for the implementation came from the [nix-rust](https://github.com/nix-rust/nix/blob/master/src/sys/socket/addr.rs#L558) crate but there are also other [historical](rust-lang@c4db068) [attempts](https://github.com/tormol/uds/blob/master/src/addr.rs#L324) with similar approaches.

A comment I did have was with this change, we now allow a `SocketAddr` to be constructed explicitly rather than just used almost as a handle for the return of `peer_addr` and `local_addr`. We could consider adding other explicit constructors (e.g. `SocketAddr::from_pathname`, `SockerAddr::from_unnamed`).

Cheers!
@Thomasdezeeuw
Copy link
Contributor

This is now possible by using the std::os::linux::net::SocketAddrExt trait to create abstract namespace addresses and then using std::os::unix::net::UnixStream::connect_addr.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-feature-accepted Category: A feature request that has been accepted pending implementation. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

10 participants