Add rebind endpoints for the shared socket

Former-commit-id: 6fd0984b13
This commit is contained in:
Owen
2026-01-17 17:05:29 -08:00
parent a13010c4af
commit a06436eeab
2 changed files with 105 additions and 0 deletions

View File

@@ -273,6 +273,11 @@ func (o *Olm) registerAPICallbacks() {
}
return nil
},
// onRebind
func() error {
logger.Info("Processing rebind request via API")
return o.RebindSocket()
},
)
}
@@ -783,6 +788,72 @@ func (o *Olm) SetPowerMode(mode string) error {
return nil
}
// RebindSocket recreates the UDP socket when network connectivity changes.
// This is necessary on macOS/iOS when transitioning between WiFi and cellular,
// as the old socket becomes stale and can no longer route packets.
// Call this method when detecting a network path change.
func (o *Olm) RebindSocket() error {
if o.sharedBind == nil {
return fmt.Errorf("shared bind is not initialized")
}
// Get the current port so we can try to reuse it
currentPort := o.sharedBind.GetPort()
logger.Info("Rebinding UDP socket (current port: %d)", currentPort)
// Create a new UDP socket
var newConn *net.UDPConn
var newPort uint16
var err error
// First try to bind to the same port
localAddr := &net.UDPAddr{
Port: int(currentPort),
IP: net.IPv4zero,
}
newConn, err = net.ListenUDP("udp4", localAddr)
if err != nil {
// If we can't reuse the port, find a new one
logger.Warn("Could not rebind to port %d, finding new port: %v", currentPort, err)
newPort, err = util.FindAvailableUDPPort(49152, 65535)
if err != nil {
return fmt.Errorf("failed to find available UDP port: %w", err)
}
localAddr = &net.UDPAddr{
Port: int(newPort),
IP: net.IPv4zero,
}
// Use udp4 explicitly to avoid IPv6 dual-stack issues
newConn, err = net.ListenUDP("udp4", localAddr)
if err != nil {
return fmt.Errorf("failed to create new UDP socket: %w", err)
}
} else {
newPort = currentPort
}
// Rebind the shared bind with the new connection
if err := o.sharedBind.Rebind(newConn); err != nil {
newConn.Close()
return fmt.Errorf("failed to rebind shared bind: %w", err)
}
logger.Info("Successfully rebound UDP socket on port %d", newPort)
// Trigger a hole punch to re-establish NAT mappings with the new socket
if o.holePunchManager != nil {
o.holePunchManager.TriggerHolePunch()
o.holePunchManager.ResetServerHolepunchInterval()
logger.Info("Triggered hole punch after socket rebind")
}
return nil
}
func (o *Olm) AddDevice(fd uint32) error {
if o.middleDev == nil {
return fmt.Errorf("middle device is not initialized")