github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/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 isConnected bool 243 skipSyncNotif bool 244 net string 245 laddr Addr 246 raddr Addr 247 248 rop operation // read operation 249 wop operation // write operation 250 251 // wait server 252 pd pollDesc 253 } 254 255 func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error) { 256 if initErr != nil { 257 return nil, initErr 258 } 259 onceStartServer.Do(startServer) 260 return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net}, nil 261 } 262 263 func (fd *netFD) init() error { 264 if err := fd.pd.init(fd); err != nil { 265 return err 266 } 267 if hasLoadSetFileCompletionNotificationModes { 268 // We do not use events, so we can skip them always. 269 flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE) 270 // It's not safe to skip completion notifications for UDP: 271 // http://blogs.technet.com/b/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx 272 if skipSyncNotif && fd.net == "tcp" { 273 flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 274 } 275 err := syscall.SetFileCompletionNotificationModes(fd.sysfd, flags) 276 if err == nil && flags&syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS != 0 { 277 fd.skipSyncNotif = true 278 } 279 } 280 // Disable SIO_UDP_CONNRESET behavior. 281 // http://support.microsoft.com/kb/263823 282 switch fd.net { 283 case "udp", "udp4", "udp6": 284 ret := uint32(0) 285 flag := uint32(0) 286 size := uint32(unsafe.Sizeof(flag)) 287 err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0) 288 if err != nil { 289 return os.NewSyscallError("wsaioctl", err) 290 } 291 } 292 fd.rop.mode = 'r' 293 fd.wop.mode = 'w' 294 fd.rop.fd = fd 295 fd.wop.fd = fd 296 fd.rop.runtimeCtx = fd.pd.runtimeCtx 297 fd.wop.runtimeCtx = fd.pd.runtimeCtx 298 if !canCancelIO { 299 fd.rop.errc = make(chan error) 300 fd.wop.errc = make(chan error) 301 } 302 return nil 303 } 304 305 func (fd *netFD) setAddr(laddr, raddr Addr) { 306 fd.laddr = laddr 307 fd.raddr = raddr 308 runtime.SetFinalizer(fd, (*netFD).Close) 309 } 310 311 func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error { 312 // Do not need to call fd.writeLock here, 313 // because fd is not yet accessible to user, 314 // so no concurrent operations are possible. 315 if err := fd.init(); err != nil { 316 return err 317 } 318 if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() { 319 fd.setWriteDeadline(deadline) 320 defer fd.setWriteDeadline(noDeadline) 321 } 322 if !canUseConnectEx(fd.net) { 323 err := connectFunc(fd.sysfd, ra) 324 return os.NewSyscallError("connect", err) 325 } 326 // ConnectEx windows API requires an unconnected, previously bound socket. 327 if la == nil { 328 switch ra.(type) { 329 case *syscall.SockaddrInet4: 330 la = &syscall.SockaddrInet4{} 331 case *syscall.SockaddrInet6: 332 la = &syscall.SockaddrInet6{} 333 default: 334 panic("unexpected type in connect") 335 } 336 if err := syscall.Bind(fd.sysfd, la); err != nil { 337 return os.NewSyscallError("bind", err) 338 } 339 } 340 // Call ConnectEx API. 341 o := &fd.wop 342 o.sa = ra 343 344 // Wait for the goroutine converting context.Done into a write timeout 345 // to exist, otherwise our caller might cancel the context and 346 // cause fd.setWriteDeadline(aLongTimeAgo) to cancel a successful dial. 347 done := make(chan bool) // must be unbuffered 348 defer func() { done <- true }() 349 go func() { 350 select { 351 case <-ctx.Done(): 352 // Force the runtime's poller to immediately give 353 // up waiting for writability. 354 fd.setWriteDeadline(aLongTimeAgo) 355 <-done 356 case <-done: 357 } 358 }() 359 360 _, err := wsrv.ExecIO(o, "ConnectEx", func(o *operation) error { 361 return connectExFunc(o.fd.sysfd, o.sa, nil, 0, nil, &o.o) 362 }) 363 if err != nil { 364 select { 365 case <-ctx.Done(): 366 return mapErr(ctx.Err()) 367 default: 368 if _, ok := err.(syscall.Errno); ok { 369 err = os.NewSyscallError("connectex", err) 370 } 371 return err 372 } 373 } 374 // Refresh socket properties. 375 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)))) 376 } 377 378 func (fd *netFD) destroy() { 379 if fd.sysfd == syscall.InvalidHandle { 380 return 381 } 382 // Poller may want to unregister fd in readiness notification mechanism, 383 // so this must be executed before closeFunc. 384 fd.pd.close() 385 closeFunc(fd.sysfd) 386 fd.sysfd = syscall.InvalidHandle 387 // no need for a finalizer anymore 388 runtime.SetFinalizer(fd, nil) 389 } 390 391 func (fd *netFD) Close() error { 392 if !fd.fdmu.increfAndClose() { 393 return errClosing 394 } 395 // unblock pending reader and writer 396 fd.pd.evict() 397 fd.decref() 398 return nil 399 } 400 401 func (fd *netFD) shutdown(how int) error { 402 if err := fd.incref(); err != nil { 403 return err 404 } 405 defer fd.decref() 406 return syscall.Shutdown(fd.sysfd, how) 407 } 408 409 func (fd *netFD) closeRead() error { 410 return fd.shutdown(syscall.SHUT_RD) 411 } 412 413 func (fd *netFD) closeWrite() error { 414 return fd.shutdown(syscall.SHUT_WR) 415 } 416 417 func (fd *netFD) Read(buf []byte) (int, error) { 418 if err := fd.readLock(); err != nil { 419 return 0, err 420 } 421 defer fd.readUnlock() 422 o := &fd.rop 423 o.InitBuf(buf) 424 n, err := rsrv.ExecIO(o, "WSARecv", func(o *operation) error { 425 return syscall.WSARecv(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil) 426 }) 427 if race.Enabled { 428 race.Acquire(unsafe.Pointer(&ioSync)) 429 } 430 if len(buf) != 0 { 431 err = fd.eofError(n, err) 432 } 433 if _, ok := err.(syscall.Errno); ok { 434 err = os.NewSyscallError("wsarecv", err) 435 } 436 return n, err 437 } 438 439 func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) { 440 if len(buf) == 0 { 441 return 0, nil, nil 442 } 443 if err := fd.readLock(); err != nil { 444 return 0, nil, err 445 } 446 defer fd.readUnlock() 447 o := &fd.rop 448 o.InitBuf(buf) 449 n, err := rsrv.ExecIO(o, "WSARecvFrom", func(o *operation) error { 450 if o.rsa == nil { 451 o.rsa = new(syscall.RawSockaddrAny) 452 } 453 o.rsan = int32(unsafe.Sizeof(*o.rsa)) 454 return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil) 455 }) 456 err = fd.eofError(n, err) 457 if _, ok := err.(syscall.Errno); ok { 458 err = os.NewSyscallError("wsarecvfrom", err) 459 } 460 if err != nil { 461 return n, nil, err 462 } 463 sa, _ := o.rsa.Sockaddr() 464 return n, sa, nil 465 } 466 467 func (fd *netFD) Write(buf []byte) (int, error) { 468 if err := fd.writeLock(); err != nil { 469 return 0, err 470 } 471 defer fd.writeUnlock() 472 if race.Enabled { 473 race.ReleaseMerge(unsafe.Pointer(&ioSync)) 474 } 475 o := &fd.wop 476 o.InitBuf(buf) 477 n, err := wsrv.ExecIO(o, "WSASend", func(o *operation) error { 478 return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil) 479 }) 480 if _, ok := err.(syscall.Errno); ok { 481 err = os.NewSyscallError("wsasend", err) 482 } 483 return n, err 484 } 485 486 func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) { 487 if len(buf) == 0 { 488 return 0, nil 489 } 490 if err := fd.writeLock(); err != nil { 491 return 0, err 492 } 493 defer fd.writeUnlock() 494 o := &fd.wop 495 o.InitBuf(buf) 496 o.sa = sa 497 n, err := wsrv.ExecIO(o, "WSASendto", func(o *operation) error { 498 return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil) 499 }) 500 if _, ok := err.(syscall.Errno); ok { 501 err = os.NewSyscallError("wsasendto", err) 502 } 503 return n, err 504 } 505 506 func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD, error) { 507 // Get new socket. 508 s, err := sysSocket(fd.family, fd.sotype, 0) 509 if err != nil { 510 return nil, err 511 } 512 513 // Associate our new socket with IOCP. 514 netfd, err := newFD(s, fd.family, fd.sotype, fd.net) 515 if err != nil { 516 closeFunc(s) 517 return nil, err 518 } 519 if err := netfd.init(); err != nil { 520 fd.Close() 521 return nil, err 522 } 523 524 // Submit accept request. 525 o.handle = s 526 o.rsan = int32(unsafe.Sizeof(rawsa[0])) 527 _, err = rsrv.ExecIO(o, "AcceptEx", func(o *operation) error { 528 return acceptFunc(o.fd.sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o) 529 }) 530 if err != nil { 531 netfd.Close() 532 if _, ok := err.(syscall.Errno); ok { 533 err = os.NewSyscallError("acceptex", err) 534 } 535 return nil, err 536 } 537 538 // Inherit properties of the listening socket. 539 err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))) 540 if err != nil { 541 netfd.Close() 542 return nil, os.NewSyscallError("setsockopt", err) 543 } 544 545 return netfd, nil 546 } 547 548 func (fd *netFD) accept() (*netFD, error) { 549 if err := fd.readLock(); err != nil { 550 return nil, err 551 } 552 defer fd.readUnlock() 553 554 o := &fd.rop 555 var netfd *netFD 556 var err error 557 var rawsa [2]syscall.RawSockaddrAny 558 for { 559 netfd, err = fd.acceptOne(rawsa[:], o) 560 if err == nil { 561 break 562 } 563 // Sometimes we see WSAECONNRESET and ERROR_NETNAME_DELETED is 564 // returned here. These happen if connection reset is received 565 // before AcceptEx could complete. These errors relate to new 566 // connection, not to AcceptEx, so ignore broken connection and 567 // try AcceptEx again for more connections. 568 nerr, ok := err.(*os.SyscallError) 569 if !ok { 570 return nil, err 571 } 572 errno, ok := nerr.Err.(syscall.Errno) 573 if !ok { 574 return nil, err 575 } 576 switch errno { 577 case syscall.ERROR_NETNAME_DELETED, syscall.WSAECONNRESET: 578 // ignore these and try again 579 default: 580 return nil, err 581 } 582 } 583 584 // Get local and peer addr out of AcceptEx buffer. 585 var lrsa, rrsa *syscall.RawSockaddrAny 586 var llen, rlen int32 587 syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&rawsa[0])), 588 0, uint32(o.rsan), uint32(o.rsan), &lrsa, &llen, &rrsa, &rlen) 589 lsa, _ := lrsa.Sockaddr() 590 rsa, _ := rrsa.Sockaddr() 591 592 netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa)) 593 return netfd, nil 594 } 595 596 // Unimplemented functions. 597 598 func (fd *netFD) dup() (*os.File, error) { 599 // TODO: Implement this 600 return nil, syscall.EWINDOWS 601 } 602 603 func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { 604 return 0, 0, 0, nil, syscall.EWINDOWS 605 } 606 607 func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { 608 return 0, 0, syscall.EWINDOWS 609 }