Home | History | Annotate | Download | only in net
      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 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 	"sync/atomic"
     15 	"syscall"
     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
     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 we can see EINVAL if the socket has
     85 		// already been accepted and closed by the server.
     86 		// Treat this as a successful connection--writes to
     87 		// the socket will see EOF.  For details and a test
     88 		// case in C see https://golang.org/issue/6828.
     89 		if runtime.GOOS == "solaris" {
     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 = 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 // tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used.
    260 // If the kernel doesn't support it, this is set to 0.
    261 var tryDupCloexec = int32(1)
    262 
    263 func dupCloseOnExec(fd int) (newfd int, err error) {
    264 	if atomic.LoadInt32(&tryDupCloexec) == 1 {
    265 		r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0)
    266 		if runtime.GOOS == "darwin" && e1 == syscall.EBADF {
    267 			// On OS X 10.6 and below (but we only support
    268 			// >= 10.6), F_DUPFD_CLOEXEC is unsupported
    269 			// and fcntl there falls back (undocumented)
    270 			// to doing an ioctl instead, returning EBADF
    271 			// in this case because fd is not of the
    272 			// expected device fd type. Treat it as
    273 			// EINVAL instead, so we fall back to the
    274 			// normal dup path.
    275 			// TODO: only do this on 10.6 if we can detect 10.6
    276 			// cheaply.
    277 			e1 = syscall.EINVAL
    278 		}
    279 		switch e1 {
    280 		case 0:
    281 			return int(r0), nil
    282 		case syscall.EINVAL:
    283 			// Old kernel. Fall back to the portable way
    284 			// from now on.
    285 			atomic.StoreInt32(&tryDupCloexec, 0)
    286 		default:
    287 			return -1, os.NewSyscallError("fcntl", e1)
    288 		}
    289 	}
    290 	return dupCloseOnExecOld(fd)
    291 }
    292 
    293 // dupCloseOnExecUnixOld is the traditional way to dup an fd and
    294 // set its O_CLOEXEC bit, using two system calls.
    295 func dupCloseOnExecOld(fd int) (newfd int, err error) {
    296 	syscall.ForkLock.RLock()
    297 	defer syscall.ForkLock.RUnlock()
    298 	newfd, err = syscall.Dup(fd)
    299 	if err != nil {
    300 		return -1, os.NewSyscallError("dup", err)
    301 	}
    302 	syscall.CloseOnExec(newfd)
    303 	return
    304 }
    305 
    306 func (fd *netFD) dup() (f *os.File, err error) {
    307 	ns, err := dupCloseOnExec(fd.pfd.Sysfd)
    308 	if err != nil {
    309 		return nil, err
    310 	}
    311 
    312 	// We want blocking mode for the new fd, hence the double negative.
    313 	// This also puts the old fd into blocking mode, meaning that
    314 	// I/O will block the thread instead of letting us use the epoll server.
    315 	// Everything will still work, just with more threads.
    316 	if err = fd.pfd.SetBlocking(); err != nil {
    317 		return nil, os.NewSyscallError("setnonblock", err)
    318 	}
    319 
    320 	return os.NewFile(uintptr(ns), fd.name()), nil
    321 }
    322