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  }