// set sets the given items using the given conflict resolution policy.
// The returned slice will have the same length as the input slice.
// If value is not nil, each element should correspond to an item.
func set(c appengine.Context, item []*Item, value [][]byte, policy int32) []os.Error {
	req := &pb.MemcacheSetRequest{
		Item: make([]*pb.MemcacheSetRequest_Item, len(item)),
	}
	for i, t := range item {
		p := &pb.MemcacheSetRequest_Item{
			Key: []byte(t.Key),
		}
		if value == nil {
			p.Value = t.Value
		} else {
			p.Value = value[i]
		}
		if t.Flags != 0 {
			p.Flags = proto.Uint32(t.Flags)
		}
		if t.Expiration != 0 {
			// In the .proto file, MemcacheSetRequest_Item uses a fixed32 (i.e. unsigned)
			// for expiration time, while MemcacheGetRequest_Item uses int32 (i.e. signed).
			// Throughout this .go file, we use int32.
			p.ExpirationTime = proto.Uint32(uint32(t.Expiration))
		}
		if t.casID != 0 {
			p.CasId = proto.Uint64(t.casID)
			p.ForCas = proto.Bool(true)
		}
		p.SetPolicy = pb.NewMemcacheSetRequest_SetPolicy(policy)
		req.Item[i] = p
	}
	res := &pb.MemcacheSetResponse{}
	e := make([]os.Error, len(item))
	if err := c.Call("memcache", "Set", req, res); err != nil {
		for i := range e {
			e[i] = err
		}
		return e
	}
	if len(e) != len(res.SetStatus) {
		for i := range e {
			e[i] = ErrServerError
		}
		return e
	}
	for i := range e {
		switch res.SetStatus[i] {
		case pb.MemcacheSetResponse_STORED:
			e[i] = nil
		case pb.MemcacheSetResponse_NOT_STORED:
			e[i] = ErrNotStored
		case pb.MemcacheSetResponse_EXISTS:
			e[i] = ErrCASConflict
		default:
			e[i] = ErrServerError
		}
	}
	return e
}
Beispiel #2
0
func interface2value(data interface{}) *TransactionValue {
	switch f := data.(type) {

	case string:
		return &TransactionValue{
			Type:        proto.Uint32(val_string),
			StringValue: proto.String(f),
		}
	}

	return &TransactionValue{
		Type: proto.Uint32(val_null),
	}
}
Beispiel #3
0
// Send permission denied by who, what, where
func (c *Client) sendPermissionDenied(who *Client, where *Channel, what Permission) {
	d, err := proto.Marshal(&mumbleproto.PermissionDenied{
		Permission: proto.Uint32(uint32(what)),
		ChannelId:  proto.Uint32(uint32(where.Id)),
		Session:    proto.Uint32(who.Session),
		Type:       mumbleproto.NewPermissionDenied_DenyType(mumbleproto.PermissionDenied_Permission),
	})
	if err != nil {
		c.Panic(err.String())
	}
	c.msgchan <- &Message{
		buf:  d,
		kind: MessagePermissionDenied,
	}
}
Beispiel #4
0
//
// Get
//
func (op *TransactionOperation_Get) executeTransaction(t *Transaction, b *TransactionBlock, vs *viewState) (ret *TransactionReturn) {
	// TODO: Walk!

	var value *TransactionValue

	if op.Source.Variable != nil {
		sourceVar := b.getRealVar(op.Source.Variable.Variable)
		value = sourceVar.Value

	} else if op.Source.Object != nil {
		// make sure we don't use variables anymore
		for _, ac := range op.Accessors {
			ac.MakeAbsoluteValue(b)
		}

		obj, osErr := vs.getObject(op.Source.Object.Container.Value().(string), op.Source.Object.Key.Value().(string), true)
		if osErr != nil {
			return &TransactionReturn{
				Error: &TransactionError{
					Id:      proto.Uint32(0), // TODO: ERRNO
					Message: proto.String(osErr.String()),
				},
			}
		}
		value = interface2value(obj.data)
	}

	destVar := b.getRealVar(op.Destination)
	destVar.Value = value

	return
}
Beispiel #5
0
func (b *TransactionBlock) Return(data ...interface{}) {
	op := &TransactionOperation{
		Type:   proto.Uint32(op_return),
		Return: &TransactionOperation_Return{},
	}
	op.Return.Returns = make([]*TransactionObject, len(data))

	for i, obj := range data {
		if vr, ok := obj.(*TransactionVariable); ok {
			op.Return.Returns[i] = &TransactionObject{
				Variable: vr,
			}
		} else {
			val := interface2value(obj)
			if val == nil {
				panic("Unknown return object")
			}

			op.Return.Returns[i] = &TransactionObject{
				Value: val,
			}
		}
	}

	b.addOperation(op)
}
Beispiel #6
0
//
// Set
//
func (op *TransactionOperation_Set) executeTransaction(t *Transaction, b *TransactionBlock, vs *viewState) (ret *TransactionReturn) {
	// TODO: Walk!

	// set into a variable
	if op.Destination.Variable != nil {
		v := b.getRealVar(op.Destination.Variable.Variable)
		if op.Value.Value != nil {
			v.Value = op.Value.Value
		} else {
			valvar := b.getRealVar(op.Value.Variable)
			v.Value = valvar.Value
		}

		// set into a database object
	} else if op.Destination.Object != nil {
		// make sure we don't use variables anymore
		for _, ac := range op.Accessors {
			ac.MakeAbsoluteValue(b)
		}
		op.Value.MakeAbsoluteValue(b)

		partial := false // TODO: if walk, partial = true
		osErr := vs.mutateObject(op, partial)
		if osErr != nil {
			return &TransactionReturn{
				Error: &TransactionError{
					Id:      proto.Uint32(0), // TODO: ERRNO
					Message: proto.String(osErr.String()),
				},
			}
		}
	}

	return
}
Beispiel #7
0
// Broadcast text messages
func (server *Server) handleTextMessage(client *Client, msg *Message) {
	txtmsg := &mumbleproto.TextMessage{}
	err := proto.Unmarshal(msg.buf, txtmsg)
	if err != nil {
		client.Panic(err.String())
		return
	}

	// fixme(mkrautz): Check text message length.
	// fixme(mkrautz): Sanitize text as well.

	clients := make(map[uint32]*Client)

	// Tree
	for _, chanid := range txtmsg.TreeId {
		if channel, ok := server.Channels[int(chanid)]; ok {
			if !server.HasPermission(client, channel, TextMessagePermission) {
				client.sendPermissionDenied(client, channel, TextMessagePermission)
			}
			for _, target := range channel.clients {
				clients[target.Session] = target
			}
		}
	}

	// Direct-to-channel
	for _, chanid := range txtmsg.ChannelId {
		if channel, ok := server.Channels[int(chanid)]; ok {
			if !server.HasPermission(client, channel, TextMessagePermission) {
				client.sendPermissionDenied(client, channel, TextMessagePermission)
				return
			}
			for _, target := range channel.clients {
				clients[target.Session] = target
			}
		}
	}

	// Direct-to-clients
	for _, session := range txtmsg.Session {
		if target, ok := server.clients[session]; ok {
			if !server.HasPermission(client, target.Channel, TextMessagePermission) {
				client.sendPermissionDenied(client, target.Channel, TextMessagePermission)
				return
			}
			clients[session] = target
		}
	}

	// Remove ourselves
	clients[client.Session] = nil, false

	for _, target := range clients {
		target.sendProtoMessage(MessageTextMessage, &mumbleproto.TextMessage{
			Actor:   proto.Uint32(client.Session),
			Message: txtmsg.Message,
		})
	}
}
Beispiel #8
0
func makeConnect() (msg *protocol.Message) {
	connect := &protocol.Connect{Version: proto.Uint32(ProtocolVersion)}

	return &protocol.Message{
		Connect: connect,
		Type:    protocol.NewMessage_Type(protocol.Message_CONNECT),
	}
}
Beispiel #9
0
func (b *TransactionBlock) NewVar() *TransactionVariable {
	v := new(TransactionVariable)

	// TODO: we should only add variables that have values
	v.Block = b.Id
	v.Id = proto.Uint32(uint32(len(b.Variables)))
	b.Variables = append(b.Variables, v)
	return v
}
Beispiel #10
0
func (server *Server) handlePingMessage(client *Client, msg *Message) {
	ping := &mumbleproto.Ping{}
	err := proto.Unmarshal(msg.buf, ping)
	if err != nil {
		client.Panic(err.String())
		return
	}

	// Phony response for ping messages. We don't keep stats
	// for this yet.
	client.sendProtoMessage(MessagePing, &mumbleproto.Ping{
		Timestamp: ping.Timestamp,
		Good:      proto.Uint32(uint32(client.crypt.Good)),
		Late:      proto.Uint32(uint32(client.crypt.Late)),
		Lost:      proto.Uint32(uint32(client.crypt.Lost)),
		Resync:    proto.Uint32(uint32(client.crypt.Resync)),
	})
}
Beispiel #11
0
// Send a client its permissions for channel.
func (server *Server) sendClientPermissions(client *Client, channel *Channel) {
	// No caching for SuperUser
	if client.IsSuperUser() {
		return
	}

	// Update cache
	server.HasPermission(client, channel, EnterPermission)

	perm := server.aclcache.GetPermission(client, channel)
	log.Printf("Permissions = 0x%x", perm)

	// fixme(mkrautz): Cache which permissions we've already sent.
	client.sendProtoMessage(MessagePermissionQuery, &mumbleproto.PermissionQuery{
		ChannelId:   proto.Uint32(uint32(channel.Id)),
		Permissions: proto.Uint32(uint32(perm)),
	})
}
Beispiel #12
0
func (client *Client) sendChannelTree(channel *Channel) {
	chanstate := &mumbleproto.ChannelState{
		ChannelId: proto.Uint32(uint32(channel.Id)),
		Name:      proto.String(channel.Name),
	}
	if channel.parent != nil {
		chanstate.Parent = proto.Uint32(uint32(channel.parent.Id))
	}

	if channel.HasDescription() {
		if client.Version >= 0x10202 {
			chanstate.DescriptionHash = channel.DescriptionBlobHashBytes()
		} else {
			buf, err := globalBlobstore.Get(channel.DescriptionBlob)
			if err != nil {
				panic("Blobstore error.")
			}
			chanstate.Description = proto.String(string(buf))
		}
	}

	if channel.Temporary {
		chanstate.Temporary = proto.Bool(true)
	}

	chanstate.Position = proto.Int32(int32(channel.Position))

	links := []uint32{}
	for cid, _ := range channel.Links {
		links = append(links, uint32(cid))
	}
	chanstate.Links = links

	err := client.sendProtoMessage(MessageChannelState, chanstate)
	if err != nil {
		client.Panic(err.String())
	}

	for _, subchannel := range channel.children {
		client.sendChannelTree(subchannel)
	}
}
Beispiel #13
0
func makeLogin(name string, authToken string, permissions uint32) (msg *protocol.Message) {
	login := &protocol.Login{
		Name:        proto.String(name),
		Authtoken:   proto.String(authToken),
		Permissions: proto.Uint32(permissions),
	}

	return &protocol.Message{
		Login: login,
		Type:  protocol.NewMessage_Type(protocol.Message_LOGIN),
	}
}
Beispiel #14
0
// 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 client to be removed.
	removeClient, 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 client's permissions
	perm := Permission(KickPermission)
	if ban {
		perm = Permission(BanPermission)
	}

	if removeClient.IsSuperUser() || !server.HasPermission(client, server.root, perm) {
		client.sendPermissionDenied(client, server.root, perm)
		return
	}

	if ban {
		// fixme(mkrautz): Implement banning.
		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
	}

	removeClient.ForceDisconnect()
}
Beispiel #15
0
// Send permission denied by type (and user)
func (c *Client) sendPermissionDeniedTypeUser(kind string, user *Client) {
	val, ok := mumbleproto.PermissionDenied_DenyType_value[kind]
	if ok {
		pd := &mumbleproto.PermissionDenied{}
		pd.Type = mumbleproto.NewPermissionDenied_DenyType(val)
		if user != nil {
			pd.Session = proto.Uint32(uint32(user.Session))
		}
		d, err := proto.Marshal(pd)
		if err != nil {
			c.Panic(err.String())
			return
		}
		c.msgchan <- &Message{
			buf:  d,
			kind: MessagePermissionDenied,
		}
	} else {
		log.Panic("Unknown permission denied type.")
	}
}
Beispiel #16
0
//type TransactionBlock struct {
//	Id			*uint32			"PB(varint,1,req,name=id)"
//	Parent			*TransactionBlock	"PB(bytes,2,opt,name=parent)"
//	Operations		[]*TransactionOperation	"PB(bytes,5,rep,name=operations)"
//	VariableCount		*uint32			"PB(varint,6,opt,name=variable_count)"
//	Variables		[]*TransactionVariable	"PB(bytes,7,rep,name=variables)"
//	XXX_unrecognized	[]byte
//}
func (b *TransactionBlock) init(t *Transaction, ti *transactionInfo) (err os.Error) {

	// initialize variables
	if b.VariableCount != nil && len(b.Variables) != int(*b.VariableCount) {
		newVars := make([]*TransactionVariable, int(*b.VariableCount))
		for _, vr := range b.Variables {
			newVars[*vr.Id] = vr
		}

		for i := uint32(0); i < *b.VariableCount; i++ {
			if newVars[i] == nil {
				newVars[i] = &TransactionVariable{
					Block: b.Id,
					Id:    proto.Uint32(i),
				}
			}
		}
	}

	// initialize operations
	for _, op := range b.Operations {
		switch *op.Type {

		case op_return:
			err = op.Return.init(t, ti)

		case op_set:
			err = op.Set.init(t, ti)

		case op_get:
			err = op.Get.init(t, ti)
		}

		if err != nil {
			return
		}
	}

	return
}
Beispiel #17
0
func (b *TransactionBlock) GetInto(dest *TransactionVariable, data ...interface{}) {
	if len(data) < 1 {
		panic("You must at least specify source")
	}

	source, rest := data2destination(data)

	acs := make([]*TransactionObject, len(rest))
	for i := 0; i < len(rest); i++ {
		acs[i] = interface2object(rest[i])
	}

	op := &TransactionOperation{
		Type: proto.Uint32(op_get),
		Get: &TransactionOperation_Get{
			Destination: dest,
			Source:      source,
			Accessors:   acs,
		},
	}
	b.addOperation(op)
}
Beispiel #18
0
// Remove a disconnected client from the server's
// internal representation.
func (server *Server) RemoveClient(client *Client, kicked bool) {
	server.hmutex.Lock()
	if client.udpaddr != nil {
		host := client.udpaddr.IP.String()
		oldclients := server.hclients[host]
		newclients := []*Client{}
		for _, hostclient := range oldclients {
			if hostclient != client {
				newclients = append(newclients, hostclient)
			}
		}
		server.hclients[host] = newclients
		server.hpclients[client.udpaddr.String()] = nil, false
	}
	server.hmutex.Unlock()

	server.clients[client.Session] = nil, false

	// Remove client from channel
	channel := client.Channel
	if channel != nil {
		channel.RemoveClient(client)
	}

	// 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 && client.state > StateClientAuthenticated {
		err := server.broadcastProtoMessage(MessageUserRemove, &mumbleproto.UserRemove{
			Session: proto.Uint32(client.Session),
		})
		if err != nil {
			log.Panic("Unable to broadcast UserRemove message for disconnected client.")
		}
	}
}
Beispiel #19
0
func (b *TransactionBlock) Set(data ...interface{}) {
	if len(data) < 2 {
		panic("You must at least specify destination and value")
	}

	dest, rest := data2destination(data)

	acs := make([]*TransactionObject, len(rest)-1)
	for i := 0; i < len(rest)-1; i++ {
		acs[i] = interface2object(rest[i])
	}

	val := interface2object(rest[len(rest)-1])

	op := &TransactionOperation{
		Type: proto.Uint32(op_set),
		Set: &TransactionOperation_Set{
			Destination: dest,
			Accessors:   acs,
			Value:       val,
		},
	}
	b.addOperation(op)
}
Beispiel #20
0
// Handle channel state change.
func (server *Server) handleChannelStateMessage(client *Client, msg *Message) {
	chanstate := &mumbleproto.ChannelState{}
	err := proto.Unmarshal(msg.buf, chanstate)
	if err != nil {
		client.Panic(err.String())
		return
	}

	var channel *Channel
	var parent *Channel
	var ok bool

	// Lookup channel for channel ID
	if chanstate.ChannelId != nil {
		channel, ok = server.Channels[int(*chanstate.ChannelId)]
		if !ok {
			client.Panic("Invalid channel specified in ChannelState message")
			return
		}
	}

	// Lookup parent
	if chanstate.Parent != nil {
		parent, ok = server.Channels[int(*chanstate.Parent)]
		if !ok {
			client.Panic("Invalid parent channel specified in ChannelState message")
			return
		}
	}

	// The server can't receive links through the links field in the ChannelState message,
	// because clients are supposed to send modifications to a channel's link state through
	// the links_add and links_remove fields.
	// Make sure the links field is clear so we can transmit the channel's link state in our reply.
	chanstate.Links = nil

	var name string
	var description string

	// Extract the description and perform sanity checks.
	if chanstate.Description != nil {
		description = *chanstate.Description
		// fixme(mkrautz): Check length
	}

	// Extract the the name of channel and check whether it's valid.
	// A valid channel name is a name that:
	//  a) Isn't already used by a channel at the same level as the channel itself (that is, channels
	//     that have a common parent can't have the same name.
	//  b) A name must be a valid name on the server (it must pass the channel name regexp)
	if chanstate.Name != nil {
		name = *chanstate.Name

		// We don't allow renames for the root channel.
		if channel != nil && channel.Id != 0 {
			// Pick a parent. If the name change is part of a re-parent (a channel move),
			// we must evaluate the parent variable. Since we're explicitly exlcuding the root
			// channel from renames, channels that are the target of renames are guaranteed to have
			// a parent.
			evalp := parent
			if evalp == nil {
				evalp = channel.parent
			}
			for _, iter := range evalp.children {
				if iter.Name == name {
					client.sendPermissionDeniedType("ChannelName")
					return
				}
			}
		}
	}

	// If the channel does not exist already, the ChannelState message is a create operation.
	if channel == nil {
		if parent == nil || len(name) == 0 {
			return
		}

		// Check whether the client has permission to create the channel in parent.
		perm := Permission(NonePermission)
		if *chanstate.Temporary {
			perm = Permission(TempChannelPermission)
		} else {
			perm = Permission(MakeChannelPermission)
		}
		if !server.HasPermission(client, parent, perm) {
			client.sendPermissionDenied(client, parent, perm)
			return
		}

		// Only registered users can create channels.
		if !client.IsRegistered() && !client.HasCertificate() {
			client.sendPermissionDeniedTypeUser("MissingCertificate", client)
			return
		}

		// We can't add channels to a temporary channel
		if parent.Temporary {
			client.sendPermissionDeniedType("TemporaryChannel")
			return
		}

		key := ""
		if len(description) > 0 {
			key, err = globalBlobstore.Put([]byte(description))
			if err != nil {
				log.Panicf("Blobstore error: %v", err.String())
			}
		}

		// Add the new channel
		channel = server.AddChannel(name)
		channel.DescriptionBlob = key
		channel.Temporary = *chanstate.Temporary
		channel.Position = int(*chanstate.Position)
		parent.AddChild(channel)

		// Add the creator to the channel's admin group
		if client.IsRegistered() {
			grp := NewGroup(channel, "admin")
			grp.Add[client.UserId()] = true
			channel.Groups["admin"] = grp
		}

		// If the client wouldn't have WritePermission in the just-created channel,
		// add a +write ACL for the user's hash.
		if !server.HasPermission(client, channel, WritePermission) {
			acl := NewChannelACL(channel)
			acl.ApplyHere = true
			acl.ApplySubs = true
			if client.IsRegistered() {
				acl.UserId = client.UserId()
			} else {
				acl.Group = "$" + client.CertHash
			}
			acl.Deny = Permission(NonePermission)
			acl.Allow = Permission(WritePermission | TraversePermission)

			channel.ACL = append(channel.ACL, acl)

			server.ClearACLCache()
		}

		chanstate.ChannelId = proto.Uint32(uint32(channel.Id))

		// Broadcast channel add
		server.broadcastProtoMessageWithPredicate(MessageChannelState, chanstate, func(client *Client) bool {
			return client.Version < 0x10202
		})

		// Remove description if client knows how to handle blobs.
		if chanstate.Description != nil && channel.HasDescription() {
			chanstate.Description = nil
			chanstate.DescriptionHash = channel.DescriptionBlobHashBytes()
		}
		server.broadcastProtoMessageWithPredicate(MessageChannelState, chanstate, func(client *Client) bool {
			return client.Version >= 0x10202
		})

		// If it's a temporary channel, move the creator in there.
		if channel.Temporary {
			userstate := &mumbleproto.UserState{}
			userstate.Session = proto.Uint32(client.Session)
			userstate.ChannelId = proto.Uint32(uint32(channel.Id))
			server.userEnterChannel(client, channel, userstate)
			server.broadcastProtoMessage(MessageUserState, userstate)
		}
	} else {
		// Edit existing channel.
		// First, check whether the actor has the neccessary permissions.

		// Name change.
		if chanstate.Name != nil {
			// The client can only rename the channel if it has WritePermission in the channel.
			// Also, clients cannot change the name of the root channel.
			if !server.HasPermission(client, channel, WritePermission) || channel.Id == 0 {
				client.sendPermissionDenied(client, channel, WritePermission)
				return
			}
		}

		// Description change
		if chanstate.Description != nil {
			if !server.HasPermission(client, channel, WritePermission) {
				client.sendPermissionDenied(client, channel, WritePermission)
				return
			}
		}

		// Position change
		if chanstate.Position != nil {
			if !server.HasPermission(client, channel, WritePermission) {
				client.sendPermissionDenied(client, channel, WritePermission)
				return
			}
		}

		// Parent change (channel move)
		if parent != nil {
			// No-op?
			if parent == channel.parent {
				return
			}

			// Make sure that channel we're operating on is not a parent of the new parent.
			iter := parent
			for iter != nil {
				if iter == channel {
					client.Panic("Illegal channel reparent")
					return
				}
				iter = iter.parent
			}

			// A temporary channel must not have any subchannels, so deny it.
			if parent.Temporary {
				client.sendPermissionDeniedType("TemporaryChannel")
				return
			}

			// To move a channel, the user must have WritePermission in the channel
			if !server.HasPermission(client, channel, WritePermission) {
				client.sendPermissionDenied(client, channel, WritePermission)
				return
			}

			// And the user must also have MakeChannel permission in the new parent
			if !server.HasPermission(client, parent, MakeChannelPermission) {
				client.sendPermissionDenied(client, parent, MakeChannelPermission)
				return
			}

			// If a sibling of parent already has this name, don't allow it.
			for _, iter := range parent.children {
				if iter.Name == channel.Name {
					client.sendPermissionDeniedType("ChannelName")
					return
				}
			}
		}

		// Links
		linkadd := []*Channel{}
		linkremove := []*Channel{}
		if len(chanstate.LinksAdd) > 0 || len(chanstate.LinksRemove) > 0 {
			// Client must have permission to link
			if !server.HasPermission(client, channel, LinkChannelPermission) {
				client.sendPermissionDenied(client, channel, LinkChannelPermission)
				return
			}
			// Add any valid channels to linkremove slice
			for _, cid := range chanstate.LinksRemove {
				if iter, ok := server.Channels[int(cid)]; ok {
					linkremove = append(linkremove, iter)
				}
			}
			// Add any valid channels to linkadd slice
			for _, cid := range chanstate.LinksAdd {
				if iter, ok := server.Channels[int(cid)]; ok {
					if !server.HasPermission(client, iter, LinkChannelPermission) {
						client.sendPermissionDenied(client, iter, LinkChannelPermission)
						return
					}
					linkadd = append(linkadd, iter)
				}
			}
		}

		// Permission checks done!

		// Channel move
		if parent != nil {
			channel.parent.RemoveChild(channel)
			parent.AddChild(channel)
		}

		// Rename
		if chanstate.Name != nil {
			channel.Name = *chanstate.Name
		}

		// Description change
		if chanstate.Description != nil {
			key, err := globalBlobstore.Put([]byte(*chanstate.Description))
			if err != nil {
				log.Panicf("Blobstore error: %v", err.String())
			}
			channel.DescriptionBlob = key
		}

		// Position change
		if chanstate.Position != nil {
			channel.Position = int(*chanstate.Position)
		}

		// Add links
		for _, iter := range linkadd {
			server.LinkChannels(channel, iter)
		}

		// Remove links
		for _, iter := range linkremove {
			server.UnlinkChannels(channel, iter)
		}

		// Broadcast the update
		server.broadcastProtoMessageWithPredicate(MessageChannelState, chanstate, func(client *Client) bool {
			return client.Version < 0x10202
		})

		// Remove description blob when sending to 1.2.2 >= users. Only send the blob hash.
		if channel.HasDescription() {
			chanstate.Description = nil
			chanstate.DescriptionHash = channel.DescriptionBlobHashBytes()
		}
		chanstate.DescriptionHash = channel.DescriptionBlobHashBytes()
		server.broadcastProtoMessageWithPredicate(MessageChannelState, chanstate, func(client *Client) bool {
			return client.Version >= 0x10202
		})
	}
}
Beispiel #21
0
// Handle user state changes
func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
	userstate := &mumbleproto.UserState{}
	err := proto.Unmarshal(msg.buf, userstate)
	if err != nil {
		client.Panic(err.String())
	}

	actor, ok := server.clients[client.Session]
	if !ok {
		log.Panic("Client not found in server's client map.")
		return
	}
	target := actor
	if userstate.Session != nil {
		target, ok = server.clients[*userstate.Session]
		if !ok {
			client.Panic("Invalid session in UserState message")
			return
		}
	}

	userstate.Session = proto.Uint32(target.Session)
	userstate.Actor = proto.Uint32(actor.Session)

	// Does it have a channel ID?
	if userstate.ChannelId != nil {
		// Destination channel
		dstChan, ok := server.Channels[int(*userstate.ChannelId)]
		if !ok {
			return
		}

		// If the user and the actor aren't the same, check whether the actor has MovePermission on
		// the user's curent channel.
		if actor != target && !server.HasPermission(actor, target.Channel, MovePermission) {
			client.sendPermissionDenied(actor, target.Channel, MovePermission)
			return
		}

		// Check whether the actor has MovePermission on dstChan.  Check whether user has EnterPermission
		// on dstChan.
		if !server.HasPermission(actor, dstChan, MovePermission) && !server.HasPermission(target, dstChan, EnterPermission) {
			client.sendPermissionDenied(target, dstChan, EnterPermission)
			return
		}

		// fixme(mkrautz): Check whether the channel is full.
	}

	if userstate.Mute != nil || userstate.Deaf != nil || userstate.Suppress != nil || userstate.PrioritySpeaker != nil {
		// Disallow for SuperUser
		if target.IsSuperUser() {
			client.sendPermissionDeniedType("SuperUser")
			return
		}

		// Check whether the actor has 'mutedeafen' permission on user's channel.
		if !server.HasPermission(actor, target.Channel, MuteDeafenPermission) {
			client.sendPermissionDenied(actor, target.Channel, MuteDeafenPermission)
			return
		}

		// Check if this was a suppress operation. Only the server can suppress users.
		if userstate.Suppress != nil {
			client.sendPermissionDenied(actor, target.Channel, MuteDeafenPermission)
			return
		}
	}

	// Comment set/clear
	if userstate.Comment != nil {
		comment := *userstate.Comment

		// Clearing another user's comment.
		if target != actor {
			// Check if actor has 'move' permissions on the root channel. It is needed
			// to clear another user's comment.
			if !server.HasPermission(actor, server.root, MovePermission) {
				client.sendPermissionDenied(actor, server.root, MovePermission)
				return
			}

			// Only allow empty text.
			if len(comment) > 0 {
				client.Panic("Cannot clear another user's comment")
				return
			}
		}

		// todo(mkrautz): Check if the text is allowed.
	}

	// Texture change
	if userstate.Texture != nil {
		// Check the length of the texture
	}

	// Registration
	if userstate.UserId != nil {
		// If user == actor, check for SelfRegisterPermission on root channel.
		// If user != actor, check for RegisterPermission permission on root channel.
		permCheck := Permission(NonePermission)
		uid := *userstate.UserId
		if target == actor {
			permCheck = SelfRegisterPermission
		} else {
			permCheck = RegisterPermission
		}
		if uid >= 0 || !server.HasPermission(actor, server.root, SelfRegisterPermission) {
			client.sendPermissionDenied(actor, server.root, permCheck)
			return
		}

		// We can't register a user with an empty hash.
		if len(target.CertHash) == 0 {
			client.sendPermissionDeniedTypeUser("MissingCertificate", target)
		}
	}

	// Prevent self-targetting state changes to be applied to other users
	// That is, if actor != user, then:
	//   Discard message if it has any of the following things set:
	//      - SelfDeaf
	//      - SelfMute
	//      - Texture
	//      - PluginContext
	//      - PluginIdentity
	//      - Recording
	if actor != target && (userstate.SelfDeaf != nil || userstate.SelfMute != nil ||
		userstate.Texture != nil || userstate.PluginContext != nil || userstate.PluginIdentity != nil ||
		userstate.Recording != nil) {
		client.Panic("Invalid UserState")
		return
	}

	broadcast := false

	if userstate.Texture != nil && target.user != nil {
		key, err := globalBlobstore.Put(userstate.Texture)
		if err != nil {
			log.Panicf("Blobstore error: %v", err.String())
		}

		if target.user.TextureBlob != key {
			target.user.TextureBlob = key
		} else {
			userstate.Texture = nil
		}

		broadcast = true
	}

	if userstate.SelfDeaf != nil {
		target.SelfDeaf = *userstate.SelfDeaf
		if target.SelfDeaf {
			userstate.SelfDeaf = proto.Bool(true)
			target.SelfMute = true
		}
		broadcast = true
	}

	if userstate.SelfMute != nil {
		target.SelfMute = *userstate.SelfMute
		if !target.SelfMute {
			userstate.SelfDeaf = proto.Bool(false)
			target.SelfDeaf = false
		}
	}

	if userstate.PluginContext != nil {
		target.PluginContext = userstate.PluginContext
	}

	if userstate.PluginIdentity != nil {
		target.PluginIdentity = *userstate.PluginIdentity
	}

	if userstate.Comment != nil && target.user != nil {
		key, err := globalBlobstore.Put([]byte(*userstate.Comment))
		if err != nil {
			log.Panicf("Blobstore error: %v", err.String())
		}

		if target.user.CommentBlob != key {
			target.user.CommentBlob = key
		} else {
			userstate.Comment = nil
		}

		broadcast = true
	}

	if userstate.Mute != nil || userstate.Deaf != nil || userstate.Suppress != nil || userstate.PrioritySpeaker != nil {
		if userstate.Deaf != nil {
			target.Deaf = *userstate.Deaf
			if target.Deaf {
				userstate.Mute = proto.Bool(true)
			}
		}
		if userstate.Mute != nil {
			target.Mute = *userstate.Mute
			if !target.Mute {
				userstate.Deaf = proto.Bool(false)
				target.Deaf = false
			}
		}
		if userstate.Suppress != nil {
			target.Suppress = *userstate.Suppress
		}
		if userstate.PrioritySpeaker != nil {
			target.PrioritySpeaker = *userstate.PrioritySpeaker
		}
		broadcast = true
	}

	if userstate.Recording != nil && *userstate.Recording != target.Recording {
		target.Recording = *userstate.Recording

		txtmsg := &mumbleproto.TextMessage{}
		txtmsg.TreeId = append(txtmsg.TreeId, uint32(0))
		if target.Recording {
			txtmsg.Message = proto.String(fmt.Sprintf("User '%s' started recording", target.ShownName()))
		} else {
			txtmsg.Message = proto.String(fmt.Sprintf("User '%s' stopped recording", target.ShownName()))
		}

		server.broadcastProtoMessageWithPredicate(MessageTextMessage, txtmsg, func(client *Client) bool {
			return client.Version < 0x10203
		})

		broadcast = true
	}

	if userstate.UserId != nil {
		// fixme(mkrautz): Registration is currently unhandled.
		log.Printf("handleUserState: (Self)Register not implemented yet!")
		userstate.UserId = nil
	}

	if userstate.ChannelId != nil {
		channel, ok := server.Channels[int(*userstate.ChannelId)]
		if ok {
			server.userEnterChannel(target, channel, userstate)
			broadcast = true
		}
	}

	if broadcast {
		// This variable denotes the length of a zlib-encoded "old-style" texture.
		// Mumble and Murmur used qCompress and qUncompress from Qt to compress
		// textures that were sent over the wire. We can use this to determine
		// whether a texture is a "new style" or an "old style" texture.
		texture := userstate.Texture
		texlen := uint32(0)
		if texture != nil && len(texture) > 4 {
			texlen = uint32(texture[0])<<24 | uint32(texture[1])<<16 | uint32(texture[2])<<8 | uint32(texture[3])
		}
		if texture != nil && len(texture) > 4 && texlen != 600*60*4 {
			// The sent texture is a new-style texture.  Strip it from the message
			// we send to pre-1.2.2 clients.
			userstate.Texture = nil
			err := server.broadcastProtoMessageWithPredicate(MessageUserState, userstate, func(client *Client) bool {
				return client.Version < 0x10202
			})
			if err != nil {
				log.Panic("Unable to broadcast UserState")
			}
			// Re-add it to the message, so that 1.2.2+ clients *do* get the new-style texture.
			userstate.Texture = texture
		} else {
			// Old style texture.  We can send the message as-is.
			err := server.broadcastProtoMessageWithPredicate(MessageUserState, userstate, func(client *Client) bool {
				return client.Version < 0x10202
			})
			if err != nil {
				log.Panic("Unable to broadcast UserState")
			}
		}

		// If a texture hash is set on user, we transmit that instead of
		// the texture itself. This allows the client to intelligently fetch
		// the blobs that it does not already have in its local storage.
		if userstate.Texture != nil && target.user != nil && target.user.HasTexture() {
			userstate.Texture = nil
			userstate.TextureHash = target.user.TextureBlobHashBytes()
		} else if target.user == nil {
			userstate.Texture = nil
			userstate.TextureHash = nil
		}

		// Ditto for comments.
		if userstate.Comment != nil && target.user.HasComment() {
			userstate.Comment = nil
			userstate.CommentHash = target.user.CommentBlobHashBytes()
		} else if target.user == nil {
			userstate.Comment = nil
			userstate.CommentHash = nil
		}

		err := server.broadcastProtoMessageWithPredicate(MessageUserState, userstate, func(client *Client) bool {
			return client.Version >= 0x10203
		})
		if err != nil {
			log.Panic("Unable to broadcast UserState")
		}
	}
}
Beispiel #22
0
func (server *Server) sendUserList(client *Client) {
	for _, connectedClient := range server.clients {
		if connectedClient.state != StateClientReady {
			continue
		}
		if connectedClient == client {
			continue
		}

		userstate := &mumbleproto.UserState{
			Session:   proto.Uint32(connectedClient.Session),
			Name:      proto.String(connectedClient.ShownName()),
			ChannelId: proto.Uint32(uint32(connectedClient.Channel.Id)),
		}

		if connectedClient.IsRegistered() {
			userstate.UserId = proto.Uint32(uint32(connectedClient.UserId()))

			if connectedClient.user.HasTexture() {
				// Does the client support blobs?
				if client.Version >= 0x10203 {
					userstate.TextureHash = connectedClient.user.TextureBlobHashBytes()
				} else {
					buf, err := globalBlobstore.Get(connectedClient.user.TextureBlob)
					if err != nil {
						log.Panicf("Blobstore error: %v", err.String())
					}
					userstate.Texture = buf
				}
			}

			if connectedClient.user.HasComment() {
				// Does the client support blobs?
				if client.Version >= 0x10203 {
					userstate.CommentHash = connectedClient.user.CommentBlobHashBytes()
				} else {
					buf, err := globalBlobstore.Get(connectedClient.user.CommentBlob)
					if err != nil {
						log.Panicf("Blobstore error: %v", err.String())
					}
					userstate.Comment = proto.String(string(buf))
				}
			}

			if len(connectedClient.user.CertHash) > 0 {
				userstate.Hash = proto.String(connectedClient.user.CertHash)
			}
		}

		if connectedClient.Mute {
			userstate.Mute = proto.Bool(true)
		}
		if connectedClient.Suppress {
			userstate.Suppress = proto.Bool(true)
		}
		if connectedClient.SelfMute {
			userstate.SelfMute = proto.Bool(true)
		}
		if connectedClient.SelfDeaf {
			userstate.SelfDeaf = proto.Bool(true)
		}
		if connectedClient.PrioritySpeaker {
			userstate.PrioritySpeaker = proto.Bool(true)
		}
		if connectedClient.Recording {
			userstate.Recording = proto.Bool(true)
		}
		if connectedClient.PluginContext != nil || len(connectedClient.PluginContext) > 0 {
			userstate.PluginContext = connectedClient.PluginContext
		}
		if len(connectedClient.PluginIdentity) > 0 {
			userstate.PluginIdentity = proto.String(connectedClient.PluginIdentity)
		}

		err := client.sendProtoMessage(MessageUserState, userstate)
		if err != nil {
			// Server panic?
			continue
		}
	}
}
Beispiel #23
0
// The last part of authentication runs in the server's synchronous handler.
func (server *Server) finishAuthenticate(client *Client) {
	// If the client succeeded in proving to the server that it should be granted
	// the credentials of a registered user, do some sanity checking to make sure
	// that user isn't already connected.
	//
	// If the user is already connected, try to check whether this new client is
	// connecting from the same IP address. If that's the case, disconnect the
	// previous client and let the new guy in.
	if client.user != nil {
		found := false
		for _, connectedClient := range server.clients {
			if connectedClient.UserId() == client.UserId() {
				found = true
				break
			}
		}
		// The user is already present on the server.
		if found {
			// todo(mkrautz): Do the address checking.
			client.RejectAuth("UsernameInUse", "A client is already connected using those credentials.")
			return
		}

		// No, that user isn't already connected. Move along.
	}

	// Add the client to the connected list
	client.Session = server.GenSessionId()
	server.clients[client.Session] = client

	// First, check whether we need to tell the other connected
	// clients to switch to a codec so the new guy can actually speak.
	server.updateCodecVersions()

	client.sendChannelList()

	// Add the client to the host slice for its host address.
	host := client.tcpaddr.IP.String()
	server.hmutex.Lock()
	server.hclients[host] = append(server.hclients[host], client)
	server.hmutex.Unlock()

	userstate := &mumbleproto.UserState{
		Session:   proto.Uint32(client.Session),
		Name:      proto.String(client.ShownName()),
		ChannelId: proto.Uint32(0),
	}
	if client.IsRegistered() {
		userstate.UserId = proto.Uint32(uint32(client.UserId()))

		if client.user.HasTexture() {
			// Does the client support blobs?
			if client.Version >= 0x10203 {
				userstate.TextureHash = client.user.TextureBlobHashBytes()
			} else {
				buf, err := globalBlobstore.Get(client.user.TextureBlob)
				if err != nil {
					log.Panicf("Blobstore error: %v", err.String())
				}
				userstate.Texture = buf
			}
		}

		if client.user.HasComment() {
			// Does the client support blobs?
			if client.Version >= 0x10203 {
				userstate.CommentHash = client.user.CommentBlobHashBytes()
			} else {
				buf, err := globalBlobstore.Get(client.user.CommentBlob)
				if err != nil {
					log.Panicf("Blobstore error: %v", err.String())
				}
				userstate.Comment = proto.String(string(buf))
			}
		}
	}

	server.userEnterChannel(client, server.root, userstate)
	if err := server.broadcastProtoMessage(MessageUserState, userstate); err != nil {
		// Server panic?
	}

	server.sendUserList(client)

	sync := &mumbleproto.ServerSync{}
	sync.Session = proto.Uint32(client.Session)
	sync.MaxBandwidth = proto.Uint32(server.MaxBandwidth)
	if client.IsSuperUser() {
		sync.Permissions = proto.Uint64(uint64(AllPermissions))
	} else {
		server.HasPermission(client, server.root, EnterPermission)
		perm := server.aclcache.GetPermission(client, server.root)
		if !perm.IsCached() {
			client.Panic("Corrupt ACL cache")
			return
		}
		perm.ClearCacheBit()
		sync.Permissions = proto.Uint64(uint64(perm))
	}
	if err := client.sendProtoMessage(MessageServerSync, sync); err != nil {
		client.Panic(err.String())
		return
	}

	err := client.sendProtoMessage(MessageServerConfig, &mumbleproto.ServerConfig{
		AllowHtml:          proto.Bool(true),
		MessageLength:      proto.Uint32(1000),
		ImageMessageLength: proto.Uint32(1000),
	})
	if err != nil {
		client.Panic(err.String())
		return
	}

	client.state = StateClientReady
	client.clientReady <- true
}
Beispiel #24
0
// ACL set/query
func (server *Server) handleAclMessage(client *Client, msg *Message) {
	acl := &mumbleproto.ACL{}
	err := proto.Unmarshal(msg.buf, acl)
	if err != nil {
		client.Panic(err.String())
	}

	// Look up the channel this ACL message operates on.
	channel, ok := server.Channels[int(*acl.ChannelId)]
	if !ok {
		return
	}

	// Does the user have permission to update or look at ACLs?
	if !server.HasPermission(client, channel, WritePermission) && !(channel.parent != nil && server.HasPermission(client, channel.parent, WritePermission)) {
		client.sendPermissionDenied(client, channel, WritePermission)
		return
	}

	reply := &mumbleproto.ACL{}
	reply.ChannelId = proto.Uint32(uint32(channel.Id))

	channels := []*Channel{}
	users := map[int]bool{}

	// Query the current ACL state for the channel
	if acl.Query != nil && *acl.Query != false {
		reply.InheritAcls = proto.Bool(channel.InheritACL)
		// Walk the channel tree to get all relevant channels.
		// (Stop if we reach a channel that doesn't have the InheritACL flag set)
		iter := channel
		for iter != nil {
			channels = append([]*Channel{iter}, channels...)
			if iter == channel || iter.InheritACL {
				iter = iter.parent
			} else {
				iter = nil
			}
		}

		// Construct the protobuf ChanACL objects corresponding to the ACLs defined
		// in our channel list.
		reply.Acls = []*mumbleproto.ACL_ChanACL{}
		for _, iter := range channels {
			for _, chanacl := range iter.ACL {
				if iter == channel || chanacl.ApplySubs {
					mpacl := &mumbleproto.ACL_ChanACL{}
					mpacl.Inherited = proto.Bool(iter != channel)
					mpacl.ApplyHere = proto.Bool(chanacl.ApplyHere)
					mpacl.ApplySubs = proto.Bool(chanacl.ApplySubs)
					if chanacl.UserId >= 0 {
						mpacl.UserId = proto.Uint32(uint32(chanacl.UserId))
						users[chanacl.UserId] = true
					} else {
						mpacl.Group = proto.String(chanacl.Group)
					}
					mpacl.Grant = proto.Uint32(uint32(chanacl.Allow))
					mpacl.Deny = proto.Uint32(uint32(chanacl.Deny))
					reply.Acls = append(reply.Acls, mpacl)
				}
			}
		}

		parent := channel.parent
		allnames := channel.GroupNames()

		// Construct the protobuf ChanGroups that we send back to the client.
		// Also constructs a usermap that is a set user ids from the channel's groups.
		reply.Groups = []*mumbleproto.ACL_ChanGroup{}
		for name, _ := range allnames {
			var (
				group  *Group
				pgroup *Group
			)
			group = channel.Groups[name]
			if parent != nil {
				pgroup = parent.Groups[name]
			}

			mpgroup := &mumbleproto.ACL_ChanGroup{}
			mpgroup.Name = proto.String(name)

			mpgroup.Inherit = proto.Bool(true)
			if group != nil {
				mpgroup.Inherit = proto.Bool(group.Inherit)
			}

			mpgroup.Inheritable = proto.Bool(true)
			if group != nil {
				mpgroup.Inheritable = proto.Bool(group.Inheritable)
			}

			mpgroup.Inherited = proto.Bool(pgroup != nil && pgroup.Inheritable)

			// Add the set of user ids that this group affects to the user map.
			// This is used later on in this function to send the client a QueryUsers
			// message that maps user ids to usernames.
			if group != nil {
				toadd := map[int]bool{}
				for uid, _ := range group.Add {
					users[uid] = true
					toadd[uid] = true
				}
				for uid, _ := range group.Remove {
					users[uid] = true
					toadd[uid] = false, false
				}
				for uid, _ := range toadd {
					mpgroup.Add = append(mpgroup.Add, uint32(uid))
				}
			}
			if pgroup != nil {
				for uid, _ := range pgroup.Members() {
					users[uid] = true
					mpgroup.InheritedMembers = append(mpgroup.InheritedMembers, uint32(uid))
				}
			}

			reply.Groups = append(reply.Groups, mpgroup)
		}

		if err := client.sendProtoMessage(MessageACL, reply); err != nil {
			client.Panic(err.String())
		}

		// Map the user ids in the user map to usernames of users.
		// fixme(mkrautz): This requires a persistent datastore, because it retrieves registered users.
		queryusers := &mumbleproto.QueryUsers{}
		for uid, _ := range users {
			queryusers.Ids = append(queryusers.Ids, uint32(uid))
			queryusers.Names = append(queryusers.Names, "Unknown")
		}
		if len(queryusers.Ids) > 0 {
			client.sendProtoMessage(MessageQueryUsers, reply)
		}

		// Set new groups and ACLs
	} else {

		// Get old temporary members
		oldtmp := map[string]map[int]bool{}
		for name, grp := range channel.Groups {
			oldtmp[name] = grp.Temporary
		}

		// Clear current ACLs and groups
		channel.ACL = []*ChannelACL{}
		channel.Groups = map[string]*Group{}

		// Add the received groups to the channel.
		channel.InheritACL = *acl.InheritAcls
		for _, pbgrp := range acl.Groups {
			changroup := NewGroup(channel, *pbgrp.Name)

			changroup.Inherit = *pbgrp.Inherit
			changroup.Inheritable = *pbgrp.Inheritable
			for _, uid := range pbgrp.Add {
				changroup.Add[int(uid)] = true
			}
			for _, uid := range pbgrp.Remove {
				changroup.Remove[int(uid)] = true
			}
			if temp, ok := oldtmp[*pbgrp.Name]; ok {
				changroup.Temporary = temp
			}

			channel.Groups[changroup.Name] = changroup
		}
		// Add the received ACLs to the channel.
		for _, pbacl := range acl.Acls {
			chanacl := NewChannelACL(channel)

			chanacl.ApplyHere = *pbacl.ApplyHere
			chanacl.ApplySubs = *pbacl.ApplySubs
			if pbacl.UserId != nil {
				chanacl.UserId = int(*pbacl.UserId)
			} else {
				chanacl.Group = *pbacl.Group
			}
			chanacl.Deny = Permission(*pbacl.Deny & AllPermissions)
			chanacl.Allow = Permission(*pbacl.Grant & AllPermissions)

			channel.ACL = append(channel.ACL, chanacl)
		}

		// Clear the server's ACL cache
		server.ClearACLCache()

		// Regular user?
		if !server.HasPermission(client, channel, WritePermission) && client.IsRegistered() || client.HasCertificate() {
			chanacl := NewChannelACL(channel)

			chanacl.ApplyHere = true
			chanacl.ApplySubs = false
			if client.IsRegistered() {
				chanacl.UserId = client.UserId()
			} else if client.HasCertificate() {
				chanacl.Group = "$" + client.CertHash
			}
			chanacl.Deny = Permission(NonePermission)
			chanacl.Allow = Permission(WritePermission | TraversePermission)

			channel.ACL = append(channel.ACL, chanacl)

			server.ClearACLCache()
		}

		// fixme(mkrautz): Sync channel to datastore
	}
}
Beispiel #25
0
func (t *Transaction) newBlock() (b *TransactionBlock) {
	b = new(TransactionBlock)
	b.Id = proto.Uint32(uint32(len(t.Blocks)))
	t.Blocks = append(t.Blocks, b)
	return
}
Beispiel #26
0
// Request big blobs from the server
func (server *Server) handleRequestBlob(client *Client, msg *Message) {
	blobreq := &mumbleproto.RequestBlob{}
	err := proto.Unmarshal(msg.buf, blobreq)
	if err != nil {
		client.Panic(err.String())
		return
	}

	userstate := &mumbleproto.UserState{}

	// Request for user textures
	if len(blobreq.SessionTexture) > 0 {
		for _, sid := range blobreq.SessionTexture {
			if target, ok := server.clients[sid]; ok {
				if target.user == nil {
					continue
				}
				if target.user.HasTexture() {
					buf, err := globalBlobstore.Get(target.user.TextureBlob)
					if err != nil {
						log.Panicf("Blobstore error: %v", err.String())
					}
					userstate.Reset()
					userstate.Session = proto.Uint32(uint32(target.Session))
					userstate.Texture = buf
					if err := client.sendProtoMessage(MessageUserState, userstate); err != nil {
						client.Panic(err.String())
						return
					}
				}
			}
		}
	}

	// Request for user comments
	if len(blobreq.SessionComment) > 0 {
		for _, sid := range blobreq.SessionComment {
			if target, ok := server.clients[sid]; ok {
				if target.user == nil {
					continue
				}
				if target.user.HasComment() {
					buf, err := globalBlobstore.Get(target.user.CommentBlob)
					if err != nil {
						log.Panicf("Blobstore error: %v", err.String())
					}
					userstate.Reset()
					userstate.Session = proto.Uint32(uint32(target.Session))
					userstate.Comment = proto.String(string(buf))
					if err := client.sendProtoMessage(MessageUserState, userstate); err != nil {
						client.Panic(err.String())
						return
					}
				}
			}
		}
	}

	chanstate := &mumbleproto.ChannelState{}

	// Request for channel descriptions
	if len(blobreq.ChannelDescription) > 0 {
		for _, cid := range blobreq.ChannelDescription {
			if channel, ok := server.Channels[int(cid)]; ok {
				if channel.HasDescription() {
					chanstate.Reset()
					buf, err := globalBlobstore.Get(channel.DescriptionBlob)
					if err != nil {
						log.Panicf("Blobstore error: %v", err.String())
					}
					chanstate.ChannelId = proto.Uint32(uint32(channel.Id))
					chanstate.Description = proto.String(string(buf))
					if err := client.sendProtoMessage(MessageChannelState, chanstate); err != nil {
						client.Panic(err.String())
						return
					}
				}
			}
		}
	}
}
Beispiel #27
0
// Receiver Goroutine
func (client *Client) receiver() {
	for {
		// The version handshake is done, the client has been authenticated and it has received
		// all necessary information regarding the server.  Now we're ready to roll!
		if client.state == StateClientReady {
			// Try to read the next message in the pool
			msg, err := client.readProtoMessage()
			if err != nil {
				if err == os.EOF {
					log.Printf("Client disconnected.")
					client.Disconnect()
				} else {
					log.Printf("Client error.")
				}
				return
			}
			// Special case UDPTunnel messages. They're high priority and shouldn't
			// go through our synchronous path.
			if msg.kind == MessageUDPTunnel {
				client.udp = false
				client.udprecv <- msg.buf
			} else {
				client.server.incoming <- msg
			}
		}

		// The client has responded to our version query. It will try to authenticate.
		if client.state == StateClientSentVersion {
			// Try to read the next message in the pool
			msg, err := client.readProtoMessage()
			if err != nil {
				client.Panic(err.String())
				return
			}

			client.clientReady = make(chan bool)
			go client.server.handleAuthenticate(client, msg)
			<-client.clientReady

			// It's possible that the client has disconnected in the meantime.
			// In that case, step out of the receiver, since there's nothing left
			// to receive.
			if client.disconnected {
				return
			}

			close(client.clientReady)
			client.clientReady = nil
		}

		// The client has just connected. Before it sends its authentication
		// information we must send it our version information so it knows
		// what version of the protocol it should speak.
		if client.state == StateClientConnected {
			client.sendProtoMessage(MessageVersion, &mumbleproto.Version{
				Version: proto.Uint32(0x10203),
				Release: proto.String("Grumble"),
			})
			// fixme(mkrautz): Re-add OS information... Does it break anything? It seems like
			// the client discards the version message if there is no OS information in it.
			client.state = StateServerSentVersion
			continue
		} else if client.state == StateServerSentVersion {
			msg, err := client.readProtoMessage()
			if err != nil {
				if err == os.EOF {
					log.Printf("Client disconnected.")
					client.Disconnect()
				} else {
					log.Printf("Client error.")
				}
				return
			}

			version := &mumbleproto.Version{}
			err = proto.Unmarshal(msg.buf, version)
			if err != nil {
				client.Panic("Unable to unmarshal client version packet.")
				return
			}

			if version.Version != nil {
				client.Version = *version.Version
			} else {
				client.Version = 0x10200
			}

			if version.Release != nil {
				client.ClientName = *version.Release
			}

			if version.Os != nil {
				client.OSName = *version.Os
			}

			if version.OsVersion != nil {
				client.OSVersion = *version.OsVersion
			}

			log.Printf("version = 0x%x", client.Version)
			log.Printf("os = %s %s", client.OSName, client.OSVersion)
			log.Printf("client = %s", client.ClientName)

			client.state = StateClientSentVersion
		}
	}
}
Beispiel #28
0
func (db *Db) Execute(trans *Transaction) (ret *TransactionReturn) {
	var err os.Error

	/*
		bytes, err := proto.Marshal(trans)
		if err != nil {
			panic(fmt.Sprintf("Got an error marshalling: %s", err))
		}

		newtrans := NewEmptyTransaction()
		err = proto.Unmarshal(bytes, newtrans)
		if err != nil {
			panic(fmt.Sprintf("Got an error unmarshalling: %s", err))
		}


		newtrans.Id = proto.Uint64(db.getNextTransactionId())

		token := Token(0) // TODO: Use real token!!
		vs := db.viewstateManager.createViewState(token, true, 0)

		err = newtrans.init()
		if err != nil {
			panic(fmt.Sprintf("Transaction initialisation error: %s", err))
		}

		ret = newtrans.execute(vs)
		bytes, err = proto.Marshal(ret)
		if err != nil {
			panic(fmt.Sprintf("Got an error marshalling: %s", err))
		}

		newret := new(TransactionReturn)
		err = proto.Unmarshal(bytes, newret)
		if err != nil {
			panic(fmt.Sprintf("Got an error unmarshalling: %s", err))
		}
		//*/

	//*
	trans.Id = proto.Uint64(db.getNextTransactionId())
	token := Token(0) // TODO: Use real token!!
	ti := &transactionInfo{
		token:    Token(0),
		readOnly: true,
	}
	trans.init(ti)
	vs := db.viewstateManager.createViewState(token, ti.readOnly, true, 0)
	newret := trans.execute(vs)
	//*/

	if newret.Error == nil {
		err = vs.prepareCommit()
		if err != nil {
			vs.rollback()

			newret.Error = &TransactionError{
				Id:      proto.Uint32(0), // TODO: ERRNO
				Message: proto.String(err.String()),
			}
			return newret
		}

		err = vs.commit()
		if err != nil {
			newret.Error = &TransactionError{
				Id:      proto.Uint32(0), // TODO: ERRNO
				Message: proto.String(err.String()),
			}
			return newret
		}
	}

	return newret

}