Source file
src/net/fd_unix.go
1
2
3
4
5
6
7 package net
8
9 import (
10 "context"
11 "internal/poll"
12 "os"
13 "runtime"
14 "syscall"
15 )
16
17 const (
18 readSyscallName = "read"
19 readFromSyscallName = "recvfrom"
20 readMsgSyscallName = "recvmsg"
21 writeSyscallName = "write"
22 writeToSyscallName = "sendto"
23 writeMsgSyscallName = "sendmsg"
24 )
25
26 func newFD(sysfd, family, sotype int, net string) (*netFD, error) {
27 ret := &netFD{
28 pfd: poll.FD{
29 Sysfd: sysfd,
30 IsStream: sotype == syscall.SOCK_STREAM,
31 ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW,
32 },
33 family: family,
34 sotype: sotype,
35 net: net,
36 }
37 return ret, nil
38 }
39
40 func (fd *netFD) init() error {
41 return fd.pfd.Init(fd.net, true)
42 }
43
44 func (fd *netFD) name() string {
45 var ls, rs string
46 if fd.laddr != nil {
47 ls = fd.laddr.String()
48 }
49 if fd.raddr != nil {
50 rs = fd.raddr.String()
51 }
52 return fd.net + ":" + ls + "->" + rs
53 }
54
55 func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (rsa syscall.Sockaddr, ret error) {
56
57
58
59 switch err := connectFunc(fd.pfd.Sysfd, ra); err {
60 case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
61 case nil, syscall.EISCONN:
62 select {
63 case <-ctx.Done():
64 return nil, mapErr(ctx.Err())
65 default:
66 }
67 if err := fd.pfd.Init(fd.net, true); err != nil {
68 return nil, err
69 }
70 runtime.KeepAlive(fd)
71 return nil, nil
72 case syscall.EINVAL:
73
74
75
76
77
78 if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" {
79 return nil, nil
80 }
81 fallthrough
82 default:
83 return nil, os.NewSyscallError("connect", err)
84 }
85 if err := fd.pfd.Init(fd.net, true); err != nil {
86 return nil, err
87 }
88 if deadline, hasDeadline := ctx.Deadline(); hasDeadline {
89 fd.pfd.SetWriteDeadline(deadline)
90 defer fd.pfd.SetWriteDeadline(noDeadline)
91 }
92
93
94
95
96
97
98 ctxDone := ctx.Done()
99 if ctxDone != nil {
100
101
102 done := make(chan struct{})
103 interruptRes := make(chan error)
104 defer func() {
105 close(done)
106 if ctxErr := <-interruptRes; ctxErr != nil && ret == nil {
107
108
109
110
111
112
113 ret = mapErr(ctxErr)
114 fd.Close()
115 }
116 }()
117 go func() {
118 select {
119 case <-ctxDone:
120
121
122
123 fd.pfd.SetWriteDeadline(aLongTimeAgo)
124 testHookCanceledDial()
125 interruptRes <- ctx.Err()
126 case <-done:
127 interruptRes <- nil
128 }
129 }()
130 }
131
132 for {
133
134
135
136
137
138
139
140
141 if err := fd.pfd.WaitWrite(); err != nil {
142 select {
143 case <-ctxDone:
144 return nil, mapErr(ctx.Err())
145 default:
146 }
147 return nil, err
148 }
149 nerr, err := getsockoptIntFunc(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
150 if err != nil {
151 return nil, os.NewSyscallError("getsockopt", err)
152 }
153 switch err := syscall.Errno(nerr); err {
154 case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
155 case syscall.EISCONN:
156 return nil, nil
157 case syscall.Errno(0):
158
159
160
161 if rsa, err := syscall.Getpeername(fd.pfd.Sysfd); err == nil {
162 return rsa, nil
163 }
164 default:
165 return nil, os.NewSyscallError("connect", err)
166 }
167 runtime.KeepAlive(fd)
168 }
169 }
170
171 func (fd *netFD) accept() (netfd *netFD, err error) {
172 d, rsa, errcall, err := fd.pfd.Accept()
173 if err != nil {
174 if errcall != "" {
175 err = wrapSyscallError(errcall, err)
176 }
177 return nil, err
178 }
179
180 if netfd, err = newFD(d, fd.family, fd.sotype, fd.net); err != nil {
181 poll.CloseFunc(d)
182 return nil, err
183 }
184 if err = netfd.init(); err != nil {
185 netfd.Close()
186 return nil, err
187 }
188 lsa, _ := syscall.Getsockname(netfd.pfd.Sysfd)
189 netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
190 return netfd, nil
191 }
192
193
194 func newUnixFile(fd int, name string) *os.File
195
196 func (fd *netFD) dup() (f *os.File, err error) {
197 ns, call, err := fd.pfd.Dup()
198 if err != nil {
199 if call != "" {
200 err = os.NewSyscallError(call, err)
201 }
202 return nil, err
203 }
204
205 return newUnixFile(ns, fd.name()), nil
206 }
207
View as plain text