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