mirror of
https://github.com/mumble-voip/grumble.git
synced 2025-12-19 21:59:59 -08:00
Handle UserState and UserRemove (with a few exceptions!)
This commit is contained in:
parent
4903558e4a
commit
925e23b0f9
4 changed files with 235 additions and 28 deletions
37
client.go
37
client.go
|
|
@ -37,12 +37,21 @@ type Client struct {
|
|||
udp bool
|
||||
|
||||
// Personal
|
||||
UserId int
|
||||
Session uint32
|
||||
Username string
|
||||
Hash string
|
||||
Tokens []string
|
||||
Channel *Channel
|
||||
UserId int
|
||||
Session uint32
|
||||
Username string
|
||||
Hash string
|
||||
Tokens []string
|
||||
Channel *Channel
|
||||
SelfMute bool
|
||||
SelfDeaf bool
|
||||
Mute bool
|
||||
Deaf bool
|
||||
Suppress bool
|
||||
PrioritySpeaker bool
|
||||
Recording bool
|
||||
PluginContext []byte
|
||||
PluginIdentity string
|
||||
}
|
||||
|
||||
// Something invalid happened on the wire.
|
||||
|
|
@ -51,18 +60,28 @@ func (client *Client) Panic(reason string) {
|
|||
client.Disconnect()
|
||||
}
|
||||
|
||||
func (client *Client) Disconnect() {
|
||||
// Internal disconnect function
|
||||
func (client *Client) disconnect(kicked bool) {
|
||||
if !client.disconnected {
|
||||
client.disconnected = true
|
||||
close(client.udprecv)
|
||||
close(client.msgchan)
|
||||
|
||||
client.conn.Close()
|
||||
|
||||
client.server.RemoveClient(client)
|
||||
client.server.RemoveClient(client, kicked)
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnect a client (client disconnected)
|
||||
func (client *Client) Disconnect() {
|
||||
client.disconnect(false)
|
||||
}
|
||||
|
||||
// Disconnect a client (kick/ban)
|
||||
func (client *Client) ForceDisconnect() {
|
||||
client.disconnect(true)
|
||||
}
|
||||
|
||||
// Read a protobuf message from a client
|
||||
func (client *Client) readProtoMessage() (msg *Message, err os.Error) {
|
||||
var length uint32
|
||||
|
|
|
|||
148
message.go
148
message.go
|
|
@ -132,7 +132,48 @@ func (server *Server) handleChannelRemoveMessage(client *Client, msg *Message) {
|
|||
func (server *Server) handleChannelStateMessage(client *Client, msg *Message) {
|
||||
}
|
||||
|
||||
// Handle a user remove packet. This can either be a client disconnecting, or a
|
||||
// user kicking or kick-banning another player.
|
||||
func (server *Server) handleUserRemoveMessage(client *Client, msg *Message) {
|
||||
userremove := &mumbleproto.UserRemove{}
|
||||
err := proto.Unmarshal(msg.buf, userremove)
|
||||
if err != nil {
|
||||
client.Panic(err.String())
|
||||
}
|
||||
|
||||
// Get the user to be removed.
|
||||
user, ok := server.clients[*userremove.Session]
|
||||
if !ok {
|
||||
client.Panic("Invalid session in UserRemove message")
|
||||
return
|
||||
}
|
||||
|
||||
ban := false
|
||||
if userremove.Ban != nil {
|
||||
ban = *userremove.Ban
|
||||
}
|
||||
|
||||
// Check user's permissions
|
||||
perm := Permission(KickPermission)
|
||||
if ban {
|
||||
perm = Permission(BanPermission)
|
||||
}
|
||||
if user.UserId == 0 || !server.HasPermission(client, server.root, perm) {
|
||||
client.sendPermissionDenied(client, server.root, perm)
|
||||
return
|
||||
}
|
||||
|
||||
if ban {
|
||||
log.Printf("handleUserRemove: Banning is not yet implemented.")
|
||||
}
|
||||
|
||||
userremove.Actor = proto.Uint32(uint32(client.Session))
|
||||
if err = server.broadcastProtoMessage(MessageUserRemove, userremove); err != nil {
|
||||
log.Panic("Unable to broadcast UserRemove message")
|
||||
return
|
||||
}
|
||||
|
||||
user.ForceDisconnect()
|
||||
}
|
||||
|
||||
func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
|
||||
|
|
@ -143,13 +184,19 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
|
|||
client.Panic(err.String())
|
||||
}
|
||||
|
||||
if userstate.Session == nil {
|
||||
log.Printf("UserState without session.")
|
||||
actor, ok := server.clients[client.Session]
|
||||
if !ok {
|
||||
log.Printf("handleUserState: !")
|
||||
return
|
||||
}
|
||||
|
||||
actor := server.clients[client.Session]
|
||||
user := server.clients[*userstate.Session]
|
||||
user := actor
|
||||
if userstate.Session != nil {
|
||||
user, ok = server.clients[*userstate.Session]
|
||||
if !ok {
|
||||
log.Printf("Invalid session in UserState message")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("actor = %v", actor)
|
||||
log.Printf("user = %v", user)
|
||||
|
|
@ -206,7 +253,6 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
|
|||
// Comment set/clear
|
||||
if userstate.Comment != nil {
|
||||
comment := *userstate.Comment
|
||||
log.Printf("comment = %v", comment)
|
||||
|
||||
// Clearing another user's comment.
|
||||
if user != actor {
|
||||
|
|
@ -266,9 +312,99 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
|
|||
if actor != user && (userstate.SelfDeaf != nil || userstate.SelfMute != nil ||
|
||||
userstate.Texture != nil || userstate.PluginContext != nil || userstate.PluginIdentity != nil ||
|
||||
userstate.Recording != nil) {
|
||||
client.Panic("Invalid UserState")
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("handleUserState: In the out-figuring state")
|
||||
|
||||
broadcast := false
|
||||
if userstate.Texture != nil {
|
||||
broadcast = true
|
||||
}
|
||||
|
||||
if userstate.SelfDeaf != nil {
|
||||
user.SelfDeaf = *userstate.SelfDeaf
|
||||
if user.SelfDeaf {
|
||||
userstate.SelfDeaf = proto.Bool(true)
|
||||
user.SelfMute = true
|
||||
}
|
||||
broadcast = true
|
||||
}
|
||||
|
||||
if userstate.SelfMute != nil {
|
||||
user.SelfMute = *userstate.SelfMute
|
||||
if !user.SelfMute {
|
||||
userstate.SelfDeaf = proto.Bool(false)
|
||||
user.SelfDeaf = false
|
||||
}
|
||||
}
|
||||
|
||||
if userstate.PluginContext != nil {
|
||||
user.PluginContext = userstate.PluginContext
|
||||
}
|
||||
|
||||
if userstate.PluginIdentity != nil {
|
||||
user.PluginIdentity = *userstate.PluginIdentity
|
||||
}
|
||||
|
||||
if userstate.Comment != nil {
|
||||
log.Printf("handleUserState: Comment unhandled")
|
||||
broadcast = true
|
||||
}
|
||||
|
||||
if userstate.Mute != nil || userstate.Deaf != nil || userstate.Suppress != nil || userstate.PrioritySpeaker != nil {
|
||||
if userstate.Deaf != nil {
|
||||
user.Deaf = *userstate.Deaf
|
||||
if user.Deaf {
|
||||
userstate.Mute = proto.Bool(true)
|
||||
}
|
||||
}
|
||||
if userstate.Mute != nil {
|
||||
user.Mute = *userstate.Mute
|
||||
if !user.Mute {
|
||||
userstate.Deaf = proto.Bool(false)
|
||||
user.Deaf = false
|
||||
}
|
||||
}
|
||||
if userstate.Suppress != nil {
|
||||
user.Suppress = *userstate.Suppress
|
||||
}
|
||||
if userstate.PrioritySpeaker != nil {
|
||||
user.PrioritySpeaker = *userstate.PrioritySpeaker
|
||||
}
|
||||
broadcast = true
|
||||
}
|
||||
|
||||
if userstate.Recording != nil && *userstate.Recording != user.Recording {
|
||||
user.Recording = *userstate.Recording
|
||||
// fixme(mkrautz): Notify older clients of recording state change.
|
||||
broadcast = true
|
||||
}
|
||||
|
||||
if userstate.UserId != nil {
|
||||
log.Printf("handleUserState: SelfRegister unhandled")
|
||||
userstate.UserId = nil
|
||||
broadcast = true
|
||||
}
|
||||
|
||||
if userstate.ChannelId != nil {
|
||||
channel, ok := server.channels[int(*userstate.ChannelId)]
|
||||
if ok {
|
||||
server.userEnterChannel(user, channel, userstate)
|
||||
broadcast = true
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("broadcast = %v", broadcast)
|
||||
if broadcast {
|
||||
log.Printf("sending broadcast!")
|
||||
err := server.broadcastProtoMessage(MessageUserState, userstate)
|
||||
if err != nil {
|
||||
log.Printf("handleUserState: failed to broadcast userstate")
|
||||
log.Panic("Unable to broadcast UserState")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (server *Server) handleBanListMessage(client *Client, msg *Message) {
|
||||
|
|
|
|||
77
server.go
77
server.go
|
|
@ -7,11 +7,13 @@ package main
|
|||
import (
|
||||
"log"
|
||||
"crypto/tls"
|
||||
"crypto/sha1"
|
||||
"os"
|
||||
"net"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"sync"
|
||||
"goprotobuf.googlecode.com/hg/proto"
|
||||
"mumbleproto"
|
||||
|
|
@ -133,7 +135,7 @@ func (server *Server) NewClient(conn net.Conn) (err os.Error) {
|
|||
|
||||
// Remove a disconnected client from the server's
|
||||
// internal representation.
|
||||
func (server *Server) RemoveClient(client *Client) {
|
||||
func (server *Server) RemoveClient(client *Client, kicked bool) {
|
||||
server.hmutex.Lock()
|
||||
if client.udpaddr != nil {
|
||||
host := client.udpaddr.IP.String()
|
||||
|
|
@ -153,13 +155,20 @@ func (server *Server) RemoveClient(client *Client) {
|
|||
|
||||
// Remove client from channel
|
||||
channel := client.Channel
|
||||
channel.RemoveClient(client)
|
||||
if channel != nil {
|
||||
channel.RemoveClient(client)
|
||||
}
|
||||
|
||||
err := server.broadcastProtoMessage(MessageUserRemove, &mumbleproto.UserRemove{
|
||||
Session: proto.Uint32(client.Session),
|
||||
})
|
||||
if err != nil {
|
||||
// server panic
|
||||
// If the user was not kicked, broadcast a UserRemove message.
|
||||
// If the user is disconnect via a kick, the UserRemove message has already been sent
|
||||
// at this point.
|
||||
if !kicked {
|
||||
err := server.broadcastProtoMessage(MessageUserRemove, &mumbleproto.UserRemove{
|
||||
Session: proto.Uint32(client.Session),
|
||||
})
|
||||
if err != nil {
|
||||
log.Panic("Unable to broadcast UserRemove message for disconnected client.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -235,6 +244,21 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
|
|||
|
||||
client.Username = *auth.Username
|
||||
|
||||
// Extract certhash
|
||||
tlsconn, ok := client.conn.(*tls.Conn)
|
||||
if !ok {
|
||||
client.Panic("Type assertion failed")
|
||||
return
|
||||
}
|
||||
certs := tlsconn.PeerCertificates()
|
||||
if len(certs) > 0 {
|
||||
hash := sha1.New()
|
||||
hash.Write(certs[0].Raw)
|
||||
client.Hash = hex.EncodeToString(hash.Sum())
|
||||
}
|
||||
|
||||
log.Printf("hash=%s", client.Hash)
|
||||
|
||||
// Setup the cryptstate for the client.
|
||||
client.crypt, err = cryptstate.New()
|
||||
if err != nil {
|
||||
|
|
@ -289,9 +313,6 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
|
|||
server.hclients[host] = append(server.hclients[host], client)
|
||||
server.hmutex.Unlock()
|
||||
|
||||
// Broadcast the the user entered a channel
|
||||
server.root.AddClient(client)
|
||||
|
||||
if client.Username == "SuperUser" {
|
||||
client.UserId = 0
|
||||
}
|
||||
|
|
@ -304,8 +325,9 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
|
|||
if client.UserId >= 0 {
|
||||
userstate.UserId = proto.Uint32(uint32(client.UserId))
|
||||
}
|
||||
if err := client.sendProtoMessage(MessageUserState, userstate); err != nil {
|
||||
client.Panic(err.String())
|
||||
server.userEnterChannel(client, server.root, userstate)
|
||||
if err := server.broadcastProtoMessage(MessageUserState, userstate); err != nil {
|
||||
// Server panic?
|
||||
}
|
||||
|
||||
server.sendUserList(client)
|
||||
|
|
@ -410,8 +432,9 @@ func (server *Server) sendUserList(client *Client) {
|
|||
err := client.sendProtoMessage(MessageUserState, &mumbleproto.UserState{
|
||||
Session: proto.Uint32(user.Session),
|
||||
Name: proto.String(user.Username),
|
||||
ChannelId: proto.Uint32(0),
|
||||
ChannelId: proto.Uint32(uint32(user.Channel.Id)),
|
||||
})
|
||||
log.Printf("ChanId = %v", user.Channel.Id)
|
||||
|
||||
if err != nil {
|
||||
// Server panic?
|
||||
|
|
@ -618,6 +641,34 @@ func (s *Server) ClearACLCache() {
|
|||
s.aclcache = NewACLCache()
|
||||
}
|
||||
|
||||
// Helper method for users entering new channels
|
||||
func (server *Server) userEnterChannel(client *Client, channel *Channel, userstate *mumbleproto.UserState) {
|
||||
if client.Channel == channel {
|
||||
return
|
||||
}
|
||||
|
||||
oldchan := client.Channel
|
||||
if oldchan != nil {
|
||||
oldchan.RemoveClient(client)
|
||||
}
|
||||
channel.AddClient(client)
|
||||
|
||||
server.ClearACLCache()
|
||||
// fixme(mkrautz): Set LastChannel for user in datastore
|
||||
// fixme(mkrautz): Remove channel if temporary
|
||||
|
||||
canspeak := server.HasPermission(client, channel, SpeakPermission)
|
||||
if canspeak == client.Suppress {
|
||||
client.Suppress = !canspeak
|
||||
userstate.Suppress = proto.Bool(client.Suppress)
|
||||
}
|
||||
|
||||
server.sendClientPermissions(client, channel)
|
||||
if channel.parent != nil {
|
||||
server.sendClientPermissions(client, channel.parent)
|
||||
}
|
||||
}
|
||||
|
||||
// The accept loop of the server.
|
||||
func (s *Server) ListenAndMurmur() {
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ func NewTLSListener(port int) (rl *tls.Listener) {
|
|||
config.Certificates = make([]tls.Certificate, 1)
|
||||
config.Certificates[0].Certificate = [][]byte{cert.Bytes}
|
||||
config.Certificates[0].PrivateKey = priv
|
||||
config.AuthenticateClient = true
|
||||
|
||||
l, err := net.ListenTCP("tcp", &net.TCPAddr{
|
||||
net.ParseIP("0.0.0.0"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue