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  }