net: avoid Shutdown during Close

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
diff --git a/src/pkg/net/dial_test.go b/src/pkg/net/dial_test.go
index bc87551..e5a797e 100644
--- a/src/pkg/net/dial_test.go
+++ b/src/pkg/net/dial_test.go
@@ -114,6 +114,12 @@
 	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 {
diff --git a/src/pkg/net/fd.go b/src/pkg/net/fd.go
index 607a6c1..596cf33 100644
--- a/src/pkg/net/fd.go
+++ b/src/pkg/net/fd.go
@@ -7,6 +7,7 @@
 package net
 
 import (
+	"errors"
 	"io"
 	"os"
 	"sync"
@@ -19,6 +20,9 @@
 	// 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 @@
 	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,19 +90,14 @@
 	deadline   int64 // next deadline (nsec since 1970)
 }
 
-func (s *pollServer) AddFD(fd *netFD, mode int) {
-	intfd := fd.sysfd
-	if intfd < 0 {
-		// fd closed underfoot
-		if mode == 'r' {
-			fd.cr <- true
-		} else {
-			fd.cw <- true
-		}
-		return
-	}
-
+func (s *pollServer) AddFD(fd *netFD, mode int) error {
 	s.Lock()
+	intfd := fd.sysfd
+	if intfd < 0 || fd.closing {
+		// fd closed underfoot
+		s.Unlock()
+		return errClosing
+	}
 
 	var t int64
 	key := intfd << 1
@@ -124,12 +123,28 @@
 	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 @@
 	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 @@
 					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 @@
 				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 @@
 		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) 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 @@
 	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) Close() error {
-	if fd == nil || fd.sysfile == nil {
-		return os.EINVAL
+	pollserver.Lock()  // needed for both fd.incref(true) and pollserver.Evict
+	defer pollserver.Unlock()
+	if err := fd.incref(true); err != nil {
+		return err
 	}
-
-	fd.incref()
-	syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
-	fd.closing = true
+	// 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) 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 {
-			if fd.rdeadline >= 0 {
-				pollserver.WaitRead(fd)
-				continue
-			}
 			err = errTimeout
+			if fd.rdeadline >= 0 {
+				if err = pollserver.WaitRead(fd); err == nil {
+					continue
+				}
+			}
 		}
 		if err != nil {
 			n = 0
@@ -404,49 +442,49 @@
 }
 
 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 {
-			if fd.rdeadline >= 0 {
-				pollserver.WaitRead(fd)
-				continue
-			}
 			err = errTimeout
+			if fd.rdeadline >= 0 {
+				if err = pollserver.WaitRead(fd); err == nil {
+					continue
+				}
+			}
 		}
 		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 {
-			if fd.rdeadline >= 0 {
-				pollserver.WaitRead(fd)
-				continue
-			}
 			err = errTimeout
+			if fd.rdeadline >= 0 {
+				if err = pollserver.WaitRead(fd); err == nil {
+					continue
+				}
+			}
 		}
 		if err == nil && n == 0 {
 			err = io.EOF
@@ -461,12 +499,11 @@
 }
 
 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 @@
 	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 @@
 			break
 		}
 		if err == syscall.EAGAIN {
-			if fd.wdeadline >= 0 {
-				pollserver.WaitWrite(fd)
-				continue
-			}
 			err = errTimeout
+			if fd.wdeadline >= 0 {
+				if err = pollserver.WaitWrite(fd); err == nil {
+					continue
+				}
+			}
 		}
 		if err != nil {
 			n = 0
@@ -506,21 +544,21 @@
 }
 
 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 {
-			if fd.wdeadline >= 0 {
-				pollserver.WaitWrite(fd)
-				continue
-			}
 			err = errTimeout
+			if fd.wdeadline >= 0 {
+				if err = pollserver.WaitWrite(fd); err == nil {
+					continue
+				}
+			}
 		}
 		break
 	}
@@ -533,21 +571,21 @@
 }
 
 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 {
-			if fd.wdeadline >= 0 {
-				pollserver.WaitWrite(fd)
-				continue
-			}
 			err = errTimeout
+			if fd.wdeadline >= 0 {
+				if err = pollserver.WaitWrite(fd); err == nil {
+					continue
+				}
+			}
 		}
 		break
 	}
@@ -561,11 +599,9 @@
 }
 
 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 @@
 	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 {
-				if fd.rdeadline >= 0 {
-					pollserver.WaitRead(fd)
-					continue
-				}
 				err = errTimeout
+				if fd.rdeadline >= 0 {
+					if err = pollserver.WaitRead(fd); err == nil {
+						continue
+					}
+				}
 			}
 			return nil, &OpError{"accept", fd.net, fd.laddr, err}
 		}
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index 78168eb..ee8f162 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -272,11 +272,27 @@
 	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) 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) 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 @@
 	}
 	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 @@
 	}
 	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 @@
 	}
 	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 @@
 	}
 	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 (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.
diff --git a/src/pkg/net/net_test.go b/src/pkg/net/net_test.go
index 3192cd4..9e792a1 100644
--- a/src/pkg/net/net_test.go
+++ b/src/pkg/net/net_test.go
@@ -10,6 +10,7 @@
 	"regexp"
 	"runtime"
 	"testing"
+	"time"
 )
 
 var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors")
@@ -173,3 +174,58 @@
 		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")
+	}
+}
diff --git a/src/pkg/net/sendfile_linux.go b/src/pkg/net/sendfile_linux.go
index ab3a381..a0d5303 100644
--- a/src/pkg/net/sendfile_linux.go
+++ b/src/pkg/net/sendfile_linux.go
@@ -38,7 +38,9 @@
 
 	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 @@
 			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
diff --git a/src/pkg/net/sendfile_windows.go b/src/pkg/net/sendfile_windows.go
index c247477..6f9b4a0 100644
--- a/src/pkg/net/sendfile_windows.go
+++ b/src/pkg/net/sendfile_windows.go
@@ -50,7 +50,9 @@
 
 	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
diff --git a/src/pkg/net/server_test.go b/src/pkg/net/server_test.go
index b0b546b..1d96056 100644
--- a/src/pkg/net/server_test.go
+++ b/src/pkg/net/server_test.go
@@ -83,7 +83,7 @@
 	}
 
 	// 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"))
 	}
diff --git a/src/pkg/net/sockopt.go b/src/pkg/net/sockopt.go
index b5b75a2..0a051d7 100644
--- a/src/pkg/net/sockopt.go
+++ b/src/pkg/net/sockopt.go
@@ -105,13 +105,17 @@
 }
 
 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 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 @@
 		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))
 }
diff --git a/src/pkg/net/sockoptip.go b/src/pkg/net/sockoptip.go
index 90b6f75..1fcad40 100644
--- a/src/pkg/net/sockoptip.go
+++ b/src/pkg/net/sockoptip.go
@@ -14,17 +14,21 @@
 )
 
 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 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 @@
 	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 @@
 	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 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 @@
 	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 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 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 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 @@
 	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 @@
 	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))
 }
diff --git a/src/pkg/net/sockoptip_bsd.go b/src/pkg/net/sockoptip_bsd.go
index 5f7dff2..19e2b14 100644
--- a/src/pkg/net/sockoptip_bsd.go
+++ b/src/pkg/net/sockoptip_bsd.go
@@ -14,17 +14,21 @@
 )
 
 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 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 {
diff --git a/src/pkg/net/sockoptip_darwin.go b/src/pkg/net/sockoptip_darwin.go
index dedfd6f..52b237c 100644
--- a/src/pkg/net/sockoptip_darwin.go
+++ b/src/pkg/net/sockoptip_darwin.go
@@ -12,7 +12,9 @@
 )
 
 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 @@
 	}
 	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 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 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 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 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 {
diff --git a/src/pkg/net/sockoptip_freebsd.go b/src/pkg/net/sockoptip_freebsd.go
index 55f7b1a..4a3bc2e 100644
--- a/src/pkg/net/sockoptip_freebsd.go
+++ b/src/pkg/net/sockoptip_freebsd.go
@@ -12,7 +12,9 @@
 )
 
 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 @@
 		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 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 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 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 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 {
diff --git a/src/pkg/net/sockoptip_linux.go b/src/pkg/net/sockoptip_linux.go
index 360f8de..169718f 100644
--- a/src/pkg/net/sockoptip_linux.go
+++ b/src/pkg/net/sockoptip_linux.go
@@ -12,7 +12,9 @@
 )
 
 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 @@
 		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 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 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 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 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 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 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 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 {
diff --git a/src/pkg/net/sockoptip_openbsd.go b/src/pkg/net/sockoptip_openbsd.go
index 89b8e45..f3e42f1 100644
--- a/src/pkg/net/sockoptip_openbsd.go
+++ b/src/pkg/net/sockoptip_openbsd.go
@@ -12,7 +12,9 @@
 )
 
 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 @@
 	}
 	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 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 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 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 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 {
diff --git a/src/pkg/net/sockoptip_windows.go b/src/pkg/net/sockoptip_windows.go
index a8a9d1c..b9db333 100644
--- a/src/pkg/net/sockoptip_windows.go
+++ b/src/pkg/net/sockoptip_windows.go
@@ -23,7 +23,9 @@
 	}
 	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 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 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 {