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 }