// toProto converts the query to a protocol buffer. func (q *Query) toProto(appID string) (*pb.Query, os.Error) { if q.kind == "" { return nil, os.NewError("datastore: empty query kind") } x := &pb.Query{ App: proto.String(appID), Kind: proto.String(q.kind), } if q.ancestor != nil { x.Ancestor = keyToProto(appID, q.ancestor) } if q.keysOnly { x.KeysOnly = proto.Bool(true) x.RequirePerfectPlan = proto.Bool(true) } for _, qf := range q.filter { if qf.FieldName == "" { return nil, os.NewError("datastore: empty query filter field name") } p, errStr := valueToProto(appID, qf.FieldName, reflect.ValueOf(qf.Value), false) if errStr != "" { return nil, os.NewError("datastore: bad query filter value type: " + errStr) } xf := &pb.Query_Filter{ Op: operatorToProto[qf.Op], Property: []*pb.Property{p}, } if xf.Op == nil { return nil, os.NewError("datastore: unknown query filter operator") } x.Filter = append(x.Filter, xf) } for _, qo := range q.order { if qo.FieldName == "" { return nil, os.NewError("datastore: empty query order field name") } xo := &pb.Query_Order{ Property: proto.String(qo.FieldName), Direction: sortDirectionToProto[qo.Direction], } if xo.Direction == nil { return nil, os.NewError("datastore: unknown query order direction") } x.Order = append(x.Order, xo) } if q.limit != 0 { x.Limit = proto.Int(q.limit) } if q.offset != 0 { x.Offset = proto.Int(q.offset) } return x, nil }
// toProto converts the query to a protocol buffer. func (q *Query) toProto(dst *pb.Query, appID string, zlp zeroLimitPolicy) error { if q.kind == "" { return errors.New("datastore: empty query kind") } dst.Reset() dst.App = proto.String(appID) dst.Kind = proto.String(q.kind) if q.ancestor != nil { dst.Ancestor = keyToProto(appID, q.ancestor) } if q.keysOnly { dst.KeysOnly = proto.Bool(true) dst.RequirePerfectPlan = proto.Bool(true) } for _, qf := range q.filter { if qf.FieldName == "" { return errors.New("datastore: empty query filter field name") } p, errStr := valueToProto(appID, qf.FieldName, reflect.ValueOf(qf.Value), false) if errStr != "" { return errors.New("datastore: bad query filter value type: " + errStr) } xf := &pb.Query_Filter{ Op: operatorToProto[qf.Op], Property: []*pb.Property{p}, } if xf.Op == nil { return errors.New("datastore: unknown query filter operator") } dst.Filter = append(dst.Filter, xf) } for _, qo := range q.order { if qo.FieldName == "" { return errors.New("datastore: empty query order field name") } xo := &pb.Query_Order{ Property: proto.String(qo.FieldName), Direction: sortDirectionToProto[qo.Direction], } if xo.Direction == nil { return errors.New("datastore: unknown query order direction") } dst.Order = append(dst.Order, xo) } if q.limit != 0 || zlp == zeroLimitMeansZero { dst.Limit = proto.Int32(q.limit) } if q.offset != 0 { dst.Offset = proto.Int32(q.offset) } return nil }
// valueToProto converts a named value to a newly allocated Property. // The returned error string is empty on success. func valueToProto(defaultAppID, name string, v reflect.Value, multiple bool) (p *pb.Property, errStr string) { var ( pv pb.PropertyValue unsupported bool ) switch v.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: pv.Int64Value = proto.Int64(v.Int()) case reflect.Bool: pv.BooleanValue = proto.Bool(v.Bool()) case reflect.String: pv.StringValue = proto.String(v.String()) case reflect.Float32, reflect.Float64: pv.DoubleValue = proto.Float64(v.Float()) case reflect.Ptr: if k, ok := v.Interface().(*Key); ok { if k == nil { return nil, nilKeyErrStr } pv.Referencevalue = keyToReferenceValue(defaultAppID, k) } else { unsupported = true } case reflect.Slice: if b, ok := v.Interface().([]byte); ok { pv.StringValue = proto.String(string(b)) } else { // nvToProto should already catch slice values. // If we get here, we have a slice of slice values. unsupported = true } default: unsupported = true } if unsupported { return nil, "unsupported datastore value type: " + v.Type().String() } p = &pb.Property{ Name: proto.String(name), Value: &pv, Multiple: proto.Bool(multiple), } switch v.Interface().(type) { case []byte: p.Meaning = pb.NewProperty_Meaning(pb.Property_BLOB) case appengine.BlobKey: p.Meaning = pb.NewProperty_Meaning(pb.Property_BLOBKEY) case Time: p.Meaning = pb.NewProperty_Meaning(pb.Property_GD_WHEN) } return p, "" }
// 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) } }
// Reads a single arbitrary type and returns the proper StateValue. func readField(val reflect.Value) *protocol.StateValue { msg := &protocol.StateValue{} switch f := val.(type) { case *reflect.BoolValue: msg.Type = protocol.NewStateValue_Type(protocol.StateValue_BOOL) msg.BoolVal = proto.Bool(f.Get()) case *reflect.IntValue: msg.Type = protocol.NewStateValue_Type(protocol.StateValue_INT) msg.IntVal = proto.Int(int(f.Get())) case *reflect.FloatValue: msg.Type = protocol.NewStateValue_Type(protocol.StateValue_FLOAT) msg.FloatVal = proto.Float32(float32(f.Get())) case *reflect.StringValue: msg.Type = protocol.NewStateValue_Type(protocol.StateValue_STRING) msg.StringVal = proto.String(f.Get()) case *reflect.SliceValue: msg.Type = protocol.NewStateValue_Type(protocol.StateValue_ARRAY) msg.ArrayVal = makeStateValueArray(f, f.Len()) case *reflect.StructValue: msg = readStructField(f) case *reflect.PtrValue: return readField(reflect.Indirect(f)) // Dereference and recurse default: panic("State value not supported: " + val.Type().String()) } return msg }
func (server *Server) updateCodecVersions() { codecusers := map[int32]int{} var winner int32 var count int for _, client := range server.clients { for _, codec := range client.codecs { codecusers[codec] += 1 } } for codec, users := range codecusers { if users > count { count = users winner = codec } if users == count && codec > winner { winner = codec } } var current int32 if server.PreferAlphaCodec { current = server.AlphaCodec } else { current = server.BetaCodec } if winner == current { return } if winner == CeltCompatBitstream { server.PreferAlphaCodec = true } else { server.PreferAlphaCodec = !server.PreferAlphaCodec } if server.PreferAlphaCodec { server.AlphaCodec = winner } else { server.BetaCodec = winner } err := server.broadcastProtoMessage(MessageCodecVersion, &mumbleproto.CodecVersion{ Alpha: proto.Int32(server.AlphaCodec), Beta: proto.Int32(server.BetaCodec), PreferAlpha: proto.Bool(server.PreferAlphaCodec), }) if err != nil { log.Printf("Unable to broadcast.") return } log.Printf("CELT codec switch %#x %#x (PreferAlpha %v)", uint32(server.AlphaCodec), uint32(server.BetaCodec), server.PreferAlphaCodec) return }
// 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 }
func makeLoginResult(succeeded bool, reason int32) (msg *protocol.Message) { loginResult := &protocol.LoginResult{ Succeeded: proto.Bool(succeeded), Reason: protocol.NewLoginResult_Reason(reason), } return &protocol.Message{ LoginResult: loginResult, Type: protocol.NewMessage_Type(protocol.Message_LOGINRESULT), } }
func newTestMessage() *pb.MyMessage { msg := &pb.MyMessage{ Count: proto.Int32(42), Name: proto.String("Dave"), Quote: proto.String(`"I didn't want to go."`), Pet: []string{"bunny", "kitty", "horsey"}, Inner: &pb.InnerMessage{ Host: proto.String("footrest.syd"), Port: proto.Int32(7001), Connected: proto.Bool(true), }, Others: []*pb.OtherMessage{ &pb.OtherMessage{ Key: proto.Int64(0xdeadbeef), Value: []byte{1, 65, 7, 12}, }, &pb.OtherMessage{ Weight: proto.Float32(6.022), Inner: &pb.InnerMessage{ Host: proto.String("lesha.mtv"), Port: proto.Int32(8002), }, }, }, Bikeshed: pb.NewMyMessage_Color(pb.MyMessage_BLUE), Somegroup: &pb.MyMessage_SomeGroup{ GroupField: proto.Int32(8), }, // One normally wouldn't do this. // This is an undeclared tag 13, as a varint (wire type 0) with value 4. XXX_unrecognized: []byte{13<<3 | 0, 4}, } ext := &pb.Ext{ Data: proto.String("Big gobs for big rats"), } if err := proto.SetExtension(msg, pb.E_Ext_More, ext); err != nil { panic(err) } // Add an unknown extension. We marshal a pb.Ext, and fake the ID. b, err := proto.Marshal(&pb.Ext{Data: proto.String("3G skiing")}) if err != nil { panic(err) } b = append(proto.EncodeVarint(104<<3|proto.WireBytes), b...) proto.SetRawExtension(msg, 104, b) // Extensions can be plain fields, too, so let's test that. b = append(proto.EncodeVarint(105<<3|proto.WireVarint), 19) proto.SetRawExtension(msg, 105, b) return msg }
// chasing a moving target with exec here. currently it's kind of // clumsy to pull out the return code. with luck the target will // move again in a way i like. func runPlugin(cmd, env []string, timeout int64) (result *CheckResult) { var output bytes.Buffer rc := 0 log.Printf("running check %s", cmd) /* c := exec.Command(cmd[0], cmd...)*/ c := exec.Command(cmd[0], cmd[1:]...) c.Stdout = &output starttime := time.Nanoseconds() err := c.Start() if err != nil { log.Fatal("Error running command ", cmd, ": ", err) } defer c.Process.Release() timer := time.AfterFunc(timeout, func() { c.Process.Kill() }) err = c.Wait() timer.Stop() endtime := time.Nanoseconds() /* log.Print(msg)*/ if err != nil { if msg, ok := err.(*os.Waitmsg); ok { rc = msg.ExitStatus() } else { log.Print("Error running command ", cmd, ": ", err) } } result = &CheckResult{ StartTimestamp: proto.Int64(starttime), EndTimestamp: proto.Int64(endtime), Status: NewCheckStatus(CheckStatus(rc)), CheckPassive: proto.Bool(*flagPassive), } switch rc { case 0, 1, 2, 3: // this is ok! log.Printf("%s: returned %s", cmd, CheckStatus_name[int32(rc)]) result.Status = NewCheckStatus(CheckStatus(rc)) result.CheckOutput = proto.String(string(bytes.TrimSpace(output.Bytes()))) break default: // XXX check for timeout/sig9, presently assumed log.Printf("%s: return code %d", cmd, rc) result.Status = NewCheckStatus(CheckStatus_UNKNOWN) result.CheckOutput = proto.String(fmt.Sprintf("UNKNOWN: Command timed out after %d seconds\n", *flagCmdTimeout) + string(bytes.TrimSpace(output.Bytes()))) } return result }
func runOnce(c appengine.Context, f func(appengine.Context) error, opts *TransactionOptions) error { // Begin the transaction. t := &transaction{Context: c} req := &pb.BeginTransactionRequest{ App: proto.String(c.FullyQualifiedAppID()), } if opts != nil && opts.XG { req.AllowMultipleEg = proto.Bool(true) } if err := t.Context.Call("datastore_v3", "BeginTransaction", req, &t.transaction, nil); err != nil { return err } // Call f, rolling back the transaction if f returns a non-nil error, or panics. // The panic is not recovered. defer func() { if t.finished { return } t.finished = true // Ignore the error return value, since we are already returning a non-nil // error (or we're panicking). c.Call("datastore_v3", "Rollback", &t.transaction, &pb.VoidProto{}, nil) }() if err := f(t); err != nil { return err } t.finished = true // Commit the transaction. res := &pb.CommitResponse{} err := c.Call("datastore_v3", "Commit", &t.transaction, res, nil) if ae, ok := err.(*appengine_internal.APIError); ok { if appengine.IsDevAppServer() { // The Python Dev AppServer raises an ApplicationError with error code 2 (which is // Error.CONCURRENT_TRANSACTION) and message "Concurrency exception.". if ae.Code == int32(pb.Error_BAD_REQUEST) && ae.Detail == "ApplicationError: 2 Concurrency exception." { return ErrConcurrentTransaction } } if ae.Code == int32(pb.Error_CONCURRENT_TRANSACTION) { return ErrConcurrentTransaction } } return err }
// callNext issues a datastore_v3/Next RPC to advance a cursor, such as that // returned by a query with more results. func callNext(c appengine.Context, res *pb.QueryResult, offset, limit int32, zlp zeroLimitPolicy) error { if res.Cursor == nil { return errors.New("datastore: internal error: server did not return a cursor") } // TODO: should I eventually call datastore_v3/DeleteCursor on the cursor? req := &pb.NextRequest{ Cursor: res.Cursor, Offset: proto.Int32(offset), } if limit != 0 || zlp == zeroLimitMeansZero { req.Count = proto.Int32(limit) } if res.CompiledCursor != nil { req.Compile = proto.Bool(true) } res.Reset() return c.Call("datastore_v3", "Next", req, res, nil) }
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) } }
// GetMulti is a batch version of Get. The returned map from keys to items may // have fewer elements than the input slice, due to memcache cache misses. // Each key must be at most 250 bytes in length. func GetMulti(c appengine.Context, key []string) (map[string]*Item, os.Error) { keyAsBytes := make([][]byte, len(key)) for i, k := range key { keyAsBytes[i] = []byte(k) } req := &pb.MemcacheGetRequest{ Key: keyAsBytes, ForCas: proto.Bool(true), } res := &pb.MemcacheGetResponse{} if err := c.Call("memcache", "Get", req, res); err != nil { return nil, err } m := make(map[string]*Item, len(res.Item)) for _, p := range res.Item { t := protoToItem(p) m[t.Key] = t } return m, nil }
// Close flushes outstanding buffered writes and finalizes the blob. After // calling Close the key can be retrieved by calling Key. func (w *Writer) Close() (closeErr error) { defer func() { // Save the error for Key w.closeErr = closeErr }() if w.closed { return errorf("Writer is already closed") } w.closed = true w.flush() if w.writeErr != nil { return w.writeErr } req := &files.CloseRequest{ Filename: proto.String(w.filename), Finalize: proto.Bool(true), } res := &files.CloseResponse{} return w.c.Call("file", "Close", req, res, nil) }
// Close flushes outstanding buffered writes and finalizes the blob. After // calling Close the key can be retrieved by calling Key. func (w *Writer) Close() (closeErr os.Error) { defer func() { // Save the error for Key w.closeErr = closeErr }() if w.closed { return errorf("Writer is already closed") } w.closed = true w.flush() if w.writeErr != nil { return w.writeErr } req := &files.CloseRequest{ Filename: proto.String(w.filename), Finalize: proto.Bool(true), } res := &files.CloseResponse{} if err := w.c.Call("file", "Close", req, res); err != nil { return err } handle := w.filename[len(blobstoreFileDirectory):] if !strings.HasPrefix(handle, creationHandlePrefix) { w.blobKey = appengine.BlobKey(handle) return nil } query := datastore.NewQuery("__BlobInfo__"). Filter("creation_handle =", handle). KeysOnly(). Limit(1) key, err := query.Run(w.c).Next(nil) if err != nil { if err != datastore.Done { return errorf("error looking up __BlobInfo__ entity for creation_handle %q: %v", handle, key) } return errorf("didn't find __BlobInfo__ entity for creation_handle %q", handle) } w.blobKey = appengine.BlobKey(key.StringID()) return nil }
// Create begins creating a new blob. The provided mimeType if non-empty // is stored in the blob's BlobInfo in datastore, else defaults to // application/octet-stream. The returned Writer should be written to, // then closed, and then its Key method can be called to retrieve the // newly-created blob key if there were no errors. func Create(c appengine.Context, mimeType string) (*Writer, error) { if mimeType == "" { mimeType = "application/octet-stream" } req := &files.CreateRequest{ Filesystem: proto.String("blobstore"), ContentType: files.NewFileContentType_ContentType(files.FileContentType_RAW), Parameters: []*files.CreateRequest_Parameter{ &files.CreateRequest_Parameter{ Name: proto.String("content_type"), Value: proto.String(mimeType), }}, } res := &files.CreateResponse{} if err := c.Call("file", "Create", req, res, nil); err != nil { return nil, err } w := &Writer{ c: c, filename: *res.Filename, } if !strings.HasPrefix(w.filename, blobstoreFileDirectory) { return nil, errorf("unexpected filename from files service") } oreq := &files.OpenRequest{ Filename: res.Filename, ContentType: files.NewFileContentType_ContentType(files.FileContentType_RAW), OpenMode: files.NewOpenRequest_OpenMode(files.OpenRequest_APPEND), ExclusiveLock: proto.Bool(true), } ores := &files.OpenResponse{} if err := c.Call("file", "Open", oreq, ores, nil); err != nil { return nil, err } return w, nil }
/* func SubMsg(data []byte, t int32, encap bool) []byte { header := NewSubHeader() header.Type = proto.Int32(t) header.Encap = proto.Bool(encap) hdrdata,_ := proto.Marhal(header) hdrlen := uint32(len(hdrdata)) datalen := uint32(len(data)) buf := make([]byte, 8+hdrlen+datalen) binary.Write(this.SBuffer, binary.BigEndian, [2]uint32{hdrlen,datalen}) copy(buf[8:8+len(hdrdata)],hdrdata) copy(buf[8+len(hdrdata):-1], data) return buf } func UnSubMsg(data []byte) (*SubHeader, []byte) { var hdrlen uint32 var datalen uint32 hdr,err := data[0:8] if err != nil { return nil,err } fmt.Printf("len(data) = %d\n", len(data)) err = binary.Read(data[0:4], binary.BigEndian, &hdrlen) if err != nil { return nil,nil,err } err = binary.Read(data[4:8], binary.BigEndian, &datalen) if err != nil { return nil,nil,err } fmt.Printf("hdrlen=%d, datalen=%d\n", hdrlen, datalen) if !(hdrlen < 96 && datalen < 16000 ) { return nil,nil,os.ENOMEM } hdrdata := make(Buf, hdrlen) newdata := make(Buf, datalen) tmp,err := this.Read(this.Buffer[0:hdrlen]) if err != nil { //this.Conn.Close() return nil,nil,err } copy(hdrdata,tmp) header := NewHeader() err = proto.Unmarshal(hdrdata, header) if err != nil { return nil,nil,err } tmp,err = this.Read(this.Buffer[0:datalen]) if err != nil { return nil,nil,err } copy(newdata,tmp) return header, newdata,nil } */ func (this *ProtoProxy) SendMsg(data []byte, port int32, t int32, encap bool) { h := NewHot(func(shared map[string]interface{}) { //self := shared["self"].(*GenericHot) header := NewHeader() header.Type = proto.Int32(t) header.Port = proto.Int32(port) header.Encap = proto.Bool(encap) hdrdata, err := proto.Marshal(header) if err != nil { fmt.Printf("%s\n", err) return } hdrlen := uint32(len(hdrdata)) datalen := uint32(len(data)) binary.Write(this.SBuffer, binary.BigEndian, [2]uint32{hdrlen, datalen}) copy(this.SBuffer[8:8+len(hdrdata)], hdrdata) copy(this.SBuffer[8+len(hdrdata):8+len(hdrdata)+len(data)], data) //fmt.Printf("Writing this: [%d]%s\n", len(this.SBuffer[0:hdrlen+len(data)]), this.SBuffer[0:hdrlen+len(data)]) this.Conn.Write(this.SBuffer[0 : 8+len(hdrdata)+len(data)]) }) this.QueryHot(h) }
func (this *ProtoHandler) Declinebool() { msg := NewAcceptBool() msg.Accept = proto.Bool(false) data, _ := proto.Marshal(msg) this.Proxy.SendMsg(data, 0, 0, false) }
// 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") } } }
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 } } }
// 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 } }
"log" "testing" "goprotobuf.googlecode.com/hg/proto" pb "./testdata/_obj/test_proto" ) var cloneTestMessage = &pb.MyMessage{ Count: proto.Int32(42), Name: proto.String("Dave"), Pet: []string{"bunny", "kitty", "horsey"}, Inner: &pb.InnerMessage{ Host: proto.String("niles"), Port: proto.Int32(9099), Connected: proto.Bool(true), }, Others: []*pb.OtherMessage{ &pb.OtherMessage{ Value: []byte("some bytes"), }, }, RepBytes: [][]byte{[]byte("sham"), []byte("wow")}, } func init() { ext := &pb.Ext{ Data: proto.String("extension"), } if err := proto.SetExtension(cloneTestMessage, pb.E_Ext_More, ext); err != nil { log.Fatalf("SetExtension: %v", err)
// RoundTrip issues a single HTTP request and returns its response. Per the // http.RoundTripper interface, RoundTrip only returns an error if there // was a problem with the request being malformed // (ErrInvalidFetchRequest) or the URL Fetch proxy fails (ErrFetch). // Note that HTTP response codes such as 5xx, 403, 404, etc are not // errors as far as the transport is concerned and will be returned // with err set to nil. func (t *Transport) RoundTrip(req *http.Request) (res *http.Response, err os.Error) { methNum, ok := pb.URLFetchRequest_RequestMethod_value[req.Method] if !ok { return nil, &ErrInvalidFetchRequest{"Unsupported method: " + req.Method, nil} } method := pb.URLFetchRequest_RequestMethod(methNum) freq := &pb.URLFetchRequest{ Method: &method, Url: proto.String(req.URL.String()), FollowRedirects: proto.Bool(false), // http.Client's responsibility MustValidateServerCertificate: proto.Bool(!t.AllowInvalidServerCertificate), } if t.DeadlineSeconds != 0 { freq.Deadline = proto.Float64(t.DeadlineSeconds) } for k, vals := range req.Header { for _, val := range vals { freq.Header = append(freq.Header, &pb.URLFetchRequest_Header{ Key: proto.String(k), Value: proto.String(val), }) } } if methodAcceptsRequestBody[req.Method] { freq.Payload, err = ioutil.ReadAll(req.Body) if err != nil { return nil, &ErrInvalidFetchRequest{"Failed to read body", err} } } fres := &pb.URLFetchResponse{} if err := t.Context.Call("urlfetch", "Fetch", freq, fres); err != nil { return nil, &ErrFetch{err.String()} } res = &http.Response{} res.StatusCode = int(*fres.StatusCode) res.Status = fmt.Sprintf("%d %s", res.StatusCode, statusCodeToText(res.StatusCode)) res.Header = http.Header(make(map[string][]string)) res.RequestMethod = req.Method // Faked: res.ProtoMajor = 1 res.ProtoMinor = 1 res.Proto = "HTTP/1.1" res.Close = true for _, h := range fres.Header { hkey := http.CanonicalHeaderKey(*h.Key) hval := *h.Value if hkey == "Content-Length" { // Will get filled in below for all but HEAD requests. if req.Method == "HEAD" { res.ContentLength, _ = strconv.Atoi64(hval) } continue } res.Header.Add(hkey, hval) } if req.Method != "HEAD" { res.ContentLength = int64(len(fres.Content)) } truncated := proto.GetBool(fres.ContentWasTruncated) res.Body = &bodyReader{content: fres.Content, truncated: truncated} return }
// 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 }