2019-06-09 07:24:20 +00:00
|
|
|
// Package reuseport provides Listen and Dial functions that set socket
|
|
|
|
// options in order to be able to reuse ports. You should only use this
|
|
|
|
// package if you know what SO_REUSEADDR and SO_REUSEPORT are.
|
2018-07-04 10:51:47 +00:00
|
|
|
//
|
|
|
|
// For example:
|
|
|
|
//
|
2023-06-30 13:41:32 +00:00
|
|
|
// // listen on the same port. oh yeah.
|
|
|
|
// l1, _ := reuse.Listen("tcp", "127.0.0.1:1234")
|
|
|
|
// l2, _ := reuse.Listen("tcp", "127.0.0.1:1234")
|
2018-07-04 10:51:47 +00:00
|
|
|
//
|
2023-06-30 13:41:32 +00:00
|
|
|
// // dial from the same port. oh yeah.
|
|
|
|
// l1, _ := reuse.Listen("tcp", "127.0.0.1:1234")
|
|
|
|
// l2, _ := reuse.Listen("tcp", "127.0.0.1:1235")
|
|
|
|
// c, _ := reuse.Dial("tcp", "127.0.0.1:1234", "127.0.0.1:1235")
|
2018-07-04 10:51:47 +00:00
|
|
|
//
|
|
|
|
// Note: cant dial self because tcp/ip stacks use 4-tuples to identify connections,
|
|
|
|
// and doing so would clash.
|
|
|
|
package reuseport
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2022-04-01 16:16:46 +00:00
|
|
|
"fmt"
|
2018-07-04 10:51:47 +00:00
|
|
|
"net"
|
2023-06-30 13:41:32 +00:00
|
|
|
"time"
|
2018-07-04 10:51:47 +00:00
|
|
|
)
|
|
|
|
|
2019-06-09 07:24:20 +00:00
|
|
|
// Available returns whether or not SO_REUSEPORT or equivalent behaviour is
|
|
|
|
// available in the OS.
|
2018-07-04 10:51:47 +00:00
|
|
|
func Available() bool {
|
2019-06-09 07:24:20 +00:00
|
|
|
return true
|
2018-07-04 10:51:47 +00:00
|
|
|
}
|
|
|
|
|
2019-06-09 07:24:20 +00:00
|
|
|
var listenConfig = net.ListenConfig{
|
|
|
|
Control: Control,
|
|
|
|
}
|
2018-07-04 10:51:47 +00:00
|
|
|
|
|
|
|
// Listen listens at the given network and address. see net.Listen
|
|
|
|
// Returns a net.Listener created from a file discriptor for a socket
|
|
|
|
// with SO_REUSEPORT and SO_REUSEADDR option set.
|
|
|
|
func Listen(network, address string) (net.Listener, error) {
|
2019-06-09 07:24:20 +00:00
|
|
|
return listenConfig.Listen(context.Background(), network, address)
|
2018-07-04 10:51:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ListenPacket listens at the given network and address. see net.ListenPacket
|
|
|
|
// Returns a net.Listener created from a file discriptor for a socket
|
|
|
|
// with SO_REUSEPORT and SO_REUSEADDR option set.
|
|
|
|
func ListenPacket(network, address string) (net.PacketConn, error) {
|
2019-06-09 07:24:20 +00:00
|
|
|
return listenConfig.ListenPacket(context.Background(), network, address)
|
2018-07-04 10:51:47 +00:00
|
|
|
}
|
|
|
|
|
2023-06-30 13:41:32 +00:00
|
|
|
// Dial dials the given network and address. see net.Dial
|
2019-06-09 07:24:20 +00:00
|
|
|
// Returns a net.Conn created from a file descriptor for a socket
|
2018-07-04 10:51:47 +00:00
|
|
|
// with SO_REUSEPORT and SO_REUSEADDR option set.
|
|
|
|
func Dial(network, laddr, raddr string) (net.Conn, error) {
|
2023-06-30 13:41:32 +00:00
|
|
|
return DialTimeout(network, laddr, raddr, time.Duration(0))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dial dials the given network and address, with the given timeout. see
|
|
|
|
// net.DialTimeout Returns a net.Conn created from a file descriptor for
|
|
|
|
// a socket with SO_REUSEPORT and SO_REUSEADDR option set.
|
|
|
|
func DialTimeout(network, laddr, raddr string, timeout time.Duration) (net.Conn, error) {
|
2019-06-09 07:24:20 +00:00
|
|
|
nla, err := ResolveAddr(network, laddr)
|
|
|
|
if err != nil {
|
2022-04-01 16:16:46 +00:00
|
|
|
return nil, fmt.Errorf("failed to resolve local addr: %w", err)
|
2018-07-04 10:51:47 +00:00
|
|
|
}
|
2019-06-09 07:24:20 +00:00
|
|
|
d := net.Dialer{
|
|
|
|
Control: Control,
|
|
|
|
LocalAddr: nla,
|
2023-06-30 13:41:32 +00:00
|
|
|
Timeout: timeout,
|
2018-07-04 10:51:47 +00:00
|
|
|
}
|
|
|
|
return d.Dial(network, raddr)
|
|
|
|
}
|