Source file
src/net/fd_windows.go
1
2
3
4
5 package net
6
7 import (
8 "context"
9 "internal/poll"
10 "internal/syscall/windows"
11 "os"
12 "runtime"
13 "syscall"
14 "unsafe"
15 )
16
17 const (
18 readSyscallName = "wsarecv"
19 readFromSyscallName = "wsarecvfrom"
20 readMsgSyscallName = "wsarecvmsg"
21 writeSyscallName = "wsasend"
22 writeToSyscallName = "wsasendto"
23 writeMsgSyscallName = "wsasendmsg"
24 )
25
26 func init() {
27 poll.InitWSA()
28 }
29
30
31
32 func canUseConnectEx(net string) bool {
33 switch net {
34 case "tcp", "tcp4", "tcp6":
35 return true
36 }
37
38 return false
39 }
40
41 func newFD(sysfd syscall.Handle, family, sotype int, net string) *netFD {
42 return &netFD{
43 pfd: poll.FD{
44 Sysfd: sysfd,
45 IsStream: sotype == syscall.SOCK_STREAM,
46 ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW,
47 },
48 family: family,
49 sotype: sotype,
50 net: net,
51 }
52 }
53
54 func (fd *netFD) init() error {
55 if err := fd.pfd.Init(fd.net, true); err != nil {
56 return err
57 }
58 switch fd.net {
59 case "udp", "udp4", "udp6":
60
61
62 ret := uint32(0)
63 flag := uint32(0)
64 size := uint32(unsafe.Sizeof(flag))
65 err := syscall.WSAIoctl(fd.pfd.Sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
66 if err != nil {
67 return wrapSyscallError("wsaioctl", err)
68 }
69
70
71 ret = 0
72 flag = 0
73 size = uint32(unsafe.Sizeof(flag))
74 err = syscall.WSAIoctl(fd.pfd.Sysfd, windows.SIO_UDP_NETRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
75 if err != nil {
76 return wrapSyscallError("wsaioctl", err)
77 }
78 }
79 return nil
80 }
81
82
83 func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (syscall.Sockaddr, error) {
84
85
86
87 if err := fd.init(); err != nil {
88 return nil, err
89 }
90
91 if ctx.Done() != nil {
92
93
94
95
96 defer fd.pfd.SetWriteDeadline(noDeadline)
97
98 if ctx.Err() != nil {
99 fd.pfd.SetWriteDeadline(aLongTimeAgo)
100 } else {
101 if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
102 fd.pfd.SetWriteDeadline(deadline)
103 }
104
105 done := make(chan struct{})
106 stop := context.AfterFunc(ctx, func() {
107
108
109 fd.pfd.SetWriteDeadline(aLongTimeAgo)
110 close(done)
111 })
112 defer func() {
113 if !stop() {
114
115
116 <-done
117 }
118 }()
119 }
120 }
121
122 if !canUseConnectEx(fd.net) {
123 err := connectFunc(fd.pfd.Sysfd, ra)
124 return nil, os.NewSyscallError("connect", err)
125 }
126
127 if la == nil {
128 switch ra.(type) {
129 case *syscall.SockaddrInet4:
130 la = &syscall.SockaddrInet4{}
131 case *syscall.SockaddrInet6:
132 la = &syscall.SockaddrInet6{}
133 default:
134 panic("unexpected type in connect")
135 }
136 if err := syscall.Bind(fd.pfd.Sysfd, la); err != nil {
137 return nil, os.NewSyscallError("bind", err)
138 }
139 }
140
141 var isloopback bool
142 switch ra := ra.(type) {
143 case *syscall.SockaddrInet4:
144 isloopback = ra.Addr[0] == 127
145 case *syscall.SockaddrInet6:
146 isloopback = ra.Addr == [16]byte(IPv6loopback)
147 default:
148 panic("unexpected type in connect")
149 }
150 if isloopback {
151
152
153 params := windows.TCP_INITIAL_RTO_PARAMETERS{
154 Rtt: windows.TCP_INITIAL_RTO_UNSPECIFIED_RTT,
155 MaxSynRetransmissions: 1,
156 }
157 if windows.SupportTCPInitialRTONoSYNRetransmissions() {
158
159 params.MaxSynRetransmissions = windows.TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS
160 }
161 var out uint32
162
163
164 _ = fd.pfd.WSAIoctl(windows.SIO_TCP_INITIAL_RTO, (*byte)(unsafe.Pointer(¶ms)), uint32(unsafe.Sizeof(params)), nil, 0, &out, nil, 0)
165 }
166
167
168 if err := fd.pfd.ConnectEx(ra); err != nil {
169 select {
170 case <-ctx.Done():
171 return nil, mapErr(ctx.Err())
172 default:
173 if _, ok := err.(syscall.Errno); ok {
174 err = os.NewSyscallError("connectex", err)
175 }
176 return nil, err
177 }
178 }
179
180 return nil, os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.pfd.Sysfd)), int32(unsafe.Sizeof(fd.pfd.Sysfd))))
181 }
182
183 func (c *conn) writeBuffers(v *Buffers) (int64, error) {
184 if !c.ok() {
185 return 0, syscall.EINVAL
186 }
187 n, err := c.fd.writeBuffers(v)
188 if err != nil {
189 return n, &OpError{Op: "wsasend", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
190 }
191 return n, nil
192 }
193
194 func (fd *netFD) writeBuffers(buf *Buffers) (int64, error) {
195 n, err := fd.pfd.Writev((*[][]byte)(buf))
196 runtime.KeepAlive(fd)
197 return n, wrapSyscallError("wsasend", err)
198 }
199
200 func (fd *netFD) accept() (*netFD, error) {
201 s, rawsa, rsan, errcall, err := fd.pfd.Accept(func() (syscall.Handle, error) {
202 return sysSocket(fd.family, fd.sotype, 0)
203 })
204
205 if err != nil {
206 if errcall != "" {
207 err = wrapSyscallError(errcall, err)
208 }
209 return nil, err
210 }
211
212
213 netfd := newFD(s, fd.family, fd.sotype, fd.net)
214 if err := netfd.init(); err != nil {
215 netfd.Close()
216 return nil, err
217 }
218
219
220 var lrsa, rrsa *syscall.RawSockaddrAny
221 var llen, rlen int32
222 syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&rawsa[0])),
223 0, rsan, rsan, &lrsa, &llen, &rrsa, &rlen)
224 lsa, _ := lrsa.Sockaddr()
225 rsa, _ := rrsa.Sockaddr()
226
227 netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
228 return netfd, nil
229 }
230
231
232 func newWindowsFile(h syscall.Handle, name string) *os.File
233
234 func (fd *netFD) dup() (*os.File, error) {
235
236
237
238 if err := fd.pfd.DisassociateIOCP(); err != nil {
239 return nil, err
240 }
241 var h syscall.Handle
242 var syserr error
243 err := fd.pfd.RawControl(func(fd uintptr) {
244 h, syserr = dupSocket(syscall.Handle(fd))
245 })
246 if err == nil {
247 err = syserr
248 }
249 if err != nil {
250 return nil, err
251 }
252
253
254
255 return newWindowsFile(h, fd.name()), nil
256 }
257
View as plain text