From 333736d8751abb06cf686ed22afae8acb55a89c1 Mon Sep 17 00:00:00 2001 From: Ian Bishop Date: Tue, 28 Aug 2018 20:54:48 +1000 Subject: [PATCH 1/2] fix sqlite import --- README.md | 7 +++++-- cmd/grumble/murmurdb.go | 39 +++++++++++++++++++++------------------ cmd/grumble/server.go | 4 ++-- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 5d9e93c..4c4976f 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,12 @@ Grumble is an implementation of a server for the Mumble voice chat system. It is Compiling Grumble from source ============================= -You must have a Go 1 environment installed to build Grumble. Those are available at: +## Dependencies -https://golang.org/dl/ +- You must have a Go 1 environment installed to build Grumble. Those are available at: https://golang.org/dl/ +- Grumble requires sqlite3 library + +## Build Once Go is installed, you should set up a GOPATH to avoid clobbering your Go environment's root directory with third party packages. diff --git a/cmd/grumble/murmurdb.go b/cmd/grumble/murmurdb.go index a3a5116..674d9e9 100644 --- a/cmd/grumble/murmurdb.go +++ b/cmd/grumble/murmurdb.go @@ -13,12 +13,14 @@ import ( "database/sql" "errors" "log" - "mumble.info/grumble/pkg/acl" - "mumble.info/grumble/pkg/ban" "net" "os" "path/filepath" "strconv" + + _ "github.com/mattn/go-sqlite3" + "mumble.info/grumble/pkg/acl" + "mumble.info/grumble/pkg/ban" ) const ( @@ -39,7 +41,7 @@ const SQLiteSupport = true // Import the structure of an existing Murmur SQLite database. func MurmurImport(filename string) (err error) { - db, err := sql.Open("sqlite", filename) + db, err := sql.Open("sqlite3", filename) if err != nil { panic(err.Error()) } @@ -67,7 +69,7 @@ func MurmurImport(filename string) (err error) { return err } - err = os.Mkdir(filepath.Join(Args.DataDir, strconv.FormatInt(sid, 10)), 0750) + err = os.MkdirAll(filepath.Join(Args.DataDir, "servers", strconv.FormatInt(sid, 10)), 0750) if err != nil { return err } @@ -187,33 +189,34 @@ func populateChannelACLFromDatabase(server *Server, c *Channel, db *sql.DB) erro for rows.Next() { var ( - UserId string - Group string - ApplyHere bool - ApplySub bool - Allow int64 - Deny int64 + UserId sql.NullString + Group sql.NullString + ApplyHere sql.NullBool + ApplySub sql.NullBool + Allow sql.NullInt64 + Deny sql.NullInt64 ) + if err := rows.Scan(&UserId, &Group, &ApplyHere, &ApplySub, &Allow, &Deny); err != nil { return err } aclEntry := acl.ACL{} - aclEntry.ApplyHere = ApplyHere - aclEntry.ApplySubs = ApplySub - if len(UserId) > 0 { - aclEntry.UserId, err = strconv.Atoi(UserId) + aclEntry.ApplyHere = ApplyHere.Bool + aclEntry.ApplySubs = ApplySub.Bool + if UserId.Valid { + aclEntry.UserId, err = strconv.Atoi(UserId.String) if err != nil { return err } - } else if len(Group) > 0 { - aclEntry.Group = Group + } else if Group.Valid { + aclEntry.Group = Group.String } else { return errors.New("Invalid ACL: Neither Group or UserId specified") } - aclEntry.Deny = acl.Permission(Deny) - aclEntry.Allow = acl.Permission(Allow) + aclEntry.Deny = acl.Permission(Deny.Int64) + aclEntry.Allow = acl.Permission(Allow.Int64) c.ACL.ACLs = append(c.ACL.ACLs, aclEntry) } diff --git a/cmd/grumble/server.go b/cmd/grumble/server.go index f6f627a..78e1bdc 100644 --- a/cmd/grumble/server.go +++ b/cmd/grumble/server.go @@ -1452,9 +1452,9 @@ func (server *Server) Start() (err error) { // Set sensible timeouts, in case no reverse proxy is in front of Grumble. // Non-conforming (or malicious) clients may otherwise block indefinitely and cause // file descriptors (or handles, depending on your OS) to leak and/or be exhausted - ReadTimeout: 5 * time.Second, + ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, - IdleTimeout: 2 * time.Minute, + IdleTimeout: 2 * time.Minute, } go func() { err := server.webhttp.ListenAndServeTLS("", "") From a0b9a4bc4f290a0783ed644495a2a2b6634e42bf Mon Sep 17 00:00:00 2001 From: Ian Bishop Date: Tue, 28 Aug 2018 21:51:07 +1000 Subject: [PATCH 2/2] fix unfreeze from a previous sqlite import --- cmd/grumble/freeze.go | 77 ++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/cmd/grumble/freeze.go b/cmd/grumble/freeze.go index edd7f7f..4394d21 100644 --- a/cmd/grumble/freeze.go +++ b/cmd/grumble/freeze.go @@ -21,6 +21,8 @@ import ( "time" ) +type parentsMap map[uint32]uint32 + // Freeze a server to disk and closes the log file. // This must be called from within the Server's synchronous handler. func (server *Server) FreezeToFile() error { @@ -261,6 +263,8 @@ func (c *Channel) Unfreeze(fc *freezer.Channel) { continue } g := acl.Group{} + g.Add = make(map[int]bool) + g.Remove = make(map[int]bool) if fgrp.Inherit != nil { g.Inherit = *fgrp.Inherit } @@ -430,7 +434,7 @@ func NewServerFromFrozen(name string) (s *Server, err error) { // Add all channels, but don't hook up parent/child relationships // until after we've walked the log file. No need to make it harder // than it really is. - parents := make(map[uint32]uint32) + parents := make(parentsMap) for _, fc := range fs.Channels { // The frozen channel must contain an Id and a Name, // since the server's frozen channels are guaranteed to @@ -487,8 +491,48 @@ func NewServerFromFrozen(name string) (s *Server, err error) { } } - // Attempt to walk the stored log file + // Attempt to walk the stored log file (if exists) logFile, err := os.Open(logFn) + if err == nil { + parents, err = s.walkLogFile(parents, logFile) + if err != nil { + return nil, err + } + } else if !os.IsNotExist(err) { + return nil, err + } + + // Hook up children with their parents + for chanId, parentId := range parents { + childChan, exists := s.Channels[int(chanId)] + if !exists { + return nil, errors.New("Non-existant child channel") + } + parentChan, exists := s.Channels[int(parentId)] + if !exists { + return nil, errors.New("Non-existant parent channel") + } + parentChan.AddChild(childChan) + } + + // Hook up all channel links + for _, channel := range s.Channels { + if len(channel.Links) > 0 { + links := channel.Links + channel.Links = make(map[int]*Channel) + for chanId, _ := range links { + targetChannel := s.Channels[chanId] + if targetChannel != nil { + s.LinkChannels(channel, targetChannel) + } + } + } + } + + return s, nil +} + +func (s *Server) walkLogFile(parents parentsMap, logFile *os.File) (parentsMap, error) { walker, err := freezer.NewReaderWalker(logFile) if err != nil { return nil, err @@ -649,34 +693,7 @@ func NewServerFromFrozen(name string) (s *Server, err error) { } } - // Hook up children with their parents - for chanId, parentId := range parents { - childChan, exists := s.Channels[int(chanId)] - if !exists { - return nil, errors.New("Non-existant child channel") - } - parentChan, exists := s.Channels[int(parentId)] - if !exists { - return nil, errors.New("Non-existant parent channel") - } - parentChan.AddChild(childChan) - } - - // Hook up all channel links - for _, channel := range s.Channels { - if len(channel.Links) > 0 { - links := channel.Links - channel.Links = make(map[int]*Channel) - for chanId, _ := range links { - targetChannel := s.Channels[chanId] - if targetChannel != nil { - s.LinkChannels(channel, targetChannel) - } - } - } - } - - return s, nil + return parents, nil } // Update the datastore with the user's current state.