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  }