...
Run Format

Source file src/net/fd_windows.go

Documentation: net

  // Copyright 2010 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  package net
  
  import (
  	"context"
  	"internal/poll"
  	"os"
  	"runtime"
  	"syscall"
  	"unsafe"
  )
  
  // canUseConnectEx reports whether we can use the ConnectEx Windows API call
  // for the given network type.
  func canUseConnectEx(net string) bool {
  	switch net {
  	case "tcp", "tcp4", "tcp6":
  		return true
  	}
  	// ConnectEx windows API does not support connectionless sockets.
  	return false
  }
  
  // Network file descriptor.
  type netFD struct {
  	pfd poll.FD
  
  	// immutable until Close
  	family      int
  	sotype      int
  	isConnected bool
  	net         string
  	laddr       Addr
  	raddr       Addr
  }
  
  func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error) {
  	ret := &netFD{
  		pfd: poll.FD{
  			Sysfd:         sysfd,
  			IsStream:      sotype == syscall.SOCK_STREAM,
  			ZeroReadIsEOF: sotype != syscall.SOCK_DGRAM && sotype != syscall.SOCK_RAW,
  		},
  		family: family,
  		sotype: sotype,
  		net:    net,
  	}
  	return ret, nil
  }
  
  func (fd *netFD) init() error {
  	errcall, err := fd.pfd.Init(fd.net, true)
  	if errcall != "" {
  		err = wrapSyscallError(errcall, err)
  	}
  	return err
  }
  
  func (fd *netFD) setAddr(laddr, raddr Addr) {
  	fd.laddr = laddr
  	fd.raddr = raddr
  	runtime.SetFinalizer(fd, (*netFD).Close)
  }
  
  // Always returns nil for connected peer address result.
  func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (syscall.Sockaddr, error) {
  	// Do not need to call fd.writeLock here,
  	// because fd is not yet accessible to user,
  	// so no concurrent operations are possible.
  	if err := fd.init(); err != nil {
  		return nil, err
  	}
  	if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
  		fd.pfd.SetWriteDeadline(deadline)
  		defer fd.pfd.SetWriteDeadline(noDeadline)
  	}
  	if !canUseConnectEx(fd.net) {
  		err := connectFunc(fd.pfd.Sysfd, ra)
  		return nil, os.NewSyscallError("connect", err)
  	}
  	// ConnectEx windows API requires an unconnected, previously bound socket.
  	if la == nil {
  		switch ra.(type) {
  		case *syscall.SockaddrInet4:
  			la = &syscall.SockaddrInet4{}
  		case *syscall.SockaddrInet6:
  			la = &syscall.SockaddrInet6{}
  		default:
  			panic("unexpected type in connect")
  		}
  		if err := syscall.Bind(fd.pfd.Sysfd, la); err != nil {
  			return nil, os.NewSyscallError("bind", err)
  		}
  	}
  
  	// Wait for the goroutine converting context.Done into a write timeout
  	// to exist, otherwise our caller might cancel the context and
  	// cause fd.setWriteDeadline(aLongTimeAgo) to cancel a successful dial.
  	done := make(chan bool) // must be unbuffered
  	defer func() { done <- true }()
  	go func() {
  		select {
  		case <-ctx.Done():
  			// Force the runtime's poller to immediately give
  			// up waiting for writability.
  			fd.pfd.SetWriteDeadline(aLongTimeAgo)
  			<-done
  		case <-done:
  		}
  	}()
  
  	// Call ConnectEx API.
  	if err := fd.pfd.ConnectEx(ra); err != nil {
  		select {
  		case <-ctx.Done():
  			return nil, mapErr(ctx.Err())
  		default:
  			if _, ok := err.(syscall.Errno); ok {
  				err = os.NewSyscallError("connectex", err)
  			}
  			return nil, err
  		}
  	}
  	// Refresh socket properties.
  	return nil, os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.pfd.Sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.pfd.Sysfd)), int32(unsafe.Sizeof(fd.pfd.Sysfd))))
  }
  
  func (fd *netFD) Close() error {
  	runtime.SetFinalizer(fd, nil)
  	return fd.pfd.Close()
  }
  
  func (fd *netFD) shutdown(how int) error {
  	err := fd.pfd.Shutdown(how)
  	runtime.KeepAlive(fd)
  	return err
  }
  
  func (fd *netFD) closeRead() error {
  	return fd.shutdown(syscall.SHUT_RD)
  }
  
  func (fd *netFD) closeWrite() error {
  	return fd.shutdown(syscall.SHUT_WR)
  }
  
  func (fd *netFD) Read(buf []byte) (int, error) {
  	n, err := fd.pfd.Read(buf)
  	runtime.KeepAlive(fd)
  	return n, wrapSyscallError("wsarecv", err)
  }
  
  func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) {
  	n, sa, err := fd.pfd.ReadFrom(buf)
  	runtime.KeepAlive(fd)
  	return n, sa, wrapSyscallError("wsarecvfrom", err)
  }
  
  func (fd *netFD) Write(buf []byte) (int, error) {
  	n, err := fd.pfd.Write(buf)
  	runtime.KeepAlive(fd)
  	return n, wrapSyscallError("wsasend", err)
  }
  
  func (c *conn) writeBuffers(v *Buffers) (int64, error) {
  	if !c.ok() {
  		return 0, syscall.EINVAL
  	}
  	n, err := c.fd.writeBuffers(v)
  	if err != nil {
  		return n, &OpError{Op: "wsasend", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
  	}
  	return n, nil
  }
  
  func (fd *netFD) writeBuffers(buf *Buffers) (int64, error) {
  	n, err := fd.pfd.Writev((*[][]byte)(buf))
  	runtime.KeepAlive(fd)
  	return n, wrapSyscallError("wsasend", err)
  }
  
  func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
  	n, err := fd.pfd.WriteTo(buf, sa)
  	runtime.KeepAlive(fd)
  	return n, wrapSyscallError("wsasendto", err)
  }
  
  func (fd *netFD) accept() (*netFD, error) {
  	s, rawsa, rsan, errcall, err := fd.pfd.Accept(func() (syscall.Handle, error) {
  		return sysSocket(fd.family, fd.sotype, 0)
  	})
  
  	if err != nil {
  		if errcall != "" {
  			err = wrapSyscallError(errcall, err)
  		}
  		return nil, err
  	}
  
  	// Associate our new socket with IOCP.
  	netfd, err := newFD(s, fd.family, fd.sotype, fd.net)
  	if err != nil {
  		poll.CloseFunc(s)
  		return nil, err
  	}
  	if err := netfd.init(); err != nil {
  		fd.Close()
  		return nil, err
  	}
  
  	// Get local and peer addr out of AcceptEx buffer.
  	var lrsa, rrsa *syscall.RawSockaddrAny
  	var llen, rlen int32
  	syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&rawsa[0])),
  		0, rsan, rsan, &lrsa, &llen, &rrsa, &rlen)
  	lsa, _ := lrsa.Sockaddr()
  	rsa, _ := rrsa.Sockaddr()
  
  	netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
  	return netfd, nil
  }
  
  // Unimplemented functions.
  
  func (fd *netFD) dup() (*os.File, error) {
  	// TODO: Implement this
  	return nil, syscall.EWINDOWS
  }
  
  func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
  	return 0, 0, 0, nil, syscall.EWINDOWS
  }
  
  func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
  	return 0, 0, syscall.EWINDOWS
  }
  

View as plain text