forked from External/grumble
Add VoiceTarget support (whispers and shouts)
This commit is contained in:
parent
b799eb2bda
commit
a42e4d07b4
7 changed files with 276 additions and 18 deletions
1
Makefile
1
Makefile
|
|
@ -54,6 +54,7 @@ GOFILES = \
|
||||||
acl.go \
|
acl.go \
|
||||||
group.go \
|
group.go \
|
||||||
user.go \
|
user.go \
|
||||||
|
voicetarget.go \
|
||||||
freeze.go \
|
freeze.go \
|
||||||
gencert.go \
|
gencert.go \
|
||||||
register.go \
|
register.go \
|
||||||
|
|
|
||||||
38
channel.go
38
channel.go
|
|
@ -84,3 +84,41 @@ func (channel *Channel) DescriptionBlobHashBytes() (buf []byte) {
|
||||||
}
|
}
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a slice of all channels in this channel's
|
||||||
|
// link chain.
|
||||||
|
func (channel *Channel) AllLinks() (seen map[int]*Channel) {
|
||||||
|
seen = make(map[int]*Channel)
|
||||||
|
walk := []*Channel{channel}
|
||||||
|
for len(walk) > 0 {
|
||||||
|
current := walk[len(walk)-1]
|
||||||
|
walk = walk[0 : len(walk)-1]
|
||||||
|
for _, linked := range current.Links {
|
||||||
|
if _, alreadySeen := seen[linked.Id]; !alreadySeen {
|
||||||
|
seen[linked.Id] = linked
|
||||||
|
walk = append(walk, linked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a slice of all of this channel's subchannels.
|
||||||
|
func (channel *Channel) AllSubChannels() (seen map[int]*Channel) {
|
||||||
|
seen = make(map[int]*Channel)
|
||||||
|
walk := []*Channel{}
|
||||||
|
if len(channel.children) > 0 {
|
||||||
|
walk = append(walk, channel)
|
||||||
|
for len(walk) > 0 {
|
||||||
|
current := walk[len(walk)-1]
|
||||||
|
walk = walk[0 : len(walk)-1]
|
||||||
|
for _, child := range current.children {
|
||||||
|
if _, alreadySeen := seen[child.Id]; !alreadySeen {
|
||||||
|
seen[child.Id] = child
|
||||||
|
walk = append(walk, child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
||||||
16
client.go
16
client.go
|
|
@ -37,10 +37,11 @@ type Client struct {
|
||||||
|
|
||||||
disconnected bool
|
disconnected bool
|
||||||
|
|
||||||
lastResync int64
|
lastResync int64
|
||||||
crypt *cryptstate.CryptState
|
crypt *cryptstate.CryptState
|
||||||
codecs []int32
|
codecs []int32
|
||||||
udp bool
|
udp bool
|
||||||
|
voiceTargets map[uint32]*VoiceTarget
|
||||||
|
|
||||||
// Ping stats
|
// Ping stats
|
||||||
UdpPingAvg float32
|
UdpPingAvg float32
|
||||||
|
|
@ -170,6 +171,13 @@ func (client *Client) ForceDisconnect() {
|
||||||
client.disconnect(true)
|
client.disconnect(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear the client's caches
|
||||||
|
func (client *Client) ClearCaches() {
|
||||||
|
for _, vt := range client.voiceTargets {
|
||||||
|
vt.ClearCache()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Reject an authentication attempt
|
// Reject an authentication attempt
|
||||||
func (client *Client) RejectAuth(rejectType mumbleproto.Reject_RejectType, reason string) {
|
func (client *Client) RejectAuth(rejectType mumbleproto.Reject_RejectType, reason string) {
|
||||||
var reasonString *string = nil
|
var reasonString *string = nil
|
||||||
|
|
|
||||||
61
message.go
61
message.go
|
|
@ -287,7 +287,7 @@ func (server *Server) handleChannelStateMessage(client *Client, msg *Message) {
|
||||||
|
|
||||||
channel.ACL = append(channel.ACL, acl)
|
channel.ACL = append(channel.ACL, acl)
|
||||||
|
|
||||||
server.ClearACLCache()
|
server.ClearCaches()
|
||||||
}
|
}
|
||||||
|
|
||||||
chanstate.ChannelId = proto.Uint32(uint32(channel.Id))
|
chanstate.ChannelId = proto.Uint32(uint32(channel.Id))
|
||||||
|
|
@ -862,7 +862,7 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if userRegistrationChanged {
|
if userRegistrationChanged {
|
||||||
server.ClearACLCache()
|
server.ClearCaches()
|
||||||
}
|
}
|
||||||
|
|
||||||
err := server.broadcastProtoMessageWithPredicate(userstate, func(client *Client) bool {
|
err := server.broadcastProtoMessageWithPredicate(userstate, func(client *Client) bool {
|
||||||
|
|
@ -1207,8 +1207,8 @@ func (server *Server) handleAclMessage(client *Client, msg *Message) {
|
||||||
channel.ACL = append(channel.ACL, chanacl)
|
channel.ACL = append(channel.ACL, chanacl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the server's ACL cache
|
// Clear the Server's caches
|
||||||
server.ClearACLCache()
|
server.ClearCaches()
|
||||||
|
|
||||||
// Regular user?
|
// Regular user?
|
||||||
if !server.HasPermission(client, channel, WritePermission) && client.IsRegistered() || client.HasCertificate() {
|
if !server.HasPermission(client, channel, WritePermission) && client.IsRegistered() || client.HasCertificate() {
|
||||||
|
|
@ -1226,7 +1226,7 @@ func (server *Server) handleAclMessage(client *Client, msg *Message) {
|
||||||
|
|
||||||
channel.ACL = append(channel.ACL, chanacl)
|
channel.ACL = append(channel.ACL, chanacl)
|
||||||
|
|
||||||
server.ClearACLCache()
|
server.ClearCaches()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update freezer
|
// Update freezer
|
||||||
|
|
@ -1374,6 +1374,57 @@ func (server *Server) handleUserStatsMessage(client *Client, msg *Message) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Voice target message
|
||||||
|
func (server *Server) handleVoiceTarget(client *Client, msg *Message) {
|
||||||
|
vt := &mumbleproto.VoiceTarget{}
|
||||||
|
err := proto.Unmarshal(msg.buf, vt)
|
||||||
|
if err != nil {
|
||||||
|
client.Panic(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if vt.Id == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
id := *vt.Id
|
||||||
|
if id < 1 || id >= 0x1f {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(vt.Targets) == 0 {
|
||||||
|
delete(client.voiceTargets, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, target := range vt.Targets {
|
||||||
|
newTarget := &VoiceTarget{}
|
||||||
|
for _, session := range target.Session {
|
||||||
|
newTarget.AddSession(session)
|
||||||
|
}
|
||||||
|
if target.ChannelId != nil {
|
||||||
|
chanid := *target.ChannelId
|
||||||
|
group := ""
|
||||||
|
links := false
|
||||||
|
subchannels := false
|
||||||
|
if target.Group != nil {
|
||||||
|
group = *target.Group
|
||||||
|
}
|
||||||
|
if target.Links != nil {
|
||||||
|
links = *target.Links
|
||||||
|
}
|
||||||
|
if target.Children != nil {
|
||||||
|
subchannels = *target.Children
|
||||||
|
}
|
||||||
|
newTarget.AddChannel(chanid, subchannels, links, group)
|
||||||
|
}
|
||||||
|
if newTarget.IsEmpty() {
|
||||||
|
delete(client.voiceTargets, id)
|
||||||
|
} else {
|
||||||
|
client.voiceTargets[id] = newTarget
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Permission query
|
// Permission query
|
||||||
func (server *Server) handlePermissionQuery(client *Client, msg *Message) {
|
func (server *Server) handlePermissionQuery(client *Client, msg *Message) {
|
||||||
query := &mumbleproto.PermissionQuery{}
|
query := &mumbleproto.PermissionQuery{}
|
||||||
|
|
|
||||||
26
server.go
26
server.go
|
|
@ -249,6 +249,7 @@ func (server *Server) NewClient(conn net.Conn) (err error) {
|
||||||
client.state = StateClientConnected
|
client.state = StateClientConnected
|
||||||
|
|
||||||
client.udprecv = make(chan []byte)
|
client.udprecv = make(chan []byte)
|
||||||
|
client.voiceTargets = make(map[uint32]*VoiceTarget)
|
||||||
|
|
||||||
client.user = nil
|
client.user = nil
|
||||||
|
|
||||||
|
|
@ -345,8 +346,7 @@ func (server *Server) handlerLoop() {
|
||||||
server.handleIncomingMessage(client, msg)
|
server.handleIncomingMessage(client, msg)
|
||||||
// Voice broadcast
|
// Voice broadcast
|
||||||
case vb := <-server.voicebroadcast:
|
case vb := <-server.voicebroadcast:
|
||||||
server.Printf("VoiceBroadcast!")
|
if vb.target == 0 { // Current channel
|
||||||
if vb.target == 0 {
|
|
||||||
channel := vb.client.Channel
|
channel := vb.client.Channel
|
||||||
for _, client := range channel.clients {
|
for _, client := range channel.clients {
|
||||||
if client != vb.client {
|
if client != vb.client {
|
||||||
|
|
@ -356,6 +356,13 @@ func (server *Server) handlerLoop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
target, ok := vb.client.voiceTargets[uint32(vb.target)]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
target.SendVoiceBroadcast(vb)
|
||||||
}
|
}
|
||||||
// Finish client authentication. Send post-authentication
|
// Finish client authentication. Send post-authentication
|
||||||
// server info.
|
// server info.
|
||||||
|
|
@ -413,7 +420,7 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
|
||||||
// by sending an Authenticate message with he contents of their new
|
// by sending an Authenticate message with he contents of their new
|
||||||
// access token list.
|
// access token list.
|
||||||
client.Tokens = auth.Tokens
|
client.Tokens = auth.Tokens
|
||||||
server.ClearACLCache()
|
server.ClearCaches()
|
||||||
|
|
||||||
if client.state >= StateClientAuthenticated {
|
if client.state >= StateClientAuthenticated {
|
||||||
return
|
return
|
||||||
|
|
@ -847,7 +854,7 @@ func (server *Server) handleIncomingMessage(client *Client, msg *Message) {
|
||||||
case mumbleproto.MessageUserList:
|
case mumbleproto.MessageUserList:
|
||||||
server.handleUserList(msg.client, msg)
|
server.handleUserList(msg.client, msg)
|
||||||
case mumbleproto.MessageVoiceTarget:
|
case mumbleproto.MessageVoiceTarget:
|
||||||
server.Printf("MessageVoiceTarget from client")
|
server.handleVoiceTarget(msg.client, msg)
|
||||||
case mumbleproto.MessagePermissionQuery:
|
case mumbleproto.MessagePermissionQuery:
|
||||||
server.handlePermissionQuery(msg.client, msg)
|
server.handlePermissionQuery(msg.client, msg)
|
||||||
case mumbleproto.MessageUserStats:
|
case mumbleproto.MessageUserStats:
|
||||||
|
|
@ -958,9 +965,12 @@ func (server *Server) handleUdpPacket(udpaddr *net.UDPAddr, buf []byte, nread in
|
||||||
match.udprecv <- plain
|
match.udprecv <- plain
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the ACL cache
|
// Clear the Server's caches
|
||||||
func (s *Server) ClearACLCache() {
|
func (server *Server) ClearCaches() {
|
||||||
s.aclcache = NewACLCache()
|
server.aclcache = NewACLCache()
|
||||||
|
for _, client := range server.clients {
|
||||||
|
client.ClearCaches()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method for users entering new channels
|
// Helper method for users entering new channels
|
||||||
|
|
@ -975,7 +985,7 @@ func (server *Server) userEnterChannel(client *Client, channel *Channel, usersta
|
||||||
}
|
}
|
||||||
channel.AddClient(client)
|
channel.AddClient(client)
|
||||||
|
|
||||||
server.ClearACLCache()
|
server.ClearCaches()
|
||||||
// fixme(mkrautz): Set LastChannel for user in datastore
|
// fixme(mkrautz): Set LastChannel for user in datastore
|
||||||
// fixme(mkrautz): Remove channel if temporary
|
// fixme(mkrautz): Remove channel if temporary
|
||||||
|
|
||||||
|
|
|
||||||
2
ssh.go
2
ssh.go
|
|
@ -390,4 +390,4 @@ func ClearConfCmd(reply SshCmdReply, args []string) error {
|
||||||
|
|
||||||
reply.WriteString(fmt.Sprintf("[%v] Cleared value for %v\r\n", serverId, key))
|
reply.WriteString(fmt.Sprintf("[%v] Cleared value for %v\r\n", serverId, key))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
150
voicetarget.go
Normal file
150
voicetarget.go
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// A VoiceTarget holds information about a single
|
||||||
|
// VoiceTarget entry of a Client.
|
||||||
|
type VoiceTarget struct {
|
||||||
|
sessions []uint32
|
||||||
|
channels []voiceTargetChannel
|
||||||
|
|
||||||
|
directCache map[uint32]*Client
|
||||||
|
fromChannelsCache map[uint32]*Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type voiceTargetChannel struct {
|
||||||
|
id uint32
|
||||||
|
subChannels bool
|
||||||
|
links bool
|
||||||
|
onlyGroup string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add's a client's session to the VoiceTarget
|
||||||
|
func (vt *VoiceTarget) AddSession(session uint32) {
|
||||||
|
vt.sessions = append(vt.sessions, session)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a channel to the VoiceTarget.
|
||||||
|
// If subchannels is true, any sent voice packets will also be sent to all subchannels.
|
||||||
|
// If links is true, any sent voice packets will also be sent to all linked channels.
|
||||||
|
// If group is a non-empty string, any sent voice packets will only be broadcast to members
|
||||||
|
// of that group who reside in the channel (or its children or linked channels).
|
||||||
|
func (vt *VoiceTarget) AddChannel(id uint32, subchannels bool, links bool, group string) {
|
||||||
|
vt.channels = append(vt.channels, voiceTargetChannel{
|
||||||
|
id: id,
|
||||||
|
subChannels: subchannels,
|
||||||
|
links: links,
|
||||||
|
onlyGroup: group,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks whether the VoiceTarget is empty (has no targets)
|
||||||
|
func (vt *VoiceTarget) IsEmpty() bool {
|
||||||
|
return len(vt.sessions) == 0 && len(vt.channels) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the VoiceTarget's cache.
|
||||||
|
func (vt *VoiceTarget) ClearCache() {
|
||||||
|
vt.directCache = nil
|
||||||
|
vt.fromChannelsCache = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the contents of the VoiceBroadcast to all targets specified in the
|
||||||
|
// VoiceTarget.
|
||||||
|
func (vt *VoiceTarget) SendVoiceBroadcast(vb *VoiceBroadcast) {
|
||||||
|
buf := vb.buf
|
||||||
|
client := vb.client
|
||||||
|
server := client.server
|
||||||
|
|
||||||
|
direct := vt.directCache
|
||||||
|
fromChannels := vt.fromChannelsCache
|
||||||
|
|
||||||
|
if direct == nil || fromChannels == nil {
|
||||||
|
direct = make(map[uint32]*Client)
|
||||||
|
fromChannels = make(map[uint32]*Client)
|
||||||
|
|
||||||
|
for _, vtc := range vt.channels {
|
||||||
|
channel := server.Channels[int(vtc.id)]
|
||||||
|
if channel == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !vtc.subChannels && !vtc.links && vtc.onlyGroup == "" {
|
||||||
|
if server.HasPermission(client, channel, WhisperPermission) {
|
||||||
|
for _, target := range channel.clients {
|
||||||
|
fromChannels[target.Session] = target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
server.Printf("%v", vtc)
|
||||||
|
newchans := make(map[int]*Channel)
|
||||||
|
if vtc.links {
|
||||||
|
newchans = channel.AllLinks()
|
||||||
|
} else {
|
||||||
|
newchans[channel.Id] = channel
|
||||||
|
}
|
||||||
|
if vtc.subChannels {
|
||||||
|
subchans := channel.AllSubChannels()
|
||||||
|
for k, v := range subchans {
|
||||||
|
newchans[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, newchan := range newchans {
|
||||||
|
if server.HasPermission(client, newchan, WhisperPermission) {
|
||||||
|
for _, target := range newchan.clients {
|
||||||
|
if vtc.onlyGroup == "" || GroupMemberCheck(newchan, newchan, vtc.onlyGroup, target) {
|
||||||
|
fromChannels[target.Session] = target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, session := range vt.sessions {
|
||||||
|
target := server.clients[session]
|
||||||
|
if target != nil {
|
||||||
|
if _, alreadyInFromChannels := fromChannels[target.Session]; !alreadyInFromChannels {
|
||||||
|
direct[target.Session] = target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we don't send to ourselves.
|
||||||
|
delete(direct, client.Session)
|
||||||
|
delete(fromChannels, client.Session)
|
||||||
|
|
||||||
|
if vt.directCache == nil {
|
||||||
|
vt.directCache = direct
|
||||||
|
}
|
||||||
|
|
||||||
|
if vt.fromChannelsCache == nil {
|
||||||
|
vt.fromChannelsCache = fromChannels
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kind := buf[0] & 0xe0
|
||||||
|
|
||||||
|
if len(fromChannels) > 0 {
|
||||||
|
for _, target := range fromChannels {
|
||||||
|
buf[0] = kind | 2
|
||||||
|
err := target.SendUDP(buf)
|
||||||
|
if err != nil {
|
||||||
|
target.Panicf("Unable to send UDP packet: %v", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(direct) > 0 {
|
||||||
|
for _, target := range direct {
|
||||||
|
buf[0] = kind | 2
|
||||||
|
target.SendUDP(buf)
|
||||||
|
err := target.SendUDP(buf)
|
||||||
|
if err != nil {
|
||||||
|
target.Panicf("Unable to send UDP packet: %v", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue