Skip to content

[API Proposal]: ValueTask-based Socket.ConnectAsync overloads for Happy Eyeballs #117548

Open

Description

@antonfirsov

Background and motivation

One of the original motivations behind #861 / #87932 was to utilize Happy Eyeballs in SocketsHttpHandler, see #26177 (comment), however since then the SocketsHttpHandler code has been updated to use the ValueTask overload. Unless we are willing to duplicate code into SocketsHttpHandler, the SAEA overload is insufficient for utilizing Happy Eyeballs in SocketsHttpHandler. Moreover ValueTask-based overloads would be more useful for the general public.

API Proposal

namespace System.Net.Sockets;

public class Socket
{
    // Existing:
    public ValueTask ConnectAsync(EndPoint remoteEP, CancellationToken cancellationToken);
    public static bool ConnectAsync(SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e)

    // Approved in #861 / #87932
    public static bool ConnectAsync(SocketType socketType, ProtocolType protocolType, SocketAsyncEventArgs e, ConnectAlgorithm connectAlgorithm);

    // Proposed:
    public ValueTask ConnectAsync(DnsEndPoint remoteEP, ConnectAlgorithm connectAlgorithm, CancellationToken cancellationToken = default);

    // Also consider (needs more implementation work)
    public ValueTask ConnectAsync(IPAddress[] addresses, int port, ConnectAlgorithm connectAlgorithm, CancellationToken cancellationToken)
}

API Usage

Using DnsEndpoint overload in SocketsHttpHandler (simplified)

public async ValueTask<Stream> ConnectToTcpHostAsync(string host, int port, CancellationToken cancellationToken)
{
    try
    {
        Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp) { NoDelay = true };
        await socket.ConnectAsync(endPoint, ConnectAlgorithm.Parallel, cancellationToken).ConfigureAwait(false);
        return new NetworkStream(socket, ownsSocket: true);
    }
    catch
    {
        socket.Dispose();
        throw;
    }
}

Using IPAddress[] overload in ConnectCallback

using SocketsHttpHandler handler = new SocketsHttpHandler();
handler.ConnectCallback = async (ctx, ct) =>
{
    DnsEndPoint dnsEndPoint = ctx.DnsEndPoint;
    IPAddress[] addresses = await Dns.GetHostAddressesAsync(dnsEndPoint.Host, dnsEndPoint.AddressFamily, ct);

    LogResolvedAdresses(addresses);

    var s = new Socket(SocketType.Stream, ProtocolType.Tcp) { NoDelay = true };
    try
    {
        await s.ConnectAsync(addresses, dnsEndPoint.Port, ConnectAlgorithm.Parallel, ct);
        return new NetworkStream(s, ownsSocket: true);
    }
    catch
    {
        s.Dispose();
        throw;
    }
};

Alternative Designs

No response

Risks

I see no high risks from the API itself, however adaption (#26177) should be done with care.

Activity

  1. added
    api-suggestionEarly API idea and discussion, it is NOT ready for implementation
    on Jul 11, 2025
  2. added
    api-suggestionEarly API idea and discussion, it is NOT ready for implementation
    and removed
    api-suggestionEarly API idea and discussion, it is NOT ready for implementation
    untriagedNew issue has not been triaged by the area owner
    on Jul 11, 2025
  3. dotnet-policy-service commented on Jul 11, 2025

    @dotnet-policy-service
    Contributor

    Tagging subscribers to this area: @dotnet/ncl
    See info in area-owners.md if you want to be subscribed.

  4. removed
    untriagedNew issue has not been triaged by the area owner
    on Jul 15, 2025
  5. added this to the 11.0.0 milestone on Jul 15, 2025
  6. self-assigned this
    on Aug 18, 2025
  7. modified the milestones: 11.0.0, 12.0.0 on Jun 30, 2026
  8. removed their assignment
    on Jul 7, 2026
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

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions