Set UDP conn to non-blocking on Linux to fix Shutdown()

The call to conn.File() causes Go to call dup() and then set the resulting FD
to be blocking. This sets the FD back to non-blocking, allowing Shutdown() to
work properly.

Fixes #279.
This commit is contained in:
Ryan Leavengood 2015-12-01 17:15:42 -05:00
parent f520760857
commit 7b51cba64a
2 changed files with 27 additions and 3 deletions

View File

@ -39,9 +39,15 @@ func AnotherHelloServer(w ResponseWriter, req *Msg) {
}
func RunLocalUDPServer(laddr string) (*Server, string, error) {
server, l, _, err := RunLocalUDPServerWithFinChan(laddr)
return server, l, err
}
func RunLocalUDPServerWithFinChan(laddr string) (*Server, string, chan struct{}, error) {
pc, err := net.ListenPacket("udp", laddr)
if err != nil {
return nil, "", err
return nil, "", nil, err
}
server := &Server{PacketConn: pc, ReadTimeout: time.Hour, WriteTimeout: time.Hour}
@ -49,13 +55,16 @@ func RunLocalUDPServer(laddr string) (*Server, string, error) {
waitLock.Lock()
server.NotifyStartedFunc = waitLock.Unlock
fin := make(chan struct{}, 0)
go func() {
server.ActivateAndServe()
close(fin)
pc.Close()
}()
waitLock.Lock()
return server, pc.LocalAddr().String(), nil
return server, pc.LocalAddr().String(), fin, nil
}
func RunLocalUDPServerUnsafe(laddr string) (*Server, string, error) {
@ -448,7 +457,7 @@ func TestHandlerCloseTCP(t *testing.T) {
}
func TestShutdownUDP(t *testing.T) {
s, _, err := RunLocalUDPServer("127.0.0.1:0")
s, _, fin, err := RunLocalUDPServerWithFinChan("127.0.0.1:0")
if err != nil {
t.Fatalf("unable to run test server: %v", err)
}
@ -456,6 +465,11 @@ func TestShutdownUDP(t *testing.T) {
if err != nil {
t.Errorf("could not shutdown test UDP server, %v", err)
}
select {
case <-fin:
case <-time.After(2 * time.Second):
t.Error("Could not shutdown test UDP server. Gave up waiting")
}
}
type ExampleFrameLengthWriter struct {

View File

@ -24,6 +24,12 @@ func setUDPSocketOptions4(conn *net.UDPConn) error {
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil {
return err
}
// Calling File() above results in the connection becoming blocking, we must fix that.
// See https://github.com/miekg/dns/issues/279
err = syscall.SetNonblock(int(file.Fd()), true)
if err != nil {
return err
}
return nil
}
@ -36,6 +42,10 @@ func setUDPSocketOptions6(conn *net.UDPConn) error {
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil {
return err
}
err = syscall.SetNonblock(int(file.Fd()), true)
if err != nil {
return err
}
return nil
}