...

Source file src/pkg/net/fd_unix.go

     1	// Copyright 2009 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris
     6	
     7	package net
     8	
     9	import (
    10		"context"
    11		"internal/poll"
    12		"os"
    13		"runtime"
    14		"syscall"
    15		"time"
    16	)
    17	
    18	// Network file descriptor.
    19	type netFD struct {
    20		pfd poll.FD
    21	
    22		// immutable until Close
    23		family      int
    24		sotype      int
    25		isConnected bool // handshake completed or use of association with peer
    26		net         string
    27		laddr       Addr
    28		raddr       Addr
    29	}
    30	
    31	func newFD(sysfd, family, sotype int, net string) (*netFD, error) {
    32		ret := &netFD{
    33			pfd: poll.FD{
    34				Sysfd:         sysfd,
    35				IsStream:      sotype == syscall.SOCK_STREAM,
    36				ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW,
    37			},
    38			family: family,
    39			sotype: sotype,
    40			net:    net,
    41		}
    42		return ret, nil
    43	}
    44	
    45	func (fd *netFD) init() error {
    46		return fd.pfd.Init(fd.net, true)
    47	}
    48	
    49	func (fd *netFD) setAddr(laddr, raddr Addr) {
    50		fd.laddr = laddr
    51		fd.raddr = raddr
    52		runtime.SetFinalizer(fd, (*netFD).Close)
    53	}
    54	
    55	func (fd *netFD) name() string {
    56		var ls, rs string
    57		if fd.laddr != nil {
    58			ls = fd.laddr.String()
    59		}
    60		if fd.raddr != nil {
    61			rs = fd.raddr.String()
    62		}
    63		return fd.net + ":" + ls + "->" + rs
    64	}
    65	
    66	func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (rsa syscall.Sockaddr, ret error) {
    67		// Do not need to call fd.writeLock here,
    68		// because fd is not yet accessible to user,
    69		// so no concurrent operations are possible.
    70		switch err := connectFunc(fd.pfd.Sysfd, ra); err {
    71		case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
    72		case nil, syscall.EISCONN:
    73			select {
    74			case <-ctx.Done():
    75				return nil, mapErr(ctx.Err())
    76			default:
    77			}
    78			if err := fd.pfd.Init(fd.net, true); err != nil {
    79				return nil, err
    80			}
    81			runtime.KeepAlive(fd)
    82			return nil, nil
    83		case syscall.EINVAL:
    84			// On Solaris and illumos we can see EINVAL if the socket has
    85			// already been accepted and closed by the server.  Treat this
    86			// as a successful connection--writes to the socket will see
    87			// EOF.  For details and a test case in C see
    88			// https://golang.org/issue/6828.
    89			if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" {
    90				return nil, nil
    91			}
    92			fallthrough
    93		default:
    94			return nil, os.NewSyscallError("connect", err)
    95		}
    96		if err := fd.pfd.Init(fd.net, true); err != nil {
    97			return nil, err
    98		}
    99		if deadline, _ := ctx.Deadline(); !deadline.IsZero() {
   100			fd.pfd.SetWriteDeadline(deadline)
   101			defer fd.pfd.SetWriteDeadline(noDeadline)
   102		}
   103	
   104		// Start the "interrupter" goroutine, if this context might be canceled.
   105		// (The background context cannot)
   106		//
   107		// The interrupter goroutine waits for the context to be done and
   108		// interrupts the dial (by altering the fd's write deadline, which
   109		// wakes up waitWrite).
   110		if ctx != context.Background() {
   111			// Wait for the interrupter goroutine to exit before returning
   112			// from connect.
   113			done := make(chan struct{})
   114			interruptRes := make(chan error)
   115			defer func() {
   116				close(done)
   117				if ctxErr := <-interruptRes; ctxErr != nil && ret == nil {
   118					// The interrupter goroutine called SetWriteDeadline,
   119					// but the connect code below had returned from
   120					// waitWrite already and did a successful connect (ret
   121					// == nil). Because we've now poisoned the connection
   122					// by making it unwritable, don't return a successful
   123					// dial. This was issue 16523.
   124					ret = mapErr(ctxErr)
   125					fd.Close() // prevent a leak
   126				}
   127			}()
   128			go func() {
   129				select {
   130				case <-ctx.Done():
   131					// Force the runtime's poller to immediately give up
   132					// waiting for writability, unblocking waitWrite
   133					// below.
   134					fd.pfd.SetWriteDeadline(aLongTimeAgo)
   135					testHookCanceledDial()
   136					interruptRes <- ctx.Err()
   137				case <-done:
   138					interruptRes <- nil
   139				}
   140			}()
   141		}
   142	
   143		for {
   144			// Performing multiple connect system calls on a
   145			// non-blocking socket under Unix variants does not
   146			// necessarily result in earlier errors being
   147			// returned. Instead, once runtime-integrated network
   148			// poller tells us that the socket is ready, get the
   149			// SO_ERROR socket option to see if the connection
   150			// succeeded or failed. See issue 7474 for further
   151			// details.
   152			if err := fd.pfd.WaitWrite(); err != nil {
   153				select {
   154				case <-ctx.Done():
   155					return nil, mapErr(ctx.Err())
   156				default:
   157				}
   158				return nil, err
   159			}
   160			nerr, err := getsockoptIntFunc(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
   161			if err != nil {
   162				return nil, os.NewSyscallError("getsockopt", err)
   163			}
   164			switch err := syscall.Errno(nerr); err {
   165			case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
   166			case syscall.EISCONN:
   167				return nil, nil
   168			case syscall.Errno(0):
   169				// The runtime poller can wake us up spuriously;
   170				// see issues 14548 and 19289. Check that we are
   171				// really connected; if not, wait again.
   172				if rsa, err := syscall.Getpeername(fd.pfd.Sysfd); err == nil {
   173					return rsa, nil
   174				}
   175			default:
   176				return nil, os.NewSyscallError("connect", err)
   177			}
   178			runtime.KeepAlive(fd)
   179		}
   180	}
   181	
   182	func (fd *netFD) Close() error {
   183		runtime.SetFinalizer(fd, nil)
   184		return fd.pfd.Close()
   185	}
   186	
   187	func (fd *netFD) shutdown(how int) error {
   188		err := fd.pfd.Shutdown(how)
   189		runtime.KeepAlive(fd)
   190		return wrapSyscallError("shutdown", err)
   191	}
   192	
   193	func (fd *netFD) closeRead() error {
   194		return fd.shutdown(syscall.SHUT_RD)
   195	}
   196	
   197	func (fd *netFD) closeWrite() error {
   198		return fd.shutdown(syscall.SHUT_WR)
   199	}
   200	
   201	func (fd *netFD) Read(p []byte) (n int, err error) {
   202		n, err = fd.pfd.Read(p)
   203		runtime.KeepAlive(fd)
   204		return n, wrapSyscallError("read", err)
   205	}
   206	
   207	func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
   208		n, sa, err = fd.pfd.ReadFrom(p)
   209		runtime.KeepAlive(fd)
   210		return n, sa, wrapSyscallError("recvfrom", err)
   211	}
   212	
   213	func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
   214		n, oobn, flags, sa, err = fd.pfd.ReadMsg(p, oob)
   215		runtime.KeepAlive(fd)
   216		return n, oobn, flags, sa, wrapSyscallError("recvmsg", err)
   217	}
   218	
   219	func (fd *netFD) Write(p []byte) (nn int, err error) {
   220		nn, err = fd.pfd.Write(p)
   221		runtime.KeepAlive(fd)
   222		return nn, wrapSyscallError("write", err)
   223	}
   224	
   225	func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
   226		n, err = fd.pfd.WriteTo(p, sa)
   227		runtime.KeepAlive(fd)
   228		return n, wrapSyscallError("sendto", err)
   229	}
   230	
   231	func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
   232		n, oobn, err = fd.pfd.WriteMsg(p, oob, sa)
   233		runtime.KeepAlive(fd)
   234		return n, oobn, wrapSyscallError("sendmsg", err)
   235	}
   236	
   237	func (fd *netFD) accept() (netfd *netFD, err error) {
   238		d, rsa, errcall, err := fd.pfd.Accept()
   239		if err != nil {
   240			if errcall != "" {
   241				err = wrapSyscallError(errcall, err)
   242			}
   243			return nil, err
   244		}
   245	
   246		if netfd, err = newFD(d, fd.family, fd.sotype, fd.net); err != nil {
   247			poll.CloseFunc(d)
   248			return nil, err
   249		}
   250		if err = netfd.init(); err != nil {
   251			fd.Close()
   252			return nil, err
   253		}
   254		lsa, _ := syscall.Getsockname(netfd.pfd.Sysfd)
   255		netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
   256		return netfd, nil
   257	}
   258	
   259	func (fd *netFD) dup() (f *os.File, err error) {
   260		ns, call, err := fd.pfd.Dup()
   261		if err != nil {
   262			if call != "" {
   263				err = os.NewSyscallError(call, err)
   264			}
   265			return nil, err
   266		}
   267	
   268		return os.NewFile(uintptr(ns), fd.name()), nil
   269	}
   270	
   271	func (fd *netFD) SetDeadline(t time.Time) error {
   272		return fd.pfd.SetDeadline(t)
   273	}
   274	
   275	func (fd *netFD) SetReadDeadline(t time.Time) error {
   276		return fd.pfd.SetReadDeadline(t)
   277	}
   278	
   279	func (fd *netFD) SetWriteDeadline(t time.Time) error {
   280		return fd.pfd.SetWriteDeadline(t)
   281	}
   282	

View as plain text