| // 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 aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris | 
 |  | 
 | package net | 
 |  | 
 | import ( | 
 | 	"context" | 
 | 	"internal/poll" | 
 | 	"os" | 
 | 	"runtime" | 
 | 	"sync/atomic" | 
 | 	"syscall" | 
 | ) | 
 |  | 
 | // Network file descriptor. | 
 | type netFD struct { | 
 | 	pfd poll.FD | 
 |  | 
 | 	// immutable until Close | 
 | 	family      int | 
 | 	sotype      int | 
 | 	isConnected bool | 
 | 	net         string | 
 | 	laddr       Addr | 
 | 	raddr       Addr | 
 | } | 
 |  | 
 | func newFD(sysfd, family, sotype int, net string) (*netFD, error) { | 
 | 	ret := &netFD{ | 
 | 		pfd: poll.FD{ | 
 | 			Sysfd:         sysfd, | 
 | 			IsStream:      sotype == syscall.SOCK_STREAM, | 
 | 			ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW, | 
 | 		}, | 
 | 		family: family, | 
 | 		sotype: sotype, | 
 | 		net:    net, | 
 | 	} | 
 | 	return ret, nil | 
 | } | 
 |  | 
 | func (fd *netFD) init() error { | 
 | 	return fd.pfd.Init(fd.net, true) | 
 | } | 
 |  | 
 | 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(ctx context.Context, la, ra syscall.Sockaddr) (rsa syscall.Sockaddr, ret 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.pfd.Sysfd, ra); err { | 
 | 	case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR: | 
 | 	case nil, syscall.EISCONN: | 
 | 		select { | 
 | 		case <-ctx.Done(): | 
 | 			return nil, mapErr(ctx.Err()) | 
 | 		default: | 
 | 		} | 
 | 		if err := fd.pfd.Init(fd.net, true); err != nil { | 
 | 			return nil, err | 
 | 		} | 
 | 		runtime.KeepAlive(fd) | 
 | 		return nil, 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, nil | 
 | 		} | 
 | 		fallthrough | 
 | 	default: | 
 | 		return nil, os.NewSyscallError("connect", err) | 
 | 	} | 
 | 	if err := fd.pfd.Init(fd.net, true); err != nil { | 
 | 		return nil, err | 
 | 	} | 
 | 	if deadline, _ := ctx.Deadline(); !deadline.IsZero() { | 
 | 		fd.pfd.SetWriteDeadline(deadline) | 
 | 		defer fd.pfd.SetWriteDeadline(noDeadline) | 
 | 	} | 
 |  | 
 | 	// Start the "interrupter" goroutine, if this context might be canceled. | 
 | 	// (The background context cannot) | 
 | 	// | 
 | 	// The interrupter goroutine waits for the context to be done and | 
 | 	// interrupts the dial (by altering the fd's write deadline, which | 
 | 	// wakes up waitWrite). | 
 | 	if ctx != context.Background() { | 
 | 		// Wait for the interrupter goroutine to exit before returning | 
 | 		// from connect. | 
 | 		done := make(chan struct{}) | 
 | 		interruptRes := make(chan error) | 
 | 		defer func() { | 
 | 			close(done) | 
 | 			if ctxErr := <-interruptRes; ctxErr != nil && ret == nil { | 
 | 				// The interrupter goroutine called SetWriteDeadline, | 
 | 				// but the connect code below had returned from | 
 | 				// waitWrite already and did a successful connect (ret | 
 | 				// == nil). Because we've now poisoned the connection | 
 | 				// by making it unwritable, don't return a successful | 
 | 				// dial. This was issue 16523. | 
 | 				ret = ctxErr | 
 | 				fd.Close() // prevent a leak | 
 | 			} | 
 | 		}() | 
 | 		go func() { | 
 | 			select { | 
 | 			case <-ctx.Done(): | 
 | 				// Force the runtime's poller to immediately give up | 
 | 				// waiting for writability, unblocking waitWrite | 
 | 				// below. | 
 | 				fd.pfd.SetWriteDeadline(aLongTimeAgo) | 
 | 				testHookCanceledDial() | 
 | 				interruptRes <- ctx.Err() | 
 | 			case <-done: | 
 | 				interruptRes <- nil | 
 | 			} | 
 | 		}() | 
 | 	} | 
 |  | 
 | 	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.pfd.WaitWrite(); err != nil { | 
 | 			select { | 
 | 			case <-ctx.Done(): | 
 | 				return nil, mapErr(ctx.Err()) | 
 | 			default: | 
 | 			} | 
 | 			return nil, err | 
 | 		} | 
 | 		nerr, err := getsockoptIntFunc(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR) | 
 | 		if err != nil { | 
 | 			return nil, os.NewSyscallError("getsockopt", err) | 
 | 		} | 
 | 		switch err := syscall.Errno(nerr); err { | 
 | 		case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR: | 
 | 		case syscall.EISCONN: | 
 | 			return nil, nil | 
 | 		case syscall.Errno(0): | 
 | 			// The runtime poller can wake us up spuriously; | 
 | 			// see issues 14548 and 19289. Check that we are | 
 | 			// really connected; if not, wait again. | 
 | 			if rsa, err := syscall.Getpeername(fd.pfd.Sysfd); err == nil { | 
 | 				return rsa, nil | 
 | 			} | 
 | 		default: | 
 | 			return nil, os.NewSyscallError("connect", err) | 
 | 		} | 
 | 		runtime.KeepAlive(fd) | 
 | 	} | 
 | } | 
 |  | 
 | func (fd *netFD) Close() error { | 
 | 	runtime.SetFinalizer(fd, nil) | 
 | 	return fd.pfd.Close() | 
 | } | 
 |  | 
 | func (fd *netFD) shutdown(how int) error { | 
 | 	err := fd.pfd.Shutdown(how) | 
 | 	runtime.KeepAlive(fd) | 
 | 	return wrapSyscallError("shutdown", err) | 
 | } | 
 |  | 
 | 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) { | 
 | 	n, err = fd.pfd.Read(p) | 
 | 	runtime.KeepAlive(fd) | 
 | 	return n, wrapSyscallError("read", err) | 
 | } | 
 |  | 
 | func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { | 
 | 	n, sa, err = fd.pfd.ReadFrom(p) | 
 | 	runtime.KeepAlive(fd) | 
 | 	return n, sa, wrapSyscallError("recvfrom", err) | 
 | } | 
 |  | 
 | func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { | 
 | 	n, oobn, flags, sa, err = fd.pfd.ReadMsg(p, oob) | 
 | 	runtime.KeepAlive(fd) | 
 | 	return n, oobn, flags, sa, wrapSyscallError("recvmsg", err) | 
 | } | 
 |  | 
 | func (fd *netFD) Write(p []byte) (nn int, err error) { | 
 | 	nn, err = fd.pfd.Write(p) | 
 | 	runtime.KeepAlive(fd) | 
 | 	return nn, wrapSyscallError("write", err) | 
 | } | 
 |  | 
 | func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) { | 
 | 	n, err = fd.pfd.WriteTo(p, sa) | 
 | 	runtime.KeepAlive(fd) | 
 | 	return n, wrapSyscallError("sendto", err) | 
 | } | 
 |  | 
 | func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { | 
 | 	n, oobn, err = fd.pfd.WriteMsg(p, oob, sa) | 
 | 	runtime.KeepAlive(fd) | 
 | 	return n, oobn, wrapSyscallError("sendmsg", err) | 
 | } | 
 |  | 
 | func (fd *netFD) accept() (netfd *netFD, err error) { | 
 | 	d, rsa, errcall, err := fd.pfd.Accept() | 
 | 	if err != nil { | 
 | 		if errcall != "" { | 
 | 			err = wrapSyscallError(errcall, err) | 
 | 		} | 
 | 		return nil, err | 
 | 	} | 
 |  | 
 | 	if netfd, err = newFD(d, fd.family, fd.sotype, fd.net); err != nil { | 
 | 		poll.CloseFunc(d) | 
 | 		return nil, err | 
 | 	} | 
 | 	if err = netfd.init(); err != nil { | 
 | 		fd.Close() | 
 | 		return nil, err | 
 | 	} | 
 | 	lsa, _ := syscall.Getsockname(netfd.pfd.Sysfd) | 
 | 	netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa)) | 
 | 	return netfd, nil | 
 | } | 
 |  | 
 | // Use a helper function to call fcntl.  This is defined in C in | 
 | // libgo/runtime. | 
 | //extern __go_fcntl_uintptr | 
 | func fcntl(uintptr, uintptr, uintptr) (uintptr, uintptr) | 
 |  | 
 | // 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 && syscall.F_DUPFD_CLOEXEC != 0 { | 
 | 		syscall.Entersyscall() | 
 | 		r0, errno := fcntl(uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0) | 
 | 		syscall.Exitsyscall() | 
 | 		e1 := syscall.Errno(errno) | 
 | 		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.pfd.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 = fd.pfd.SetBlocking(); err != nil { | 
 | 		return nil, os.NewSyscallError("setnonblock", err) | 
 | 	} | 
 |  | 
 | 	return os.NewFile(uintptr(ns), fd.name()), nil | 
 | } |