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