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
7package net
8
9import (
10	"context"
11	"internal/poll"
12	"os"
13	"runtime"
14	"sync/atomic"
15	"syscall"
16)
17
18// Network file descriptor.
19type 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
31func 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
45func (fd *netFD) init() error {
46	return fd.pfd.Init(fd.net, true)
47}
48
49func (fd *netFD) setAddr(laddr, raddr Addr) {
50	fd.laddr = laddr
51	fd.raddr = raddr
52	runtime.SetFinalizer(fd, (*netFD).Close)
53}
54
55func (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
66func (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
182func (fd *netFD) Close() error {
183	runtime.SetFinalizer(fd, nil)
184	return fd.pfd.Close()
185}
186
187func (fd *netFD) shutdown(how int) error {
188	err := fd.pfd.Shutdown(how)
189	runtime.KeepAlive(fd)
190	return wrapSyscallError("shutdown", err)
191}
192
193func (fd *netFD) closeRead() error {
194	return fd.shutdown(syscall.SHUT_RD)
195}
196
197func (fd *netFD) closeWrite() error {
198	return fd.shutdown(syscall.SHUT_WR)
199}
200
201func (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
207func (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
213func (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
219func (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
225func (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
231func (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
237func (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// Use a helper function to call fcntl.  This is defined in C in
260// libgo/runtime.
261//extern __go_fcntl_uintptr
262func fcntl(uintptr, uintptr, uintptr) (uintptr, uintptr)
263
264// tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used.
265// If the kernel doesn't support it, this is set to 0.
266var tryDupCloexec = int32(1)
267
268func dupCloseOnExec(fd int) (newfd int, err error) {
269	if atomic.LoadInt32(&tryDupCloexec) == 1 && syscall.F_DUPFD_CLOEXEC != 0 {
270		syscall.Entersyscall()
271		r0, errno := fcntl(uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0)
272		syscall.Exitsyscall()
273		e1 := syscall.Errno(errno)
274		if runtime.GOOS == "darwin" && e1 == syscall.EBADF {
275			// On OS X 10.6 and below (but we only support
276			// >= 10.6), F_DUPFD_CLOEXEC is unsupported
277			// and fcntl there falls back (undocumented)
278			// to doing an ioctl instead, returning EBADF
279			// in this case because fd is not of the
280			// expected device fd type. Treat it as
281			// EINVAL instead, so we fall back to the
282			// normal dup path.
283			// TODO: only do this on 10.6 if we can detect 10.6
284			// cheaply.
285			e1 = syscall.EINVAL
286		}
287		switch e1 {
288		case 0:
289			return int(r0), nil
290		case syscall.EINVAL:
291			// Old kernel. Fall back to the portable way
292			// from now on.
293			atomic.StoreInt32(&tryDupCloexec, 0)
294		default:
295			return -1, os.NewSyscallError("fcntl", e1)
296		}
297	}
298	return dupCloseOnExecOld(fd)
299}
300
301// dupCloseOnExecUnixOld is the traditional way to dup an fd and
302// set its O_CLOEXEC bit, using two system calls.
303func dupCloseOnExecOld(fd int) (newfd int, err error) {
304	syscall.ForkLock.RLock()
305	defer syscall.ForkLock.RUnlock()
306	newfd, err = syscall.Dup(fd)
307	if err != nil {
308		return -1, os.NewSyscallError("dup", err)
309	}
310	syscall.CloseOnExec(newfd)
311	return
312}
313
314func (fd *netFD) dup() (f *os.File, err error) {
315	ns, err := dupCloseOnExec(fd.pfd.Sysfd)
316	if err != nil {
317		return nil, err
318	}
319
320	// We want blocking mode for the new fd, hence the double negative.
321	// This also puts the old fd into blocking mode, meaning that
322	// I/O will block the thread instead of letting us use the epoll server.
323	// Everything will still work, just with more threads.
324	if err = fd.pfd.SetBlocking(); err != nil {
325		return nil, os.NewSyscallError("setnonblock", err)
326	}
327
328	return os.NewFile(uintptr(ns), fd.name()), nil
329}
330