-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
I just hit a problem in grpc-go (grpc/grpc-go#1058) where their tests were assuming they could write code like this:
lis, err := net.Listen("tcp", ":0")
if err != nil {
t.Fatalf("Failed to listen: %v", err)
}
conn, err := net.Dial("tcp", lis.Addr().String())The code looks reasonable, and often works (on both Go 1.7 and Go 1.8, on Linux and Darwin).
But not always.
lis.Addr().String() returns [::]:NNNNN, which looks like an IPv6 address literal for all zeros (like 0.0.0.0), regardless of whether the machine has IPv6.
And if a machine doesn't have an IPv6 address on the loopback interface, then net.Dial("tcp", "[::]:12345") fails.
But it passes otherwise.
The net.Dial documentation (https://beta.golang.org/pkg/net/#Dial) is kinda fuzzy on whether dialing the all zero address works. It does document and implement this behavior this, though:
If the host is empty, as in ":80", the local system is assumed.
Thus, the solution for gRPC's tests and anybody else is apparently adding something hacky like:
// dialAddr returns a valid net.Dial address to dial using network "tcp".
func dialAddr(ln net.Listener) string {
addr := ln.Addr().String()
addr = strings.TrimPrefix(addr, "[::]")
addr = strings.TrimPrefix(addr, "0.0.0.0")
return addr
}But that's kinda lame and tedious.
Maybe we should just treat a net.Dial of [::] or 0.0.0.0 the same as an empty string for the host part?