Skip to content

Tracking Issue for feature(unix_socket_ancillary_data) #76915

Open
@LinkTed

Description

@LinkTed
Contributor

Tracking issue for feature(unix_socket_ancillary_data) to extend UnixStream and UnixDatagram to send and receive ancillary data. For example file descriptors.

Unresolved Questions

  • Review the SocketAncillary struct before stabilization to ensure it is compatible with all OSes.
  • fuchsia, haiku, illumos, ios, macos and solaris does not have MSG_CMSG_CLOEXEC constant in libc
  • fuchsia and uclibc(x86_64) does not have cmsghdr struct in libc
  • The current version of rust libc does not have ucred struct for the target OS emscripten, but emscripten has this struct in the standard C library

Known bugs/issues

Implementation history

Activity

added
C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
on Sep 19, 2020
added
T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.
on Sep 19, 2020
added
Libs-TrackedLibs issues that are tracked on the team's project board.
on Nov 6, 2020
added
A-ioArea: `std::io`, `std::fs`, `std::net` and `std::path`
O-unixOperating system: Unix-like
on Jan 6, 2021
tadeokondrak

tadeokondrak commented on Feb 25, 2021

@tadeokondrak
Contributor

send_vectored_with_ancillary should switch to non-mutable references for its parameters, since sendmsg doesn't write through them.

#79753 changes just the bufs parameter, but it was closed for inactivity.

(Edit: Hmm, actually changing the ancillary data too would require both a SocketAncillary and SocketAncillaryMut, like IoSlice. Probably not worth it there)

LinkTed

LinkTed commented on Feb 27, 2021

@LinkTed
ContributorAuthor

@tadeokondrak I open a new PR #82589.

LinkTed

LinkTed commented on Mar 7, 2021

@LinkTed
ContributorAuthor

I create a new PR to send and receive TTL for UdpSocket from the ancillary interface. #82858

reyk

reyk commented on Mar 26, 2021

@reyk
Contributor

Hi @LinkTed, I posted a fix in #83374 for macOS, OpenBSD, and possibly other BSDs.

added a commit that references this issue on Mar 29, 2021

Rollup merge of rust-lang#83374 - reyk:fix/bsd-ancillary, r=joshtriplett

772582e
LinkTed

LinkTed commented on Apr 4, 2021

@LinkTed
ContributorAuthor

What has to be done to stabilize this API?

the8472

the8472 commented on Apr 15, 2021

@the8472
Member

I think the API still needs polish. All those niche socket features are tricky and right now it's probably not extensible enough for 3rd party libraries to fill platform-specific gaps such as flags or cmsgs only supported on one particular OS. These basically are wrappers for the recvmsg and sndmsg syscalls, we should expose them in a way that's forwards-compatible so we don't have to add recv_vectored_with_ancillary_from_with_flags or something like that in the future.

Before stabilizing we should consider whether recv_vectored_with_ancillary_from should gain another argument. I would recommend adding a ReceiveOptions argument that allows one to specify flags, similar to OpenOptions. The options could then be used to set linux' MSG_DONTWAIT, MSG_PEEK or MSG_ERRQUEUE for example, maybe via custom_flags() similar to OpenOptions. That way we don't have to support all OS-specific peculiarities.

Or we could put the flags into SocketAncillary or at least reserve the right to do that in the future, but in that case the struct would need to be renamed because it would serve several purposes at once.

Similar could be done for sending.

Additionally the AncillaryData enum should be marked as #[non_exhaustive] and maybe gain a Unknown variant for things that the standard library doesn't support. And a way to get the raw ancillary message. That way one could for example decode struct sock_extended_err in a 3rd party crate without waiting for std to implement it.

LinkTed

LinkTed commented on Apr 17, 2021

@LinkTed
ContributorAuthor

@the8472 Thank you for your feedback. If this PR request is #82858 merged I will start implementing your suggestions.

93 remaining items

jmillikin

jmillikin commented on Oct 26, 2023

@jmillikin
Contributor

The RFC looks like it's moving now (tagged libs-api-nominated) so I've started work on the implementation of non-contentious parts.

purplesyringa

purplesyringa commented on Jan 3, 2024

@purplesyringa
Contributor

As far as I can see, the current implementation is unsound: it takes a user-provided buffer and performs unaligned reads and writes. Is this a known issue?

GrahamBarnett

GrahamBarnett commented on Apr 26, 2024

@GrahamBarnett
  1. Would if be possible to make the constructor public?
  pub fn new(buffer: &'a mut [u8]), current_length: usize, truncated: bool -> Self {
    SocketAncillary { buffer, length: current_length, truncated }
  }

this allows us to work on an existing ancillary buffer or re-use a SocketAncillary on different read buffers if we want, and as a by-product makes testing a lot easier

  1. Please add #[derive(Debug)] to
  SocketCred, 
  ScmRights, 
  AncillaryDataIter<'a, T>
  AncillaryData<'a>

and:

  impl<'a> std::fmt::Debug for ScmRights<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_list()
            .entries(Self(unsafe { AncillaryDataIter::<'a, RawFd>::new(self.0.data) }).collect::<Vec<RawFd>>())
            .finish()
    }
  }
  
  impl<'a> std::fmt::Debug for ScmCredentials<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_list()
            .entries(Self(unsafe { AncillaryDataIter::<'a, libc::ucred>::new(self.0.data) }).collect::<Vec<SocketCred>>())
            .finish()
    }
  }
  
  impl<'a> std::fmt::Debug for Messages<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let messages = Messages{buffer: self.buffer, current: self.current};
        f.debug_list().entries(messages.collect::<Vec<Result<AncillaryData<'a>, AncillaryError>>>()).finish()
    }
  }`

this allows us to println!("{:?}", ancillary.messages()) which makes logging/ debugging a lot easier.
It also means that you can debug the SocketAncillary struct itself (and get buffer status), or can show messages themselves as needed.

  1. I had these changes suggested by the linter on 1.75:
    let data_len = (*cmsg).cmsg_len as usize - cmsg_len_zero; -->linter says should be--> let data_len = cmsg.cmsg_len - cmsg_len_zero;
    match (*cmsg).cmsg_level { -->linter says should be--> match cmsg.cmsg_level {
    cmsg_type: (*cmsg).cmsg_type, -->linter says should be--> cmsg_type: cmsg.cmsg_type,

Many thanks

andrewbaxter

andrewbaxter commented on May 4, 2024

@andrewbaxter
  1. Would if be possible to make the constructor public?

My use case is I don't know exactly where in a stream ancillary data will appear - I'd like to use several reads to parse a message and aggregate ancillary data across them (in a single buffer) to be used at the end. It doesn't appear trivially possible with the current design.

GrahamBarnett

GrahamBarnett commented on May 4, 2024

@GrahamBarnett
MaxVerevkin

MaxVerevkin commented on Sep 16, 2024

@MaxVerevkin

Wouldn't it be better for SocketAncillary's add_creds and add_fds to return a Result<(), NotEnoughSpaceErrror> instead of a bool?

jonleivent

jonleivent commented on Sep 17, 2024

@jonleivent

Would it be better for SocketAncillary::new to take a MaybeUninit buffer? I assume that the original buffer should not be read from after calling SocketAncillary::new. Also, this saves the initialization expense.

the8472

the8472 commented on Sep 17, 2024

@the8472
Member
When initializing a buffer that will contain a series of
              cmsghdr structures (e.g., to be sent with [sendmsg(2)](https://man7.org/linux/man-pages/man2/sendmsg.2.html)),
              that buffer should first be zero-initialized to ensure the
              correct operation of CMSG_NXTHDR().

at least sending it requires zero-initialization anyway.

jonleivent

jonleivent commented on Sep 17, 2024

@jonleivent

that buffer should first be zero-initialized to ensure the
correct operation of CMSG_NXTHDR().

Is that the responsibility of the caller of, or of SocketAncillary::new itself? Because if this is a safety concern, how do you enforce it on the caller? Wouldn't a common mistake be to re-use the buffer for subsequent SocketAncillary::new calls without resetting its contents?

septatrix

septatrix commented on Sep 28, 2024

@septatrix

I see that it currently only includes SO_PASSCRED. What is the reason for that, is support for the other socket options also planned? It seems a bit arbitrary to only support one option but not the others (which are also frequently used)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ioArea: `std::io`, `std::fs`, `std::net` and `std::path`C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCF-unix_socket_ancillary_data`#![feature(unix_socket_ancillary_data)]`Libs-TrackedLibs issues that are tracked on the team's project board.O-unixOperating system: Unix-likeT-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @comex@joshtriplett@tv42@andrewbaxter@jmillikin

        Issue actions

          Tracking Issue for feature(unix_socket_ancillary_data) · Issue #76915 · rust-lang/rust