github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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 "internal/race" 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, 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, 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, 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 cancelation 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, err 220 } 221 // We issued a cancelation request. But, it seems, IO operation succeeded 222 // before the cancelation request run. We need to treat the 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, cancel <-chan struct{}) 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 os.NewSyscallError("connect", 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 os.NewSyscallError("bind", err) 349 } 350 } 351 // Call ConnectEx API. 352 o := &fd.wop 353 o.sa = ra 354 if cancel != nil { 355 done := make(chan bool) 356 defer func() { 357 // This is unbuffered; wait for the goroutine before returning. 358 done <- true 359 }() 360 go func() { 361 select { 362 case <-cancel: 363 // Force the runtime's poller to immediately give 364 // up waiting for writability. 365 fd.setWriteDeadline(aLongTimeAgo) 366 <-done 367 case <-done: 368 } 369 }() 370 } 371 _, err := wsrv.ExecIO(o, "ConnectEx", func(o *operation) error { 372 return connectExFunc(o.fd.sysfd, o.sa, nil, 0, nil, &o.o) 373 }) 374 if err != nil { 375 select { 376 case <-cancel: 377 return errCanceled 378 default: 379 if _, ok := err.(syscall.Errno); ok { 380 err = os.NewSyscallError("connectex", err) 381 } 382 return err 383 } 384 } 385 // Refresh socket properties. 386 return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))) 387 } 388 389 func (fd *netFD) destroy() { 390 if fd.sysfd == syscall.InvalidHandle { 391 return 392 } 393 // Poller may want to unregister fd in readiness notification mechanism, 394 // so this must be executed before closeFunc. 395 fd.pd.close() 396 closeFunc(fd.sysfd) 397 fd.sysfd = syscall.InvalidHandle 398 // no need for a finalizer anymore 399 runtime.SetFinalizer(fd, nil) 400 } 401 402 func (fd *netFD) Close() error { 403 if !fd.fdmu.increfAndClose() { 404 return errClosing 405 } 406 // unblock pending reader and writer 407 fd.pd.evict() 408 fd.decref() 409 return nil 410 } 411 412 func (fd *netFD) shutdown(how int) error { 413 if err := fd.incref(); err != nil { 414 return err 415 } 416 defer fd.decref() 417 return syscall.Shutdown(fd.sysfd, how) 418 } 419 420 func (fd *netFD) closeRead() error { 421 return fd.shutdown(syscall.SHUT_RD) 422 } 423 424 func (fd *netFD) closeWrite() error { 425 return fd.shutdown(syscall.SHUT_WR) 426 } 427 428 func (fd *netFD) Read(buf []byte) (int, error) { 429 if err := fd.readLock(); err != nil { 430 return 0, err 431 } 432 defer fd.readUnlock() 433 o := &fd.rop 434 o.InitBuf(buf) 435 n, err := rsrv.ExecIO(o, "WSARecv", func(o *operation) error { 436 return syscall.WSARecv(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil) 437 }) 438 if race.Enabled { 439 race.Acquire(unsafe.Pointer(&ioSync)) 440 } 441 err = fd.eofError(n, err) 442 if _, ok := err.(syscall.Errno); ok { 443 err = os.NewSyscallError("wsarecv", err) 444 } 445 return n, err 446 } 447 448 func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) { 449 if len(buf) == 0 { 450 return 0, nil, nil 451 } 452 if err := fd.readLock(); err != nil { 453 return 0, nil, err 454 } 455 defer fd.readUnlock() 456 o := &fd.rop 457 o.InitBuf(buf) 458 n, err := rsrv.ExecIO(o, "WSARecvFrom", func(o *operation) error { 459 if o.rsa == nil { 460 o.rsa = new(syscall.RawSockaddrAny) 461 } 462 o.rsan = int32(unsafe.Sizeof(*o.rsa)) 463 return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil) 464 }) 465 err = fd.eofError(n, err) 466 if _, ok := err.(syscall.Errno); ok { 467 err = os.NewSyscallError("wsarecvfrom", err) 468 } 469 if err != nil { 470 return n, nil, err 471 } 472 sa, _ := o.rsa.Sockaddr() 473 return n, sa, nil 474 } 475 476 func (fd *netFD) Write(buf []byte) (int, error) { 477 if err := fd.writeLock(); err != nil { 478 return 0, err 479 } 480 defer fd.writeUnlock() 481 if race.Enabled { 482 race.ReleaseMerge(unsafe.Pointer(&ioSync)) 483 } 484 o := &fd.wop 485 o.InitBuf(buf) 486 n, err := wsrv.ExecIO(o, "WSASend", func(o *operation) error { 487 return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil) 488 }) 489 if _, ok := err.(syscall.Errno); ok { 490 err = os.NewSyscallError("wsasend", err) 491 } 492 return n, err 493 } 494 495 func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) { 496 if len(buf) == 0 { 497 return 0, nil 498 } 499 if err := fd.writeLock(); err != nil { 500 return 0, err 501 } 502 defer fd.writeUnlock() 503 o := &fd.wop 504 o.InitBuf(buf) 505 o.sa = sa 506 n, err := wsrv.ExecIO(o, "WSASendto", func(o *operation) error { 507 return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil) 508 }) 509 if _, ok := err.(syscall.Errno); ok { 510 err = os.NewSyscallError("wsasendto", err) 511 } 512 return n, err 513 } 514 515 func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD, error) { 516 // Get new socket. 517 s, err := sysSocket(fd.family, fd.sotype, 0) 518 if err != nil { 519 return nil, err 520 } 521 522 // Associate our new socket with IOCP. 523 netfd, err := newFD(s, fd.family, fd.sotype, fd.net) 524 if err != nil { 525 closeFunc(s) 526 return nil, err 527 } 528 if err := netfd.init(); err != nil { 529 fd.Close() 530 return nil, err 531 } 532 533 // Submit accept request. 534 o.handle = s 535 o.rsan = int32(unsafe.Sizeof(rawsa[0])) 536 _, err = rsrv.ExecIO(o, "AcceptEx", func(o *operation) error { 537 return acceptFunc(o.fd.sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o) 538 }) 539 if err != nil { 540 netfd.Close() 541 if _, ok := err.(syscall.Errno); ok { 542 err = os.NewSyscallError("acceptex", err) 543 } 544 return nil, err 545 } 546 547 // Inherit properties of the listening socket. 548 err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))) 549 if err != nil { 550 netfd.Close() 551 return nil, os.NewSyscallError("setsockopt", err) 552 } 553 554 return netfd, nil 555 } 556 557 func (fd *netFD) accept() (*netFD, error) { 558 if err := fd.readLock(); err != nil { 559 return nil, err 560 } 561 defer fd.readUnlock() 562 563 o := &fd.rop 564 var netfd *netFD 565 var err error 566 var rawsa [2]syscall.RawSockaddrAny 567 for { 568 netfd, err = fd.acceptOne(rawsa[:], o) 569 if err == nil { 570 break 571 } 572 // Sometimes we see WSAECONNRESET and ERROR_NETNAME_DELETED is 573 // returned here. These happen if connection reset is received 574 // before AcceptEx could complete. These errors relate to new 575 // connection, not to AcceptEx, so ignore broken connection and 576 // try AcceptEx again for more connections. 577 nerr, ok := err.(*os.SyscallError) 578 if !ok { 579 return nil, err 580 } 581 errno, ok := nerr.Err.(syscall.Errno) 582 if !ok { 583 return nil, err 584 } 585 switch errno { 586 case syscall.ERROR_NETNAME_DELETED, syscall.WSAECONNRESET: 587 // ignore these and try again 588 default: 589 return nil, err 590 } 591 } 592 593 // Get local and peer addr out of AcceptEx buffer. 594 var lrsa, rrsa *syscall.RawSockaddrAny 595 var llen, rlen int32 596 syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&rawsa[0])), 597 0, uint32(o.rsan), uint32(o.rsan), &lrsa, &llen, &rrsa, &rlen) 598 lsa, _ := lrsa.Sockaddr() 599 rsa, _ := rrsa.Sockaddr() 600 601 netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa)) 602 return netfd, nil 603 } 604 605 // Unimplemented functions. 606 607 func (fd *netFD) dup() (*os.File, error) { 608 // TODO: Implement this 609 return nil, syscall.EWINDOWS 610 } 611 612 func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { 613 return 0, 0, 0, nil, syscall.EWINDOWS 614 } 615 616 func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { 617 return 0, 0, syscall.EWINDOWS 618 }