mirror of
https://github.com/golang/go
synced 2024-11-25 10:07:56 -07:00
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
This commit is contained in:
parent
b7360b9b06
commit
5e4e3d8e44
@ -114,6 +114,12 @@ func TestSelfConnect(t *testing.T) {
|
|||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
n = 1000
|
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++ {
|
for i := 0; i < n; i++ {
|
||||||
c, err := Dial("tcp", addr)
|
c, err := Dial("tcp", addr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
@ -19,6 +20,9 @@ type netFD struct {
|
|||||||
// locking/lifetime of sysfd
|
// locking/lifetime of sysfd
|
||||||
sysmu sync.Mutex
|
sysmu sync.Mutex
|
||||||
sysref int
|
sysref int
|
||||||
|
|
||||||
|
// must lock both sysmu and pollserver to write
|
||||||
|
// can lock either to read
|
||||||
closing bool
|
closing bool
|
||||||
|
|
||||||
// immutable until Close
|
// immutable until Close
|
||||||
@ -27,8 +31,8 @@ type netFD struct {
|
|||||||
sotype int
|
sotype int
|
||||||
isConnected bool
|
isConnected bool
|
||||||
sysfile *os.File
|
sysfile *os.File
|
||||||
cr chan bool
|
cr chan error
|
||||||
cw chan bool
|
cw chan error
|
||||||
net string
|
net string
|
||||||
laddr Addr
|
laddr Addr
|
||||||
raddr Addr
|
raddr Addr
|
||||||
@ -86,19 +90,14 @@ type pollServer struct {
|
|||||||
deadline int64 // next deadline (nsec since 1970)
|
deadline int64 // next deadline (nsec since 1970)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pollServer) AddFD(fd *netFD, mode int) {
|
func (s *pollServer) AddFD(fd *netFD, mode int) error {
|
||||||
intfd := fd.sysfd
|
|
||||||
if intfd < 0 {
|
|
||||||
// fd closed underfoot
|
|
||||||
if mode == 'r' {
|
|
||||||
fd.cr <- true
|
|
||||||
} else {
|
|
||||||
fd.cw <- true
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Lock()
|
s.Lock()
|
||||||
|
intfd := fd.sysfd
|
||||||
|
if intfd < 0 || fd.closing {
|
||||||
|
// fd closed underfoot
|
||||||
|
s.Unlock()
|
||||||
|
return errClosing
|
||||||
|
}
|
||||||
|
|
||||||
var t int64
|
var t int64
|
||||||
key := intfd << 1
|
key := intfd << 1
|
||||||
@ -124,12 +123,28 @@ func (s *pollServer) AddFD(fd *netFD, mode int) {
|
|||||||
if wake {
|
if wake {
|
||||||
doWakeup = true
|
doWakeup = true
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Unlock()
|
s.Unlock()
|
||||||
|
|
||||||
if doWakeup {
|
if doWakeup {
|
||||||
s.Wakeup()
|
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
|
var wakeupbuf [1]byte
|
||||||
@ -149,16 +164,16 @@ func (s *pollServer) LookupFD(fd int, mode int) *netFD {
|
|||||||
return netfd
|
return netfd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pollServer) WakeFD(fd *netFD, mode int) {
|
func (s *pollServer) WakeFD(fd *netFD, mode int, err error) {
|
||||||
if mode == 'r' {
|
if mode == 'r' {
|
||||||
for fd.ncr > 0 {
|
for fd.ncr > 0 {
|
||||||
fd.ncr--
|
fd.ncr--
|
||||||
fd.cr <- true
|
fd.cr <- err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for fd.ncw > 0 {
|
for fd.ncw > 0 {
|
||||||
fd.ncw--
|
fd.ncw--
|
||||||
fd.cw <- true
|
fd.cw <- err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,7 +211,7 @@ func (s *pollServer) CheckDeadlines() {
|
|||||||
s.poll.DelFD(fd.sysfd, mode)
|
s.poll.DelFD(fd.sysfd, mode)
|
||||||
fd.wdeadline = -1
|
fd.wdeadline = -1
|
||||||
}
|
}
|
||||||
s.WakeFD(fd, mode)
|
s.WakeFD(fd, mode, nil)
|
||||||
} else if next_deadline == 0 || t < next_deadline {
|
} else if next_deadline == 0 || t < next_deadline {
|
||||||
next_deadline = t
|
next_deadline = t
|
||||||
}
|
}
|
||||||
@ -240,19 +255,25 @@ func (s *pollServer) Run() {
|
|||||||
print("pollServer: unexpected wakeup for fd=", fd, " mode=", string(mode), "\n")
|
print("pollServer: unexpected wakeup for fd=", fd, " mode=", string(mode), "\n")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
s.WakeFD(netfd, mode)
|
s.WakeFD(netfd, mode, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pollServer) WaitRead(fd *netFD) {
|
func (s *pollServer) WaitRead(fd *netFD) error {
|
||||||
s.AddFD(fd, 'r')
|
err := s.AddFD(fd, 'r')
|
||||||
<-fd.cr
|
if err == nil {
|
||||||
|
err = <-fd.cr
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *pollServer) WaitWrite(fd *netFD) {
|
func (s *pollServer) WaitWrite(fd *netFD) error {
|
||||||
s.AddFD(fd, 'w')
|
err := s.AddFD(fd, 'w')
|
||||||
<-fd.cw
|
if err == nil {
|
||||||
|
err = <-fd.cw
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Network FD methods.
|
// Network FD methods.
|
||||||
@ -280,8 +301,8 @@ func newFD(fd, family, sotype int, net string) (*netFD, error) {
|
|||||||
sotype: sotype,
|
sotype: sotype,
|
||||||
net: net,
|
net: net,
|
||||||
}
|
}
|
||||||
netfd.cr = make(chan bool, 1)
|
netfd.cr = make(chan error, 1)
|
||||||
netfd.cw = make(chan bool, 1)
|
netfd.cw = make(chan error, 1)
|
||||||
return netfd, nil
|
return netfd, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +322,9 @@ func (fd *netFD) setAddr(laddr, raddr Addr) {
|
|||||||
func (fd *netFD) connect(ra syscall.Sockaddr) error {
|
func (fd *netFD) connect(ra syscall.Sockaddr) error {
|
||||||
err := syscall.Connect(fd.sysfd, ra)
|
err := syscall.Connect(fd.sysfd, ra)
|
||||||
if err == syscall.EINPROGRESS {
|
if err == syscall.EINPROGRESS {
|
||||||
pollserver.WaitWrite(fd)
|
if err = pollserver.WaitWrite(fd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
var e int
|
var e int
|
||||||
e, err = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
|
e, err = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -314,24 +337,37 @@ func (fd *netFD) connect(ra syscall.Sockaddr) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errClosing = errors.New("use of closed network connection")
|
||||||
|
|
||||||
// Add a reference to this fd.
|
// 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()
|
fd.sysmu.Lock()
|
||||||
fd.sysref++
|
if fd.closing {
|
||||||
fd.sysmu.Unlock()
|
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
|
// Remove a reference to this FD and close if we've been asked to do so (and
|
||||||
// there are no references left.
|
// there are no references left.
|
||||||
func (fd *netFD) decref() {
|
func (fd *netFD) decref() {
|
||||||
|
if fd == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
fd.sysmu.Lock()
|
fd.sysmu.Lock()
|
||||||
fd.sysref--
|
fd.sysref--
|
||||||
if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
|
if fd.closing && fd.sysref == 0 && fd.sysfile != nil {
|
||||||
// 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)
|
|
||||||
fd.sysfile.Close()
|
fd.sysfile.Close()
|
||||||
fd.sysfile = nil
|
fd.sysfile = nil
|
||||||
fd.sysfd = -1
|
fd.sysfd = -1
|
||||||
@ -340,21 +376,26 @@ func (fd *netFD) decref() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) Close() error {
|
func (fd *netFD) Close() error {
|
||||||
if fd == nil || fd.sysfile == nil {
|
pollserver.Lock() // needed for both fd.incref(true) and pollserver.Evict
|
||||||
return os.EINVAL
|
defer pollserver.Unlock()
|
||||||
|
if err := fd.incref(true); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
// Unblock any I/O. Once it all unblocks and returns,
|
||||||
fd.incref()
|
// so that it cannot be referring to fd.sysfd anymore,
|
||||||
syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
|
// the final decref will close fd.sysfd. This should happen
|
||||||
fd.closing = true
|
// 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()
|
fd.decref()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) shutdown(how int) error {
|
func (fd *netFD) shutdown(how int) error {
|
||||||
if fd == nil || fd.sysfile == nil {
|
if err := fd.incref(false); err != nil {
|
||||||
return os.EINVAL
|
return err
|
||||||
}
|
}
|
||||||
|
defer fd.decref()
|
||||||
err := syscall.Shutdown(fd.sysfd, how)
|
err := syscall.Shutdown(fd.sysfd, how)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &OpError{"shutdown", fd.net, fd.laddr, err}
|
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) {
|
func (fd *netFD) Read(p []byte) (n int, err error) {
|
||||||
if fd == nil {
|
|
||||||
return 0, os.EINVAL
|
|
||||||
}
|
|
||||||
fd.rio.Lock()
|
fd.rio.Lock()
|
||||||
defer fd.rio.Unlock()
|
defer fd.rio.Unlock()
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
defer fd.decref()
|
return 0, err
|
||||||
if fd.sysfile == nil {
|
|
||||||
return 0, os.EINVAL
|
|
||||||
}
|
}
|
||||||
|
defer fd.decref()
|
||||||
for {
|
for {
|
||||||
n, err = syscall.Read(int(fd.sysfile.Fd()), p)
|
n, err = syscall.Read(int(fd.sysfd), p)
|
||||||
if err == syscall.EAGAIN {
|
if err == syscall.EAGAIN {
|
||||||
|
err = errTimeout
|
||||||
if fd.rdeadline >= 0 {
|
if fd.rdeadline >= 0 {
|
||||||
pollserver.WaitRead(fd)
|
if err = pollserver.WaitRead(fd); err == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = errTimeout
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n = 0
|
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) {
|
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()
|
fd.rio.Lock()
|
||||||
defer fd.rio.Unlock()
|
defer fd.rio.Unlock()
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
for {
|
for {
|
||||||
n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
|
n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
|
||||||
if err == syscall.EAGAIN {
|
if err == syscall.EAGAIN {
|
||||||
|
err = errTimeout
|
||||||
if fd.rdeadline >= 0 {
|
if fd.rdeadline >= 0 {
|
||||||
pollserver.WaitRead(fd)
|
if err = pollserver.WaitRead(fd); err == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = errTimeout
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n = 0
|
n = 0
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil && err != io.EOF {
|
||||||
err = &OpError{"read", fd.net, fd.laddr, err}
|
err = &OpError{"read", fd.net, fd.laddr, err}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
|
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()
|
fd.rio.Lock()
|
||||||
defer fd.rio.Unlock()
|
defer fd.rio.Unlock()
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return 0, 0, 0, nil, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
for {
|
for {
|
||||||
n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
|
n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
|
||||||
if err == syscall.EAGAIN {
|
if err == syscall.EAGAIN {
|
||||||
|
err = errTimeout
|
||||||
if fd.rdeadline >= 0 {
|
if fd.rdeadline >= 0 {
|
||||||
pollserver.WaitRead(fd)
|
if err = pollserver.WaitRead(fd); err == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = errTimeout
|
}
|
||||||
}
|
}
|
||||||
if err == nil && n == 0 {
|
if err == nil && n == 0 {
|
||||||
err = io.EOF
|
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) {
|
func (fd *netFD) Write(p []byte) (int, error) {
|
||||||
if fd == nil {
|
|
||||||
return 0, os.EINVAL
|
|
||||||
}
|
|
||||||
fd.wio.Lock()
|
fd.wio.Lock()
|
||||||
defer fd.wio.Unlock()
|
defer fd.wio.Unlock()
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
if fd.sysfile == nil {
|
if fd.sysfile == nil {
|
||||||
return 0, os.EINVAL
|
return 0, os.EINVAL
|
||||||
@ -476,7 +513,7 @@ func (fd *netFD) Write(p []byte) (int, error) {
|
|||||||
nn := 0
|
nn := 0
|
||||||
for {
|
for {
|
||||||
var n int
|
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 {
|
if n > 0 {
|
||||||
nn += n
|
nn += n
|
||||||
}
|
}
|
||||||
@ -484,11 +521,12 @@ func (fd *netFD) Write(p []byte) (int, error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err == syscall.EAGAIN {
|
if err == syscall.EAGAIN {
|
||||||
|
err = errTimeout
|
||||||
if fd.wdeadline >= 0 {
|
if fd.wdeadline >= 0 {
|
||||||
pollserver.WaitWrite(fd)
|
if err = pollserver.WaitWrite(fd); err == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = errTimeout
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
n = 0
|
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) {
|
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()
|
fd.wio.Lock()
|
||||||
defer fd.wio.Unlock()
|
defer fd.wio.Unlock()
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
for {
|
for {
|
||||||
err = syscall.Sendto(fd.sysfd, p, 0, sa)
|
err = syscall.Sendto(fd.sysfd, p, 0, sa)
|
||||||
if err == syscall.EAGAIN {
|
if err == syscall.EAGAIN {
|
||||||
|
err = errTimeout
|
||||||
if fd.wdeadline >= 0 {
|
if fd.wdeadline >= 0 {
|
||||||
pollserver.WaitWrite(fd)
|
if err = pollserver.WaitWrite(fd); err == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = errTimeout
|
}
|
||||||
}
|
}
|
||||||
break
|
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) {
|
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()
|
fd.wio.Lock()
|
||||||
defer fd.wio.Unlock()
|
defer fd.wio.Unlock()
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
for {
|
for {
|
||||||
err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
|
err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
|
||||||
if err == syscall.EAGAIN {
|
if err == syscall.EAGAIN {
|
||||||
|
err = errTimeout
|
||||||
if fd.wdeadline >= 0 {
|
if fd.wdeadline >= 0 {
|
||||||
pollserver.WaitWrite(fd)
|
if err = pollserver.WaitWrite(fd); err == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = errTimeout
|
}
|
||||||
}
|
}
|
||||||
break
|
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) {
|
func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err error) {
|
||||||
if fd == nil || fd.sysfile == nil {
|
if err := fd.incref(false); err != nil {
|
||||||
return nil, os.EINVAL
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fd.incref()
|
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
|
|
||||||
// See ../syscall/exec.go for description of ForkLock.
|
// 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 s int
|
||||||
var rsa syscall.Sockaddr
|
var rsa syscall.Sockaddr
|
||||||
for {
|
for {
|
||||||
if fd.closing {
|
|
||||||
return nil, os.EINVAL
|
|
||||||
}
|
|
||||||
syscall.ForkLock.RLock()
|
syscall.ForkLock.RLock()
|
||||||
s, rsa, err = syscall.Accept(fd.sysfd)
|
s, rsa, err = syscall.Accept(fd.sysfd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
syscall.ForkLock.RUnlock()
|
syscall.ForkLock.RUnlock()
|
||||||
if err == syscall.EAGAIN {
|
if err == syscall.EAGAIN {
|
||||||
|
err = errTimeout
|
||||||
if fd.rdeadline >= 0 {
|
if fd.rdeadline >= 0 {
|
||||||
pollserver.WaitRead(fd)
|
if err = pollserver.WaitRead(fd); err == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = errTimeout
|
}
|
||||||
}
|
}
|
||||||
return nil, &OpError{"accept", fd.net, fd.laddr, err}
|
return nil, &OpError{"accept", fd.net, fd.laddr, err}
|
||||||
}
|
}
|
||||||
|
@ -272,11 +272,27 @@ func (fd *netFD) connect(ra syscall.Sockaddr) error {
|
|||||||
return syscall.Connect(fd.sysfd, ra)
|
return syscall.Connect(fd.sysfd, ra)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errClosing = errors.New("use of closed network connection")
|
||||||
|
|
||||||
// Add a reference to this fd.
|
// 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()
|
fd.sysmu.Lock()
|
||||||
fd.sysref++
|
if fd.closing {
|
||||||
fd.sysmu.Unlock()
|
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
|
// 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() {
|
func (fd *netFD) decref() {
|
||||||
fd.sysmu.Lock()
|
fd.sysmu.Lock()
|
||||||
fd.sysref--
|
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
|
// In case the user has set linger, switch to blocking mode so
|
||||||
// the close blocks. As long as this doesn't happen often, we
|
// the close blocks. As long as this doesn't happen often, we
|
||||||
// can handle the extra OS processes. Otherwise we'll need to
|
// can handle the extra OS processes. Otherwise we'll need to
|
||||||
@ -299,13 +325,9 @@ func (fd *netFD) decref() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) Close() error {
|
func (fd *netFD) Close() error {
|
||||||
if fd == nil || fd.sysfd == syscall.InvalidHandle {
|
if err := fd.incref(true); err != nil {
|
||||||
return os.EINVAL
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fd.incref()
|
|
||||||
syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
|
|
||||||
fd.closing = true
|
|
||||||
fd.decref()
|
fd.decref()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -350,7 +372,9 @@ func (fd *netFD) Read(buf []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
fd.rio.Lock()
|
fd.rio.Lock()
|
||||||
defer fd.rio.Unlock()
|
defer fd.rio.Unlock()
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
if fd.sysfd == syscall.InvalidHandle {
|
if fd.sysfd == syscall.InvalidHandle {
|
||||||
return 0, os.EINVAL
|
return 0, os.EINVAL
|
||||||
@ -390,11 +414,10 @@ func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
|
|||||||
}
|
}
|
||||||
fd.rio.Lock()
|
fd.rio.Lock()
|
||||||
defer fd.rio.Unlock()
|
defer fd.rio.Unlock()
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
defer fd.decref()
|
return 0, nil, err
|
||||||
if fd.sysfd == syscall.InvalidHandle {
|
|
||||||
return 0, nil, os.EINVAL
|
|
||||||
}
|
}
|
||||||
|
defer fd.decref()
|
||||||
var o readFromOp
|
var o readFromOp
|
||||||
o.Init(fd, buf, 'r')
|
o.Init(fd, buf, 'r')
|
||||||
o.rsan = int32(unsafe.Sizeof(o.rsa))
|
o.rsan = int32(unsafe.Sizeof(o.rsa))
|
||||||
@ -427,11 +450,10 @@ func (fd *netFD) Write(buf []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
fd.wio.Lock()
|
fd.wio.Lock()
|
||||||
defer fd.wio.Unlock()
|
defer fd.wio.Unlock()
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
defer fd.decref()
|
return 0, err
|
||||||
if fd.sysfd == syscall.InvalidHandle {
|
|
||||||
return 0, os.EINVAL
|
|
||||||
}
|
}
|
||||||
|
defer fd.decref()
|
||||||
var o writeOp
|
var o writeOp
|
||||||
o.Init(fd, buf, 'w')
|
o.Init(fd, buf, 'w')
|
||||||
return iosrv.ExecIO(&o, fd.wdeadline)
|
return iosrv.ExecIO(&o, fd.wdeadline)
|
||||||
@ -462,7 +484,9 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
|
|||||||
}
|
}
|
||||||
fd.wio.Lock()
|
fd.wio.Lock()
|
||||||
defer fd.wio.Unlock()
|
defer fd.wio.Unlock()
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
if fd.sysfd == syscall.InvalidHandle {
|
if fd.sysfd == syscall.InvalidHandle {
|
||||||
return 0, os.EINVAL
|
return 0, os.EINVAL
|
||||||
@ -493,10 +517,9 @@ func (o *acceptOp) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
|
func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
|
||||||
if fd == nil || fd.sysfd == syscall.InvalidHandle {
|
if err := fd.incref(false); err != nil {
|
||||||
return nil, os.EINVAL
|
return 0, err
|
||||||
}
|
}
|
||||||
fd.incref()
|
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
|
|
||||||
// Get new socket.
|
// Get new socket.
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors")
|
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)
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -38,7 +38,9 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
|
|||||||
|
|
||||||
c.wio.Lock()
|
c.wio.Lock()
|
||||||
defer c.wio.Unlock()
|
defer c.wio.Unlock()
|
||||||
c.incref()
|
if err := c.incref(false); err != nil {
|
||||||
|
return 0, err, true
|
||||||
|
}
|
||||||
defer c.decref()
|
defer c.decref()
|
||||||
|
|
||||||
dst := c.sysfd
|
dst := c.sysfd
|
||||||
@ -57,9 +59,10 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err1 == syscall.EAGAIN && c.wdeadline >= 0 {
|
if err1 == syscall.EAGAIN && c.wdeadline >= 0 {
|
||||||
pollserver.WaitWrite(c)
|
if err1 = pollserver.WaitWrite(c); err1 == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
// This includes syscall.ENOSYS (no kernel
|
// This includes syscall.ENOSYS (no kernel
|
||||||
// support) and syscall.EINVAL (fd types which
|
// support) and syscall.EINVAL (fd types which
|
||||||
|
@ -50,7 +50,9 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
|
|||||||
|
|
||||||
c.wio.Lock()
|
c.wio.Lock()
|
||||||
defer c.wio.Unlock()
|
defer c.wio.Unlock()
|
||||||
c.incref()
|
if err := c.incref(); err != nil {
|
||||||
|
return 0, err, true
|
||||||
|
}
|
||||||
defer c.decref()
|
defer c.decref()
|
||||||
|
|
||||||
var o sendfileOp
|
var o sendfileOp
|
||||||
|
@ -83,7 +83,7 @@ func connect(t *testing.T, network, addr string, isEmpty bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send explicit ending for unixpacket.
|
// 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" {
|
if network == "unixpacket" {
|
||||||
fd.Write([]byte("END"))
|
fd.Write([]byte("END"))
|
||||||
}
|
}
|
||||||
|
@ -105,13 +105,17 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setReadBuffer(fd *netFD, bytes int) error {
|
func setReadBuffer(fd *netFD, bytes int) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes))
|
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
func setWriteBuffer(fd *netFD, bytes int) error {
|
func setWriteBuffer(fd *netFD, bytes int) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes))
|
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 {
|
func setReuseAddr(fd *netFD, reuse bool) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse)))
|
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func setDontRoute(fd *netFD, dontroute bool) error {
|
func setDontRoute(fd *netFD, dontroute bool) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute)))
|
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func setKeepAlive(fd *netFD, keepalive bool) error {
|
func setKeepAlive(fd *netFD, keepalive bool) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive)))
|
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func setNoDelay(fd *netFD, noDelay bool) error {
|
func setNoDelay(fd *netFD, noDelay bool) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay)))
|
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.Onoff = 0
|
||||||
l.Linger = 0
|
l.Linger = 0
|
||||||
}
|
}
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l))
|
return os.NewSyscallError("setsockopt", syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l))
|
||||||
}
|
}
|
||||||
|
@ -14,17 +14,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ipv4TOS(fd *netFD) (int, error) {
|
func ipv4TOS(fd *netFD) (int, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TOS)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TOS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, os.NewSyscallError("getsockopt", err)
|
return 0, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIPv4TOS(fd *netFD, v int) error {
|
func setIPv4TOS(fd *netFD, v int) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TOS, v)
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TOS, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -34,17 +38,21 @@ func setIPv4TOS(fd *netFD, v int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ipv4TTL(fd *netFD) (int, error) {
|
func ipv4TTL(fd *netFD) (int, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TTL)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TTL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, os.NewSyscallError("getsockopt", err)
|
return 0, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIPv4TTL(fd *netFD, v int) error {
|
func setIPv4TTL(fd *netFD, v int) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TTL, v)
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TTL, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -58,7 +66,9 @@ func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error {
|
|||||||
if err := setIPv4MreqToInterface(mreq, ifi); err != nil {
|
if err := setIPv4MreqToInterface(mreq, ifi); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq))
|
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 {
|
if err := setIPv4MreqToInterface(mreq, ifi); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq))
|
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq))
|
||||||
}
|
}
|
||||||
|
|
||||||
func ipv6HopLimit(fd *netFD) (int, error) {
|
func ipv6HopLimit(fd *netFD) (int, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, os.NewSyscallError("getsockopt", err)
|
return 0, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIPv6HopLimit(fd *netFD, v int) error {
|
func setIPv6HopLimit(fd *netFD, v int) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS, v)
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -94,7 +110,9 @@ func setIPv6HopLimit(fd *netFD, v int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ipv6MulticastInterface(fd *netFD) (*Interface, error) {
|
func ipv6MulticastInterface(fd *netFD) (*Interface, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -115,7 +133,9 @@ func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
|
|||||||
if ifi != nil {
|
if ifi != nil {
|
||||||
v = ifi.Index
|
v = ifi.Index
|
||||||
}
|
}
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF, v)
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -125,17 +145,21 @@ func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ipv6MulticastHopLimit(fd *netFD) (int, error) {
|
func ipv6MulticastHopLimit(fd *netFD) (int, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_HOPS)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_HOPS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, os.NewSyscallError("getsockopt", err)
|
return 0, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIPv6MulticastHopLimit(fd *netFD, v int) error {
|
func setIPv6MulticastHopLimit(fd *netFD, v int) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_HOPS, v)
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_HOPS, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -145,7 +169,9 @@ func setIPv6MulticastHopLimit(fd *netFD, v int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ipv6MulticastLoopback(fd *netFD) (bool, error) {
|
func ipv6MulticastLoopback(fd *netFD) (bool, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -155,7 +181,9 @@ func ipv6MulticastLoopback(fd *netFD) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setIPv6MulticastLoopback(fd *netFD, v bool) error {
|
func setIPv6MulticastLoopback(fd *netFD, v bool) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP, boolint(v))
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP, boolint(v))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -170,7 +198,9 @@ func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error {
|
|||||||
if ifi != nil {
|
if ifi != nil {
|
||||||
mreq.Interface = uint32(ifi.Index)
|
mreq.Interface = uint32(ifi.Index)
|
||||||
}
|
}
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq))
|
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 {
|
if ifi != nil {
|
||||||
mreq.Interface = uint32(ifi.Index)
|
mreq.Interface = uint32(ifi.Index)
|
||||||
}
|
}
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_LEAVE_GROUP, mreq))
|
return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_LEAVE_GROUP, mreq))
|
||||||
}
|
}
|
||||||
|
@ -14,17 +14,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ipv4MulticastTTL(fd *netFD) (int, error) {
|
func ipv4MulticastTTL(fd *netFD) (int, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL)
|
v, err := syscall.GetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, os.NewSyscallError("getsockopt", err)
|
return 0, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return int(v), nil
|
return int(v), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIPv4MulticastTTL(fd *netFD, v int) error {
|
func setIPv4MulticastTTL(fd *netFD, v int) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, byte(v))
|
err := syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, byte(v))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -34,17 +38,21 @@ func setIPv4MulticastTTL(fd *netFD, v int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ipv6TrafficClass(fd *netFD) (int, error) {
|
func ipv6TrafficClass(fd *netFD) (int, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, os.NewSyscallError("getsockopt", err)
|
return 0, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIPv6TrafficClass(fd *netFD, v int) error {
|
func setIPv6TrafficClass(fd *netFD, v int) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS, v)
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -12,7 +12,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
|
func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
a, err := syscall.GetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
|
a, err := syscall.GetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -28,7 +30,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
|
|||||||
}
|
}
|
||||||
var x [4]byte
|
var x [4]byte
|
||||||
copy(x[:], ip.To4())
|
copy(x[:], ip.To4())
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
|
err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -38,7 +42,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ipv4MulticastLoopback(fd *netFD) (bool, error) {
|
func ipv4MulticastLoopback(fd *netFD) (bool, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -48,7 +54,9 @@ func ipv4MulticastLoopback(fd *netFD) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
|
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -58,7 +66,9 @@ func setIPv4MulticastLoopback(fd *netFD, v bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ipv4ReceiveInterface(fd *netFD) (bool, error) {
|
func ipv4ReceiveInterface(fd *netFD) (bool, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -68,7 +78,9 @@ func ipv4ReceiveInterface(fd *netFD) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setIPv4ReceiveInterface(fd *netFD, v bool) error {
|
func setIPv4ReceiveInterface(fd *netFD, v bool) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v))
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -12,7 +12,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
|
func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
mreq, err := syscall.GetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
|
mreq, err := syscall.GetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -30,7 +32,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
|
|||||||
v = int32(ifi.Index)
|
v = int32(ifi.Index)
|
||||||
}
|
}
|
||||||
mreq := &syscall.IPMreqn{Ifindex: v}
|
mreq := &syscall.IPMreqn{Ifindex: v}
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq)
|
err := syscall.SetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -40,7 +44,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ipv4MulticastLoopback(fd *netFD) (bool, error) {
|
func ipv4MulticastLoopback(fd *netFD) (bool, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -50,7 +56,9 @@ func ipv4MulticastLoopback(fd *netFD) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
|
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -60,7 +68,9 @@ func setIPv4MulticastLoopback(fd *netFD, v bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ipv4ReceiveInterface(fd *netFD) (bool, error) {
|
func ipv4ReceiveInterface(fd *netFD) (bool, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -70,7 +80,9 @@ func ipv4ReceiveInterface(fd *netFD) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setIPv4ReceiveInterface(fd *netFD, v bool) error {
|
func setIPv4ReceiveInterface(fd *netFD, v bool) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v))
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -12,7 +12,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
|
func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
mreq, err := syscall.GetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
|
mreq, err := syscall.GetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -30,7 +32,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
|
|||||||
v = int32(ifi.Index)
|
v = int32(ifi.Index)
|
||||||
}
|
}
|
||||||
mreq := &syscall.IPMreqn{Ifindex: v}
|
mreq := &syscall.IPMreqn{Ifindex: v}
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq)
|
err := syscall.SetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -40,7 +44,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ipv4MulticastTTL(fd *netFD) (int, error) {
|
func ipv4MulticastTTL(fd *netFD) (int, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -50,7 +56,9 @@ func ipv4MulticastTTL(fd *netFD) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setIPv4MulticastTTL(fd *netFD, v int) error {
|
func setIPv4MulticastTTL(fd *netFD, v int) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, v)
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -60,7 +68,9 @@ func setIPv4MulticastTTL(fd *netFD, v int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ipv4MulticastLoopback(fd *netFD) (bool, error) {
|
func ipv4MulticastLoopback(fd *netFD) (bool, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -70,7 +80,9 @@ func ipv4MulticastLoopback(fd *netFD) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
|
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -80,7 +92,9 @@ func setIPv4MulticastLoopback(fd *netFD, v bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ipv4ReceiveInterface(fd *netFD) (bool, error) {
|
func ipv4ReceiveInterface(fd *netFD) (bool, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_PKTINFO)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_PKTINFO)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -90,7 +104,9 @@ func ipv4ReceiveInterface(fd *netFD) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setIPv4ReceiveInterface(fd *netFD, v bool) error {
|
func setIPv4ReceiveInterface(fd *netFD, v bool) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_PKTINFO, boolint(v))
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_PKTINFO, boolint(v))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -100,17 +116,21 @@ func setIPv4ReceiveInterface(fd *netFD, v bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ipv6TrafficClass(fd *netFD) (int, error) {
|
func ipv6TrafficClass(fd *netFD) (int, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, os.NewSyscallError("getsockopt", err)
|
return 0, os.NewSyscallError("getsockopt", err)
|
||||||
}
|
}
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setIPv6TrafficClass(fd *netFD, v int) error {
|
func setIPv6TrafficClass(fd *netFD, v int) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS, v)
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -12,7 +12,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
|
func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
a, err := syscall.GetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
|
a, err := syscall.GetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -28,7 +30,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
|
|||||||
}
|
}
|
||||||
var x [4]byte
|
var x [4]byte
|
||||||
copy(x[:], ip.To4())
|
copy(x[:], ip.To4())
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
|
err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -38,7 +42,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ipv4MulticastLoopback(fd *netFD) (bool, error) {
|
func ipv4MulticastLoopback(fd *netFD) (bool, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
|
v, err := syscall.GetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -48,7 +54,9 @@ func ipv4MulticastLoopback(fd *netFD) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
|
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, byte(boolint(v)))
|
err := syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, byte(boolint(v)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -58,7 +66,9 @@ func setIPv4MulticastLoopback(fd *netFD, v bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ipv4ReceiveInterface(fd *netFD) (bool, error) {
|
func ipv4ReceiveInterface(fd *netFD) (bool, error) {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF)
|
v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -68,7 +78,9 @@ func ipv4ReceiveInterface(fd *netFD) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setIPv4ReceiveInterface(fd *netFD, v bool) error {
|
func setIPv4ReceiveInterface(fd *netFD, v bool) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v))
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -23,7 +23,9 @@ func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
|
|||||||
}
|
}
|
||||||
var x [4]byte
|
var x [4]byte
|
||||||
copy(x[:], ip.To4())
|
copy(x[:], ip.To4())
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
|
err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -38,7 +40,9 @@ func ipv4MulticastTTL(fd *netFD) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setIPv4MulticastTTL(fd *netFD, v int) error {
|
func setIPv4MulticastTTL(fd *netFD, v int) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, v)
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -54,7 +58,9 @@ func ipv4MulticastLoopback(fd *netFD) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
|
func setIPv4MulticastLoopback(fd *netFD, v bool) error {
|
||||||
fd.incref()
|
if err := fd.incref(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer fd.decref()
|
defer fd.decref()
|
||||||
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
|
err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user