| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris |
| |
| package net |
| |
| import ( |
| "io" |
| "os" |
| "runtime" |
| "sync/atomic" |
| "syscall" |
| "time" |
| ) |
| |
| // Network file descriptor. |
| type netFD struct { |
| // locking/lifetime of sysfd + serialize access to Read and Write methods |
| fdmu fdMutex |
| |
| // immutable until Close |
| sysfd int |
| family int |
| sotype int |
| isConnected bool |
| net string |
| laddr Addr |
| raddr Addr |
| |
| // wait server |
| pd pollDesc |
| } |
| |
| func sysInit() { |
| } |
| |
| func dial(network string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) { |
| return dialer(deadline) |
| } |
| |
| func newFD(sysfd, family, sotype int, net string) (*netFD, error) { |
| return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net}, nil |
| } |
| |
| func (fd *netFD) init() error { |
| if err := fd.pd.Init(fd); err != nil { |
| return err |
| } |
| return nil |
| } |
| |
| func (fd *netFD) setAddr(laddr, raddr Addr) { |
| fd.laddr = laddr |
| fd.raddr = raddr |
| runtime.SetFinalizer(fd, (*netFD).Close) |
| } |
| |
| func (fd *netFD) name() string { |
| var ls, rs string |
| if fd.laddr != nil { |
| ls = fd.laddr.String() |
| } |
| if fd.raddr != nil { |
| rs = fd.raddr.String() |
| } |
| return fd.net + ":" + ls + "->" + rs |
| } |
| |
| func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-chan struct{}) error { |
| // Do not need to call fd.writeLock here, |
| // because fd is not yet accessible to user, |
| // so no concurrent operations are possible. |
| switch err := connectFunc(fd.sysfd, ra); err { |
| case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR: |
| case nil, syscall.EISCONN: |
| if !deadline.IsZero() && deadline.Before(time.Now()) { |
| return errTimeout |
| } |
| if err := fd.init(); err != nil { |
| return err |
| } |
| return nil |
| case syscall.EINVAL: |
| // On Solaris we can see EINVAL if the socket has |
| // already been accepted and closed by the server. |
| // Treat this as a successful connection--writes to |
| // the socket will see EOF. For details and a test |
| // case in C see https://golang.org/issue/6828. |
| if runtime.GOOS == "solaris" { |
| return nil |
| } |
| fallthrough |
| default: |
| return os.NewSyscallError("connect", err) |
| } |
| if err := fd.init(); err != nil { |
| return err |
| } |
| if !deadline.IsZero() { |
| fd.setWriteDeadline(deadline) |
| defer fd.setWriteDeadline(noDeadline) |
| } |
| if cancel != nil { |
| done := make(chan bool) |
| defer close(done) |
| go func() { |
| select { |
| case <-cancel: |
| // Force the runtime's poller to immediately give |
| // up waiting for writability. |
| fd.setWriteDeadline(aLongTimeAgo) |
| case <-done: |
| } |
| }() |
| } |
| for { |
| // Performing multiple connect system calls on a |
| // non-blocking socket under Unix variants does not |
| // necessarily result in earlier errors being |
| // returned. Instead, once runtime-integrated network |
| // poller tells us that the socket is ready, get the |
| // SO_ERROR socket option to see if the connection |
| // succeeded or failed. See issue 7474 for further |
| // details. |
| if err := fd.pd.WaitWrite(); err != nil { |
| select { |
| case <-cancel: |
| return errCanceled |
| default: |
| } |
| return err |
| } |
| nerr, err := getsockoptIntFunc(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR) |
| if err != nil { |
| return os.NewSyscallError("getsockopt", err) |
| } |
| switch err := syscall.Errno(nerr); err { |
| case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR: |
| case syscall.Errno(0), syscall.EISCONN: |
| return nil |
| default: |
| return os.NewSyscallError("getsockopt", err) |
| } |
| } |
| } |
| |
| func (fd *netFD) destroy() { |
| // Poller may want to unregister fd in readiness notification mechanism, |
| // so this must be executed before closeFunc. |
| fd.pd.Close() |
| closeFunc(fd.sysfd) |
| fd.sysfd = -1 |
| runtime.SetFinalizer(fd, nil) |
| } |
| |
| // Add a reference to this fd. |
| // Returns an error if the fd cannot be used. |
| func (fd *netFD) incref() error { |
| if !fd.fdmu.Incref() { |
| return errClosing |
| } |
| 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.fdmu.Decref() { |
| fd.destroy() |
| } |
| } |
| |
| // Add a reference to this fd and lock for reading. |
| // Returns an error if the fd cannot be used. |
| func (fd *netFD) readLock() error { |
| if !fd.fdmu.RWLock(true) { |
| return errClosing |
| } |
| return nil |
| } |
| |
| // Unlock for reading and remove a reference to this FD. |
| func (fd *netFD) readUnlock() { |
| if fd.fdmu.RWUnlock(true) { |
| fd.destroy() |
| } |
| } |
| |
| // Add a reference to this fd and lock for writing. |
| // Returns an error if the fd cannot be used. |
| func (fd *netFD) writeLock() error { |
| if !fd.fdmu.RWLock(false) { |
| return errClosing |
| } |
| return nil |
| } |
| |
| // Unlock for writing and remove a reference to this FD. |
| func (fd *netFD) writeUnlock() { |
| if fd.fdmu.RWUnlock(false) { |
| fd.destroy() |
| } |
| } |
| |
| func (fd *netFD) Close() error { |
| if !fd.fdmu.IncrefAndClose() { |
| return errClosing |
| } |
| // 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 pollDesc will return errClosing. |
| fd.pd.Evict() |
| fd.decref() |
| return nil |
| } |
| |
| func (fd *netFD) shutdown(how int) error { |
| if err := fd.incref(); err != nil { |
| return err |
| } |
| defer fd.decref() |
| return os.NewSyscallError("shutdown", syscall.Shutdown(fd.sysfd, how)) |
| } |
| |
| func (fd *netFD) closeRead() error { |
| return fd.shutdown(syscall.SHUT_RD) |
| } |
| |
| func (fd *netFD) closeWrite() error { |
| return fd.shutdown(syscall.SHUT_WR) |
| } |
| |
| func (fd *netFD) Read(p []byte) (n int, err error) { |
| if err := fd.readLock(); err != nil { |
| return 0, err |
| } |
| defer fd.readUnlock() |
| if err := fd.pd.PrepareRead(); err != nil { |
| return 0, err |
| } |
| for { |
| n, err = syscall.Read(fd.sysfd, p) |
| if err != nil { |
| n = 0 |
| if err == syscall.EAGAIN { |
| if err = fd.pd.WaitRead(); err == nil { |
| continue |
| } |
| } |
| } |
| err = fd.eofError(n, err) |
| break |
| } |
| if _, ok := err.(syscall.Errno); ok { |
| err = os.NewSyscallError("read", err) |
| } |
| return |
| } |
| |
| func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { |
| if err := fd.readLock(); err != nil { |
| return 0, nil, err |
| } |
| defer fd.readUnlock() |
| if err := fd.pd.PrepareRead(); err != nil { |
| return 0, nil, err |
| } |
| for { |
| n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0) |
| if err != nil { |
| n = 0 |
| if err == syscall.EAGAIN { |
| if err = fd.pd.WaitRead(); err == nil { |
| continue |
| } |
| } |
| } |
| err = fd.eofError(n, err) |
| break |
| } |
| if _, ok := err.(syscall.Errno); ok { |
| err = os.NewSyscallError("recvfrom", err) |
| } |
| return |
| } |
| |
| func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { |
| if err := fd.readLock(); err != nil { |
| return 0, 0, 0, nil, err |
| } |
| defer fd.readUnlock() |
| if err := fd.pd.PrepareRead(); err != nil { |
| return 0, 0, 0, nil, err |
| } |
| for { |
| n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0) |
| if err != nil { |
| // TODO(dfc) should n and oobn be set to 0 |
| if err == syscall.EAGAIN { |
| if err = fd.pd.WaitRead(); err == nil { |
| continue |
| } |
| } |
| } |
| err = fd.eofError(n, err) |
| break |
| } |
| if _, ok := err.(syscall.Errno); ok { |
| err = os.NewSyscallError("recvmsg", err) |
| } |
| return |
| } |
| |
| func (fd *netFD) Write(p []byte) (nn int, err error) { |
| if err := fd.writeLock(); err != nil { |
| return 0, err |
| } |
| defer fd.writeUnlock() |
| if err := fd.pd.PrepareWrite(); err != nil { |
| return 0, err |
| } |
| for { |
| var n int |
| n, err = syscall.Write(fd.sysfd, p[nn:]) |
| if n > 0 { |
| nn += n |
| } |
| if nn == len(p) { |
| break |
| } |
| if err == syscall.EAGAIN { |
| if err = fd.pd.WaitWrite(); err == nil { |
| continue |
| } |
| } |
| if err != nil { |
| break |
| } |
| if n == 0 { |
| err = io.ErrUnexpectedEOF |
| break |
| } |
| } |
| if _, ok := err.(syscall.Errno); ok { |
| err = os.NewSyscallError("write", err) |
| } |
| return nn, err |
| } |
| |
| func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) { |
| if err := fd.writeLock(); err != nil { |
| return 0, err |
| } |
| defer fd.writeUnlock() |
| if err := fd.pd.PrepareWrite(); err != nil { |
| return 0, err |
| } |
| for { |
| err = syscall.Sendto(fd.sysfd, p, 0, sa) |
| if err == syscall.EAGAIN { |
| if err = fd.pd.WaitWrite(); err == nil { |
| continue |
| } |
| } |
| break |
| } |
| if err == nil { |
| n = len(p) |
| } |
| if _, ok := err.(syscall.Errno); ok { |
| err = os.NewSyscallError("sendto", err) |
| } |
| return |
| } |
| |
| func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { |
| if err := fd.writeLock(); err != nil { |
| return 0, 0, err |
| } |
| defer fd.writeUnlock() |
| if err := fd.pd.PrepareWrite(); err != nil { |
| return 0, 0, err |
| } |
| for { |
| n, err = syscall.SendmsgN(fd.sysfd, p, oob, sa, 0) |
| if err == syscall.EAGAIN { |
| if err = fd.pd.WaitWrite(); err == nil { |
| continue |
| } |
| } |
| break |
| } |
| if err == nil { |
| oobn = len(oob) |
| } |
| if _, ok := err.(syscall.Errno); ok { |
| err = os.NewSyscallError("sendmsg", err) |
| } |
| return |
| } |
| |
| func (fd *netFD) accept() (netfd *netFD, err error) { |
| if err := fd.readLock(); err != nil { |
| return nil, err |
| } |
| defer fd.readUnlock() |
| |
| var s int |
| var rsa syscall.Sockaddr |
| if err = fd.pd.PrepareRead(); err != nil { |
| return nil, err |
| } |
| for { |
| s, rsa, err = accept(fd.sysfd) |
| if err != nil { |
| nerr, ok := err.(*os.SyscallError) |
| if !ok { |
| return nil, err |
| } |
| switch nerr.Err { |
| case syscall.EAGAIN: |
| if err = fd.pd.WaitRead(); err == nil { |
| continue |
| } |
| case syscall.ECONNABORTED: |
| // This means that a socket on the |
| // listen queue was closed before we |
| // Accept()ed it; it's a silly error, |
| // so try again. |
| continue |
| } |
| return nil, err |
| } |
| break |
| } |
| |
| if netfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil { |
| closeFunc(s) |
| return nil, err |
| } |
| if err = netfd.init(); err != nil { |
| fd.Close() |
| return nil, err |
| } |
| lsa, _ := syscall.Getsockname(netfd.sysfd) |
| netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa)) |
| return netfd, nil |
| } |
| |
| // tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used. |
| // If the kernel doesn't support it, this is set to 0. |
| var tryDupCloexec = int32(1) |
| |
| func dupCloseOnExec(fd int) (newfd int, err error) { |
| if atomic.LoadInt32(&tryDupCloexec) == 1 { |
| r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0) |
| if runtime.GOOS == "darwin" && e1 == syscall.EBADF { |
| // On OS X 10.6 and below (but we only support |
| // >= 10.6), F_DUPFD_CLOEXEC is unsupported |
| // and fcntl there falls back (undocumented) |
| // to doing an ioctl instead, returning EBADF |
| // in this case because fd is not of the |
| // expected device fd type. Treat it as |
| // EINVAL instead, so we fall back to the |
| // normal dup path. |
| // TODO: only do this on 10.6 if we can detect 10.6 |
| // cheaply. |
| e1 = syscall.EINVAL |
| } |
| switch e1 { |
| case 0: |
| return int(r0), nil |
| case syscall.EINVAL: |
| // Old kernel. Fall back to the portable way |
| // from now on. |
| atomic.StoreInt32(&tryDupCloexec, 0) |
| default: |
| return -1, os.NewSyscallError("fcntl", e1) |
| } |
| } |
| return dupCloseOnExecOld(fd) |
| } |
| |
| // dupCloseOnExecUnixOld is the traditional way to dup an fd and |
| // set its O_CLOEXEC bit, using two system calls. |
| func dupCloseOnExecOld(fd int) (newfd int, err error) { |
| syscall.ForkLock.RLock() |
| defer syscall.ForkLock.RUnlock() |
| newfd, err = syscall.Dup(fd) |
| if err != nil { |
| return -1, os.NewSyscallError("dup", err) |
| } |
| syscall.CloseOnExec(newfd) |
| return |
| } |
| |
| func (fd *netFD) dup() (f *os.File, err error) { |
| ns, err := dupCloseOnExec(fd.sysfd) |
| if err != nil { |
| return nil, err |
| } |
| |
| // We want blocking mode for the new fd, hence the double negative. |
| // This also puts the old fd into blocking mode, meaning that |
| // I/O will block the thread instead of letting us use the epoll server. |
| // Everything will still work, just with more threads. |
| if err = syscall.SetNonblock(ns, false); err != nil { |
| return nil, os.NewSyscallError("setnonblock", err) |
| } |
| |
| return os.NewFile(uintptr(ns), fd.name()), nil |
| } |