Skip to content

Commit

Permalink
Add functions to find freeport UDP/TCP ports
Browse files Browse the repository at this point in the history
  • Loading branch information
jrouzierinverse committed Dec 16, 2024
1 parent 0278434 commit 3dfbd93
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 0 deletions.
45 changes: 45 additions & 0 deletions go/reuse_port/freeport.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package reuseport

import (
"context"
"errors"
"net"
)

func FreeTcpPort() (*net.TCPListener, int, error) {
l, err := ReusePortListenConfig.Listen(context.Background(), "tcp", "localhost:0")
if err != nil {
return nil, 0, err
}

tl, ok := l.(*net.TCPListener)
if !ok {
return nil, 0, errors.New("Bad Cast")
}

addr, ok := l.Addr().(*net.TCPAddr)
if !ok {
return nil, 0, errors.New("Bad Cast")
}

return tl, addr.Port, nil
}

func FreeUdpPort() (*net.UDPConn, int, error) {
l, err := ReusePortListenConfig.ListenPacket(context.Background(), "udp", "localhost:0")
if err != nil {
return nil, 0, err
}

uc, ok := l.(*net.UDPConn)
if !ok {
return nil, 0, errors.New("Bad Cast")
}

addr, ok := l.LocalAddr().(*net.UDPAddr)
if !ok {
return nil, 0, errors.New("Bad Cast")
}

return uc, addr.Port, nil
}
40 changes: 40 additions & 0 deletions go/reuse_port/freeport_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package reuseport

import (
"context"
"testing"
)

func TestFreeTcpPort(t *testing.T) {
l1, _, err := FreeTcpPort()
if err != nil {
t.Fatalf("%s", err.Error())
}

defer l1.Close()
l2, err := ReusePortListenConfig.Listen(context.Background(), "tcp", l1.Addr().String())
if err != nil {
t.Fatalf("%s", err.Error())
}

if l2.Addr().String() != l1.Addr().String() {
t.Fatalf("Not the same address")
}
}

func TestFreeUdpPort(t *testing.T) {
l1, _, err := FreeUdpPort()
if err != nil {
t.Fatalf("%s", err.Error())
}

defer l1.Close()
l2, err := ReusePortListenConfig.ListenPacket(context.Background(), "udp", l1.LocalAddr().String())
if err != nil {
t.Fatalf("%s", err.Error())
}

if l2.LocalAddr().String() != l1.LocalAddr().String() {
t.Fatalf("Not the same address")
}
}
24 changes: 24 additions & 0 deletions go/reuse_port/reuse_port.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package reuseport

import (
"net"
"syscall"

"golang.org/x/sys/unix"
)

func reusePort(network, address string, conn syscall.RawConn) error {
var opErr error
err := conn.Control(func(fd uintptr) {
opErr = syscall.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
})
if err != nil {
return err
}

return opErr
}

var ReusePortListenConfig = net.ListenConfig{
Control: reusePort,
}

0 comments on commit 3dfbd93

Please sign in to comment.