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