rsc.io/go@v0.0.0-20150416155037-e040fd465409/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 "errors" 9 "os" 10 "runtime" 11 "sync" 12 "syscall" 13 "time" 14 "unsafe" 15 ) 16 17 var ( 18 initErr error 19 ioSync uint64 20 ) 21 22 // CancelIo Windows API cancels all outstanding IO for a particular 23 // socket on current thread. To overcome that limitation, we run 24 // special goroutine, locked to OS single thread, that both starts 25 // and cancels IO. It means, there are 2 unavoidable thread switches 26 // for every IO. 27 // Some newer versions of Windows has new CancelIoEx API, that does 28 // not have that limitation and can be used from any thread. This 29 // package uses CancelIoEx API, if present, otherwise it fallback 30 // to CancelIo. 31 32 var ( 33 canCancelIO bool // determines if CancelIoEx API is present 34 skipSyncNotif bool 35 hasLoadSetFileCompletionNotificationModes bool 36 ) 37 38 func sysInit() { 39 var d syscall.WSAData 40 e := syscall.WSAStartup(uint32(0x202), &d) 41 if e != nil { 42 initErr = os.NewSyscallError("WSAStartup", e) 43 } 44 canCancelIO = syscall.LoadCancelIoEx() == nil 45 if syscall.LoadGetAddrInfo() == nil { 46 lookupPort = newLookupPort 47 lookupIP = newLookupIP 48 } 49 50 hasLoadSetFileCompletionNotificationModes = syscall.LoadSetFileCompletionNotificationModes() == nil 51 if hasLoadSetFileCompletionNotificationModes { 52 // It's not safe to use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS if non IFS providers are installed: 53 // http://support.microsoft.com/kb/2568167 54 skipSyncNotif = true 55 protos := [2]int32{syscall.IPPROTO_TCP, 0} 56 var buf [32]syscall.WSAProtocolInfo 57 len := uint32(unsafe.Sizeof(buf)) 58 n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len) 59 if err != nil { 60 skipSyncNotif = false 61 } else { 62 for i := int32(0); i < n; i++ { 63 if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 { 64 skipSyncNotif = false 65 break 66 } 67 } 68 } 69 } 70 } 71 72 func canUseConnectEx(net string) bool { 73 switch net { 74 case "udp", "udp4", "udp6", "ip", "ip4", "ip6": 75 // ConnectEx windows API does not support connectionless sockets. 76 return false 77 } 78 return syscall.LoadConnectEx() == nil 79 } 80 81 func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) { 82 if !canUseConnectEx(net) { 83 // Use the relatively inefficient goroutine-racing 84 // implementation of DialTimeout. 85 return dialChannel(net, ra, dialer, deadline) 86 } 87 return dialer(deadline) 88 } 89 90 // operation contains superset of data necessary to perform all async IO. 91 type operation struct { 92 // Used by IOCP interface, it must be first field 93 // of the struct, as our code rely on it. 94 o syscall.Overlapped 95 96 // fields used by runtime.netpoll 97 runtimeCtx uintptr 98 mode int32 99 errno int32 100 qty uint32 101 102 // fields used only by net package 103 fd *netFD 104 errc chan error 105 buf syscall.WSABuf 106 sa syscall.Sockaddr 107 rsa *syscall.RawSockaddrAny 108 rsan int32 109 handle syscall.Handle 110 flags uint32 111 } 112 113 func (o *operation) InitBuf(buf []byte) { 114 o.buf.Len = uint32(len(buf)) 115 o.buf.Buf = nil 116 if len(buf) != 0 { 117 o.buf.Buf = &buf[0] 118 } 119 } 120 121 // ioSrv executes net IO requests. 122 type ioSrv struct { 123 req chan ioSrvReq 124 } 125 126 type ioSrvReq struct { 127 o *operation 128 submit func(o *operation) error // if nil, cancel the operation 129 } 130 131 // ProcessRemoteIO will execute submit IO requests on behalf 132 // of other goroutines, all on a single os thread, so it can 133 // cancel them later. Results of all operations will be sent 134 // back to their requesters via channel supplied in request. 135 // It is used only when the CancelIoEx API is unavailable. 136 func (s *ioSrv) ProcessRemoteIO() { 137 runtime.LockOSThread() 138 defer runtime.UnlockOSThread() 139 for r := range s.req { 140 if r.submit != nil { 141 r.o.errc <- r.submit(r.o) 142 } else { 143 r.o.errc <- syscall.CancelIo(r.o.fd.sysfd) 144 } 145 } 146 } 147 148 // ExecIO executes a single IO operation o. It submits and cancels 149 // IO in the current thread for systems where Windows CancelIoEx API 150 // is available. Alternatively, it passes the request onto 151 // runtime netpoll and waits for completion or cancels request. 152 func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) error) (int, error) { 153 fd := o.fd 154 // Notify runtime netpoll about starting IO. 155 err := fd.pd.Prepare(int(o.mode)) 156 if err != nil { 157 return 0, &OpError{name, fd.net, fd.laddr, err} 158 } 159 // Start IO. 160 if canCancelIO { 161 err = submit(o) 162 } else { 163 // Send request to a special dedicated thread, 164 // so it can stop the IO with CancelIO later. 165 s.req <- ioSrvReq{o, submit} 166 err = <-o.errc 167 } 168 switch err { 169 case nil: 170 // IO completed immediately 171 if o.fd.skipSyncNotif { 172 // No completion message will follow, so return immediately. 173 return int(o.qty), nil 174 } 175 // Need to get our completion message anyway. 176 case syscall.ERROR_IO_PENDING: 177 // IO started, and we have to wait for its completion. 178 err = nil 179 default: 180 return 0, &OpError{name, fd.net, fd.laddr, err} 181 } 182 // Wait for our request to complete. 183 err = fd.pd.Wait(int(o.mode)) 184 if err == nil { 185 // All is good. Extract our IO results and return. 186 if o.errno != 0 { 187 err = syscall.Errno(o.errno) 188 return 0, &OpError{name, fd.net, fd.laddr, err} 189 } 190 return int(o.qty), nil 191 } 192 // IO is interrupted by "close" or "timeout" 193 netpollErr := err 194 switch netpollErr { 195 case errClosing, errTimeout: 196 // will deal with those. 197 default: 198 panic("net: unexpected runtime.netpoll error: " + netpollErr.Error()) 199 } 200 // Cancel our request. 201 if canCancelIO { 202 err := syscall.CancelIoEx(fd.sysfd, &o.o) 203 // Assuming ERROR_NOT_FOUND is returned, if IO is completed. 204 if err != nil && err != syscall.ERROR_NOT_FOUND { 205 // TODO(brainman): maybe do something else, but panic. 206 panic(err) 207 } 208 } else { 209 s.req <- ioSrvReq{o, nil} 210 <-o.errc 211 } 212 // Wait for cancellation to complete. 213 fd.pd.WaitCanceled(int(o.mode)) 214 if o.errno != 0 { 215 err = syscall.Errno(o.errno) 216 if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled 217 err = netpollErr 218 } 219 return 0, &OpError{name, fd.net, fd.laddr, err} 220 } 221 // We issued cancellation request. But, it seems, IO operation succeeded 222 // before cancellation request run. We need to treat IO operation as 223 // succeeded (the bytes are actually sent/recv from network). 224 return int(o.qty), nil 225 } 226 227 // Start helper goroutines. 228 var rsrv, wsrv *ioSrv 229 var onceStartServer sync.Once 230 231 func startServer() { 232 rsrv = new(ioSrv) 233 wsrv = new(ioSrv) 234 if !canCancelIO { 235 // Only CancelIo API is available. Lets start two special goroutines 236 // locked to an OS thread, that both starts and cancels IO. One will 237 // process read requests, while other will do writes. 238 rsrv.req = make(chan ioSrvReq) 239 go rsrv.ProcessRemoteIO() 240 wsrv.req = make(chan ioSrvReq) 241 go wsrv.ProcessRemoteIO() 242 } 243 } 244 245 // Network file descriptor. 246 type netFD struct { 247 // locking/lifetime of sysfd + serialize access to Read and Write methods 248 fdmu fdMutex 249 250 // immutable until Close 251 sysfd syscall.Handle 252 family int 253 sotype int 254 isConnected bool 255 skipSyncNotif bool 256 net string 257 laddr Addr 258 raddr Addr 259 260 rop operation // read operation 261 wop operation // write operation 262 263 // wait server 264 pd pollDesc 265 } 266 267 func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error) { 268 if initErr != nil { 269 return nil, initErr 270 } 271 onceStartServer.Do(startServer) 272 return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net}, nil 273 } 274 275 func (fd *netFD) init() error { 276 if err := fd.pd.Init(fd); err != nil { 277 return err 278 } 279 if hasLoadSetFileCompletionNotificationModes { 280 // We do not use events, so we can skip them always. 281 flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE) 282 // It's not safe to skip completion notifications for UDP: 283 // http://blogs.technet.com/b/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx 284 if skipSyncNotif && fd.net == "tcp" { 285 flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 286 } 287 err := syscall.SetFileCompletionNotificationModes(fd.sysfd, flags) 288 if err == nil && flags&syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS != 0 { 289 fd.skipSyncNotif = true 290 } 291 } 292 // Disable SIO_UDP_CONNRESET behavior. 293 // http://support.microsoft.com/kb/263823 294 switch fd.net { 295 case "udp", "udp4", "udp6": 296 ret := uint32(0) 297 flag := uint32(0) 298 size := uint32(unsafe.Sizeof(flag)) 299 err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0) 300 if err != nil { 301 return os.NewSyscallError("WSAIoctl", err) 302 } 303 } 304 fd.rop.mode = 'r' 305 fd.wop.mode = 'w' 306 fd.rop.fd = fd 307 fd.wop.fd = fd 308 fd.rop.runtimeCtx = fd.pd.runtimeCtx 309 fd.wop.runtimeCtx = fd.pd.runtimeCtx 310 if !canCancelIO { 311 fd.rop.errc = make(chan error) 312 fd.wop.errc = make(chan error) 313 } 314 return nil 315 } 316 317 func (fd *netFD) setAddr(laddr, raddr Addr) { 318 fd.laddr = laddr 319 fd.raddr = raddr 320 runtime.SetFinalizer(fd, (*netFD).Close) 321 } 322 323 func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error { 324 // Do not need to call fd.writeLock here, 325 // because fd is not yet accessible to user, 326 // so no concurrent operations are possible. 327 if err := fd.init(); err != nil { 328 return err 329 } 330 if !deadline.IsZero() { 331 fd.setWriteDeadline(deadline) 332 defer fd.setWriteDeadline(noDeadline) 333 } 334 if !canUseConnectEx(fd.net) { 335 return connectFunc(fd.sysfd, ra) 336 } 337 // ConnectEx windows API requires an unconnected, previously bound socket. 338 if la == nil { 339 switch ra.(type) { 340 case *syscall.SockaddrInet4: 341 la = &syscall.SockaddrInet4{} 342 case *syscall.SockaddrInet6: 343 la = &syscall.SockaddrInet6{} 344 default: 345 panic("unexpected type in connect") 346 } 347 if err := syscall.Bind(fd.sysfd, la); err != nil { 348 return err 349 } 350 } 351 // Call ConnectEx API. 352 o := &fd.wop 353 o.sa = ra 354 _, err := wsrv.ExecIO(o, "ConnectEx", func(o *operation) error { 355 return connectExFunc(o.fd.sysfd, o.sa, nil, 0, nil, &o.o) 356 }) 357 if err != nil { 358 return err 359 } 360 // Refresh socket properties. 361 return syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))) 362 } 363 364 func (fd *netFD) destroy() { 365 if fd.sysfd == syscall.InvalidHandle { 366 return 367 } 368 // Poller may want to unregister fd in readiness notification mechanism, 369 // so this must be executed before closeFunc. 370 fd.pd.Close() 371 closeFunc(fd.sysfd) 372 fd.sysfd = syscall.InvalidHandle 373 // no need for a finalizer anymore 374 runtime.SetFinalizer(fd, nil) 375 } 376 377 // Add a reference to this fd. 378 // Returns an error if the fd cannot be used. 379 func (fd *netFD) incref() error { 380 if !fd.fdmu.Incref() { 381 return errClosing 382 } 383 return nil 384 } 385 386 // Remove a reference to this FD and close if we've been asked to do so 387 // (and there are no references left). 388 func (fd *netFD) decref() { 389 if fd.fdmu.Decref() { 390 fd.destroy() 391 } 392 } 393 394 // Add a reference to this fd and lock for reading. 395 // Returns an error if the fd cannot be used. 396 func (fd *netFD) readLock() error { 397 if !fd.fdmu.RWLock(true) { 398 return errClosing 399 } 400 return nil 401 } 402 403 // Unlock for reading and remove a reference to this FD. 404 func (fd *netFD) readUnlock() { 405 if fd.fdmu.RWUnlock(true) { 406 fd.destroy() 407 } 408 } 409 410 // Add a reference to this fd and lock for writing. 411 // Returns an error if the fd cannot be used. 412 func (fd *netFD) writeLock() error { 413 if !fd.fdmu.RWLock(false) { 414 return errClosing 415 } 416 return nil 417 } 418 419 // Unlock for writing and remove a reference to this FD. 420 func (fd *netFD) writeUnlock() { 421 if fd.fdmu.RWUnlock(false) { 422 fd.destroy() 423 } 424 } 425 426 func (fd *netFD) Close() error { 427 if !fd.fdmu.IncrefAndClose() { 428 return errClosing 429 } 430 // unblock pending reader and writer 431 fd.pd.Evict() 432 fd.decref() 433 return nil 434 } 435 436 func (fd *netFD) shutdown(how int) error { 437 if err := fd.incref(); err != nil { 438 return err 439 } 440 defer fd.decref() 441 err := syscall.Shutdown(fd.sysfd, how) 442 if err != nil { 443 return &OpError{"shutdown", fd.net, fd.laddr, err} 444 } 445 return nil 446 } 447 448 func (fd *netFD) closeRead() error { 449 return fd.shutdown(syscall.SHUT_RD) 450 } 451 452 func (fd *netFD) closeWrite() error { 453 return fd.shutdown(syscall.SHUT_WR) 454 } 455 456 func (fd *netFD) Read(buf []byte) (int, error) { 457 if err := fd.readLock(); err != nil { 458 return 0, err 459 } 460 defer fd.readUnlock() 461 o := &fd.rop 462 o.InitBuf(buf) 463 n, err := rsrv.ExecIO(o, "WSARecv", func(o *operation) error { 464 return syscall.WSARecv(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil) 465 }) 466 if raceenabled { 467 raceAcquire(unsafe.Pointer(&ioSync)) 468 } 469 err = fd.eofError(n, err) 470 return n, err 471 } 472 473 func (fd *netFD) readFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) { 474 if len(buf) == 0 { 475 return 0, nil, nil 476 } 477 if err := fd.readLock(); err != nil { 478 return 0, nil, err 479 } 480 defer fd.readUnlock() 481 o := &fd.rop 482 o.InitBuf(buf) 483 n, err = rsrv.ExecIO(o, "WSARecvFrom", func(o *operation) error { 484 if o.rsa == nil { 485 o.rsa = new(syscall.RawSockaddrAny) 486 } 487 o.rsan = int32(unsafe.Sizeof(*o.rsa)) 488 return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil) 489 }) 490 err = fd.eofError(n, err) 491 if err != nil { 492 return 0, nil, err 493 } 494 sa, _ = o.rsa.Sockaddr() 495 return 496 } 497 498 func (fd *netFD) Write(buf []byte) (int, error) { 499 if err := fd.writeLock(); err != nil { 500 return 0, err 501 } 502 defer fd.writeUnlock() 503 if raceenabled { 504 raceReleaseMerge(unsafe.Pointer(&ioSync)) 505 } 506 o := &fd.wop 507 o.InitBuf(buf) 508 return wsrv.ExecIO(o, "WSASend", func(o *operation) error { 509 return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil) 510 }) 511 } 512 513 func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) { 514 if len(buf) == 0 { 515 return 0, nil 516 } 517 if err := fd.writeLock(); err != nil { 518 return 0, err 519 } 520 defer fd.writeUnlock() 521 o := &fd.wop 522 o.InitBuf(buf) 523 o.sa = sa 524 return wsrv.ExecIO(o, "WSASendto", func(o *operation) error { 525 return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil) 526 }) 527 } 528 529 func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD, error) { 530 // Get new socket. 531 s, err := sysSocket(fd.family, fd.sotype, 0) 532 if err != nil { 533 return nil, &OpError{"socket", fd.net, fd.laddr, err} 534 } 535 536 // Associate our new socket with IOCP. 537 netfd, err := newFD(s, fd.family, fd.sotype, fd.net) 538 if err != nil { 539 closeFunc(s) 540 return nil, &OpError{"accept", fd.net, fd.laddr, err} 541 } 542 if err := netfd.init(); err != nil { 543 fd.Close() 544 return nil, err 545 } 546 547 // Submit accept request. 548 o.handle = s 549 o.rsan = int32(unsafe.Sizeof(rawsa[0])) 550 _, err = rsrv.ExecIO(o, "AcceptEx", func(o *operation) error { 551 return syscall.AcceptEx(o.fd.sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o) 552 }) 553 if err != nil { 554 netfd.Close() 555 return nil, err 556 } 557 558 // Inherit properties of the listening socket. 559 err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))) 560 if err != nil { 561 netfd.Close() 562 return nil, &OpError{"Setsockopt", fd.net, fd.laddr, err} 563 } 564 565 return netfd, nil 566 } 567 568 func (fd *netFD) accept() (*netFD, error) { 569 if err := fd.readLock(); err != nil { 570 return nil, err 571 } 572 defer fd.readUnlock() 573 574 o := &fd.rop 575 var netfd *netFD 576 var err error 577 var rawsa [2]syscall.RawSockaddrAny 578 for { 579 netfd, err = fd.acceptOne(rawsa[:], o) 580 if err == nil { 581 break 582 } 583 // Sometimes we see WSAECONNRESET and ERROR_NETNAME_DELETED is 584 // returned here. These happen if connection reset is received 585 // before AcceptEx could complete. These errors relate to new 586 // connection, not to AcceptEx, so ignore broken connection and 587 // try AcceptEx again for more connections. 588 operr, ok := err.(*OpError) 589 if !ok { 590 return nil, err 591 } 592 errno, ok := operr.Err.(syscall.Errno) 593 if !ok { 594 return nil, err 595 } 596 switch errno { 597 case syscall.ERROR_NETNAME_DELETED, syscall.WSAECONNRESET: 598 // ignore these and try again 599 default: 600 return nil, err 601 } 602 } 603 604 // Get local and peer addr out of AcceptEx buffer. 605 var lrsa, rrsa *syscall.RawSockaddrAny 606 var llen, rlen int32 607 syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&rawsa[0])), 608 0, uint32(o.rsan), uint32(o.rsan), &lrsa, &llen, &rrsa, &rlen) 609 lsa, _ := lrsa.Sockaddr() 610 rsa, _ := rrsa.Sockaddr() 611 612 netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa)) 613 return netfd, nil 614 } 615 616 // Unimplemented functions. 617 618 func (fd *netFD) dup() (*os.File, error) { 619 // TODO: Implement this 620 return nil, os.NewSyscallError("dup", syscall.EWINDOWS) 621 } 622 623 var errNoSupport = errors.New("address family not supported") 624 625 func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { 626 return 0, 0, 0, nil, errNoSupport 627 } 628 629 func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { 630 return 0, 0, errNoSupport 631 }