Skip to content

Use dual-mode sockets for hostname endpoints to support IPv6-only brokers#361

Merged
Lanayx merged 5 commits into
developfrom
copilot/fix-pulsar-client-ipv6-issue
Jul 7, 2026
Merged

Use dual-mode sockets for hostname endpoints to support IPv6-only brokers#361
Lanayx merged 5 commits into
developfrom
copilot/fix-pulsar-client-ipv6-issue

Conversation

Copilot AI commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Hostname-based broker connections were always created with an IPv4 socket when DnsEndPoint.AddressFamily was Unspecified, which breaks AAAA-only environments. This change moves socket selection into a testable helper and uses a dual-mode IPv6 socket for the hostname/default path while preserving explicit-family and Unix behavior.

  • Connection behavior

    • Added SocketFactory.createSocket in ConnectionPool.fs (internal, unit-testable).
    • Unspecified endpoints now create Socket(AddressFamily.InterNetworkV6, Stream, Tcp) with DualMode <- true.
    • Explicit InterNetwork, InterNetworkV6, and Unix handling remains unchanged from prior semantics.
  • ConnectionPool integration

    • getSocket now delegates socket creation to SocketFactory.createSocket.
    • Existing connection flow, retry path, TLS/SNI setup, and certificate validation logic are unchanged.
  • Unit coverage

    • Added tests/UnitTests/Internal/ConnectionPoolTests.fs.
    • New tests assert:
      • DnsEndPoint(host, port) => IPv6 + dual-mode + TCP stream socket.
      • Explicit IPv4 endpoint => IPv4 + TCP.
      • Explicit IPv6 endpoint => IPv6 + TCP.
    • Wired new test file into tests/UnitTests/UnitTests.fsproj.
module internal SocketFactory =
    let createSocket (endpoint: DnsEndPoint) : Socket =
        match endpoint.AddressFamily with
        | AddressFamily.Unspecified ->
            let socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp)
            socket.DualMode <- true
            socket
        | AddressFamily.Unix ->
            new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified)
        | family ->
            new Socket(family, SocketType.Stream, ProtocolType.Tcp)

Copilot AI changed the title [WIP] Fix Pulsar client connection issue in IPv6-only environments Use dual-mode sockets for hostname endpoints to support IPv6-only brokers Jul 6, 2026
Copilot finished work on behalf of Lanayx July 6, 2026 23:10
Copilot AI requested a review from Lanayx July 6, 2026 23:10
@Lanayx Lanayx marked this pull request as ready for review July 7, 2026 04:39
@Lanayx Lanayx requested a review from Copilot July 7, 2026 04:40

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR updates ConnectionPool socket creation for hostname-based DnsEndPoints so that AddressFamily.Unspecified uses an IPv6 dual-mode socket, enabling connections to IPv6-only (AAAA-only) brokers while keeping explicit address-family behavior testable via a dedicated helper.

Changes:

  • Added internal SocketFactory.createSocket helper and refactored ConnectionPool.getSocket to use it.
  • Changed AddressFamily.Unspecified socket creation to InterNetworkV6 with DualMode <- true.
  • Added unit tests covering socket family selection for unspecified/IPv4/IPv6 endpoints and wired them into the UnitTests project.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/Pulsar.Client/Internal/ConnectionPool.fs Introduces SocketFactory.createSocket and delegates socket creation from getSocket.
tests/UnitTests/Internal/ConnectionPoolTests.fs Adds unit tests for socket family/protocol behavior of SocketFactory.
tests/UnitTests/UnitTests.fsproj Includes the new ConnectionPoolTests.fs in the test project compilation list.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Pulsar.Client/Internal/ConnectionPool.fs
Comment thread tests/UnitTests/Internal/ConnectionPoolTests.fs Outdated
Addresses review feedback: on hosts where IPv6 is disabled/unsupported,
creating an InterNetworkV6 socket can throw and break previously-working
IPv4 hostname connections. Only use a dual-mode IPv6 socket when
Socket.OSSupportsIPv6 is true; otherwise fall back to an IPv4 socket.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread tests/UnitTests/Internal/ConnectionPoolTests.fs Outdated
Addresses review feedback: the production code falls back to an IPv4
socket when Socket.OSSupportsIPv6 is false, so the test should branch its
assertions accordingly to stay portable on IPv6-disabled hosts/containers
(and avoid reading DualMode on an IPv4 socket).

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@Lanayx Lanayx merged commit aa6307d into develop Jul 7, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants