8000 Allow SO_REUSEADDR and SO_REUSEPORT to be set simultaneously (#1623) · miekg/dns@cbe4275 · GitHub
[go: up one dir, main page]

Skip to content

Commit cbe4275

Browse files
Allow SO_REUSEADDR and SO_REUSEPORT to be set simultaneously (#1623)
1 parent b77d1ed commit cbe4275

File tree

3 files changed

+144
-5
lines changed

3 files changed

+144
-5
lines changed

listen_no_reuseport.go renamed to listen_no_socket_options.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@
33

44
package dns
55

6-
import "net"
6+
import (
7+
"fmt"
8+
"net"
9+
)
710

8-
const supportsReusePort = false
11+
const (
12+
supportsReusePort = false
13+
supportsReuseAddr = false
14+
)
915

1016
func listenTCP(network, addr string, reuseport, reuseaddr bool) (net.Listener, error) {
1117
if reuseport || reuseaddr {
@@ -15,12 +21,20 @@ func listenTCP(network, addr string, reuseport, reuseaddr bool) (net.Listener, e
1521
return net.Listen(network, addr)
1622
}
1723

18-
const supportsReuseAddr = false
19-
2024
func listenUDP(network, addr string, reuseport, reuseaddr bool) (net.PacketConn, error) {
2125
if reuseport || reuseaddr {
2226
// TODO(tmthrgd): return an error?
2327
}
2428

2529
return net.ListenPacket(network, addr)
2630
}
31+
32+
// this is just for test compatibility
33+
func checkReuseport(fd uintptr) (bool, error) {
34+
return false, fmt.Errorf("not supported")
35+
}
36+
37+
// this is just for test compatibility
38+
func checkReuseaddr(fd uintptr) (bool, error) {
39+
return false, fmt.Errorf("not supported")
40+
}

listen_reuseport.go renamed to listen_socket_options.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,40 @@ func reuseaddrControl(network, address string, c syscall.RawConn) error {
3939
return opErr
4040
}
4141

42+
func reuseaddrandportControl(network, address string, c syscall.RawConn) error {
43+
err := reuseaddrControl(network, address, c)
44+
if err != nil {
45+
return err
46+
}
47+
48+
return reuseportControl(network, address, c)
49+
}
50+
51+
// this is just for test compatibility
52+
func checkReuseport(fd uintptr) (bool, error) {
53+
v, err := unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT)
54+
if err != nil {
55+
return false, err
56+
}
57+
58+
return v == 1, nil
59+
}
60+
61+
// this is just for test compatibility
62+
func checkReuseaddr(fd uintptr) (bool, error) {
63+
v, err := unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR)
64+
if err != nil {
65+
return false, err
66+
}
67+
68+
return v == 1, nil
69+
}
70+
4271
func listenTCP(network, addr string, reuseport, reuseaddr bool) (net.Listener, error) {
4372
var lc net.ListenConfig
4473
switch {
4574
case reuseaddr && reuseport:
75+
lc.Control = reuseaddrandportControl
4676
case reuseport:
4777
lc.Control = reuseportControl
4878
case reuseaddr:
@@ -56,6 +86,7 @@ func listenUDP(network, addr string, reuseport, reuseaddr bool) (net.PacketConn,
5686
var lc net.ListenConfig
5787
switch {
5888
case reuseaddr && reuseport:
89+
lc.Control = reuseaddrandportControl
5990
case reuseport:
6091
lc.Control = reuseportControl
6192
case reuseaddr:

server_test.go

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,101 @@ func TestServerStartStopRace(t *testing.T) {
996996
wg.Wait()
997997
}
998998

999+
func TestSocketOptions(t *testing.T) {
1000+
if !supportsReuseAddr || !supportsReusePort {
1001+
t.Skip("reuseaddr or reuseport is not supported")
1002+
}
1003+
1004+
testSocketOptions := func(t *testing.T, reuseAddr bool, reusePort bool) {
1005+
wait := make(chan struct{})
1006+
1007+
srv := &Server{
1008+
Net: "udp",
1009+
Addr: ":0",
1010+
ReuseAddr: reuseAddr,
1011+
ReusePort: reusePort,
1012+
}
1013+
1014+
srv.NotifyStartedFunc = func() {
1015+
defer close(wait)
1016+
1017+
conn, ok := srv.PacketConn.(*net.UDPConn)
1018+
if !ok {
1019+
t.Errorf("unexpected conn type: %T", srv.PacketConn)
1020+
return
1021+
}
1022+
1023+
syscallConn, err := conn.SyscallConn()
1024+
if err != nil {
1025+
t.Errorf("cannot cast UDP conn to syscall conn: %v", err)
1026+
return
1027+
1028+
}
1029+
1030+
err = syscallConn.Control(func(fd uintptr) {
1031+
actualReusePort, err := checkReuseport(fd)
1032+
if err != nil {
1033+
t.Errorf("cannot get SO_REUSEPORT socket option: %v", err)
1034+
return
1035+
}
1036+
1037+
if actualReusePort != reusePort {
1038+
t.Errorf("SO_REUSEPORT is %v instead of %v", actualReusePort, reusePort)
1039+
}
1040+
1041+
actualReuseAddr, err := checkReuseaddr(fd)
1042+
if err != nil {
1043+
t.Errorf("cannot get SO_REUSEADDR socket option: %v", err)
1044+
return
1045+
}
1046+
1047+
if actualReuseAddr != reuseAddr {
1048+
t.Errorf("SO_REUSEADDR is %v instead of %v", actualReuseAddr, reusePort)
1049+
}
1050+
})
1051+
if err != nil {
1052+
t.Errorf("cannot check socket options: %v", err)
1053+
}
1054+
}
1055+
1056+
fin := make(chan error, 1)
1057+
go func() {
1058+
fin <- srv.ListenAndServe()
1059+
}()
1060+
1061+
select {
1062+
case <-wait:
1063+
err := srv.Shutdown()
1064+
if err != nil {
1065+
t.Fatalf("cannot shutdown server: %v", err)
1066+
}
1067+
1068+
err = <-fin
1069+
if err != nil {
1070+
t.Fatalf("listen adn serve: %v", err)
1071+
}
1072+
case err := <-fin:
1073+
t.Fatalf("listen adn serve: %v", err)
1074+
}
1075+
}
1076+
1077+
t.Run("no socket options", func(t *testing.T) {
1078+
testSocketOptions(t, false, false)
1079+
})
1080+
1081+
t.Run("SO_REUSEPORT", func(t *testing.T) {
1082+
testSocketOptions(t, false, true)
1083+
})
1084+
1085+
t.Run("SO_REUSEADDR", func(t *testing.T) {
1086+
testSocketOptions(t, true, false)
1087+
})
1088+
1089+
t.Run("SO_REUSEADDR and SO_REUSEPORT", func(t *testing.T) {
1090+
testSocketOptions(t, true, true)
1091+
})
1092+
}
1093+
9991094
func TestServerReuseport(t *testing.T) {
10001095
if !supportsReusePort {
10011096
t.Skip("reuseport is not supported")
@@ -1329,7 +1424,6 @@ func TestResponseWriteSinglePacket(t *testing.T) {
13291424
m.SetQuestion("miek.nl.", TypeTXT)
13301425
m.Response = true
13311426
err := rw.WriteMsg(m)
1332-
13331427
if err != nil {
13341428
t.Fatalf("failed to write: %v", err)
13351429
}

0 commit comments

Comments
 (0)
0