diff --git a/src/pkg/net/dial_test.go b/src/pkg/net/dial_test.go index bc875517fbd..e5a797e13bf 100644 --- a/src/pkg/net/dial_test.go +++ b/src/pkg/net/dial_test.go @@ -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 { diff --git a/src/pkg/net/fd.go b/src/pkg/net/fd.go index 607a6c115ac..596cf33004e 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 @@ 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,19 +90,14 @@ type pollServer struct { 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 @@ 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 + 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) 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 { - 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) 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 { - 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) 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 { - 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) 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 { - 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) 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 { - 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) 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 { - 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 78168eb6c86..ee8f162120d 100644 --- a/src/pkg/net/fd_windows.go +++ b/src/pkg/net/fd_windows.go @@ -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. diff --git a/src/pkg/net/net_test.go b/src/pkg/net/net_test.go index 3192cd4a9a2..9e792a1f85c 100644 --- a/src/pkg/net/net_test.go +++ b/src/pkg/net/net_test.go @@ -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") + } +} diff --git a/src/pkg/net/sendfile_linux.go b/src/pkg/net/sendfile_linux.go index ab3a3811fe2..a0d53036263 100644 --- a/src/pkg/net/sendfile_linux.go +++ b/src/pkg/net/sendfile_linux.go @@ -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 diff --git a/src/pkg/net/sendfile_windows.go b/src/pkg/net/sendfile_windows.go index c247477d5af..6f9b4a04c6c 100644 --- a/src/pkg/net/sendfile_windows.go +++ b/src/pkg/net/sendfile_windows.go @@ -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 diff --git a/src/pkg/net/server_test.go b/src/pkg/net/server_test.go index b0b546be32b..1d960565f79 100644 --- a/src/pkg/net/server_test.go +++ b/src/pkg/net/server_test.go @@ -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")) } diff --git a/src/pkg/net/sockopt.go b/src/pkg/net/sockopt.go index b5b75a2745a..0a051d7ae3c 100644 --- a/src/pkg/net/sockopt.go +++ b/src/pkg/net/sockopt.go @@ -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)) } diff --git a/src/pkg/net/sockoptip.go b/src/pkg/net/sockoptip.go index 90b6f751e1d..1fcad4018cc 100644 --- a/src/pkg/net/sockoptip.go +++ b/src/pkg/net/sockoptip.go @@ -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)) } diff --git a/src/pkg/net/sockoptip_bsd.go b/src/pkg/net/sockoptip_bsd.go index 5f7dff248a3..19e2b142e92 100644 --- a/src/pkg/net/sockoptip_bsd.go +++ b/src/pkg/net/sockoptip_bsd.go @@ -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 { diff --git a/src/pkg/net/sockoptip_darwin.go b/src/pkg/net/sockoptip_darwin.go index dedfd6f4c3a..52b237c4b8d 100644 --- a/src/pkg/net/sockoptip_darwin.go +++ b/src/pkg/net/sockoptip_darwin.go @@ -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 { diff --git a/src/pkg/net/sockoptip_freebsd.go b/src/pkg/net/sockoptip_freebsd.go index 55f7b1a6025..4a3bc2e82c8 100644 --- a/src/pkg/net/sockoptip_freebsd.go +++ b/src/pkg/net/sockoptip_freebsd.go @@ -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 { diff --git a/src/pkg/net/sockoptip_linux.go b/src/pkg/net/sockoptip_linux.go index 360f8dea60a..169718f14aa 100644 --- a/src/pkg/net/sockoptip_linux.go +++ b/src/pkg/net/sockoptip_linux.go @@ -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 { diff --git a/src/pkg/net/sockoptip_openbsd.go b/src/pkg/net/sockoptip_openbsd.go index 89b8e459207..f3e42f1a9bc 100644 --- a/src/pkg/net/sockoptip_openbsd.go +++ b/src/pkg/net/sockoptip_openbsd.go @@ -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 { diff --git a/src/pkg/net/sockoptip_windows.go b/src/pkg/net/sockoptip_windows.go index a8a9d1c2bfb..b9db3334d5f 100644 --- a/src/pkg/net/sockoptip_windows.go +++ b/src/pkg/net/sockoptip_windows.go @@ -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 {