mirror of
https://github.com/libp2p/go-reuseport.git
synced 2025-10-04 06:26:24 +08:00
155 lines
3.4 KiB
Go
155 lines
3.4 KiB
Go
// +build darwin freebsd dragonfly netbsd openbsd linux
|
|
|
|
package reuseport
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"strconv"
|
|
"syscall"
|
|
|
|
resolve "github.com/jbenet/go-net-resolve-addr"
|
|
sockaddrnet "github.com/jbenet/go-sockaddr/net"
|
|
)
|
|
|
|
const (
|
|
tcp4 = 52 // "4"
|
|
tcp6 = 54 // "6"
|
|
filePrefix = "port."
|
|
)
|
|
|
|
func dial(dialer net.Dialer, netw, addr string) (c net.Conn, err error) {
|
|
var (
|
|
family, fd int
|
|
file *os.File
|
|
remoteSockaddr syscall.Sockaddr
|
|
localSockaddr syscall.Sockaddr
|
|
)
|
|
|
|
netAddr, err := resolve.ResolveAddr("dial", netw, addr)
|
|
if err != nil {
|
|
fmt.Println("resolve addr failed")
|
|
return nil, err
|
|
}
|
|
fmt.Println("resolve addr ok")
|
|
|
|
switch netAddr.(type) {
|
|
case *net.TCPAddr, *net.UDPAddr:
|
|
default:
|
|
return nil, ErrUnsupportedProtocol
|
|
}
|
|
|
|
switch dialer.LocalAddr.(type) {
|
|
case *net.TCPAddr, *net.UDPAddr:
|
|
default:
|
|
return nil, ErrUnsupportedProtocol
|
|
}
|
|
|
|
family = sockaddrnet.NetAddrAF(netAddr)
|
|
localSockaddr = sockaddrnet.NetAddrToSockaddr(dialer.LocalAddr)
|
|
remoteSockaddr = sockaddrnet.NetAddrToSockaddr(netAddr)
|
|
|
|
if fd, err = syscall.Socket(family, syscall.SOCK_STREAM, syscall.IPPROTO_TCP); err != nil {
|
|
fmt.Println("tcp socket failed")
|
|
return nil, err
|
|
}
|
|
|
|
if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, soReuseAddr, 1); err != nil {
|
|
fmt.Println("reuse addr failed")
|
|
return nil, err
|
|
}
|
|
|
|
if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, soReusePort, 1); err != nil {
|
|
fmt.Println("reuse port failed")
|
|
return nil, err
|
|
}
|
|
|
|
if localSockaddr != nil {
|
|
if err = syscall.Bind(fd, localSockaddr); err != nil {
|
|
fmt.Println("bind failed")
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// Set backlog size to the maximum
|
|
if err = syscall.Connect(fd, remoteSockaddr); err != nil {
|
|
fmt.Println("connect failed")
|
|
return nil, err
|
|
}
|
|
|
|
// File Name get be nil
|
|
file = os.NewFile(uintptr(fd), filePrefix+strconv.Itoa(os.Getpid()))
|
|
if c, err = net.FileConn(file); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err = file.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return c, err
|
|
}
|
|
|
|
func listen(netw, addr string) (l net.Listener, err error) {
|
|
var (
|
|
family, fd int
|
|
file *os.File
|
|
sockaddr syscall.Sockaddr
|
|
)
|
|
|
|
netAddr, err := resolve.ResolveAddr("listen", netw, addr)
|
|
if err != nil {
|
|
fmt.Println("resolve addr failed")
|
|
return nil, err
|
|
}
|
|
fmt.Println("resolve addr ok")
|
|
|
|
switch netAddr.(type) {
|
|
case *net.TCPAddr, *net.UDPAddr:
|
|
default:
|
|
return nil, ErrUnsupportedProtocol
|
|
}
|
|
|
|
family = sockaddrnet.NetAddrAF(netAddr)
|
|
sockaddr = sockaddrnet.NetAddrToSockaddr(netAddr)
|
|
|
|
if fd, err = syscall.Socket(family, syscall.SOCK_STREAM, syscall.IPPROTO_TCP); err != nil {
|
|
fmt.Println("socket failed")
|
|
return nil, err
|
|
}
|
|
|
|
if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, soReusePort, 1); err != nil {
|
|
fmt.Println("setsockopt reuseport failed")
|
|
return nil, err
|
|
}
|
|
|
|
if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, soReuseAddr, 1); err != nil {
|
|
fmt.Println("setsockopt reuseaddr failed")
|
|
return nil, err
|
|
}
|
|
|
|
if err = syscall.Bind(fd, sockaddr); err != nil {
|
|
fmt.Println("bind failed")
|
|
return nil, err
|
|
}
|
|
|
|
// Set backlog size to the maximum
|
|
if err = syscall.Listen(fd, syscall.SOMAXCONN); err != nil {
|
|
fmt.Println("listen failed")
|
|
return nil, err
|
|
}
|
|
|
|
// File Name get be nil
|
|
file = os.NewFile(uintptr(fd), filePrefix+strconv.Itoa(os.Getpid()))
|
|
if l, err = net.FileListener(file); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err = file.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return l, err
|
|
}
|