forked from External/grumble
Add 'grumble ctl'.
This commit is contained in:
parent
01182d36b3
commit
41f6af2334
10 changed files with 343 additions and 34 deletions
7
Makefile
7
Makefile
|
|
@ -11,6 +11,7 @@ PACKAGES = \
|
||||||
pkg/cryptstate \
|
pkg/cryptstate \
|
||||||
pkg/mumbleproto \
|
pkg/mumbleproto \
|
||||||
pkg/blobstore \
|
pkg/blobstore \
|
||||||
|
pkg/serverconf \
|
||||||
pkg/sqlite
|
pkg/sqlite
|
||||||
|
|
||||||
GCFLAGS = \
|
GCFLAGS = \
|
||||||
|
|
@ -18,6 +19,7 @@ GCFLAGS = \
|
||||||
-Ipkg/packetdatastream/_obj \
|
-Ipkg/packetdatastream/_obj \
|
||||||
-Ipkg/mumbleproto/_obj \
|
-Ipkg/mumbleproto/_obj \
|
||||||
-Ipkg/blobstore/_obj \
|
-Ipkg/blobstore/_obj \
|
||||||
|
-Ipkg/serverconf/_obj \
|
||||||
-Ipkg/sqlite/_obj
|
-Ipkg/sqlite/_obj
|
||||||
|
|
||||||
LDFLAGS = \
|
LDFLAGS = \
|
||||||
|
|
@ -25,6 +27,7 @@ LDFLAGS = \
|
||||||
-Lpkg/packetdatastream/_obj \
|
-Lpkg/packetdatastream/_obj \
|
||||||
-Lpkg/mumbleproto/_obj \
|
-Lpkg/mumbleproto/_obj \
|
||||||
-Lpkg/blobstore/_obj \
|
-Lpkg/blobstore/_obj \
|
||||||
|
-Lpkg/serverconf/_obj \
|
||||||
-Lpkg/sqlite/_obj
|
-Lpkg/sqlite/_obj
|
||||||
|
|
||||||
GOFILES = \
|
GOFILES = \
|
||||||
|
|
@ -39,7 +42,9 @@ GOFILES = \
|
||||||
murmurdb.go \
|
murmurdb.go \
|
||||||
freeze.go \
|
freeze.go \
|
||||||
gencert.go \
|
gencert.go \
|
||||||
register.go
|
register.go \
|
||||||
|
ctlrpc.go \
|
||||||
|
ctl.go
|
||||||
|
|
||||||
.PHONY: grumble
|
.PHONY: grumble
|
||||||
grumble: pkg
|
grumble: pkg
|
||||||
|
|
|
||||||
82
ctl.go
Normal file
82
ctl.go
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
// 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 main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"rpc"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
var CtlUsage = `grumble ctl
|
||||||
|
|
||||||
|
help
|
||||||
|
Show this help
|
||||||
|
|
||||||
|
start [id]
|
||||||
|
Start a server
|
||||||
|
|
||||||
|
stop [id]
|
||||||
|
Stop a server
|
||||||
|
|
||||||
|
setconf [id] [key] [value]
|
||||||
|
Set a config value for server with id
|
||||||
|
|
||||||
|
getconf [id] [key] [value]
|
||||||
|
Get a config value for server with id
|
||||||
|
`
|
||||||
|
|
||||||
|
func GrumbleCtl(args []string) {
|
||||||
|
log.SetFlags(0)
|
||||||
|
|
||||||
|
if len(args) <= 1 || args[0] == "help" {
|
||||||
|
log.Printf(CtlUsage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sid, _ := strconv.Atoi64(args[1])
|
||||||
|
|
||||||
|
client, err := rpc.Dial("unix", filepath.Join(os.Getenv("HOME"), ".grumble", "ctl"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Could not connect to control socket: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch args[0] {
|
||||||
|
case "start":
|
||||||
|
err := client.Call("ctl.Start", sid, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to start: %v", err)
|
||||||
|
}
|
||||||
|
log.Printf("[%v] Started")
|
||||||
|
case "stop":
|
||||||
|
err := client.Call("ctl.Stop", sid, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to stop: %v", err)
|
||||||
|
}
|
||||||
|
log.Printf("[%v] Stopped", sid)
|
||||||
|
case "setconf":
|
||||||
|
if len(args) < 4 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result := &ConfigValue{}
|
||||||
|
err := client.Call("ctl.SetConfig", &ConfigValue{sid, args[2], args[3]}, result)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to set config: %v", err)
|
||||||
|
}
|
||||||
|
log.Printf("[%v] %v=%v", result.Id, result.Key, result.Value)
|
||||||
|
case "getconf":
|
||||||
|
if len(args) < 3 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result := &ConfigValue{}
|
||||||
|
err := client.Call("ctl.GetConfig", &ConfigValue{sid, args[2], ""}, result)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to get config: %v", err)
|
||||||
|
}
|
||||||
|
log.Printf("[%v] %v=%v", result.Id, result.Key, result.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
46
ctlrpc.go
Normal file
46
ctlrpc.go
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
// 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 main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ControlRPC struct {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start a server
|
||||||
|
func (c *ControlRPC) Start(in *int, out *int) os.Error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop a server
|
||||||
|
func (c *ControlRPC) Stop(in *int, out *int) os.Error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigValue struct {
|
||||||
|
Id int64
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a config value
|
||||||
|
func (c *ControlRPC) SetConfig(in *ConfigValue, out *ConfigValue) os.Error {
|
||||||
|
servers[in.Id].SetConfig(in.Key, in.Value)
|
||||||
|
out.Id = in.Id
|
||||||
|
out.Key = in.Key
|
||||||
|
out.Value = in.Value
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a config value
|
||||||
|
func (c *ControlRPC) GetConfig(in *ConfigValue, out *ConfigValue) os.Error {
|
||||||
|
out.Id = in.Id
|
||||||
|
out.Key = in.Key
|
||||||
|
out.Value = servers[in.Id].GetConfig(in.Key)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -15,7 +15,7 @@ import (
|
||||||
|
|
||||||
type frozenServer struct {
|
type frozenServer struct {
|
||||||
Id int "id"
|
Id int "id"
|
||||||
MaxUsers int "max_user"
|
Config map[string]string "config"
|
||||||
Channels []frozenChannel "channels"
|
Channels []frozenChannel "channels"
|
||||||
Users []frozenUser "users"
|
Users []frozenUser "users"
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +98,7 @@ func (server *Server) FreezeToFile(filename string) (err os.Error) {
|
||||||
// Freeze a server
|
// Freeze a server
|
||||||
func (server *Server) Freeze() (fs frozenServer, err os.Error) {
|
func (server *Server) Freeze() (fs frozenServer, err os.Error) {
|
||||||
fs.Id = int(server.Id)
|
fs.Id = int(server.Id)
|
||||||
fs.MaxUsers = server.MaxUsers
|
fs.Config = server.cfg
|
||||||
|
|
||||||
channels := []frozenChannel{}
|
channels := []frozenChannel{}
|
||||||
for _, c := range server.Channels {
|
for _, c := range server.Channels {
|
||||||
|
|
@ -224,6 +224,10 @@ func NewServerFromFrozen(filename string) (s *Server, err os.Error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fs.Config != nil {
|
||||||
|
s.cfg = fs.Config
|
||||||
|
}
|
||||||
|
|
||||||
// Add all channels, but don't hook up parent/child relationships
|
// Add all channels, but don't hook up parent/child relationships
|
||||||
// until all of them are loaded.
|
// until all of them are loaded.
|
||||||
for _, fc := range fs.Channels {
|
for _, fc := range fs.Channels {
|
||||||
|
|
|
||||||
40
grumble.go
40
grumble.go
|
|
@ -11,20 +11,24 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"sqlite"
|
"sqlite"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"rpc"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var help *bool = flag.Bool("help", false, "Show this help")
|
var help *bool = flag.Bool("help", false, "Show this help")
|
||||||
var datadir *string = flag.String("datadir", "", "Directory to use for server storage")
|
var datadir *string = flag.String("datadir", "", "Directory to use for server storage")
|
||||||
var blobdir *string = flag.String("blobdir", "", "Directory to use for blob storage")
|
var blobdir *string = flag.String("blobdir", "", "Directory to use for blob storage")
|
||||||
|
var ctlpath *string = flag.String("ctlpath", "", "File to use for ctl socket")
|
||||||
var sqlitedb *string = flag.String("murmurdb", "", "Path to murmur.sqlite to import server structure from")
|
var sqlitedb *string = flag.String("murmurdb", "", "Path to murmur.sqlite to import server structure from")
|
||||||
var cleanup *bool = flag.Bool("clean", false, "Clean up existing data dir content before importing Murmur data")
|
var cleanup *bool = flag.Bool("clean", false, "Clean up existing data dir content before importing Murmur data")
|
||||||
var gencert *bool = flag.Bool("gencert", false, "Generate a self-signed certificate for use with Grumble")
|
var gencert *bool = flag.Bool("gencert", false, "Generate a self-signed certificate for use with Grumble")
|
||||||
|
|
||||||
var globalBlobstore *blobstore.BlobStore
|
var globalBlobstore *blobstore.BlobStore
|
||||||
|
var servers map[int64]*Server
|
||||||
|
|
||||||
func Usage() {
|
func Usage() {
|
||||||
fmt.Fprintf(os.Stderr, "usage: grumble [options]\n")
|
fmt.Fprintf(os.Stderr, "usage: grumble [options]\n")
|
||||||
|
|
@ -42,16 +46,16 @@ func MurmurImport(filename string) (err os.Error) {
|
||||||
panic(err.String())
|
panic(err.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
var servers []int64
|
var serverids []int64
|
||||||
var sid int64
|
var sid int64
|
||||||
for stmt.Next() {
|
for stmt.Next() {
|
||||||
stmt.Scan(&sid)
|
stmt.Scan(&sid)
|
||||||
servers = append(servers, sid)
|
serverids = append(serverids, sid)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Found servers: %v (%v servers)", servers, len(servers))
|
log.Printf("Found servers: %v (%v servers)", serverids, len(serverids))
|
||||||
|
|
||||||
for _, sid := range servers {
|
for _, sid := range serverids {
|
||||||
m, err := NewServerFromSQLite(sid, db)
|
m, err := NewServerFromSQLite(sid, db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -70,6 +74,12 @@ func MurmurImport(filename string) (err os.Error) {
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var err os.Error
|
var err os.Error
|
||||||
|
|
||||||
|
if len(os.Args) >= 2 && os.Args[1] == "ctl" {
|
||||||
|
GrumbleCtl(os.Args[2:])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *help == true {
|
if *help == true {
|
||||||
Usage()
|
Usage()
|
||||||
|
|
@ -88,6 +98,10 @@ func main() {
|
||||||
*blobdir = filepath.Join(os.Getenv("HOME"), ".grumble", "blob")
|
*blobdir = filepath.Join(os.Getenv("HOME"), ".grumble", "blob")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(*ctlpath) == 0 {
|
||||||
|
*ctlpath = filepath.Join(os.Getenv("HOME"), ".grumble", "ctl")
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("Using blob directory: %s", *blobdir)
|
log.Printf("Using blob directory: %s", *blobdir)
|
||||||
globalBlobstore, err = blobstore.NewBlobStore(*blobdir, true)
|
globalBlobstore, err = blobstore.NewBlobStore(*blobdir, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -161,7 +175,7 @@ func main() {
|
||||||
log.Fatalf("Murmur import failed: %s", err.String())
|
log.Fatalf("Murmur import failed: %s", err.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
servers := make(map[int64]*Server)
|
servers = make(map[int64]*Server)
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
if matched, _ := regexp.MatchString("^[0-9]+$", name); matched {
|
if matched, _ := regexp.MatchString("^[0-9]+$", name); matched {
|
||||||
log.Printf("Loading server %v", name)
|
log.Printf("Loading server %v", name)
|
||||||
|
|
@ -184,6 +198,22 @@ func main() {
|
||||||
go s.ListenAndMurmur()
|
go s.ListenAndMurmur()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
os.Remove(*ctlpath)
|
||||||
|
|
||||||
|
addr, err := net.ResolveUnixAddr("unix", *ctlpath)
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("Unable to resolve ctl addr: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lis, err := net.ListenUnix("unix", addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("Unable to listen on ctl socket: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctl := &ControlRPC{}
|
||||||
|
rpc.RegisterName("ctl", ctl)
|
||||||
|
go rpc.Accept(lis)
|
||||||
|
|
||||||
if len(servers) > 0 {
|
if len(servers) > 0 {
|
||||||
ticker := time.NewTicker(10e9) // 10 secs
|
ticker := time.NewTicker(10e9) // 10 secs
|
||||||
for {
|
for {
|
||||||
|
|
|
||||||
6
pkg/serverconf/Makefile
Normal file
6
pkg/serverconf/Makefile
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
include $(GOROOT)/src/Make.inc
|
||||||
|
|
||||||
|
TARG = grumble/serverconf
|
||||||
|
GOFILES = config.go
|
||||||
|
|
||||||
|
include $(GOROOT)/src/Make.pkg
|
||||||
64
pkg/serverconf/config.go
Normal file
64
pkg/serverconf/config.go
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
// 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 serverconf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
var defaultCfg = map[string]string{
|
||||||
|
"MaxBandwidth": "72000",
|
||||||
|
"MaxUsers": "1000",
|
||||||
|
"MaxUsersPerChannel": "0",
|
||||||
|
"MaxTextMessageLength": "5000",
|
||||||
|
"MaxImageMessageLength": "131072",
|
||||||
|
"AllowHTML": "true",
|
||||||
|
"DefaultChannel": "0",
|
||||||
|
"RememberChannel": "true",
|
||||||
|
"WelcomeText": "Welcome to this server running <b>Grumble</b>.",
|
||||||
|
"SendVersion": "true",
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config map[string]string
|
||||||
|
|
||||||
|
func (cfg Config) Set(key string, value string) {
|
||||||
|
cfg[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg Config) StringValue(key string) (value string) {
|
||||||
|
value, exists := cfg[key]
|
||||||
|
if exists {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
value, exists = defaultCfg[key]
|
||||||
|
if exists {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg Config) IntValue(key string) (intval int) {
|
||||||
|
str := cfg.StringValue(key)
|
||||||
|
intval, _ = strconv.Atoi(str)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg Config) Uint32Value(key string) (uint32val uint32) {
|
||||||
|
str := cfg.StringValue(key)
|
||||||
|
uintval, _ := strconv.Atoui(str)
|
||||||
|
return uint32(uintval)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg Config) BoolValue(key string) (boolval bool) {
|
||||||
|
str := cfg.StringValue(key)
|
||||||
|
boolval, _ = strconv.Atob(str)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg Config) Reset(key string) {
|
||||||
|
cfg[key] = "", false
|
||||||
|
}
|
||||||
40
pkg/serverconf/config_test.go
Normal file
40
pkg/serverconf/config_test.go
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
// 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 serverconf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIntValue(t *testing.T) {
|
||||||
|
cfg := make(Config)
|
||||||
|
cfg.Set("Test", "13")
|
||||||
|
if cfg.IntValue("Test") != 13 {
|
||||||
|
t.Errorf("Expected 13")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFloatAsInt(t *testing.T) {
|
||||||
|
cfg := make(Config)
|
||||||
|
cfg.Set("Test", "13.4")
|
||||||
|
if cfg.IntValue("Test") != 0 {
|
||||||
|
t.Errorf("Expected 0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDefaultValue(t *testing.T) {
|
||||||
|
cfg := make(Config)
|
||||||
|
if cfg.IntValue("MaxBandwidth") != 72000 {
|
||||||
|
t.Errorf("Expected 72000")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBoolValue(t *testing.T) {
|
||||||
|
cfg := make(Config)
|
||||||
|
cfg.Set("DoStuffOnStartup", "true")
|
||||||
|
if cfg.BoolValue("DoStuffOnStartup") != true {
|
||||||
|
t.Errorf("Expected true")
|
||||||
|
}
|
||||||
|
}
|
||||||
18
register.go
18
register.go
|
|
@ -74,16 +74,16 @@ func newTLSClientAuthConn(addr string, cfg *tls.Config) (c *http.ClientConn, err
|
||||||
// This function is used to determine whether or not to periodically
|
// This function is used to determine whether or not to periodically
|
||||||
// contact the master server list and update this server's metadata.
|
// contact the master server list and update this server's metadata.
|
||||||
func (server *Server) IsPublic() bool {
|
func (server *Server) IsPublic() bool {
|
||||||
if len(server.RegisterName) == 0 {
|
if len(server.cfg.StringValue("RegisterName")) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if len(server.RegisterHost) == 0 {
|
if len(server.cfg.StringValue("RegisterHost")) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if len(server.RegisterPassword) == 0 {
|
if len(server.cfg.StringValue("RegisterPassword")) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if len(server.RegisterWebUrl) == 0 {
|
if len(server.cfg.StringValue("RegisterWebUrl")) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
@ -121,11 +121,11 @@ func (server *Server) RegisterPublicServer() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = t.Execute(buf, map[string]string{
|
err = t.Execute(buf, map[string]string{
|
||||||
"name": server.RegisterName,
|
"name": server.cfg.StringValue("RegisterName"),
|
||||||
"host": server.RegisterHost,
|
"host": server.cfg.StringValue("RegisterHost"),
|
||||||
"password": server.RegisterPassword,
|
"password": server.cfg.StringValue("RegisterPassword"),
|
||||||
"url": server.RegisterWebUrl,
|
"url": server.cfg.StringValue("RegisterWebUrl"),
|
||||||
"location": server.RegisterLocation,
|
"location": server.cfg.StringValue("RegisterLocation"),
|
||||||
"port": strconv.Itoa(server.port),
|
"port": strconv.Itoa(server.port),
|
||||||
"digest": digest,
|
"digest": digest,
|
||||||
"users": strconv.Itoa(len(server.clients)),
|
"users": strconv.Itoa(len(server.clients)),
|
||||||
|
|
|
||||||
60
server.go
60
server.go
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"cryptstate"
|
"cryptstate"
|
||||||
"fmt"
|
"fmt"
|
||||||
"gob"
|
"gob"
|
||||||
|
"grumble/serverconf"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
@ -57,19 +58,14 @@ type Server struct {
|
||||||
udpsend chan *Message
|
udpsend chan *Message
|
||||||
voicebroadcast chan *VoiceBroadcast
|
voicebroadcast chan *VoiceBroadcast
|
||||||
freezeRequest chan *freezeRequest
|
freezeRequest chan *freezeRequest
|
||||||
|
configRequest chan *configRequest
|
||||||
|
|
||||||
// Signals to the server that a client has been successfully
|
// Signals to the server that a client has been successfully
|
||||||
// authenticated.
|
// authenticated.
|
||||||
clientAuthenticated chan *Client
|
clientAuthenticated chan *Client
|
||||||
|
|
||||||
// Config-related
|
// Server configuration
|
||||||
MaxUsers int
|
cfg serverconf.Config
|
||||||
MaxBandwidth uint32
|
|
||||||
RegisterName string
|
|
||||||
RegisterHost string
|
|
||||||
RegisterPassword string
|
|
||||||
RegisterWebUrl string
|
|
||||||
RegisterLocation string
|
|
||||||
|
|
||||||
// Clients
|
// Clients
|
||||||
clients map[uint32]*Client
|
clients map[uint32]*Client
|
||||||
|
|
@ -128,6 +124,13 @@ type freezeRequest struct {
|
||||||
readCloser io.ReadCloser
|
readCloser io.ReadCloser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type configRequest struct {
|
||||||
|
done chan bool
|
||||||
|
set bool
|
||||||
|
key string
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
// Allocate a new Murmur instance
|
// Allocate a new Murmur instance
|
||||||
func NewServer(id int64, addr string, port int) (s *Server, err os.Error) {
|
func NewServer(id int64, addr string, port int) (s *Server, err os.Error) {
|
||||||
s = new(Server)
|
s = new(Server)
|
||||||
|
|
@ -137,6 +140,8 @@ func NewServer(id int64, addr string, port int) (s *Server, err os.Error) {
|
||||||
s.port = port
|
s.port = port
|
||||||
s.running = false
|
s.running = false
|
||||||
|
|
||||||
|
s.cfg = make(map[string]string)
|
||||||
|
|
||||||
s.sessions = make(map[uint32]bool)
|
s.sessions = make(map[uint32]bool)
|
||||||
s.clients = make(map[uint32]*Client)
|
s.clients = make(map[uint32]*Client)
|
||||||
s.Users = make(map[uint32]*User)
|
s.Users = make(map[uint32]*User)
|
||||||
|
|
@ -150,11 +155,9 @@ func NewServer(id int64, addr string, port int) (s *Server, err os.Error) {
|
||||||
s.udpsend = make(chan *Message)
|
s.udpsend = make(chan *Message)
|
||||||
s.voicebroadcast = make(chan *VoiceBroadcast)
|
s.voicebroadcast = make(chan *VoiceBroadcast)
|
||||||
s.freezeRequest = make(chan *freezeRequest)
|
s.freezeRequest = make(chan *freezeRequest)
|
||||||
|
s.configRequest = make(chan *configRequest)
|
||||||
s.clientAuthenticated = make(chan *Client)
|
s.clientAuthenticated = make(chan *Client)
|
||||||
|
|
||||||
s.MaxBandwidth = 300000
|
|
||||||
s.MaxUsers = 10
|
|
||||||
|
|
||||||
s.Channels = make(map[int]*Channel)
|
s.Channels = make(map[int]*Channel)
|
||||||
s.root = s.NewChannel(0, "Root")
|
s.root = s.NewChannel(0, "Root")
|
||||||
s.aclcache = NewACLCache()
|
s.aclcache = NewACLCache()
|
||||||
|
|
@ -391,6 +394,10 @@ func (server *Server) handler() {
|
||||||
}
|
}
|
||||||
go server.handleFreezeRequest(req, &fs)
|
go server.handleFreezeRequest(req, &fs)
|
||||||
|
|
||||||
|
// Synchronzied config get/set
|
||||||
|
case req := <-server.configRequest:
|
||||||
|
server.handleConfigRequest(req)
|
||||||
|
|
||||||
// Server registration update
|
// Server registration update
|
||||||
// Tick every hour + a minute offset based on the server id.
|
// Tick every hour + a minute offset based on the server id.
|
||||||
case <-time.Tick((3600 + ((server.Id * 60) % 600)) * 1e9):
|
case <-time.Tick((3600 + ((server.Id * 60) % 600)) * 1e9):
|
||||||
|
|
@ -426,6 +433,15 @@ func (server *Server) handleFreezeRequest(freq *freezeRequest, fs *frozenServer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (server *Server) handleConfigRequest(cfgReq *configRequest) {
|
||||||
|
if cfgReq.set {
|
||||||
|
server.cfg.Set(cfgReq.key, cfgReq.value)
|
||||||
|
} else {
|
||||||
|
cfgReq.value = server.cfg.StringValue(cfgReq.key)
|
||||||
|
}
|
||||||
|
cfgReq.done <- true
|
||||||
|
}
|
||||||
|
|
||||||
// Handle an Authenticate protobuf message. This is handled in a separate
|
// Handle an Authenticate protobuf message. This is handled in a separate
|
||||||
// goroutine to allow for remote authenticators that are slow to respond.
|
// goroutine to allow for remote authenticators that are slow to respond.
|
||||||
//
|
//
|
||||||
|
|
@ -639,7 +655,7 @@ func (server *Server) finishAuthenticate(client *Client) {
|
||||||
|
|
||||||
sync := &mumbleproto.ServerSync{}
|
sync := &mumbleproto.ServerSync{}
|
||||||
sync.Session = proto.Uint32(client.Session)
|
sync.Session = proto.Uint32(client.Session)
|
||||||
sync.MaxBandwidth = proto.Uint32(server.MaxBandwidth)
|
sync.MaxBandwidth = proto.Uint32(server.cfg.Uint32Value("MaxBandwidth"))
|
||||||
if client.IsSuperUser() {
|
if client.IsSuperUser() {
|
||||||
sync.Permissions = proto.Uint64(uint64(AllPermissions))
|
sync.Permissions = proto.Uint64(uint64(AllPermissions))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -951,8 +967,8 @@ func (server *Server) ListenUDP() {
|
||||||
_ = binary.Write(buffer, binary.BigEndian, uint32((1<<16)|(2<<8)|2))
|
_ = binary.Write(buffer, binary.BigEndian, uint32((1<<16)|(2<<8)|2))
|
||||||
_ = binary.Write(buffer, binary.BigEndian, rand)
|
_ = binary.Write(buffer, binary.BigEndian, rand)
|
||||||
_ = binary.Write(buffer, binary.BigEndian, uint32(len(server.clients)))
|
_ = binary.Write(buffer, binary.BigEndian, uint32(len(server.clients)))
|
||||||
_ = binary.Write(buffer, binary.BigEndian, uint32(server.MaxUsers))
|
_ = binary.Write(buffer, binary.BigEndian, server.cfg.Uint32Value("MaxUsers"))
|
||||||
_ = binary.Write(buffer, binary.BigEndian, uint32(server.MaxBandwidth))
|
_ = binary.Write(buffer, binary.BigEndian, server.cfg.Uint32Value("MaxBandwidth"))
|
||||||
|
|
||||||
server.udpsend <- &Message{
|
server.udpsend <- &Message{
|
||||||
buf: buffer.Bytes(),
|
buf: buffer.Bytes(),
|
||||||
|
|
@ -1059,6 +1075,22 @@ func (s *Server) FreezeServer() io.ReadCloser {
|
||||||
return fr.readCloser
|
return fr.readCloser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the value of a config key
|
||||||
|
func (s *Server) SetConfig(key string, value string) {
|
||||||
|
cfgReq := &configRequest{make(chan bool), true, key, value}
|
||||||
|
s.configRequest <- cfgReq
|
||||||
|
<-cfgReq.done
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the value of a config key
|
||||||
|
func (s *Server) GetConfig(key string) (value string) {
|
||||||
|
cfgReq := &configRequest{make(chan bool), false, key, ""}
|
||||||
|
s.configRequest <- cfgReq
|
||||||
|
<-cfgReq.done
|
||||||
|
return cfgReq.value
|
||||||
|
}
|
||||||
|
|
||||||
// Register a client on the server.
|
// Register a client on the server.
|
||||||
func (s *Server) RegisterClient(client *Client) (uid uint32) {
|
func (s *Server) RegisterClient(client *Client) (uid uint32) {
|
||||||
// Increment nextUserId only if registration succeeded.
|
// Increment nextUserId only if registration succeeded.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue