github.com/cbeuw/gotfo@v0.0.0-20180331191851-f2b091af84de/sock_windows.go (about)

     1  // Copyright 2009 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 gotfo
     6  
     7  import (
     8  	"context"
     9  	"net"
    10  	"os"
    11  	"syscall"
    12  )
    13  
    14  // socket returns a network file descriptor that is ready for
    15  // asynchronous I/O using the network poller.
    16  func socket(ctx context.Context, family int, ipv6only bool, addr *net.TCPAddr, dial bool, fastOpen bool, data []byte) (fd *netFD, err error) {
    17  	syscall.ForkLock.RLock()
    18  	s, err := syscall.Socket(family, syscall.SOCK_STREAM, 0)
    19  	if err == nil {
    20  		syscall.CloseOnExec(s)
    21  	}
    22  	syscall.ForkLock.RUnlock()
    23  
    24  	if err != nil {
    25  		return nil, os.NewSyscallError("socket", err)
    26  	}
    27  
    28  	if fd, err = newFD(s, family); err != nil {
    29  		syscall.Close(s)
    30  		return nil, err
    31  	}
    32  
    33  	if dial {
    34  		if family == syscall.AF_INET6 && ipv6only {
    35  			syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 1)
    36  		}
    37  
    38  		syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
    39  
    40  		if fastOpen {
    41  			syscall.SetsockoptInt(s, syscall.IPPROTO_TCP, TCP_FASTOPEN, 1)
    42  		}
    43  
    44  		if err := fd.dial(ctx, addr, data); err != nil {
    45  			fd.Close()
    46  			return nil, err
    47  		}
    48  	} else {
    49  		if err := fd.listen(addr); err != nil {
    50  			fd.Close()
    51  			return nil, err
    52  		}
    53  	}
    54  	return fd, nil
    55  }
    56  
    57  func (fd *netFD) dial(ctx context.Context, addr *net.TCPAddr, data []byte) error {
    58  	var lsa syscall.Sockaddr
    59  	var rsa syscall.Sockaddr
    60  	raddr := tcpAddrToSockaddr(addr)
    61  
    62  	if err := fd.connect(ctx, raddr, data); err != nil {
    63  		return err
    64  	}
    65  	fd.isConnected = true
    66  
    67  	lsa, _ = syscall.Getsockname(fd.sysfd)
    68  	if rsa, _ = syscall.Getpeername(fd.sysfd); rsa != nil {
    69  		fd.setAddr(sockaddrToTCPAddr(lsa), sockaddrToTCPAddr(rsa))
    70  	} else {
    71  		fd.setAddr(sockaddrToTCPAddr(lsa), addr)
    72  	}
    73  	return nil
    74  }
    75  
    76  func (fd *netFD) listen(addr *net.TCPAddr) error {
    77  	laddr := &syscall.SockaddrInet4{Port: addr.Port}
    78  	copy(laddr.Addr[:], addr.IP.To4())
    79  
    80  	if err := syscall.Bind(fd.sysfd, laddr); err != nil {
    81  		return os.NewSyscallError("bind", err)
    82  	}
    83  
    84  	if err := syscall.Listen(fd.sysfd, syscall.SOMAXCONN); err != nil {
    85  		return os.NewSyscallError("listen", err)
    86  	}
    87  	if err := fd.init(); err != nil {
    88  		return err
    89  	}
    90  
    91  	fd.setAddr(addr, nil)
    92  	return nil
    93  }