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//go:build unix || js || wasip1 || windows
6
7package net
8
9import (
10	"context"
11	"io"
12	"os"
13	"syscall"
14)
15
16func sockaddrToTCP(sa syscall.Sockaddr) Addr {
17	switch sa := sa.(type) {
18	case *syscall.SockaddrInet4:
19		return &TCPAddr{IP: sa.Addr[0:], Port: sa.Port}
20	case *syscall.SockaddrInet6:
21		return &TCPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
22	}
23	return nil
24}
25
26func (a *TCPAddr) family() int {
27	if a == nil || len(a.IP) <= IPv4len {
28		return syscall.AF_INET
29	}
30	if a.IP.To4() != nil {
31		return syscall.AF_INET
32	}
33	return syscall.AF_INET6
34}
35
36func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
37	if a == nil {
38		return nil, nil
39	}
40	return ipToSockaddr(family, a.IP, a.Port, a.Zone)
41}
42
43func (a *TCPAddr) toLocal(net string) sockaddr {
44	return &TCPAddr{loopbackIP(net), a.Port, a.Zone}
45}
46
47func (c *TCPConn) readFrom(r io.Reader) (int64, error) {
48	if n, err, handled := spliceFrom(c.fd, r); handled {
49		return n, err
50	}
51	if n, err, handled := sendFile(c.fd, r); handled {
52		return n, err
53	}
54	return genericReadFrom(c, r)
55}
56
57func (c *TCPConn) writeTo(w io.Writer) (int64, error) {
58	if n, err, handled := spliceTo(w, c.fd); handled {
59		return n, err
60	}
61	return genericWriteTo(c, w)
62}
63
64func (sd *sysDialer) dialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) {
65	if h := sd.testHookDialTCP; h != nil {
66		return h(ctx, sd.network, laddr, raddr)
67	}
68	if h := testHookDialTCP; h != nil {
69		return h(ctx, sd.network, laddr, raddr)
70	}
71	return sd.doDialTCP(ctx, laddr, raddr)
72}
73
74func (sd *sysDialer) doDialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) {
75	return sd.doDialTCPProto(ctx, laddr, raddr, 0)
76}
77
78func (sd *sysDialer) doDialTCPProto(ctx context.Context, laddr, raddr *TCPAddr, proto int) (*TCPConn, error) {
79	ctrlCtxFn := sd.Dialer.ControlContext
80	if ctrlCtxFn == nil && sd.Dialer.Control != nil {
81		ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error {
82			return sd.Dialer.Control(network, address, c)
83		}
84	}
85	fd, err := internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_STREAM, proto, "dial", ctrlCtxFn)
86
87	// TCP has a rarely used mechanism called a 'simultaneous connection' in
88	// which Dial("tcp", addr1, addr2) run on the machine at addr1 can
89	// connect to a simultaneous Dial("tcp", addr2, addr1) run on the machine
90	// at addr2, without either machine executing Listen. If laddr == nil,
91	// it means we want the kernel to pick an appropriate originating local
92	// address. Some Linux kernels cycle blindly through a fixed range of
93	// local ports, regardless of destination port. If a kernel happens to
94	// pick local port 50001 as the source for a Dial("tcp", "", "localhost:50001"),
95	// then the Dial will succeed, having simultaneously connected to itself.
96	// This can only happen when we are letting the kernel pick a port (laddr == nil)
97	// and when there is no listener for the destination address.
98	// It's hard to argue this is anything other than a kernel bug. If we
99	// see this happen, rather than expose the buggy effect to users, we
100	// close the fd and try again. If it happens twice more, we relent and
101	// use the result. See also:
102	//	https://golang.org/issue/2690
103	//	https://stackoverflow.com/questions/4949858/
104	//
105	// The opposite can also happen: if we ask the kernel to pick an appropriate
106	// originating local address, sometimes it picks one that is already in use.
107	// So if the error is EADDRNOTAVAIL, we have to try again too, just for
108	// a different reason.
109	//
110	// The kernel socket code is no doubt enjoying watching us squirm.
111	for i := 0; i < 2 && (laddr == nil || laddr.Port == 0) && (selfConnect(fd, err) || spuriousENOTAVAIL(err)); i++ {
112		if err == nil {
113			fd.Close()
114		}
115		fd, err = internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_STREAM, proto, "dial", ctrlCtxFn)
116	}
117
118	if err != nil {
119		return nil, err
120	}
121	return newTCPConn(fd, sd.Dialer.KeepAlive, sd.Dialer.KeepAliveConfig, testPreHookSetKeepAlive, testHookSetKeepAlive), nil
122}
123
124func selfConnect(fd *netFD, err error) bool {
125	// If the connect failed, we clearly didn't connect to ourselves.
126	if err != nil {
127		return false
128	}
129
130	// The socket constructor can return an fd with raddr nil under certain
131	// unknown conditions. The errors in the calls there to Getpeername
132	// are discarded, but we can't catch the problem there because those
133	// calls are sometimes legally erroneous with a "socket not connected".
134	// Since this code (selfConnect) is already trying to work around
135	// a problem, we make sure if this happens we recognize trouble and
136	// ask the DialTCP routine to try again.
137	// TODO: try to understand what's really going on.
138	if fd.laddr == nil || fd.raddr == nil {
139		return true
140	}
141	l := fd.laddr.(*TCPAddr)
142	r := fd.raddr.(*TCPAddr)
143	return l.Port == r.Port && l.IP.Equal(r.IP)
144}
145
146func spuriousENOTAVAIL(err error) bool {
147	if op, ok := err.(*OpError); ok {
148		err = op.Err
149	}
150	if sys, ok := err.(*os.SyscallError); ok {
151		err = sys.Err
152	}
153	return err == syscall.EADDRNOTAVAIL
154}
155
156func (ln *TCPListener) ok() bool { return ln != nil && ln.fd != nil }
157
158func (ln *TCPListener) accept() (*TCPConn, error) {
159	fd, err := ln.fd.accept()
160	if err != nil {
161		return nil, err
162	}
163	return newTCPConn(fd, ln.lc.KeepAlive, ln.lc.KeepAliveConfig, testPreHookSetKeepAlive, testHookSetKeepAlive), nil
164}
165
166func (ln *TCPListener) close() error {
167	return ln.fd.Close()
168}
169
170func (ln *TCPListener) file() (*os.File, error) {
171	f, err := ln.fd.dup()
172	if err != nil {
173		return nil, err
174	}
175	return f, nil
176}
177
178func (sl *sysListener) listenTCP(ctx context.Context, laddr *TCPAddr) (*TCPListener, error) {
179	return sl.listenTCPProto(ctx, laddr, 0)
180}
181
182func (sl *sysListener) listenTCPProto(ctx context.Context, laddr *TCPAddr, proto int) (*TCPListener, error) {
183	var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error
184	if sl.ListenConfig.Control != nil {
185		ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error {
186			return sl.ListenConfig.Control(network, address, c)
187		}
188	}
189	fd, err := internetSocket(ctx, sl.network, laddr, nil, syscall.SOCK_STREAM, proto, "listen", ctrlCtxFn)
190	if err != nil {
191		return nil, err
192	}
193	return &TCPListener{fd: fd, lc: sl.ListenConfig}, nil
194}
195