Source file
src/net/tcpsock_posix.go
Documentation: net
1
2
3
4
5
6
7
8 package net
9
10 import (
11 "context"
12 "io"
13 "os"
14 "syscall"
15 )
16
17 func sockaddrToTCP(sa syscall.Sockaddr) Addr {
18 switch sa := sa.(type) {
19 case *syscall.SockaddrInet4:
20 return &TCPAddr{IP: sa.Addr[0:], Port: sa.Port}
21 case *syscall.SockaddrInet6:
22 return &TCPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneCache.name(int(sa.ZoneId))}
23 }
24 return nil
25 }
26
27 func (a *TCPAddr) family() int {
28 if a == nil || len(a.IP) <= IPv4len {
29 return syscall.AF_INET
30 }
31 if a.IP.To4() != nil {
32 return syscall.AF_INET
33 }
34 return syscall.AF_INET6
35 }
36
37 func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
38 if a == nil {
39 return nil, nil
40 }
41 return ipToSockaddr(family, a.IP, a.Port, a.Zone)
42 }
43
44 func (a *TCPAddr) toLocal(net string) sockaddr {
45 return &TCPAddr{loopbackIP(net), a.Port, a.Zone}
46 }
47
48 func (c *TCPConn) readFrom(r io.Reader) (int64, error) {
49 if n, err, handled := splice(c.fd, r); handled {
50 return n, err
51 }
52 if n, err, handled := sendFile(c.fd, r); handled {
53 return n, err
54 }
55 return genericReadFrom(c, r)
56 }
57
58 func (sd *sysDialer) dialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) {
59 if testHookDialTCP != nil {
60 return testHookDialTCP(ctx, sd.network, laddr, raddr)
61 }
62 return sd.doDialTCP(ctx, laddr, raddr)
63 }
64
65 func (sd *sysDialer) doDialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) {
66 fd, err := internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_STREAM, 0, "dial", sd.Dialer.Control)
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 for i := 0; i < 2 && (laddr == nil || laddr.Port == 0) && (selfConnect(fd, err) || spuriousENOTAVAIL(err)); i++ {
93 if err == nil {
94 fd.Close()
95 }
96 fd, err = internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_STREAM, 0, "dial", sd.Dialer.Control)
97 }
98
99 if err != nil {
100 return nil, err
101 }
102 return newTCPConn(fd), nil
103 }
104
105 func selfConnect(fd *netFD, err error) bool {
106
107 if err != nil {
108 return false
109 }
110
111
112
113
114
115
116
117
118
119 if fd.laddr == nil || fd.raddr == nil {
120 return true
121 }
122 l := fd.laddr.(*TCPAddr)
123 r := fd.raddr.(*TCPAddr)
124 return l.Port == r.Port && l.IP.Equal(r.IP)
125 }
126
127 func spuriousENOTAVAIL(err error) bool {
128 if op, ok := err.(*OpError); ok {
129 err = op.Err
130 }
131 if sys, ok := err.(*os.SyscallError); ok {
132 err = sys.Err
133 }
134 return err == syscall.EADDRNOTAVAIL
135 }
136
137 func (ln *TCPListener) ok() bool { return ln != nil && ln.fd != nil }
138
139 func (ln *TCPListener) accept() (*TCPConn, error) {
140 fd, err := ln.fd.accept()
141 if err != nil {
142 return nil, err
143 }
144 tc := newTCPConn(fd)
145 if ln.lc.KeepAlive >= 0 {
146 setKeepAlive(fd, true)
147 ka := ln.lc.KeepAlive
148 if ln.lc.KeepAlive == 0 {
149 ka = defaultTCPKeepAlive
150 }
151 setKeepAlivePeriod(fd, ka)
152 }
153 return tc, nil
154 }
155
156 func (ln *TCPListener) close() error {
157 return ln.fd.Close()
158 }
159
160 func (ln *TCPListener) file() (*os.File, error) {
161 f, err := ln.fd.dup()
162 if err != nil {
163 return nil, err
164 }
165 return f, nil
166 }
167
168 func (sl *sysListener) listenTCP(ctx context.Context, laddr *TCPAddr) (*TCPListener, error) {
169 fd, err := internetSocket(ctx, sl.network, laddr, nil, syscall.SOCK_STREAM, 0, "listen", sl.ListenConfig.Control)
170 if err != nil {
171 return nil, err
172 }
173 return &TCPListener{fd: fd, lc: sl.ListenConfig}, nil
174 }
175
View as plain text