Skip to content

Commit

Permalink
use random port checks instead of incremental port checks
Browse files Browse the repository at this point in the history
  • Loading branch information
linyows committed Oct 4, 2023
1 parent da6ea0e commit 2f3b54d
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 53 deletions.
23 changes: 9 additions & 14 deletions port_range.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,28 @@ package warp

import (
"fmt"
"math/rand"
"net"
"strconv"
"time"
)

type PortRange struct {
Start int
End int
}

func (p *PortRange) TakeOut(host string) (int, error) {
timeout := time.Second

func (p *PortRange) TakeOut() (int, error) {
diff := p.End - p.Start
for i := p.Start; i <= p.End; i++ {
address := net.JoinHostPort(host, strconv.Itoa(i))
if ok := isAvailablePort(address, timeout); ok {
// Incremental port checks is port duplicate, when consecutive send. so using random port checks.
port := p.Start + rand.Intn(diff)
if ok := isPortAvailable(port); ok {
return i, nil
}
}

return 0, fmt.Errorf("not found open port by %d-%d", p.Start, p.End)
}

func isAvailablePort(address string, timeout time.Duration) bool {
conn, err := net.DialTimeout("tcp", address, timeout)
if conn != nil {
defer conn.Close()
}
return err != nil
func isPortAvailable(port int) bool {
_, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
return err == nil
}
56 changes: 19 additions & 37 deletions port_range_test.go
Original file line number Diff line number Diff line change
@@ -1,57 +1,39 @@
package warp

import (
"fmt"
"net"
"strconv"
"testing"
)

func listenLocalPort(t *testing.T) (net.Listener, int) {
ln, err := net.Listen("tcp", ":0")
if err != nil {
t.Fatal(err)
}
func TestTakeOut(t *testing.T) {
port := 35555
start := port - 10
end := port + 10

go func() {
for {
conn, _ := ln.Accept()
if conn != nil {
conn.Close()
}
}
}()
r := &PortRange{Start: start, End: end}
got, err := r.TakeOut()

_, p, err := net.SplitHostPort(ln.Addr().String())
if err != nil {
t.Fatal(err)
if start != got || err != nil {
t.Errorf("port range take out expected %d, but got %d", start, got)
}
}

port, err := strconv.Atoi(p)
func TestIsPortAvailable(t *testing.T) {
used := 35555
unused := 36666

ln, err := net.Listen("tcp", fmt.Sprintf(":%d", used))
if err != nil {
t.Fatal(err)
}

return ln, port
}

func TestTakeOut(t *testing.T) {
ip := "127.0.0.1"

ln, port := listenLocalPort(t)
defer ln.Close()

start := port - 10
end := port + 10

r1 := &PortRange{Start: start, End: end}
got1, err := r1.TakeOut(ip)
if start != got1 || err != nil {
t.Errorf("port range take out expected %d, but got %d", start, got1)
if isPortAvailable(used) {
t.Error("port was listened, but isPortAvailable returns true")
}

r2 := &PortRange{Start: port, End: port}
got2, err := r2.TakeOut(ip)
if 0 != got2 || err == nil {
t.Error("port range take out expected error, but got no error")
if !isPortAvailable(unused) {
t.Error("port was not listened, but isPortAvailable returns false")
}
}
4 changes: 2 additions & 2 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func (s *Server) HandleConnection(conn net.Conn) {

outboundPort := 0
if s.OutboundPorts != nil {
outboundPort, err = s.OutboundPorts.TakeOut(s.Addr)
outboundPort, err = s.OutboundPorts.TakeOut()
if err != nil {
s.log.Printf("%s %s outbound ports take out error: %#v", uuid, onPxy, err)
return
Expand All @@ -104,7 +104,7 @@ func (s *Server) HandleConnection(conn net.Conn) {
dialer := &net.Dialer{LocalAddr: laddr}
dstConn, err := dialer.Dial("tcp", raddr.String())
if err != nil {
s.log.Printf("%s %s dial `%s` error: %#v", uuid, onPxy, raddr, err)
s.log.Printf("%s %s dial `%s` with `%s` error: %#v", uuid, onPxy, raddr, laddr, err)
return
}

Expand Down

0 comments on commit 2f3b54d

Please sign in to comment.