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

add UnboundUdpSocket to std::net #66

Closed
keepsimple1 opened this issue Jul 10, 2022 · 4 comments
Closed

add UnboundUdpSocket to std::net #66

keepsimple1 opened this issue Jul 10, 2022 · 4 comments
Labels
api-change-proposal A proposal to add or alter unstable APIs in the standard libraries T-libs-api

Comments

@keepsimple1
Copy link

keepsimple1 commented Jul 10, 2022

Proposal

Problem statement

Currently std::net does not support socket configurations (i.e. setsockopt) before binding to an address. This is also evident from UDPSocket::bind, TcpListener::bind and TcpStream::connect methods.

Motivation, use-cases

Example 1: setting SO_REUSEADDR is common for UDP sockets but it is not possible using std::net.
Example 2: setting SO_EXCLUSIVEADDRUSE in useful on Windows, but it is not possible using std::net.

Solution sketches

Primary solution

Add a new UnboundUdpSocket to support UDP socket configurations before binding to an address. Once bound, UnboundUdpSocket will be consumed and become a regular UdpSocket. The API looks like this:

pub struct UnboundUdpSocket {
     inner: net_imp::UnboundUdpSocket,
 }

impl UnboundUdpSocket {
    pub fn new(addr_family: SocketAddrFamily) -> io::Result<UnboundUdpSocket>;

    pub fn set_reuseaddr(&self, enable: bool) -> io::Result<()>; // The example use case.

    pub fn bind(self, addr: &SocketAddr) -> io::Result<UdpSocket>;
}

Note:

  • SocketAddrFamily is a new type to simplify creating socket without an address.

Similarly add UnboundTcpSocket to support TCP socket configurations before connecting or binding.

The benefits of this solution:

  1. Compatible with the existing std::net API.
  2. Simple to get started, easy to add more socket configurations gradually.
  3. Using different types to simplify socket state management.

Alternative solution

There have been other solutions suggested in the PR opened earlier. One is adding UDPSocket::new() to
create an unbound UDP socket. I think it has following downsides:

  • Breaking the existing UDPSocket semantics: an UDPSocket is always bound.
  • Adding more complex state management inside UDPSocket.

Links and related work

Original discussion(s)

The original discussion that prompted this proposal is in Rust internal forum.

Existing crate(s)

The most popular crate for socket programming is probably socket2. However, I believe it's worth it to enhance std::net to support socket configurations before binding.

Note that there is also a deprecated crate net2. I just looked its code now and found it was using a Builder pattern which is surprising similar with what I proposed earlier in the internal forum. For the record, I didn't know the design of net2 until now. In any case, the current proposal no longer suggests the Builder pattern and hopefully is different enough from the net2.

PR

I have had opened an PR on this issue before the ACP process came out (AFAIK). Here is the PR.

What happens now?

This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two.

@keepsimple1 keepsimple1 added api-change-proposal A proposal to add or alter unstable APIs in the standard libraries T-libs-api labels Jul 10, 2022
@keepsimple1
Copy link
Author

keepsimple1 commented Aug 2, 2022

Could anyone in libs team please help review / comment on this proposal? It has been here more than 3 weeks. I don't know if it has been looked at by libs team. @rust-lang/libs-impl @rust-lang/libs

@thomcc
Copy link
Member

thomcc commented Oct 20, 2022

Is there a reason this doesn't use a similar Builder pattern to what's proposed on IRLO and is common elsewhere in the stdlib? You mention it in the ACP but don't elaborate on that.

@keepsimple1
Copy link
Author

Is there a reason this doesn't use a similar Builder pattern to what's proposed on IRLO and is common elsewhere in the stdlib? You mention it in the ACP but don't elaborate on that.

The main reason is that I felt that calling out Unbound explicitly in the name helps clarifying its scope and naturally distinguishing from the existing UdpSocket. Also it makes bind() method feel natural.

If we use a Builder pattern and name the new type something like UdpSocketBuilder, there are two downsides I see:

  1. Its name continues the confusion that whether the UdpSocket in stdlib behaves like UDP socket in the regular socket programming world. (It doesn't as it has to be bound).

  2. Most Builder patterns seem to save all configurations before applying all at once when creating the object. In this case, the builder actually already created a UDP socket at the beginning, and then applying configurations. Again, we could argue that this UDP socket is not the final UdpSocket type, but I wanted to avoid such confusion.

@the8472
Copy link
Member

the8472 commented May 18, 2023

We discussed this in the libs meetup. We came to the conclusion that we do want a mechanism to configure unbound sockets but UnboundUdpSocket is too narrow since there are other socket types that need this too and we eventually want to see the socket2 crate (or a polished subset thereof) uplifted to std; but that's a larger project which will require an RFC.
So we're closing this until that larger work can happen

CC @de-vri-es

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-change-proposal A proposal to add or alter unstable APIs in the standard libraries T-libs-api
Projects
None yet
Development

No branches or pull requests

4 participants