31
}
32
}
34
}
35
36
>
func getFreePort(host string) (int, error) {
freeport.go
37
>
l, err := net.Listen("tcp", host+":0")
38
>
if err != nil {
39
return 0, fmt.Errorf("failed to assign a free port: %v", err)
40
}
42
>
port := l.Addr().(*net.TCPAddr).Port
43
>
44
>
// On Linux and some BSD variants, ephemeral ports are randomized, and may
45
>
// consequently repeat within a short time frame after the listening end
46
>
// has been closed. To avoid this, we make a connection to the port, then
47
>
// close that connection from the server's side (this is very important),
48
>
// which puts the connection in TIME_WAIT state for some time (by default,
49
>
// 60s on Linux). While it remains in that state, the OS will not reallocate
50
>
// that port number for bind(:0) syscalls, yet we are not prevented from
51
>
// explicitly binding to it (thanks to SO_REUSEADDR).
52
>
//
53
>
// On macOS and Windows, the above technique is not necessary, as the OS
54
>
// allocates ephemeral ports sequentially, meaning a port number will only
55
>
// be reused after the entire range has been exhausted. Quite the opposite,
56
>
// given that these OSes use a significantly smaller range for ephemeral
57
>
// ports, making an extra connection just to reserve a port might actually
58
>
// be harmful (by hastening ephemeral port exhaustion).
59
>
if runtime.GOOS != "darwin" && runtime.GOOS != "windows" {
60
>
r, err := net.DialTCP("tcp", nil, l.Addr().(*net.TCPAddr))
61
>
if err != nil {
62
return 0, fmt.Errorf("failed to assign a free port: %v", err)
63
}
65
>
if err != nil {
66
return 0, fmt.Errorf("failed to assign a free port: %v", err)
67
}
68
// Closing the socket from the server side
70
>
defer r.Close()
71
}
72
74
}