Skip to content

bind(::UDPSocket; reuseaddr=true) doesn't always behave as documented on macOS #57900

Open
@maleadt

Description

@maleadt

With bind(::UDPSocket; reuseaddr=true), it's possible to bind the same address multiple times, with only the last bind receiving any traffic. On macOS, that fails for specific addresses, such as 0.0.0.0. This does not cause any errors (I expected -EADDRINUSE) while causing subsequent recvs to hang.

MWE:

using Sockets

const ip = IPv4("0.0.0.0")

let sock = UDPSocket()
    bind(sock, ip, 12345; reuseaddr=true)
    println("Waiting...")
    @show data = recv(sock)
    println("Received ", Base.format_bytes(length(data)))
end

println()

let sock = UDPSocket()
    bind(sock, ip, 12345; reuseaddr=true)
    println("Waiting...")
    @show data = recv(sock)
    println("Received ", Base.format_bytes(length(data)))
end

Meanwhile, in a different terminal, run echo -n test | nc -u 127.0.0.1 12345 or so twice. On macOS, this will result in the second recv call never returning, while on Linux everything works fine.

I haven't looked in the platform specifics of SO_REUSEADDR/SO_REUSEPORT yet -- it seems like quite a mess -- so this may be a platform limitation (as the libuv docs suggest). However, if possible I think we should detect an impossible reuseaddr request and throw an error. If that's not possible, at the very least the docs should warn about it.

Changing the address to 127.0.0.1 works around the issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions