mirror of
https://github.com/Gouryella/drip.git
synced 2026-02-23 21:00:44 +00:00
feat(tcp): Fix reconnect behavior to keep stable subdomain and TCP port
Persist the assigned subdomain after first connect so reconnects reuse it. Allow reserving a specific TCP port when the subdomain is tcp-<port> to prevent port drift.
This commit is contained in:
@@ -58,6 +58,12 @@ func runTunnelWithUI(connConfig *tcp.ConnectorConfig, daemonInfo *DaemonInfo) er
|
||||
}
|
||||
|
||||
reconnectAttempts = 0
|
||||
if assignedSubdomain := connector.GetSubdomain(); assignedSubdomain != "" {
|
||||
connConfig.Subdomain = assignedSubdomain
|
||||
if daemonInfo != nil {
|
||||
daemonInfo.Subdomain = assignedSubdomain
|
||||
}
|
||||
}
|
||||
|
||||
if daemonInfo != nil {
|
||||
daemonInfo.URL = connector.GetURL()
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -131,15 +132,24 @@ func (c *Connection) Handle() error {
|
||||
return fmt.Errorf("port allocator not configured")
|
||||
}
|
||||
|
||||
port, err := c.portAlloc.Allocate()
|
||||
if err != nil {
|
||||
c.sendError("port_allocation_failed", err.Error())
|
||||
return fmt.Errorf("failed to allocate port: %w", err)
|
||||
}
|
||||
c.port = port
|
||||
if requestedPort, ok := parseTCPSubdomainPort(req.CustomSubdomain); ok {
|
||||
port, err := c.portAlloc.AllocateSpecific(requestedPort)
|
||||
if err != nil {
|
||||
c.sendError("port_allocation_failed", err.Error())
|
||||
return fmt.Errorf("failed to allocate requested port %d: %w", requestedPort, err)
|
||||
}
|
||||
c.port = port
|
||||
} else {
|
||||
port, err := c.portAlloc.Allocate()
|
||||
if err != nil {
|
||||
c.sendError("port_allocation_failed", err.Error())
|
||||
return fmt.Errorf("failed to allocate port: %w", err)
|
||||
}
|
||||
c.port = port
|
||||
|
||||
if req.CustomSubdomain == "" {
|
||||
req.CustomSubdomain = fmt.Sprintf("tcp-%d", port)
|
||||
if req.CustomSubdomain == "" {
|
||||
req.CustomSubdomain = fmt.Sprintf("tcp-%d", port)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,6 +393,24 @@ func min(a, b int) int {
|
||||
return b
|
||||
}
|
||||
|
||||
func parseTCPSubdomainPort(subdomain string) (int, bool) {
|
||||
if !strings.HasPrefix(subdomain, "tcp-") {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
portStr := strings.TrimPrefix(subdomain, "tcp-")
|
||||
if portStr == "" {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil || port < 1 || port > 65535 {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return port, true
|
||||
}
|
||||
|
||||
func (c *Connection) handleFrames(reader *bufio.Reader) error {
|
||||
for {
|
||||
select {
|
||||
|
||||
@@ -56,6 +56,28 @@ func (p *PortAllocator) Allocate() (int, error) {
|
||||
return 0, fmt.Errorf("no available port in range %d-%d", p.min, p.max)
|
||||
}
|
||||
|
||||
// AllocateSpecific reserves a specific port if it is within range and available.
|
||||
func (p *PortAllocator) AllocateSpecific(port int) (int, error) {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
if port < p.min || port > p.max {
|
||||
return 0, fmt.Errorf("requested port %d outside range %d-%d", port, p.min, p.max)
|
||||
}
|
||||
if p.used[port] {
|
||||
return 0, fmt.Errorf("requested port %d already in use", port)
|
||||
}
|
||||
|
||||
ln, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("requested port %d unavailable: %w", port, err)
|
||||
}
|
||||
_ = ln.Close()
|
||||
|
||||
p.used[port] = true
|
||||
return port, nil
|
||||
}
|
||||
|
||||
// Release frees a previously allocated port.
|
||||
func (p *PortAllocator) Release(port int) {
|
||||
p.mu.Lock()
|
||||
|
||||
Reference in New Issue
Block a user