]> Cypherpunks repositories - gostls13.git/commitdiff
net: avoid Shutdown during Close
authorRuss Cox <rsc@golang.org>
Tue, 14 Feb 2012 05:40:37 +0000 (00:40 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 14 Feb 2012 05:40:37 +0000 (00:40 -0500)
Once we've evicted all the blocked I/O, the ref count
should go to zero quickly, so it should be safe to
postpone the close(2) until then.

Fixes #1898.
Fixes #2116.
Fixes #2122.

R=golang-dev, mikioh.mikioh, bradfitz, fullung, iant
CC=golang-dev
https://golang.org/cl/5649076

15 files changed:
src/pkg/net/dial_test.go
src/pkg/net/fd.go
src/pkg/net/fd_windows.go
src/pkg/net/net_test.go
src/pkg/net/sendfile_linux.go
src/pkg/net/sendfile_windows.go
src/pkg/net/server_test.go
src/pkg/net/sockopt.go
src/pkg/net/sockoptip.go
src/pkg/net/sockoptip_bsd.go
src/pkg/net/sockoptip_darwin.go
src/pkg/net/sockoptip_freebsd.go
src/pkg/net/sockoptip_linux.go
src/pkg/net/sockoptip_openbsd.go
src/pkg/net/sockoptip_windows.go

index bc875517fbdbadd15f075b37481892de71d24010..e5a797e13bf6ca0f6e24e64bfe1be3ea0946bcf5 100644 (file)
@@ -114,6 +114,12 @@ func TestSelfConnect(t *testing.T) {
        if testing.Short() {
                n = 1000
        }
+       switch runtime.GOOS {
+       case "darwin", "freebsd", "openbsd", "windows":
+               // Non-Linux systems take a long time to figure
+               // out that there is nothing listening on localhost.
+               n = 100
+       }
        for i := 0; i < n; i++ {
                c, err := Dial("tcp", addr)
                if err == nil {
index 607a6c115ac0e683b923e89dbd97244e0f366be9..596cf33004e2491b24f5c522b2a30b44493f869c 100644 (file)
@@ -7,6 +7,7 @@
 package net
 
 import (
+       "errors"
        "io"
        "os"
        "sync"
@@ -19,6 +20,9 @@ type netFD struct {
        // locking/lifetime of sysfd
        sysmu   sync.Mutex
        sysref  int
+       
+       // must lock both sysmu and pollserver to write
+       // can lock either to read
        closing bool
 
        // immutable until Close
@@ -27,8 +31,8 @@ type netFD struct {
        sotype      int
        isConnected bool
        sysfile     *os.File
-       cr          chan bool
-       cw          chan bool
+       cr          chan error
+       cw          chan error
        net         string
        laddr       Addr
        raddr       Addr
@@ -86,20 +90,15 @@ type pollServer struct {
        deadline   int64 // next deadline (nsec since 1970)
 }
 
-func (s *pollServer) AddFD(fd *netFD, mode int) {
+func (s *pollServer) AddFD(fd *netFD, mode int) error {
+       s.Lock()
        intfd := fd.sysfd
-       if intfd < 0 {
+       if intfd < 0 || fd.closing {
                // fd closed underfoot
-               if mode == 'r' {
-                       fd.cr <- true
-               } else {
-                       fd.cw <- true
-               }
-               return
+               s.Unlock()
+               return errClosing
        }
 
-       s.Lock()
-
        var t int64
        key := intfd << 1
        if mode == 'r' {
@@ -124,12 +123,28 @@ func (s *pollServer) AddFD(fd *netFD, mode int) {
        if wake {
                doWakeup = true
        }
-
        s.Unlock()
 
        if doWakeup {
                s.Wakeup()
        }
+       return nil
+}
+
+// Evict evicts fd from the pending list, unblocking
+// any I/O running on fd.  The caller must have locked
+// pollserver.
+func (s *pollServer) Evict(fd *netFD) {
+       if s.pending[fd.sysfd<<1] == fd {
+               s.WakeFD(fd, 'r', errClosing)
+               s.poll.DelFD(fd.sysfd, 'r')
+               delete(s.pending, fd.sysfd<<1)
+       }
+       if s.pending[fd.sysfd<<1|1] == fd {
+               s.WakeFD(fd, 'w', errClosing)
+               s.poll.DelFD(fd.sysfd, 'w')
+               delete(s.pending, fd.sysfd<<1|1)
+       }
 }
 
 var wakeupbuf [1]byte
@@ -149,16 +164,16 @@ func (s *pollServer) LookupFD(fd int, mode int) *netFD {
        return netfd
 }
 
-func (s *pollServer) WakeFD(fd *netFD, mode int) {
+func (s *pollServer) WakeFD(fd *netFD, mode int, err error) {
        if mode == 'r' {
                for fd.ncr > 0 {
                        fd.ncr--
-                       fd.cr <- true
+                       fd.cr <- err
                }
        } else {
                for fd.ncw > 0 {
                        fd.ncw--
-                       fd.cw <- true
+                       fd.cw <- err
                }
        }
 }
@@ -196,7 +211,7 @@ func (s *pollServer) CheckDeadlines() {
                                        s.poll.DelFD(fd.sysfd, mode)
                                        fd.wdeadline = -1
                                }
-                               s.WakeFD(fd, mode)
+                               s.WakeFD(fd, mode, nil)
                        } else if next_deadline == 0 || t < next_deadline {
                                next_deadline = t
                        }
@@ -240,19 +255,25 @@ func (s *pollServer) Run() {
                                print("pollServer: unexpected wakeup for fd=", fd, " mode=", string(mode), "\n")
                                continue
                        }
-                       s.WakeFD(netfd, mode)
+                       s.WakeFD(netfd, mode, nil)
                }
        }
 }
 
-func (s *pollServer) WaitRead(fd *netFD) {
-       s.AddFD(fd, 'r')
-       <-fd.cr
+func (s *pollServer) WaitRead(fd *netFD) error {
+       err := s.AddFD(fd, 'r')
+       if err == nil {
+               err = <-fd.cr
+       }
+       return err
 }
 
-func (s *pollServer) WaitWrite(fd *netFD) {
-       s.AddFD(fd, 'w')
-       <-fd.cw
+func (s *pollServer) WaitWrite(fd *netFD) error {
+       err := s.AddFD(fd, 'w')
+       if err == nil {
+               err = <-fd.cw
+       }
+       return err
 }
 
 // Network FD methods.
@@ -280,8 +301,8 @@ func newFD(fd, family, sotype int, net string) (*netFD, error) {
                sotype: sotype,
                net:    net,
        }
-       netfd.cr = make(chan bool, 1)
-       netfd.cw = make(chan bool, 1)
+       netfd.cr = make(chan error, 1)
+       netfd.cw = make(chan error, 1)
        return netfd, nil
 }
 
@@ -301,7 +322,9 @@ func (fd *netFD) setAddr(laddr, raddr Addr) {
 func (fd *netFD) connect(ra syscall.Sockaddr) error {
        err := syscall.Connect(fd.sysfd, ra)
        if err == syscall.EINPROGRESS {
-               pollserver.WaitWrite(fd)
+               if err = pollserver.WaitWrite(fd); err != nil {
+                       return err
+               }
                var e int
                e, err = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
                if err != nil {
@@ -314,24 +337,37 @@ func (fd *netFD) connect(ra syscall.Sockaddr) error {
        return err
 }
 
+var errClosing = errors.New("use of closed network connection")
+
 // Add a reference to this fd.
-func (fd *netFD) incref() {
+// If closing==true, pollserver must be locked; mark the fd as closing.
+// Returns an error if the fd cannot be used.
+func (fd *netFD) incref(closing bool) error {
+       if fd == nil {
+               return errClosing
+       }
        fd.sysmu.Lock()
+       if fd.closing {
+               fd.sysmu.Unlock()
+               return errClosing
+       }
        fd.sysref++
+       if closing {
+               fd.closing = true
+       }
        fd.sysmu.Unlock()
+       return nil
 }
 
 // Remove a reference to this FD and close if we've been asked to do so (and
 // there are no references left.
 func (fd *netFD) decref() {
+       if fd == nil {
+               return
+       }
        fd.sysmu.Lock()
        fd.sysref--
-       if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
-               // In case the user has set linger, switch to blocking mode so
-               // the close blocks.  As long as this doesn't happen often, we
-               // can handle the extra OS processes.  Otherwise we'll need to
-               // use the pollserver for Close too.  Sigh.
-               syscall.SetNonblock(fd.sysfd, false)
+       if fd.closing && fd.sysref == 0 && fd.sysfile != nil {
                fd.sysfile.Close()
                fd.sysfile = nil
                fd.sysfd = -1
@@ -340,21 +376,26 @@ func (fd *netFD) decref() {
 }
 
 func (fd *netFD) Close() error {
-       if fd == nil || fd.sysfile == nil {
-               return os.EINVAL
-       }
-
-       fd.incref()
-       syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
-       fd.closing = true
+       pollserver.Lock()  // needed for both fd.incref(true) and pollserver.Evict
+       defer pollserver.Unlock()
+       if err := fd.incref(true); err != nil {
+               return err
+       }
+       // Unblock any I/O.  Once it all unblocks and returns,
+       // so that it cannot be referring to fd.sysfd anymore,
+       // the final decref will close fd.sysfd.  This should happen
+       // fairly quickly, since all the I/O is non-blocking, and any
+       // attempts to block in the pollserver will return errClosing.
+       pollserver.Evict(fd)
        fd.decref()
        return nil
 }
 
 func (fd *netFD) shutdown(how int) error {
-       if fd == nil || fd.sysfile == nil {
-               return os.EINVAL
+       if err := fd.incref(false); err != nil {
+               return err
        }
+       defer fd.decref()
        err := syscall.Shutdown(fd.sysfd, how)
        if err != nil {
                return &OpError{"shutdown", fd.net, fd.laddr, err}
@@ -371,24 +412,21 @@ func (fd *netFD) CloseWrite() error {
 }
 
 func (fd *netFD) Read(p []byte) (n int, err error) {
-       if fd == nil {
-               return 0, os.EINVAL
-       }
        fd.rio.Lock()
        defer fd.rio.Unlock()
-       fd.incref()
-       defer fd.decref()
-       if fd.sysfile == nil {
-               return 0, os.EINVAL
+       if err := fd.incref(false); err != nil {
+               return 0, err
        }
+       defer fd.decref()
        for {
-               n, err = syscall.Read(int(fd.sysfile.Fd()), p)
+               n, err = syscall.Read(int(fd.sysfd), p)
                if err == syscall.EAGAIN {
+                       err = errTimeout
                        if fd.rdeadline >= 0 {
-                               pollserver.WaitRead(fd)
-                               continue
+                               if err = pollserver.WaitRead(fd); err == nil {
+                                       continue
+                               }
                        }
-                       err = errTimeout
                }
                if err != nil {
                        n = 0
@@ -404,49 +442,49 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
 }
 
 func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
-       if fd == nil || fd.sysfile == nil {
-               return 0, nil, os.EINVAL
-       }
        fd.rio.Lock()
        defer fd.rio.Unlock()
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return 0, nil, err
+       }
        defer fd.decref()
        for {
                n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
                if err == syscall.EAGAIN {
+                       err = errTimeout
                        if fd.rdeadline >= 0 {
-                               pollserver.WaitRead(fd)
-                               continue
+                               if err = pollserver.WaitRead(fd); err == nil {
+                                       continue
+                               }
                        }
-                       err = errTimeout
                }
                if err != nil {
                        n = 0
                }
                break
        }
-       if err != nil {
+       if err != nil && err != io.EOF {
                err = &OpError{"read", fd.net, fd.laddr, err}
        }
        return
 }
 
 func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
-       if fd == nil || fd.sysfile == nil {
-               return 0, 0, 0, nil, os.EINVAL
-       }
        fd.rio.Lock()
        defer fd.rio.Unlock()
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return 0, 0, 0, nil, err
+       }
        defer fd.decref()
        for {
                n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
                if err == syscall.EAGAIN {
+                       err = errTimeout
                        if fd.rdeadline >= 0 {
-                               pollserver.WaitRead(fd)
-                               continue
+                               if err = pollserver.WaitRead(fd); err == nil {
+                                       continue
+                               }
                        }
-                       err = errTimeout
                }
                if err == nil && n == 0 {
                        err = io.EOF
@@ -461,12 +499,11 @@ func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
 }
 
 func (fd *netFD) Write(p []byte) (int, error) {
-       if fd == nil {
-               return 0, os.EINVAL
-       }
        fd.wio.Lock()
        defer fd.wio.Unlock()
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return 0, err
+       }
        defer fd.decref()
        if fd.sysfile == nil {
                return 0, os.EINVAL
@@ -476,7 +513,7 @@ func (fd *netFD) Write(p []byte) (int, error) {
        nn := 0
        for {
                var n int
-               n, err = syscall.Write(int(fd.sysfile.Fd()), p[nn:])
+               n, err = syscall.Write(int(fd.sysfd), p[nn:])
                if n > 0 {
                        nn += n
                }
@@ -484,11 +521,12 @@ func (fd *netFD) Write(p []byte) (int, error) {
                        break
                }
                if err == syscall.EAGAIN {
+                       err = errTimeout
                        if fd.wdeadline >= 0 {
-                               pollserver.WaitWrite(fd)
-                               continue
+                               if err = pollserver.WaitWrite(fd); err == nil {
+                                       continue
+                               }
                        }
-                       err = errTimeout
                }
                if err != nil {
                        n = 0
@@ -506,21 +544,21 @@ func (fd *netFD) Write(p []byte) (int, error) {
 }
 
 func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
-       if fd == nil || fd.sysfile == nil {
-               return 0, os.EINVAL
-       }
        fd.wio.Lock()
        defer fd.wio.Unlock()
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return 0, err
+       }
        defer fd.decref()
        for {
                err = syscall.Sendto(fd.sysfd, p, 0, sa)
                if err == syscall.EAGAIN {
+                       err = errTimeout
                        if fd.wdeadline >= 0 {
-                               pollserver.WaitWrite(fd)
-                               continue
+                               if err = pollserver.WaitWrite(fd); err == nil {
+                                       continue
+                               }
                        }
-                       err = errTimeout
                }
                break
        }
@@ -533,21 +571,21 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
 }
 
 func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
-       if fd == nil || fd.sysfile == nil {
-               return 0, 0, os.EINVAL
-       }
        fd.wio.Lock()
        defer fd.wio.Unlock()
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return 0, 0, err
+       }
        defer fd.decref()
        for {
                err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
                if err == syscall.EAGAIN {
+                       err = errTimeout
                        if fd.wdeadline >= 0 {
-                               pollserver.WaitWrite(fd)
-                               continue
+                               if err = pollserver.WaitWrite(fd); err == nil {
+                                       continue
+                               }
                        }
-                       err = errTimeout
                }
                break
        }
@@ -561,11 +599,9 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
 }
 
 func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err error) {
-       if fd == nil || fd.sysfile == nil {
-               return nil, os.EINVAL
+       if err := fd.incref(false); err != nil {
+               return nil, err
        }
-
-       fd.incref()
        defer fd.decref()
 
        // See ../syscall/exec.go for description of ForkLock.
@@ -574,19 +610,17 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err e
        var s int
        var rsa syscall.Sockaddr
        for {
-               if fd.closing {
-                       return nil, os.EINVAL
-               }
                syscall.ForkLock.RLock()
                s, rsa, err = syscall.Accept(fd.sysfd)
                if err != nil {
                        syscall.ForkLock.RUnlock()
                        if err == syscall.EAGAIN {
+                               err = errTimeout
                                if fd.rdeadline >= 0 {
-                                       pollserver.WaitRead(fd)
-                                       continue
+                                       if err = pollserver.WaitRead(fd); err == nil {
+                                               continue
+                                       }
                                }
-                               err = errTimeout
                        }
                        return nil, &OpError{"accept", fd.net, fd.laddr, err}
                }
index 78168eb6c861436f43bdd8ee5c6e6753eaa66bc1..ee8f162120dd148becffecd73ab01bd8852dc650 100644 (file)
@@ -272,11 +272,27 @@ func (fd *netFD) connect(ra syscall.Sockaddr) error {
        return syscall.Connect(fd.sysfd, ra)
 }
 
+var errClosing = errors.New("use of closed network connection")
+
 // Add a reference to this fd.
-func (fd *netFD) incref() {
+// If closing==true, mark the fd as closing.
+// Returns an error if the fd cannot be used.
+func (fd *netFD) incref(closing bool) error {
+       if fd == nil {
+               return errClosing
+       }
        fd.sysmu.Lock()
+       if fd.closing {
+               fd.sysmu.Unlock()
+               return errClosing
+       }
        fd.sysref++
+       if closing {
+               fd.closing = true
+       }
+       closing = fd.closing
        fd.sysmu.Unlock()
+       return nil
 }
 
 // Remove a reference to this FD and close if we've been asked to do so (and
@@ -284,7 +300,17 @@ func (fd *netFD) incref() {
 func (fd *netFD) decref() {
        fd.sysmu.Lock()
        fd.sysref--
-       if fd.closing && fd.sysref == 0 && fd.sysfd != syscall.InvalidHandle {
+       // NOTE(rsc): On Unix we check fd.sysref == 0 here before closing,
+       // but on Windows we have no way to wake up the blocked I/O other
+       // than closing the socket (or calling Shutdown, which breaks other
+       // programs that might have a reference to the socket).  So there is
+       // a small race here that we might close fd.sysfd and then some other
+       // goroutine might start a read of fd.sysfd (having read it before we
+       // write InvalidHandle to it), which might refer to some other file
+       // if the specific handle value gets reused.  I think handle values on
+       // Windows are not reused as aggressively as file descriptors on Unix,
+       // so this might be tolerable.
+       if fd.closing && fd.sysfd != syscall.InvalidHandle {
                // In case the user has set linger, switch to blocking mode so
                // the close blocks.  As long as this doesn't happen often, we
                // can handle the extra OS processes.  Otherwise we'll need to
@@ -299,13 +325,9 @@ func (fd *netFD) decref() {
 }
 
 func (fd *netFD) Close() error {
-       if fd == nil || fd.sysfd == syscall.InvalidHandle {
-               return os.EINVAL
+       if err := fd.incref(true); err != nil {
+               return err
        }
-
-       fd.incref()
-       syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
-       fd.closing = true
        fd.decref()
        return nil
 }
@@ -350,7 +372,9 @@ func (fd *netFD) Read(buf []byte) (int, error) {
        }
        fd.rio.Lock()
        defer fd.rio.Unlock()
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return 0, err
+       }
        defer fd.decref()
        if fd.sysfd == syscall.InvalidHandle {
                return 0, os.EINVAL
@@ -390,11 +414,10 @@ func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
        }
        fd.rio.Lock()
        defer fd.rio.Unlock()
-       fd.incref()
-       defer fd.decref()
-       if fd.sysfd == syscall.InvalidHandle {
-               return 0, nil, os.EINVAL
+       if err := fd.incref(false); err != nil {
+               return 0, nil, err
        }
+       defer fd.decref()
        var o readFromOp
        o.Init(fd, buf, 'r')
        o.rsan = int32(unsafe.Sizeof(o.rsa))
@@ -427,11 +450,10 @@ func (fd *netFD) Write(buf []byte) (int, error) {
        }
        fd.wio.Lock()
        defer fd.wio.Unlock()
-       fd.incref()
-       defer fd.decref()
-       if fd.sysfd == syscall.InvalidHandle {
-               return 0, os.EINVAL
+       if err := fd.incref(false); err != nil {
+               return 0, err
        }
+       defer fd.decref()
        var o writeOp
        o.Init(fd, buf, 'w')
        return iosrv.ExecIO(&o, fd.wdeadline)
@@ -462,7 +484,9 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
        }
        fd.wio.Lock()
        defer fd.wio.Unlock()
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return 0, err
+       }
        defer fd.decref()
        if fd.sysfd == syscall.InvalidHandle {
                return 0, os.EINVAL
@@ -493,10 +517,9 @@ func (o *acceptOp) Name() string {
 }
 
 func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
-       if fd == nil || fd.sysfd == syscall.InvalidHandle {
-               return nil, os.EINVAL
+       if err := fd.incref(false); err != nil {
+               return 0, err
        }
-       fd.incref()
        defer fd.decref()
 
        // Get new socket.
index 3192cd4a9a251290a7666cabf2c977dd14d0f8e0..9e792a1f85c1cc480ed04717289b3c4d77fca45d 100644 (file)
@@ -10,6 +10,7 @@ import (
        "regexp"
        "runtime"
        "testing"
+       "time"
 )
 
 var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors")
@@ -173,3 +174,58 @@ func TestShutdown(t *testing.T) {
                t.Errorf("read = %q, want \"response\"", got)
        }
 }
+
+func TestTCPListenClose(t *testing.T) {
+       l, err := Listen("tcp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatalf("Listen failed: %v", err)
+       }
+
+       done := make(chan bool, 1)
+       go func() {
+               time.Sleep(100 * time.Millisecond)
+               l.Close()
+       }()
+       go func() {
+               _, err = l.Accept()
+               if err == nil {
+                       t.Error("Accept succeeded")
+               } else {
+                       t.Logf("Accept timeout error: %s (any error is fine)", err)
+               }
+               done <- true
+       }()
+       select {
+       case <-done:
+       case <-time.After(2 * time.Second):
+               t.Fatal("timeout waiting for TCP close")
+       }
+}
+
+func TestUDPListenClose(t *testing.T) {
+       l, err := ListenPacket("udp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatalf("Listen failed: %v", err)
+       }
+
+       buf := make([]byte, 1000)
+       done := make(chan bool, 1)
+       go func() {
+               time.Sleep(100 * time.Millisecond)
+               l.Close()
+       }()
+       go func() {
+               _, _, err = l.ReadFrom(buf)
+               if err == nil {
+                       t.Error("ReadFrom succeeded")
+               } else {
+                       t.Logf("ReadFrom timeout error: %s (any error is fine)", err)
+               }
+               done <- true
+       }()
+       select {
+       case <-done:
+       case <-time.After(2 * time.Second):
+               t.Fatal("timeout waiting for UDP close")
+       }
+}
index ab3a3811fe2ea9ac9b776d418e72f182068d10d7..a0d53036263e6f1f93e9bc0a92432c2fff3873d4 100644 (file)
@@ -38,7 +38,9 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 
        c.wio.Lock()
        defer c.wio.Unlock()
-       c.incref()
+       if err := c.incref(false); err != nil {
+               return 0, err, true
+       }
        defer c.decref()
 
        dst := c.sysfd
@@ -57,8 +59,9 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
                        break
                }
                if err1 == syscall.EAGAIN && c.wdeadline >= 0 {
-                       pollserver.WaitWrite(c)
-                       continue
+                       if err1 = pollserver.WaitWrite(c); err1 == nil {
+                               continue
+                       }
                }
                if err1 != nil {
                        // This includes syscall.ENOSYS (no kernel
index c247477d5af7769bd2b369a5f196d7bb50d40d67..6f9b4a04c6cfb1ea9a217b41e027b580ed28be58 100644 (file)
@@ -50,7 +50,9 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 
        c.wio.Lock()
        defer c.wio.Unlock()
-       c.incref()
+       if err := c.incref(); err != nil {
+               return 0, err, true
+       }
        defer c.decref()
 
        var o sendfileOp
index b0b546be32b7047d2dfd19023f3e6d818813fdaa..1d960565f795978c8fb644b0613f36a001372d82 100644 (file)
@@ -83,7 +83,7 @@ func connect(t *testing.T, network, addr string, isEmpty bool) {
        }
 
        // Send explicit ending for unixpacket.
-       // Older Linux kernels do stop reads on close.
+       // Older Linux kernels do not stop reads on close.
        if network == "unixpacket" {
                fd.Write([]byte("END"))
        }
index b5b75a2745ac80a609f42c04ccb6d49afcc06e7f..0a051d7ae3c6ec0ce82497333deb8a91ebeeb13a 100644 (file)
@@ -105,13 +105,17 @@ done:
 }
 
 func setReadBuffer(fd *netFD, bytes int) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes))
 }
 
 func setWriteBuffer(fd *netFD, bytes int) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes))
 }
@@ -142,25 +146,33 @@ func setDeadline(fd *netFD, t time.Time) error {
 }
 
 func setReuseAddr(fd *netFD, reuse bool) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse)))
 }
 
 func setDontRoute(fd *netFD, dontroute bool) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute)))
 }
 
 func setKeepAlive(fd *netFD, keepalive bool) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive)))
 }
 
 func setNoDelay(fd *netFD, noDelay bool) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay)))
 }
@@ -174,7 +186,9 @@ func setLinger(fd *netFD, sec int) error {
                l.Onoff = 0
                l.Linger = 0
        }
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        return os.NewSyscallError("setsockopt", syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l))
 }
index 90b6f751e1d3ffaaafe9f8c3ee08079862b99e54..1fcad4018cc7df378b66886538a895675446f5cb 100644 (file)
@@ -14,17 +14,21 @@ import (
 )
 
 func ipv4TOS(fd *netFD) (int, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return 0, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TOS)
        if err != nil {
-               return -1, os.NewSyscallError("getsockopt", err)
+               return 0, os.NewSyscallError("getsockopt", err)
        }
        return v, nil
 }
 
 func setIPv4TOS(fd *netFD, v int) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TOS, v)
        if err != nil {
@@ -34,17 +38,21 @@ func setIPv4TOS(fd *netFD, v int) error {
 }
 
 func ipv4TTL(fd *netFD) (int, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return 0, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TTL)
        if err != nil {
-               return -1, os.NewSyscallError("getsockopt", err)
+               return 0, os.NewSyscallError("getsockopt", err)
        }
        return v, nil
 }
 
 func setIPv4TTL(fd *netFD, v int) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TTL, v)
        if err != nil {
@@ -58,7 +66,9 @@ func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
        if err := setIPv4MreqToInterface(mreq, ifi); err != nil {
                return err
        }
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq))
 }
@@ -68,23 +78,29 @@ func leaveIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
        if err := setIPv4MreqToInterface(mreq, ifi); err != nil {
                return err
        }
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq))
 }
 
 func ipv6HopLimit(fd *netFD) (int, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return 0, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS)
        if err != nil {
-               return -1, os.NewSyscallError("getsockopt", err)
+               return 0, os.NewSyscallError("getsockopt", err)
        }
        return v, nil
 }
 
 func setIPv6HopLimit(fd *netFD, v int) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS, v)
        if err != nil {
@@ -94,7 +110,9 @@ func setIPv6HopLimit(fd *netFD, v int) error {
 }
 
 func ipv6MulticastInterface(fd *netFD) (*Interface, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return nil, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF)
        if err != nil {
@@ -115,7 +133,9 @@ func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
        if ifi != nil {
                v = ifi.Index
        }
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF, v)
        if err != nil {
@@ -125,17 +145,21 @@ func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
 }
 
 func ipv6MulticastHopLimit(fd *netFD) (int, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return 0, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_HOPS)
        if err != nil {
-               return -1, os.NewSyscallError("getsockopt", err)
+               return 0, os.NewSyscallError("getsockopt", err)
        }
        return v, nil
 }
 
 func setIPv6MulticastHopLimit(fd *netFD, v int) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_HOPS, v)
        if err != nil {
@@ -145,7 +169,9 @@ func setIPv6MulticastHopLimit(fd *netFD, v int) error {
 }
 
 func ipv6MulticastLoopback(fd *netFD) (bool, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return false, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP)
        if err != nil {
@@ -155,7 +181,9 @@ func ipv6MulticastLoopback(fd *netFD) (bool, error) {
 }
 
 func setIPv6MulticastLoopback(fd *netFD, v bool) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP, boolint(v))
        if err != nil {
@@ -170,7 +198,9 @@ func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
        if ifi != nil {
                mreq.Interface = uint32(ifi.Index)
        }
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq))
 }
@@ -181,7 +211,9 @@ func leaveIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
        if ifi != nil {
                mreq.Interface = uint32(ifi.Index)
        }
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_LEAVE_GROUP, mreq))
 }
index 5f7dff248a3ff15a575d67fbad7fee60f7ad3dfb..19e2b142e92a5760f97a04fe778aa0a466ece599 100644 (file)
@@ -14,17 +14,21 @@ import (
 )
 
 func ipv4MulticastTTL(fd *netFD) (int, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return 0, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL)
        if err != nil {
-               return -1, os.NewSyscallError("getsockopt", err)
+               return 0, os.NewSyscallError("getsockopt", err)
        }
        return int(v), nil
 }
 
 func setIPv4MulticastTTL(fd *netFD, v int) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, byte(v))
        if err != nil {
@@ -34,17 +38,21 @@ func setIPv4MulticastTTL(fd *netFD, v int) error {
 }
 
 func ipv6TrafficClass(fd *netFD) (int, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return 0, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS)
        if err != nil {
-               return -1, os.NewSyscallError("getsockopt", err)
+               return 0, os.NewSyscallError("getsockopt", err)
        }
        return v, nil
 }
 
 func setIPv6TrafficClass(fd *netFD, v int) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS, v)
        if err != nil {
index dedfd6f4c3aa8c65a6cc7af7ddca7c98c857ef0b..52b237c4b8db8ba77984d7fd64c845501bad815e 100644 (file)
@@ -12,7 +12,9 @@ import (
 )
 
 func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return nil, err
+       }
        defer fd.decref()
        a, err := syscall.GetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
        if err != nil {
@@ -28,7 +30,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
        }
        var x [4]byte
        copy(x[:], ip.To4())
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
        if err != nil {
@@ -38,7 +42,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
 }
 
 func ipv4MulticastLoopback(fd *netFD) (bool, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return false, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
        if err != nil {
@@ -48,7 +54,9 @@ func ipv4MulticastLoopback(fd *netFD) (bool, error) {
 }
 
 func setIPv4MulticastLoopback(fd *netFD, v bool) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
        if err != nil {
@@ -58,7 +66,9 @@ func setIPv4MulticastLoopback(fd *netFD, v bool) error {
 }
 
 func ipv4ReceiveInterface(fd *netFD) (bool, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return false, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF)
        if err != nil {
@@ -68,7 +78,9 @@ func ipv4ReceiveInterface(fd *netFD) (bool, error) {
 }
 
 func setIPv4ReceiveInterface(fd *netFD, v bool) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v))
        if err != nil {
index 55f7b1a60250a27456c184405f856c6671fa8125..4a3bc2e82c8b200959a408e1aa49e3cf6eea4b7c 100644 (file)
@@ -12,7 +12,9 @@ import (
 )
 
 func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return nil, err
+       }
        defer fd.decref()
        mreq, err := syscall.GetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
        if err != nil {
@@ -30,7 +32,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
                v = int32(ifi.Index)
        }
        mreq := &syscall.IPMreqn{Ifindex: v}
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq)
        if err != nil {
@@ -40,7 +44,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
 }
 
 func ipv4MulticastLoopback(fd *netFD) (bool, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return false, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
        if err != nil {
@@ -50,7 +56,9 @@ func ipv4MulticastLoopback(fd *netFD) (bool, error) {
 }
 
 func setIPv4MulticastLoopback(fd *netFD, v bool) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
        if err != nil {
@@ -60,7 +68,9 @@ func setIPv4MulticastLoopback(fd *netFD, v bool) error {
 }
 
 func ipv4ReceiveInterface(fd *netFD) (bool, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return false, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF)
        if err != nil {
@@ -70,7 +80,9 @@ func ipv4ReceiveInterface(fd *netFD) (bool, error) {
 }
 
 func setIPv4ReceiveInterface(fd *netFD, v bool) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v))
        if err != nil {
index 360f8dea60a3e5bea570379ce2e25132266de8eb..169718f14aa9d0070130899ea02a9ebf0d183903 100644 (file)
@@ -12,7 +12,9 @@ import (
 )
 
 func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return nil, err
+       }
        defer fd.decref()
        mreq, err := syscall.GetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
        if err != nil {
@@ -30,7 +32,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
                v = int32(ifi.Index)
        }
        mreq := &syscall.IPMreqn{Ifindex: v}
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq)
        if err != nil {
@@ -40,7 +44,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
 }
 
 func ipv4MulticastTTL(fd *netFD) (int, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return 0, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL)
        if err != nil {
@@ -50,7 +56,9 @@ func ipv4MulticastTTL(fd *netFD) (int, error) {
 }
 
 func setIPv4MulticastTTL(fd *netFD, v int) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, v)
        if err != nil {
@@ -60,7 +68,9 @@ func setIPv4MulticastTTL(fd *netFD, v int) error {
 }
 
 func ipv4MulticastLoopback(fd *netFD) (bool, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return false, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
        if err != nil {
@@ -70,7 +80,9 @@ func ipv4MulticastLoopback(fd *netFD) (bool, error) {
 }
 
 func setIPv4MulticastLoopback(fd *netFD, v bool) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
        if err != nil {
@@ -80,7 +92,9 @@ func setIPv4MulticastLoopback(fd *netFD, v bool) error {
 }
 
 func ipv4ReceiveInterface(fd *netFD) (bool, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return false, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_PKTINFO)
        if err != nil {
@@ -90,7 +104,9 @@ func ipv4ReceiveInterface(fd *netFD) (bool, error) {
 }
 
 func setIPv4ReceiveInterface(fd *netFD, v bool) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_PKTINFO, boolint(v))
        if err != nil {
@@ -100,17 +116,21 @@ func setIPv4ReceiveInterface(fd *netFD, v bool) error {
 }
 
 func ipv6TrafficClass(fd *netFD) (int, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return 0, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS)
        if err != nil {
-               return -1, os.NewSyscallError("getsockopt", err)
+               return 0, os.NewSyscallError("getsockopt", err)
        }
        return v, nil
 }
 
 func setIPv6TrafficClass(fd *netFD, v int) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS, v)
        if err != nil {
index 89b8e4592079430b59882baf7d06a11c268b7b2c..f3e42f1a9bcf3f2913882033e1f7c8aba77ca9ac 100644 (file)
@@ -12,7 +12,9 @@ import (
 )
 
 func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return nil, err
+       }
        defer fd.decref()
        a, err := syscall.GetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
        if err != nil {
@@ -28,7 +30,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
        }
        var x [4]byte
        copy(x[:], ip.To4())
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
        if err != nil {
@@ -38,7 +42,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
 }
 
 func ipv4MulticastLoopback(fd *netFD) (bool, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return false, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
        if err != nil {
@@ -48,7 +54,9 @@ func ipv4MulticastLoopback(fd *netFD) (bool, error) {
 }
 
 func setIPv4MulticastLoopback(fd *netFD, v bool) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, byte(boolint(v)))
        if err != nil {
@@ -58,7 +66,9 @@ func setIPv4MulticastLoopback(fd *netFD, v bool) error {
 }
 
 func ipv4ReceiveInterface(fd *netFD) (bool, error) {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return false, err
+       }
        defer fd.decref()
        v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF)
        if err != nil {
@@ -68,7 +78,9 @@ func ipv4ReceiveInterface(fd *netFD) (bool, error) {
 }
 
 func setIPv4ReceiveInterface(fd *netFD, v bool) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v))
        if err != nil {
index a8a9d1c2bfb4787501ebd3312de3806732a34397..b9db3334d5ff47b059b93a01bcc19e74a9530350 100644 (file)
@@ -23,7 +23,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
        }
        var x [4]byte
        copy(x[:], ip.To4())
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
        if err != nil {
@@ -38,7 +40,9 @@ func ipv4MulticastTTL(fd *netFD) (int, error) {
 }
 
 func setIPv4MulticastTTL(fd *netFD, v int) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, v)
        if err != nil {
@@ -54,7 +58,9 @@ func ipv4MulticastLoopback(fd *netFD) (bool, error) {
 }
 
 func setIPv4MulticastLoopback(fd *netFD, v bool) error {
-       fd.incref()
+       if err := fd.incref(false); err != nil {
+               return err
+       }
        defer fd.decref()
        err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
        if err != nil {