grumble/pkg/sessionpool/sessionpool.go
rubenseyer ae41a612ba Minor features for parity with murmur.ini
MaxUsers: modifies existing sessionpool similar to Murmur
MaxUsersPerChannel: already implemented, inconsistent name
AllowPing: affects registration, too
DefaultChannel
RememberChannel
ServerPassword
SendOSInfo: already implemented, inconsistent name

Config keys are renamed to conform to murmur.ini
2020-04-16 22:43:02 +02:00

101 lines
2.5 KiB
Go

// Copyright (c) 2011 The Grumble Authors
// The use of this source code is goverened by a BSD-style
// license that can be found in the LICENSE-file.
// Package sessionpool implements a reuse pool for session IDs.
package sessionpool
import (
"errors"
"math"
"sync"
)
// A SessionPool is a pool for session IDs.
// IDs are re-used in MRU order, for ease of implementation in Go.
type SessionPool struct {
mutex sync.Mutex
used map[uint32]bool
unused []uint32
cur uint32
max uint32
}
// Create a new SessionPool container.
func New(max uint32) (pool *SessionPool) {
pool = new(SessionPool)
if max == 0 {
pool.max = math.MaxUint32
} else {
pool.max = max
}
return
}
// Enable use-tracking for the SessionPool.
//
// When enabled, the SessionPool stores all session IDs
// returned by Get() internally. When an ID is reclaimed,
// the SessionPool checks whether the ID being reclaimed
// is in its list of used IDs. If this is not the case,
// the program will panic.
func (pool *SessionPool) EnableUseTracking() {
if len(pool.unused) != 0 || pool.cur != 0 {
panic("Attempt to enable use tracking on an existing SessionPool.")
}
pool.used = make(map[uint32]bool)
}
// Get a new session ID from the SessionPool.
// Must be reclaimed using Reclaim() when done using it.
func (pool *SessionPool) Get() (id uint32, err error) {
pool.mutex.Lock()
defer pool.mutex.Unlock()
// If use tracking is enabled, mark our returned session id as used.
if pool.used != nil {
defer func() {
pool.used[id] = true
}()
}
// First, look in the unused stack.
length := len(pool.unused)
if length > 0 {
id = pool.unused[length-1]
pool.unused = pool.unused[:length-1]
return
}
// Check for depletion. If cur is max,
// there aren't any session IDs left, since the
// increment below would return an out of range ID.
if pool.cur == pool.max {
err = errors.New("depleted session pool")
return
}
// Increment the next session id and return it.
// Note: By incrementing and *then* returning, we skip 0.
// This is deliberate, as 0 is an invalid session ID in Mumble.
pool.cur += 1
id = pool.cur
return
}
// Reclaim a session ID so it can be reused.
func (pool *SessionPool) Reclaim(id uint32) {
pool.mutex.Lock()
defer pool.mutex.Unlock()
// Check whether this ID is marked as being in use.
if pool.used != nil {
_, inUse := pool.used[id]
if !inUse {
panic("Attempt to reclaim invalid session ID")
}
delete(pool.used, id)
}
pool.unused = append(pool.unused, id)
}