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" 13 "time" 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 35 isConnected bool // handshake completed or use of association with peer 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 { 56 errcall, err := fd.pfd.Init(fd.net, true) 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 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 239 // Unimplemented functions. 240 241 func (fd *netFD) dup() (*os.File, error) { 242 // TODO: Implement this 243 return nil, syscall.EWINDOWS 244 } 245 246 func (fd *netFD) SetDeadline(t time.Time) error { 247 return fd.pfd.SetDeadline(t) 248 } 249 250 func (fd *netFD) SetReadDeadline(t time.Time) error { 251 return fd.pfd.SetReadDeadline(t) 252 } 253 254 func (fd *netFD) SetWriteDeadline(t time.Time) error { 255 return fd.pfd.SetWriteDeadline(t) 256 } 257
View as plain text