111
|
1 // Copyright 2010 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 package net
|
|
6
|
|
7 import (
|
|
8 "context"
|
|
9 "internal/poll"
|
|
10 "os"
|
|
11 "runtime"
|
|
12 "syscall"
|
131
|
13 "time"
|
111
|
14 "unsafe"
|
|
15 )
|
|
16
|
|
17 // canUseConnectEx reports whether we can use the ConnectEx Windows API call
|
|
18 // for the given network type.
|
|
19 func canUseConnectEx(net string) bool {
|
|
20 switch net {
|
|
21 case "tcp", "tcp4", "tcp6":
|
|
22 return true
|
|
23 }
|
|
24 // ConnectEx windows API does not support connectionless sockets.
|
|
25 return false
|
|
26 }
|
|
27
|
|
28 // Network file descriptor.
|
|
29 type netFD struct {
|
|
30 pfd poll.FD
|
|
31
|
|
32 // immutable until Close
|
|
33 family int
|
|
34 sotype int
|
131
|
35 isConnected bool // handshake completed or use of association with peer
|
111
|
36 net string
|
|
37 laddr Addr
|
|
38 raddr Addr
|
|
39 }
|
|
40
|
|
41 func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error) {
|
|
42 ret := &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 return ret, nil
|
|
53 }
|
|
54
|
|
55 func (fd *netFD) init() error {
|
131
|
56 errcall, err := fd.pfd.Init(fd.net, true)
|
111
|
57 if errcall != "" {
|
|
58 err = wrapSyscallError(errcall, err)
|
|
59 }
|
|
60 return err
|
|
61 }
|
|
62
|
|
63 func (fd *netFD) setAddr(laddr, raddr Addr) {
|
|
64 fd.laddr = laddr
|
|
65 fd.raddr = raddr
|
|
66 runtime.SetFinalizer(fd, (*netFD).Close)
|
|
67 }
|
|
68
|
|
69 // Always returns nil for connected peer address result.
|
|
70 func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (syscall.Sockaddr, error) {
|
|
71 // Do not need to call fd.writeLock here,
|
|
72 // because fd is not yet accessible to user,
|
|
73 // so no concurrent operations are possible.
|
|
74 if err := fd.init(); err != nil {
|
|
75 return nil, err
|
|
76 }
|
|
77 if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
|
|
78 fd.pfd.SetWriteDeadline(deadline)
|
|
79 defer fd.pfd.SetWriteDeadline(noDeadline)
|
|
80 }
|
|
81 if !canUseConnectEx(fd.net) {
|
|
82 err := connectFunc(fd.pfd.Sysfd, ra)
|
|
83 return nil, os.NewSyscallError("connect", err)
|
|
84 }
|
|
85 // ConnectEx windows API requires an unconnected, previously bound socket.
|
|
86 if la == nil {
|
|
87 switch ra.(type) {
|
|
88 case *syscall.SockaddrInet4:
|
|
89 la = &syscall.SockaddrInet4{}
|
|
90 case *syscall.SockaddrInet6:
|
|
91 la = &syscall.SockaddrInet6{}
|
|
92 default:
|
|
93 panic("unexpected type in connect")
|
|
94 }
|
|
95 if err := syscall.Bind(fd.pfd.Sysfd, la); err != nil {
|
|
96 return nil, os.NewSyscallError("bind", err)
|
|
97 }
|
|
98 }
|
|
99
|
|
100 // Wait for the goroutine converting context.Done into a write timeout
|
|
101 // to exist, otherwise our caller might cancel the context and
|
|
102 // cause fd.setWriteDeadline(aLongTimeAgo) to cancel a successful dial.
|
|
103 done := make(chan bool) // must be unbuffered
|
|
104 defer func() { done <- true }()
|
|
105 go func() {
|
|
106 select {
|
|
107 case <-ctx.Done():
|
|
108 // Force the runtime's poller to immediately give
|
|
109 // up waiting for writability.
|
|
110 fd.pfd.SetWriteDeadline(aLongTimeAgo)
|
|
111 <-done
|
|
112 case <-done:
|
|
113 }
|
|
114 }()
|
|
115
|
|
116 // Call ConnectEx API.
|
|
117 if err := fd.pfd.ConnectEx(ra); err != nil {
|
|
118 select {
|
|
119 case <-ctx.Done():
|
|
120 return nil, mapErr(ctx.Err())
|
|
121 default:
|
|
122 if _, ok := err.(syscall.Errno); ok {
|
|
123 err = os.NewSyscallError("connectex", err)
|
|
124 }
|
|
125 return nil, err
|
|
126 }
|
|
127 }
|
|
128 // Refresh socket properties.
|
|
129 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))))
|
|
130 }
|
|
131
|
|
132 func (fd *netFD) Close() error {
|
|
133 runtime.SetFinalizer(fd, nil)
|
|
134 return fd.pfd.Close()
|
|
135 }
|
|
136
|
|
137 func (fd *netFD) shutdown(how int) error {
|
|
138 err := fd.pfd.Shutdown(how)
|
|
139 runtime.KeepAlive(fd)
|
|
140 return err
|
|
141 }
|
|
142
|
|
143 func (fd *netFD) closeRead() error {
|
|
144 return fd.shutdown(syscall.SHUT_RD)
|
|
145 }
|
|
146
|
|
147 func (fd *netFD) closeWrite() error {
|
|
148 return fd.shutdown(syscall.SHUT_WR)
|
|
149 }
|
|
150
|
|
151 func (fd *netFD) Read(buf []byte) (int, error) {
|
|
152 n, err := fd.pfd.Read(buf)
|
|
153 runtime.KeepAlive(fd)
|
|
154 return n, wrapSyscallError("wsarecv", err)
|
|
155 }
|
|
156
|
|
157 func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) {
|
|
158 n, sa, err := fd.pfd.ReadFrom(buf)
|
|
159 runtime.KeepAlive(fd)
|
|
160 return n, sa, wrapSyscallError("wsarecvfrom", err)
|
|
161 }
|
|
162
|
|
163 func (fd *netFD) Write(buf []byte) (int, error) {
|
|
164 n, err := fd.pfd.Write(buf)
|
|
165 runtime.KeepAlive(fd)
|
|
166 return n, wrapSyscallError("wsasend", err)
|
|
167 }
|
|
168
|
|
169 func (c *conn) writeBuffers(v *Buffers) (int64, error) {
|
|
170 if !c.ok() {
|
|
171 return 0, syscall.EINVAL
|
|
172 }
|
|
173 n, err := c.fd.writeBuffers(v)
|
|
174 if err != nil {
|
|
175 return n, &OpError{Op: "wsasend", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
|
|
176 }
|
|
177 return n, nil
|
|
178 }
|
|
179
|
|
180 func (fd *netFD) writeBuffers(buf *Buffers) (int64, error) {
|
|
181 n, err := fd.pfd.Writev((*[][]byte)(buf))
|
|
182 runtime.KeepAlive(fd)
|
|
183 return n, wrapSyscallError("wsasend", err)
|
|
184 }
|
|
185
|
|
186 func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
|
|
187 n, err := fd.pfd.WriteTo(buf, sa)
|
|
188 runtime.KeepAlive(fd)
|
|
189 return n, wrapSyscallError("wsasendto", err)
|
|
190 }
|
|
191
|
|
192 func (fd *netFD) accept() (*netFD, error) {
|
|
193 s, rawsa, rsan, errcall, err := fd.pfd.Accept(func() (syscall.Handle, error) {
|
|
194 return sysSocket(fd.family, fd.sotype, 0)
|
|
195 })
|
|
196
|
|
197 if err != nil {
|
|
198 if errcall != "" {
|
|
199 err = wrapSyscallError(errcall, err)
|
|
200 }
|
|
201 return nil, err
|
|
202 }
|
|
203
|
|
204 // Associate our new socket with IOCP.
|
|
205 netfd, err := newFD(s, fd.family, fd.sotype, fd.net)
|
|
206 if err != nil {
|
|
207 poll.CloseFunc(s)
|
|
208 return nil, err
|
|
209 }
|
|
210 if err := netfd.init(); err != nil {
|
|
211 fd.Close()
|
|
212 return nil, err
|
|
213 }
|
|
214
|
|
215 // Get local and peer addr out of AcceptEx buffer.
|
|
216 var lrsa, rrsa *syscall.RawSockaddrAny
|
|
217 var llen, rlen int32
|
|
218 syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&rawsa[0])),
|
|
219 0, rsan, rsan, &lrsa, &llen, &rrsa, &rlen)
|
|
220 lsa, _ := lrsa.Sockaddr()
|
|
221 rsa, _ := rrsa.Sockaddr()
|
|
222
|
|
223 netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
|
|
224 return netfd, nil
|
|
225 }
|
|
226
|
131
|
227 func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
|
|
228 n, oobn, flags, sa, err = fd.pfd.ReadMsg(p, oob)
|
|
229 runtime.KeepAlive(fd)
|
|
230 return n, oobn, flags, sa, wrapSyscallError("wsarecvmsg", err)
|
|
231 }
|
|
232
|
|
233 func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
|
|
234 n, oobn, err = fd.pfd.WriteMsg(p, oob, sa)
|
|
235 runtime.KeepAlive(fd)
|
|
236 return n, oobn, wrapSyscallError("wsasendmsg", err)
|
|
237 }
|
|
238
|
111
|
239 // Unimplemented functions.
|
|
240
|
|
241 func (fd *netFD) dup() (*os.File, error) {
|
|
242 // TODO: Implement this
|
|
243 return nil, syscall.EWINDOWS
|
|
244 }
|
|
245
|
131
|
246 func (fd *netFD) SetDeadline(t time.Time) error {
|
|
247 return fd.pfd.SetDeadline(t)
|
111
|
248 }
|
|
249
|
131
|
250 func (fd *netFD) SetReadDeadline(t time.Time) error {
|
|
251 return fd.pfd.SetReadDeadline(t)
|
111
|
252 }
|
131
|
253
|
|
254 func (fd *netFD) SetWriteDeadline(t time.Time) error {
|
|
255 return fd.pfd.SetWriteDeadline(t)
|
|
256 }
|