Browse Source

tunnel affinity by client identifier _and_ ip address

Alan Shreve 12 years ago
parent
commit
81495a8dcb
1 changed files with 25 additions and 10 deletions
  1. 25 10
      server/manager.go

+ 25 - 10
server/manager.go

@@ -10,21 +10,28 @@ import (
 	"time"
 	"time"
 )
 )
 
 
+const (
+	cacheDuration        time.Duration = 24 * time.Hour
+	cacheCleanupInterval time.Duration = time.Minute
+)
+
 /**
 /**
  * TunnelManager: Manages a set of tunnels
  * TunnelManager: Manages a set of tunnels
  */
  */
 type TunnelManager struct {
 type TunnelManager struct {
-	domain         string
-	tunnels        map[string]*Tunnel
-	domainAffinity *cache.Cache
+	domain           string
+	tunnels          map[string]*Tunnel
+	idDomainAffinity *cache.Cache
+	ipDomainAffinity *cache.Cache
 	sync.RWMutex
 	sync.RWMutex
 }
 }
 
 
 func NewTunnelManager(domain string) *TunnelManager {
 func NewTunnelManager(domain string) *TunnelManager {
 	return &TunnelManager{
 	return &TunnelManager{
-		domain:         domain,
-		tunnels:        make(map[string]*Tunnel),
-		domainAffinity: cache.New(24*time.Hour, time.Minute),
+		domain:           domain,
+		tunnels:          make(map[string]*Tunnel),
+		idDomainAffinity: cache.New(cacheDuration, cacheCleanupInterval),
+		ipDomainAffinity: cache.New(cacheDuration, cacheCleanupInterval),
 	}
 	}
 }
 }
 
 
@@ -63,10 +70,17 @@ func (m *TunnelManager) Add(t *Tunnel) error {
 				return t.Warn("The tunnel address %s is already registered!", url)
 				return t.Warn("The tunnel address %s is already registered!", url)
 			}
 			}
 		} else {
 		} else {
+			clientIp := t.ctl.conn.RemoteAddr().(*net.TCPAddr).IP.String()
+			clientId := t.regMsg.ClientId
+
 			// try to give the same subdomain back if it's available
 			// try to give the same subdomain back if it's available
-			subdomain, ok := m.domainAffinity.Get(t.regMsg.ClientId)
-			if !ok {
-				subdomain = fmt.Sprintf("%x", rand.Int31())
+			subdomain := fmt.Sprintf("%x", rand.Int31())
+			if lastDomain, ok := m.idDomainAffinity.Get(clientId); ok {
+				t.Debug("Found affinity for subdomain %s with client id %s", subdomain, clientId)
+				subdomain = lastDomain.(string)
+			} else if lastDomain, ok = m.ipDomainAffinity.Get(clientIp); ok {
+				t.Debug("Found affinity for subdomain %s with client ip %s", subdomain, clientIp)
+				subdomain = lastDomain.(string)
 			}
 			}
 
 
 			// pick one randomly
 			// pick one randomly
@@ -81,7 +95,8 @@ func (m *TunnelManager) Add(t *Tunnel) error {
 
 
 			// save our choice for later
 			// save our choice for later
 			// XXX: this is going to leak memory
 			// XXX: this is going to leak memory
-			m.domainAffinity.Set(t.regMsg.ClientId, subdomain, 0)
+			m.idDomainAffinity.Set(clientId, subdomain, 0)
+			m.ipDomainAffinity.Set(clientIp, subdomain, 0)
 		}
 		}
 
 
 	default:
 	default: