pax_global_header00006660000000000000000000000064123005120240014477gustar00rootroot0000000000000052 comment=cbb7c630ef0500925ccad8d660dbfd94fba5fdfd golang-go-dbus-1~bzr20140217/000077500000000000000000000000001230051202400155435ustar00rootroot00000000000000golang-go-dbus-1~bzr20140217/LICENSE000066400000000000000000000020401230051202400165440ustar00rootroot00000000000000Copyright (c) 2009 papamitra Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. golang-go-dbus-1~bzr20140217/README.markdown000066400000000000000000000026161230051202400202510ustar00rootroot00000000000000Documentation ============= Look at the API on [GoPkgDoc](http://gopkgdoc.appspot.com/pkg/github.com/norisatir/go-dbus). Installation ============ go get launchpad.net/go-dbus/v1 Usage ===== An example ---------- ```go // Issue OSD notifications according to the Desktop Notifications Specification 1.1 // http://people.canonical.com/~agateau/notifications-1.1/spec/index.html // See also // https://wiki.ubuntu.com/NotifyOSD#org.freedesktop.Notifications.Notify package main import "launchpad.net/go-dbus/v1" import "log" func main() { var ( err error conn *dbus.Connection ) // Connect to Session or System buses. if conn, err = dbus.Connect(dbus.SessionBus); err != nil { log.Fatal("Connection error:", err) } // Create an object proxy obj := conn.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications") // Call object methods. reply, err := obj.Call("org.freedesktop.Notifications", "Notify", "dbus-tutorial", uint32(0), "", "dbus-tutorial", "You've been notified!", []string{}, map[string]dbus.Variant{}, int32(-1)) if err != nil { log.Fatal("Notification error:", err) } // Parse the reply message var notification_id uint32 if err := reply.GetArgs(¬ification_id); err != nil { log.Fatal(err) } log.Print("Notification id:", notification_id) } ``` golang-go-dbus-1~bzr20140217/auth.go000066400000000000000000000105511230051202400170350ustar00rootroot00000000000000package dbus import ( "bufio" "bytes" "crypto/rand" "crypto/sha1" "encoding/hex" "errors" "io" "net" "os" "strconv" ) type authenticator interface { Mechanism() []byte InitialResponse() []byte ProcessData(challenge []byte) (response []byte, err error) } type authExternal struct { } func (p *authExternal) Mechanism() []byte { return []byte("EXTERNAL") } func (p *authExternal) InitialResponse() []byte { uid := []byte(strconv.Itoa(os.Geteuid())) uidHex := make([]byte, hex.EncodedLen(len(uid))) hex.Encode(uidHex, uid) return uidHex } func (p *authExternal) ProcessData([]byte) ([]byte, error) { return nil, errors.New("Unexpected Response") } type authDbusCookieSha1 struct { } func (p *authDbusCookieSha1) Mechanism() []byte { return []byte("DBUS_COOKIE_SHA1") } func (p *authDbusCookieSha1) InitialResponse() []byte { user := []byte(os.Getenv("USER")) userHex := make([]byte, hex.EncodedLen(len(user))) hex.Encode(userHex, user) return userHex } func (p *authDbusCookieSha1) ProcessData(mesg []byte) ([]byte, error) { decodedLen, err := hex.Decode(mesg, mesg) if err != nil { return nil, err } mesgTokens := bytes.SplitN(mesg[:decodedLen], []byte(" "), 3) file, err := os.Open(os.Getenv("HOME") + "/.dbus-keyrings/" + string(mesgTokens[0])) if err != nil { return nil, err } defer file.Close() fileStream := bufio.NewReader(file) var cookie []byte for { line, _, err := fileStream.ReadLine() if err == io.EOF { return nil, errors.New("SHA1 Cookie not found") } else if err != nil { return nil, err } cookieTokens := bytes.SplitN(line, []byte(" "), 3) if bytes.Compare(cookieTokens[0], mesgTokens[1]) == 0 { cookie = cookieTokens[2] break } } challenge := make([]byte, len(mesgTokens[2])) if _, err = rand.Read(challenge); err != nil { return nil, err } for temp := challenge; ; { if index := bytes.IndexAny(temp, " \t"); index == -1 { break } else if _, err := rand.Read(temp[index : index+1]); err != nil { return nil, err } else { temp = temp[index:] } } hash := sha1.New() if _, err := hash.Write(bytes.Join([][]byte{mesgTokens[2], challenge, cookie}, []byte(":"))); err != nil { return nil, err } resp := bytes.Join([][]byte{challenge, []byte(hex.EncodeToString(hash.Sum(nil)))}, []byte(" ")) respHex := make([]byte, hex.EncodedLen(len(resp))) hex.Encode(respHex, resp) return respHex, nil } func authenticate(conn net.Conn, authenticators []authenticator) error { // If no authenticators are provided, try them all if authenticators == nil { authenticators = []authenticator{ new(authExternal), new(authDbusCookieSha1)} } // The authentication process starts by writing a nul byte if _, err := conn.Write([]byte{0}); err != nil { return err } inStream := bufio.NewReader(conn) send := func(command ...[]byte) ([][]byte, error) { msg := bytes.Join(command, []byte(" ")) _, err := conn.Write(append(msg, []byte("\r\n")...)) if err != nil { return nil, err } line, isPrefix, err := inStream.ReadLine() if err != nil { return nil, err } if isPrefix { return nil, errors.New("Received line is too long") } return bytes.Split(line, []byte(" ")), err } success := false for _, auth := range authenticators { reply, err := send([]byte("AUTH"), auth.Mechanism(), auth.InitialResponse()) StatementLoop: for { if err != nil { return err } if len(reply) < 1 { return errors.New("No response command from server") } switch string(reply[0]) { case "OK": success = true break StatementLoop case "REJECTED": // XXX: should note the list of // supported mechanisms break StatementLoop case "ERROR": return errors.New("Received error from server: " + string(bytes.Join(reply, []byte(" ")))) case "DATA": var response []byte response, err = auth.ProcessData(reply[1]) if err == nil { reply, err = send([]byte("DATA"), response) } else { // Cancel so we can move on to // the next mechanism. reply, err = send([]byte("CANCEL")) } default: return errors.New("Unknown response from server: " + string(bytes.Join(reply, []byte(" ")))) } } if success { break } } if !success { return errors.New("Could not authenticate with any mechanism") } // XXX: UNIX FD negotiation would go here. if _, err := conn.Write([]byte("BEGIN\r\n")); err != nil { return err } return nil } golang-go-dbus-1~bzr20140217/auth_test.go000066400000000000000000000014461230051202400200770ustar00rootroot00000000000000package dbus import ( "bufio" . "launchpad.net/gocheck" "net" ) func (s *S) TestAuthenticate(c *C) { server, client := net.Pipe() clientWrites := []string{} complete := make(chan int) go func() { r := bufio.NewReader(server) // Read the nul byte that marks the start of the protocol zero := []byte{0} r.Read(zero) clientWrites = append(clientWrites, string(zero)) line, _, _ := r.ReadLine() clientWrites = append(clientWrites, string(line)) server.Write([]byte("OK\r\n")) line, _, _ = r.ReadLine() clientWrites = append(clientWrites, string(line)) complete <- 1 }() c.Check(authenticate(client, nil), Equals, nil) <-complete c.Check(clientWrites[0], Equals, "\x00") c.Check(clientWrites[1][:13], Equals, "AUTH EXTERNAL") c.Check(clientWrites[2], Equals, "BEGIN") } golang-go-dbus-1~bzr20140217/dbus.go000066400000000000000000000170361230051202400170360ustar00rootroot00000000000000// Package dbus provides a client interface to the D-Bus IPC system. // It can be used to talk to system services (via the "system bus") or // services within the user's session (via the "session bus"). package dbus import ( "errors" "fmt" "io" "log" "net" "os" "sync" "sync/atomic" ) type StandardBus int const ( SessionBus StandardBus = iota SystemBus ) const ( BUS_DAEMON_NAME = "org.freedesktop.DBus" BUS_DAEMON_PATH = ObjectPath("/org/freedesktop/DBus") BUS_DAEMON_IFACE = "org.freedesktop.DBus" ) type MessageFilter struct { filter func(*Message) *Message } // Connection represents a connection to a message bus. type Connection struct { // The unique name of this connection on the message bus. UniqueName string conn net.Conn busProxy BusDaemon lastSerial uint32 handlerMutex sync.Mutex // covers the next three messageFilters []*MessageFilter methodCallReplies map[uint32]chan<- *Message objectPathHandlers map[ObjectPath]chan<- *Message signalMatchRules signalWatchSet nameInfoMutex sync.Mutex nameInfo map[string]*nameInfo } // ObjectProxy represents a remote object on the bus. It can be used // to simplify constructing method calls, and acts as a basis for // D-Bus interface client stubs. type ObjectProxy struct { bus *Connection destination string path ObjectPath } func (o *ObjectProxy) ObjectPath() ObjectPath { return o.path } // Call the given method on the remote object. // // On success, the reply message will be returned, whose arguments can // be unpacked with its Args() method. // // On failure (both network failures and D-Bus level errors), an error // will be returned. func (o *ObjectProxy) Call(iface, method string, args ...interface{}) (*Message, error) { msg := NewMethodCallMessage(o.destination, o.path, iface, method) if err := msg.AppendArgs(args...); err != nil { return nil, err } reply, err := o.bus.SendWithReply(msg) if err != nil { return nil, err } if reply.Type == TypeError { return nil, reply.AsError() } return reply, nil } func (o *ObjectProxy) WatchSignal(iface, member string) (*SignalWatch, error) { return o.bus.WatchSignal(&MatchRule{ Type: TypeSignal, Sender: o.destination, Path: o.path, Interface: iface, Member: member}) } // Connect returns a connection to the message bus identified by busType. func Connect(busType StandardBus) (*Connection, error) { var address string switch busType { case SessionBus: address = os.Getenv("DBUS_SESSION_BUS_ADDRESS") case SystemBus: if address = os.Getenv("DBUS_SYSTEM_BUS_ADDRESS"); len(address) == 0 { address = "unix:path=/var/run/dbus/system_bus_socket" } default: return nil, errors.New("Unknown bus") } trans, err := newTransport(address) if err != nil { return nil, err } bus := new(Connection) if bus.conn, err = trans.Dial(); err != nil { return nil, err } if err = authenticate(bus.conn, nil); err != nil { bus.conn.Close() return nil, err } bus.busProxy = BusDaemon{bus.Object(BUS_DAEMON_NAME, BUS_DAEMON_PATH)} bus.messageFilters = []*MessageFilter{} bus.methodCallReplies = make(map[uint32]chan<- *Message) bus.objectPathHandlers = make(map[ObjectPath]chan<- *Message) bus.signalMatchRules = make(signalWatchSet) bus.nameInfo = make(map[string]*nameInfo) go bus.receiveLoop() if bus.UniqueName, err = bus.busProxy.Hello(); err != nil { bus.Close() return nil, err } return bus, nil } func (p *Connection) Authenticate() error { log.Println("dbus.Connection.Authenticate() is deprecated. This call can be removed") return nil } func (p *Connection) receiveLoop() { for { msg, err := readMessage(p.conn) if err != nil { if err != io.EOF { log.Println("Failed to read message:", err) } break } if err = p.dispatchMessage(msg); err != nil { log.Println("Error dispatching message:", err) break } } } func (p *Connection) dispatchMessage(msg *Message) error { // Run the message through the registered filters, stopping // processing if a filter returns nil. for _, filter := range p.messageFilters { msg := filter.filter(msg) if msg == nil { return nil } } switch msg.Type { case TypeMethodCall: switch { case msg.Interface == "org.freedesktop.DBus.Peer" && msg.Member == "Ping": reply := NewMethodReturnMessage(msg) if err := p.Send(reply); err != nil { return err } case msg.Interface == "org.freedesktop.DBus.Peer" && msg.Member == "GetMachineId": // Should be returning the UUID found in /var/lib/dbus/machine-id fmt.Println("XXX: handle GetMachineId") reply := NewMethodReturnMessage(msg) if err := reply.AppendArgs("machine-id"); err != nil { return err } if err := p.Send(reply); err != nil { return err } default: p.handlerMutex.Lock() handler, ok := p.objectPathHandlers[msg.Path] p.handlerMutex.Unlock() if ok { handler <- msg } else { reply := NewErrorMessage(msg, "org.freedesktop.DBus.Error.UnknownObject", "Unknown object path "+string(msg.Path)) if err := p.Send(reply); err != nil { return err } } } case TypeMethodReturn, TypeError: p.handlerMutex.Lock() rs := msg.replySerial replyChan, ok := p.methodCallReplies[rs] if ok { delete(p.methodCallReplies, rs) } p.handlerMutex.Unlock() if ok { replyChan <- msg } case TypeSignal: p.handlerMutex.Lock() watches := p.signalMatchRules.FindMatches(msg) p.handlerMutex.Unlock() for _, watch := range watches { watch.C <- msg } } return nil } func (p *Connection) Close() error { return p.conn.Close() } func (p *Connection) nextSerial() uint32 { return atomic.AddUint32(&p.lastSerial, 1) } func (p *Connection) Send(msg *Message) error { msg.setSerial(p.nextSerial()) if _, err := msg.WriteTo(p.conn); err != nil { return err } return nil } func (p *Connection) SendWithReply(msg *Message) (*Message, error) { // XXX: also check for "no reply" flag. if msg.Type != TypeMethodCall { panic("Only method calls have replies") } serial := p.nextSerial() msg.setSerial(serial) replyChan := make(chan *Message, 1) p.handlerMutex.Lock() p.methodCallReplies[serial] = replyChan p.handlerMutex.Unlock() if _, err := msg.WriteTo(p.conn); err != nil { p.handlerMutex.Lock() delete(p.methodCallReplies, serial) p.handlerMutex.Unlock() return nil, err } reply := <-replyChan return reply, nil } func (p *Connection) RegisterMessageFilter(filter func(*Message) *Message) *MessageFilter { msgFilter := &MessageFilter{filter} p.messageFilters = append(p.messageFilters, msgFilter) return msgFilter } func (p *Connection) UnregisterMessageFilter(filter *MessageFilter) { for i, other := range p.messageFilters { if other == filter { p.messageFilters = append(p.messageFilters[:i], p.messageFilters[i+1:]...) return } } panic("Message filter not registered to this bus") } func (p *Connection) RegisterObjectPath(path ObjectPath, handler chan<- *Message) { p.handlerMutex.Lock() defer p.handlerMutex.Unlock() if _, ok := p.objectPathHandlers[path]; ok { panic("A handler has already been registered for " + string(path)) } p.objectPathHandlers[path] = handler } func (p *Connection) UnregisterObjectPath(path ObjectPath) { p.handlerMutex.Lock() defer p.handlerMutex.Unlock() if _, ok := p.objectPathHandlers[path]; !ok { panic("No handler registered for " + string(path)) } delete(p.objectPathHandlers, path) } // Object returns a proxy for the object identified by the given // destination address and path func (p *Connection) Object(dest string, path ObjectPath) *ObjectProxy { return &ObjectProxy{p, dest, path} } golang-go-dbus-1~bzr20140217/dbus_test.go000066400000000000000000000041001230051202400200610ustar00rootroot00000000000000package dbus import ( "fmt" . "launchpad.net/gocheck" ) type callTest struct { dest string path ObjectPath iface, method string args []interface{} validate func(*Message) error } var callTests = []callTest{ {"org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", "Notify", []interface{}{ "go-dbus", uint32(0), "info", "testing go-dbus", "test_body", []string{}, map[string]Variant{}, int32(2000)}, func(*Message) error { return nil }}, } func (test callTest) Call(c *Connection) error { proxy := c.Object(test.dest, test.path) reply, err := proxy.Call(test.iface, test.method, test.args...) if err != nil { return fmt.Errorf("failed Method.Call: %v", err) } if err = test.validate(reply); err != nil { err = fmt.Errorf("failed validation: %v", err) } return err } func (s *S) TestDBus(c *C) { bus, err := Connect(SessionBus) c.Assert(err, IsNil) defer bus.Close() for i, test := range callTests { err = test.Call(bus) if err != nil { c.Errorf("callTest %d: %v", i, err) } } } func (s *S) TestConnectionConnectSessionBus(c *C) { bus, err := Connect(SessionBus) c.Assert(err, IsNil) c.Check(bus.Close(), IsNil) } func (s *S) TestConnectionConnectSystemBus(c *C) { bus, err := Connect(SystemBus) c.Assert(err, IsNil) c.Check(bus.Close(), IsNil) } func (s *S) TestConnectionRegisterMessageFilter(c *C) { bus, err := Connect(SessionBus) c.Assert(err, IsNil) defer bus.Close() filter := bus.RegisterMessageFilter(func(msg *Message) *Message { // Make a change that shows the filter ran. if msg.Type == TypeMethodReturn { if err := msg.AppendArgs("Added by filter"); err != nil { c.Error(err) } } return msg }) c.Check(filter, NotNil) defer bus.UnregisterMessageFilter(filter) msg := NewMethodCallMessage(BUS_DAEMON_NAME, BUS_DAEMON_PATH, BUS_DAEMON_IFACE, "GetId") reply, err := bus.SendWithReply(msg) c.Assert(err, IsNil) var busId, extra string c.Assert(reply.Args(&busId, &extra), IsNil) c.Assert(extra, Equals, "Added by filter") } golang-go-dbus-1~bzr20140217/decoder.go000066400000000000000000000302151230051202400175000ustar00rootroot00000000000000package dbus import ( "encoding/binary" "errors" "math" "reflect" ) type decoder struct { signature Signature data []byte order binary.ByteOrder dataOffset, sigOffset int } var ( bufferOverrunError = errors.New("Buffer too small") signatureOverrunError = errors.New("Signature too small") ) func newDecoder(signature Signature, data []byte, order binary.ByteOrder) *decoder { return &decoder{signature: signature, data: data, order: order} } func (self *decoder) align(alignment int) { inc := -self.dataOffset % alignment if inc < 0 { inc += alignment } self.dataOffset += inc } func (self *decoder) Decode(args ...interface{}) error { for _, arg := range args { v := reflect.ValueOf(arg) // We expect to be given pointers here, so the caller // can see the decoded values. if v.Kind() != reflect.Ptr { return errors.New("arguments to Decode should be pointers") } if err := self.decodeValue(v.Elem()); err != nil { return err } } return nil } func (self *decoder) HasMore() bool { return self.sigOffset < len(self.signature) } func (self *decoder) Remainder() []byte { return self.data[self.dataOffset:] } func (self *decoder) readByte() (byte, error) { if len(self.data) < self.dataOffset+1 { return 0, bufferOverrunError } value := self.data[self.dataOffset] self.dataOffset += 1 return value, nil } func (self *decoder) readInt16() (int16, error) { self.align(2) if len(self.data) < self.dataOffset+2 { return 0, bufferOverrunError } value := int16(self.order.Uint16(self.data[self.dataOffset:])) self.dataOffset += 2 return value, nil } func (self *decoder) readUint16() (uint16, error) { self.align(2) if len(self.data) < self.dataOffset+2 { return 0, bufferOverrunError } value := self.order.Uint16(self.data[self.dataOffset:]) self.dataOffset += 2 return value, nil } func (self *decoder) readInt32() (int32, error) { self.align(4) if len(self.data) < self.dataOffset+4 { return 0, bufferOverrunError } value := int32(self.order.Uint32(self.data[self.dataOffset:])) self.dataOffset += 4 return value, nil } func (self *decoder) readUint32() (uint32, error) { self.align(4) if len(self.data) < self.dataOffset+4 { return 0, bufferOverrunError } value := self.order.Uint32(self.data[self.dataOffset:]) self.dataOffset += 4 return value, nil } func (self *decoder) readInt64() (int64, error) { self.align(8) if len(self.data) < self.dataOffset+8 { return 0, bufferOverrunError } value := int64(self.order.Uint64(self.data[self.dataOffset:])) self.dataOffset += 8 return value, nil } func (self *decoder) readUint64() (uint64, error) { self.align(8) if len(self.data) < self.dataOffset+8 { return 0, bufferOverrunError } value := self.order.Uint64(self.data[self.dataOffset:]) self.dataOffset += 8 return value, nil } func (self *decoder) readFloat64() (float64, error) { value, err := self.readUint64() return math.Float64frombits(value), err } func (self *decoder) readString() (string, error) { length, err := self.readUint32() if err != nil { return "", err } // One extra byte for null termination if len(self.data) < self.dataOffset+int(length)+1 { return "", bufferOverrunError } value := string(self.data[self.dataOffset : self.dataOffset+int(length)]) self.dataOffset += int(length) + 1 return value, nil } func (self *decoder) readSignature() (Signature, error) { length, err := self.readByte() if err != nil { return "", err } // One extra byte for null termination if len(self.data) < self.dataOffset+int(length)+1 { return "", bufferOverrunError } value := Signature(self.data[self.dataOffset : self.dataOffset+int(length)]) self.dataOffset += int(length) + 1 return value, nil } func (self *decoder) decodeValue(v reflect.Value) error { if len(self.signature) < self.sigOffset { return signatureOverrunError } sigCode := self.signature[self.sigOffset] self.sigOffset += 1 switch sigCode { case 'y': value, err := self.readByte() if err != nil { return err } switch { case v.Kind() == reflect.Uint8: v.SetUint(uint64(value)) return nil case typeBlankInterface.AssignableTo(v.Type()): v.Set(reflect.ValueOf(value)) return nil } case 'b': value, err := self.readUint32() if err != nil { return err } switch { case v.Kind() == reflect.Bool: v.SetBool(value != 0) return nil case typeBlankInterface.AssignableTo(v.Type()): v.Set(reflect.ValueOf(value != 0)) return nil } case 'n': value, err := self.readInt16() if err != nil { return err } switch { case v.Kind() == reflect.Int16: v.SetInt(int64(value)) return nil case typeBlankInterface.AssignableTo(v.Type()): v.Set(reflect.ValueOf(value)) return nil } case 'q': value, err := self.readUint16() if err != nil { return err } switch { case v.Kind() == reflect.Uint16: v.SetUint(uint64(value)) return nil case typeBlankInterface.AssignableTo(v.Type()): v.Set(reflect.ValueOf(value)) return nil } case 'i': value, err := self.readInt32() if err != nil { return err } switch { case v.Kind() == reflect.Int32: v.SetInt(int64(value)) return nil case typeBlankInterface.AssignableTo(v.Type()): v.Set(reflect.ValueOf(value)) return nil } case 'u': value, err := self.readUint32() if err != nil { return err } switch { case v.Kind() == reflect.Uint32: v.SetUint(uint64(value)) return nil case typeBlankInterface.AssignableTo(v.Type()): v.Set(reflect.ValueOf(value)) return nil } case 'x': value, err := self.readInt64() if err != nil { return err } switch { case v.Kind() == reflect.Int64: v.SetInt(int64(value)) return nil case typeBlankInterface.AssignableTo(v.Type()): v.Set(reflect.ValueOf(value)) return nil } case 't': value, err := self.readUint64() if err != nil { return err } switch { case v.Kind() == reflect.Uint64: v.SetUint(uint64(value)) return nil case typeBlankInterface.AssignableTo(v.Type()): v.Set(reflect.ValueOf(value)) return nil } case 'd': value, err := self.readFloat64() if err != nil { return err } switch { case v.Kind() == reflect.Float64: v.SetFloat(value) return nil case typeBlankInterface.AssignableTo(v.Type()): v.Set(reflect.ValueOf(value)) return nil } case 's': value, err := self.readString() if err != nil { return err } switch { case v.Kind() == reflect.String: v.SetString(value) return nil case typeBlankInterface.AssignableTo(v.Type()): v.Set(reflect.ValueOf(value)) return nil } case 'o': value, err := self.readString() if err != nil { return err } switch { case v.Kind() == reflect.String: v.SetString(value) return nil case typeBlankInterface.AssignableTo(v.Type()): v.Set(reflect.ValueOf(ObjectPath(value))) return nil } case 'g': value, err := self.readSignature() if err != nil { return err } switch { case v.Kind() == reflect.String: v.SetString(string(value)) return nil case typeBlankInterface.AssignableTo(v.Type()): v.Set(reflect.ValueOf(value)) return nil } case 'a': length, err := self.readUint32() if err != nil { return err } elemSigOffset := self.sigOffset afterElemOffset, err := self.signature.NextType(elemSigOffset) if err != nil { return err } // Adjust data offset so we are aligned to read array // elements. Anything with an alignment of 4 or less // will already be aligned due to reading the length. switch self.signature[self.sigOffset] { case 'x', 't', 'd', '(', '{': self.align(8) } arrayEnd := self.dataOffset + int(length) if len(self.data) < arrayEnd { return bufferOverrunError } switch { case v.Kind() == reflect.Array: for i := 0; self.dataOffset < arrayEnd; i++ { // Reset signature offset to the array element. self.sigOffset = elemSigOffset if err := self.decodeValue(v.Index(i)); err != nil { return err } } self.sigOffset = afterElemOffset return nil case v.Kind() == reflect.Slice: if v.IsNil() { v.Set(reflect.MakeSlice(v.Type(), 0, 0)) } v.SetLen(0) for self.dataOffset < arrayEnd { // Reset signature offset to the array element. self.sigOffset = elemSigOffset elem := reflect.New(v.Type().Elem()).Elem() if err := self.decodeValue(elem); err != nil { return err } v.Set(reflect.Append(v, elem)) } self.sigOffset = afterElemOffset return nil case v.Kind() == reflect.Map: if self.signature[elemSigOffset] != '{' { return errors.New("Expected type code '{' but got " + string(self.signature[elemSigOffset]) + " when decoding to map") } v.Set(reflect.MakeMap(v.Type())) for self.dataOffset < arrayEnd { self.align(8) // Reset signature offset to first // item in dictionary entry: self.sigOffset = elemSigOffset + 1 key := reflect.New(v.Type().Key()).Elem() value := reflect.New(v.Type().Elem()).Elem() if err := self.decodeValue(key); err != nil { return err } if err := self.decodeValue(value); err != nil { return err } v.SetMapIndex(key, value) } self.sigOffset = afterElemOffset return nil case typeBlankInterface.AssignableTo(v.Type()): if self.signature[elemSigOffset] == '{' { mapv := make(map[interface{}]interface{}) for self.dataOffset < arrayEnd { self.align(8) var key, value interface{} self.sigOffset = elemSigOffset + 1 if err := self.decodeValue(reflect.ValueOf(&key).Elem()); err != nil { return err } self.sigOffset = elemSigOffset + 2 if err := self.decodeValue(reflect.ValueOf(&value).Elem()); err != nil { return err } mapv[key] = value } v.Set(reflect.ValueOf(mapv)) return nil } else { array := make([]interface{}, 0) for self.dataOffset < arrayEnd { // Reset signature offset to the array element. self.sigOffset = elemSigOffset var elem interface{} if err := self.decodeValue(reflect.ValueOf(&elem).Elem()); err != nil { return err } array = append(array, elem) } v.Set(reflect.ValueOf(array)) return nil } } case '(': self.align(8) // Do we have a pointer to a struct? if v.Kind() == reflect.Ptr && v.Type().Elem().Kind() == reflect.Struct { if v.IsNil() { v.Set(reflect.New(v.Type().Elem())) } v = v.Elem() } switch { case v.Kind() == reflect.Struct: for i := 0; i < v.NumField() && self.sigOffset < len(self.signature) && self.signature[self.sigOffset] != ')'; i++ { if err := self.decodeValue(v.Field(i)); err != nil { return err } } if self.sigOffset >= len(self.signature) || self.signature[self.sigOffset] != ')' { return signatureOverrunError } // move past the closing parentheses self.sigOffset += 1 return nil case typeBlankInterface.AssignableTo(v.Type()): // Decode as a slice of interface{} values. s := make([]interface{}, 0) for self.sigOffset < len(self.signature) && self.signature[self.sigOffset] != ')' { var field interface{} if err := self.decodeValue(reflect.ValueOf(&field).Elem()); err != nil { return err } s = append(s, field) } v.Set(reflect.ValueOf(s)) return nil } case 'v': var variant *Variant switch { case v.Kind() == reflect.Ptr && v.Type().Elem() == typeVariant: if v.IsNil() { variant = &Variant{} v.Set(reflect.ValueOf(variant)) } else { variant = v.Interface().(*Variant) } case v.Type() == typeVariant: variant = v.Addr().Interface().(*Variant) case typeBlankInterface.AssignableTo(v.Type()): variant = &Variant{} v.Set(reflect.ValueOf(variant)) } if variant != nil { signature, err := self.readSignature() if err != nil { return err } // Decode the variant value through a sub-decoder. variantDec := decoder{ signature: signature, data: self.data, order: self.order, dataOffset: self.dataOffset, sigOffset: 0} if err := variantDec.decodeValue(reflect.ValueOf(&variant.Value).Elem()); err != nil { return err } // Decoding continues after the variant value. self.dataOffset = variantDec.dataOffset return nil } } return errors.New("Could not decode " + string(sigCode) + " to " + v.Type().String()) } golang-go-dbus-1~bzr20140217/decoder_test.go000066400000000000000000000314221230051202400205400ustar00rootroot00000000000000package dbus import "encoding/binary" import . "launchpad.net/gocheck" func (s *S) TestDecoderDecodeByte(c *C) { dec := newDecoder("yy", []byte{42, 100}, binary.LittleEndian) var value1 byte var value2 interface{} if err := dec.Decode(&value1, &value2); err != nil { c.Error(err) } c.Check(value1, Equals, byte(42)) c.Check(value2, Equals, byte(100)) c.Check(dec.dataOffset, Equals, 2) c.Check(dec.sigOffset, Equals, 2) } func (s *S) TestDecoderDecodeBool(c *C) { dec := newDecoder("bb", []byte{0, 0, 0, 0, 1, 0, 0, 0}, binary.LittleEndian) var value1 bool var value2 interface{} if err := dec.Decode(&value1, &value2); err != nil { c.Error(err) } c.Check(value1, Equals, false) c.Check(value2, Equals, true) c.Check(dec.dataOffset, Equals, 8) c.Check(dec.sigOffset, Equals, 2) } func (s *S) TestDecoderDecodeInt16(c *C) { dec := newDecoder("nn", []byte{42, 0, 100, 0}, binary.LittleEndian) var value1 int16 var value2 interface{} if err := dec.Decode(&value1, &value2); err != nil { c.Error(err) } c.Check(value1, Equals, int16(42)) c.Check(value2, Equals, int16(100)) c.Check(dec.dataOffset, Equals, 4) c.Check(dec.sigOffset, Equals, 2) } func (s *S) TestDecoderDecodeUint16(c *C) { dec := newDecoder("qq", []byte{42, 0, 100, 0}, binary.LittleEndian) var value1 uint16 var value2 interface{} if err := dec.Decode(&value1, &value2); err != nil { c.Error(err) } c.Check(value1, Equals, uint16(42)) c.Check(value2, Equals, uint16(100)) c.Check(dec.dataOffset, Equals, 4) c.Check(dec.sigOffset, Equals, 2) } func (s *S) TestDecoderDecodeInt32(c *C) { dec := newDecoder("ii", []byte{42, 0, 0, 0, 100, 0, 0, 0}, binary.LittleEndian) var value1 int32 var value2 interface{} if err := dec.Decode(&value1, &value2); err != nil { c.Error(err) } c.Check(value1, Equals, int32(42)) c.Check(value2, Equals, int32(100)) c.Check(dec.dataOffset, Equals, 8) c.Check(dec.sigOffset, Equals, 2) } func (s *S) TestDecoderDecodeUint32(c *C) { dec := newDecoder("uu", []byte{42, 0, 0, 0, 100, 0, 0, 0}, binary.LittleEndian) var value1 uint32 var value2 interface{} if err := dec.Decode(&value1, &value2); err != nil { c.Error(err) } c.Check(value1, Equals, uint32(42)) c.Check(value2, Equals, uint32(100)) c.Check(dec.dataOffset, Equals, 8) c.Check(dec.sigOffset, Equals, 2) } func (s *S) TestDecoderDecodeInt64(c *C) { dec := newDecoder("xx", []byte{42, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0}, binary.LittleEndian) var value1 int64 var value2 interface{} if err := dec.Decode(&value1, &value2); err != nil { c.Error(err) } c.Check(value1, Equals, int64(42)) c.Check(value2, Equals, int64(100)) c.Check(dec.dataOffset, Equals, 16) c.Check(dec.sigOffset, Equals, 2) } func (s *S) TestDecoderDecodeUint64(c *C) { dec := newDecoder("tt", []byte{42, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0}, binary.LittleEndian) var value1 uint64 var value2 interface{} if err := dec.Decode(&value1, &value2); err != nil { c.Error(err) } c.Check(value1, Equals, uint64(42)) c.Check(value2, Equals, uint64(100)) c.Check(dec.dataOffset, Equals, 16) c.Check(dec.sigOffset, Equals, 2) } func (s *S) TestDecoderDecodeFloat64(c *C) { dec := newDecoder("dd", []byte{0, 0, 0, 0, 0, 0, 69, 64, 0, 0, 0, 0, 0, 0, 89, 64}, binary.LittleEndian) var value1 float64 var value2 interface{} if err := dec.Decode(&value1, &value2); err != nil { c.Error(err) } c.Check(value1, Equals, float64(42)) c.Check(value2, Equals, float64(100)) c.Check(dec.dataOffset, Equals, 16) c.Check(dec.sigOffset, Equals, 2) } func (s *S) TestDecoderDecodeString(c *C) { dec := newDecoder("ss", []byte{ 5, 0, 0, 0, // len("hello") 'h', 'e', 'l', 'l', 'o', 0, // "hello" 0, 0, // padding 5, 0, 0, 0, // len("world") 'w', 'o', 'r', 'l', 'd', 0}, // "world" binary.LittleEndian) var value1 string var value2 interface{} if err := dec.Decode(&value1, &value2); err != nil { c.Error(err) } c.Check(value1, Equals, "hello") c.Check(value2, Equals, "world") c.Check(dec.dataOffset, Equals, 22) c.Check(dec.sigOffset, Equals, 2) } func (s *S) TestDecoderDecodeObjectPath(c *C) { dec := newDecoder("oo", []byte{ 4, 0, 0, 0, // len("/foo") '/', 'f', 'o', 'o', 0, // ObjectPath("/foo") 0, 0, 0, // padding 4, 0, 0, 0, // len("/bar") '/', 'b', 'a', 'r', 0}, // ObjectPath("/bar") binary.LittleEndian) var value1 ObjectPath var value2 interface{} if err := dec.Decode(&value1, &value2); err != nil { c.Error(err) } c.Check(value1, Equals, ObjectPath("/foo")) c.Check(value2, Equals, ObjectPath("/bar")) c.Check(dec.dataOffset, Equals, 21) c.Check(dec.sigOffset, Equals, 2) } func (s *S) TestDecoderDecodeSignature(c *C) { dec := newDecoder("gg", []byte{ 8, // len("a{s(iv)}") 'a', '{', 's', '(', 'i', 'v', ')', '}', 0, // Signature("a{s(iv)}") 4, // len("asvi") 'a', 's', 'v', 'i', 0}, // Signature("asvi") binary.LittleEndian) var value1 Signature var value2 interface{} if err := dec.Decode(&value1, &value2); err != nil { c.Error(err) } c.Check(value1, Equals, Signature("a{s(iv)}")) c.Check(value2, Equals, Signature("asvi")) c.Check(dec.dataOffset, Equals, 16) c.Check(dec.sigOffset, Equals, 2) } func (s *S) TestDecoderDecodeArray(c *C) { dec := newDecoder("ai", []byte{ 8, 0, 0, 0, // array length 42, 0, 0, 0, // int32(42) 100, 0, 0, 0}, // int32(100) binary.LittleEndian) // Decode as an array var value1 [2]int32 if err := dec.Decode(&value1); err != nil { c.Error("Decode as array:", err) } c.Check(dec.dataOffset, Equals, 12) c.Check(dec.sigOffset, Equals, 2) c.Check(value1[0], Equals, int32(42)) c.Check(value1[1], Equals, int32(100)) // Decode as a slice dec.dataOffset = 0 dec.sigOffset = 0 var value2 []int32 if err := dec.Decode(&value2); err != nil { c.Error("Decode as slice:", err) } c.Check(value2, DeepEquals, []int32{42, 100}) // Decode as blank interface dec.dataOffset = 0 dec.sigOffset = 0 var value3 interface{} if err := dec.Decode(&value3); err != nil { c.Error("Decode as interface:", err) } c.Check(value3, DeepEquals, []interface{}{int32(42), int32(100)}) } func (s *S) TestDecoderDecodeEmptyArray(c *C) { dec := newDecoder("ai", []byte{ 0, 0, 0, 0}, // array length binary.LittleEndian) var value []int32 c.Check(dec.Decode(&value), Equals, nil) c.Check(dec.dataOffset, Equals, 4) c.Check(dec.sigOffset, Equals, 2) c.Check(value, DeepEquals, []int32{}) } func (s *S) TestDecoderDecodeArrayPaddingAfterLength(c *C) { dec := newDecoder("ax", []byte{ 8, 0, 0, 0, // array length 0, 0, 0, 0, // padding 42, 0, 0, 0, 0, 0, 0, 0}, // uint64(42) binary.LittleEndian) var value []int64 c.Check(dec.Decode(&value), Equals, nil) c.Check(dec.dataOffset, Equals, 16) c.Check(dec.sigOffset, Equals, 2) c.Check(value, DeepEquals, []int64{42}) // This padding exists even for empty arays dec = newDecoder("ax", []byte{ 0, 0, 0, 0, // array length 0, 0, 0, 0}, // padding binary.LittleEndian) c.Check(dec.Decode(&value), Equals, nil) c.Check(dec.dataOffset, Equals, 8) c.Check(dec.sigOffset, Equals, 2) c.Check(value, DeepEquals, []int64{}) } func (s *S) TestDecoderDecodeMap(c *C) { dec := newDecoder("a{si}", []byte{ 36, 0, 0, 0, // array length 0, 0, 0, 0, // padding 3, 0, 0, 0, // len("one") 'o', 'n', 'e', 0, // "one" 1, 0, 0, 0, // int32(1) 0, 0, 0, 0, // padding 9, 0, 0, 0, // len("forty two") 'f', 'o', 'r', 't', 'y', ' ', 't', 'w', 'o', 0, 0, 0, // padding 42, 0, 0, 0}, // int32(42) binary.LittleEndian) var value map[string]int32 c.Check(dec.Decode(&value), Equals, nil) c.Check(len(value), Equals, 2) c.Check(value["one"], Equals, int32(1)) c.Check(value["forty two"], Equals, int32(42)) } func (s *S) TestDecoderDecodeStruct(c *C) { dec := newDecoder("(si)", []byte{ 5, 0, 0, 0, // len("hello") 'h', 'e', 'l', 'l', 'o', 0, // "hello" 0, 0, // padding 42, 0, 0, 0}, // int32(42) binary.LittleEndian) type Dummy struct { S string I int32 } // Decode as structure var value1 Dummy if err := dec.Decode(&value1); err != nil { c.Error("Decode as structure:", err) } c.Check(dec.dataOffset, Equals, 16) c.Check(dec.sigOffset, Equals, 4) c.Check(value1, DeepEquals, Dummy{"hello", 42}) // Decode as pointer to structure dec.dataOffset = 0 dec.sigOffset = 0 var value2 *Dummy if err := dec.Decode(&value2); err != nil { c.Error("Decode as structure pointer:", err) } c.Check(value2, DeepEquals, &Dummy{"hello", 42}) // Decode as blank interface dec.dataOffset = 0 dec.sigOffset = 0 var value3 interface{} if err := dec.Decode(&value3); err != nil { c.Error("Decode as interface:", err) } c.Check(value3, DeepEquals, []interface{}{"hello", int32(42)}) } func (s *S) TestDecoderDecodeVariant(c *C) { dec := newDecoder("v", []byte{ 1, // len("i") 'i', 0, // Signature("i") 0, // padding 42, 0, 0, 0}, // int32(42) binary.LittleEndian) var value1 Variant if err := dec.Decode(&value1); err != nil { c.Error("Decode as Variant:", err) } c.Check(dec.dataOffset, Equals, 8) c.Check(dec.sigOffset, Equals, 1) c.Check(value1, DeepEquals, Variant{int32(42)}) // Decode as pointer to Variant dec.dataOffset = 0 dec.sigOffset = 0 var value2 *Variant if err := dec.Decode(&value2); err != nil { c.Error("Decode as *Variant:", err) } c.Check(value2, DeepEquals, &Variant{int32(42)}) // Decode as pointer to blank interface dec.dataOffset = 0 dec.sigOffset = 0 var value3 interface{} if err := dec.Decode(&value3); err != nil { c.Error("Decode as interface:", err) } c.Check(value3, DeepEquals, &Variant{int32(42)}) } func (s *S) TestDecoderDecodeVariantMap(c *C) { dec := newDecoder("v", []byte{ 5, // len("a{ii}") 'a', '{', 'i', 'i', '}', // Signature("a{ii}") 0, 0, // padding 16, 0, 0, 0, 0, 0, 0, 0, // array length 42, 0, 0, 0, // int32(42) 17, 0, 0, 0, // int32(17) 44, 0, 0, 0, // int32(44) 33, 0, 0, 0}, // int32(33) binary.LittleEndian) var value1 Variant if err := dec.Decode(&value1); err != nil { c.Fatal("Decode as Variant:", err) } moo, ok := value1.Value.(map[interface{}]interface{}) c.Assert(ok, Equals, true) m := make(map[int32]int32) for k, v := range moo { ik, ok := k.(int32) c.Assert(ok, Equals, true) iv, ok := v.(int32) c.Assert(ok, Equals, true) m[ik] = iv } c.Check(m, DeepEquals, map[int32]int32{42: 17, 44: 33}) } func (s *S) TestDecoderDecodeVariantMapStringInt(c *C) { dec := newDecoder("v", []byte{ 5, // len("a{si}") 'a', '{', 's', 'i', '}', // Signature("a{si}") 0, 0, // padding 36, 0, 0, 0, // array length 0, 0, 0, 0, // padding 3, 0, 0, 0, // len("one") 'o', 'n', 'e', 0, // "one" 1, 0, 0, 0, // int32(1) 0, 0, 0, 0, // padding 9, 0, 0, 0, // len("forty two") 'f', 'o', 'r', 't', 'y', ' ', 't', 'w', 'o', 0, 0, 0, // padding 42, 0, 0, 0}, // int32(42) binary.LittleEndian) var value1 Variant if err := dec.Decode(&value1); err != nil { c.Fatal("Decode as Variant:", err) } moo, ok := value1.Value.(map[interface{}]interface{}) c.Assert(ok, Equals, true) m := make(map[string]int32) for k, v := range moo { ik, ok := k.(string) c.Assert(ok, Equals, true) iv, ok := v.(int32) c.Assert(ok, Equals, true) m[ik] = iv } c.Check(m, DeepEquals, map[string]int32{"one": 1, "forty two": 42}) } func (s *S) TestDecoderDecodeVariantMapIntString(c *C) { dec := newDecoder("v", []byte{ 5, // len("a{is}") 'a', '{', 'i', 's', '}', // Signature("a{is}") 0, 0, // padding 34, 0, 0, 0, // array length 0, 0, 0, 0, // padding (maps are 8-aligned) 1, 0, 0, 0, // int32(1) 3, 0, 0, 0, // len("one") 'o', 'n', 'e', 0, // "one" 0, 0, 0, 0, // padding 42, 0, 0, 0, // int32(42) 9, 0, 0, 0, // len("forty two") 'f', 'o', 'r', 't', 'y', ' ', 't', 'w', 'o', 0, 0, 0}, // padding binary.LittleEndian) var value1 Variant if err := dec.Decode(&value1); err != nil { c.Fatal("Decode as Variant:", err) } moo, ok := value1.Value.(map[interface{}]interface{}) c.Assert(ok, Equals, true) m := make(map[int32]string) for k, v := range moo { ik, ok := k.(int32) c.Assert(ok, Equals, true) iv, ok := v.(string) c.Assert(ok, Equals, true) m[ik] = iv } c.Check(m, DeepEquals, map[int32]string{1: "one", 42: "forty two"}) } func (s *S) TestDecoderDecodeVariantMapIntStruct(c *C) { dec := newDecoder("v", []byte{ 8, // len("a{i(ii)}") 'a', '{', 'i', '(', 'i', 'i', ')', '}', // Signature("a{i(ii)}") 0, 0, 0, // padding 12, 0, 0, 0, // array length 0, 0, 0, 0, // padding (maps are 8-aligned) 1, 0, 0, 0, // int32(1) 2, 0, 0, 0, // int32(2) 3, 0, 0, 0, // int32(3) 0, 0, 0, 0}, // padding binary.LittleEndian) var value1 Variant if err := dec.Decode(&value1); err != nil { c.Fatal("Decode as Variant:", err) } _, ok := value1.Value.(map[interface{}]interface{}) c.Assert(ok, Equals, true) } golang-go-dbus-1~bzr20140217/encoder.go000066400000000000000000000117621230051202400175200ustar00rootroot00000000000000package dbus import ( "bytes" "encoding/binary" "errors" "reflect" ) type encoder struct { signature Signature data bytes.Buffer order binary.ByteOrder } func newEncoder(signature Signature, data []byte, order binary.ByteOrder) *encoder { enc := &encoder{signature: signature, order: order} if data != nil { enc.data.Write(data) } return enc } func (self *encoder) align(alignment int) { for self.data.Len()%alignment != 0 { self.data.WriteByte(0) } } func (self *encoder) Append(args ...interface{}) error { for _, arg := range args { if err := self.appendValue(reflect.ValueOf(arg)); err != nil { return err } } return nil } func (self *encoder) alignForType(t reflect.Type) error { // If type matches the ObjectPather interface, treat like an // ObjectPath if t.AssignableTo(typeObjectPather) { t = reflect.TypeOf(ObjectPath("")) } // dereference pointers for t.Kind() == reflect.Ptr { t = t.Elem() } switch t.Kind() { case reflect.Uint8: self.align(1) case reflect.Int16, reflect.Uint16: self.align(2) case reflect.Bool, reflect.Int32, reflect.Uint32, reflect.Array, reflect.Slice, reflect.Map: self.align(4) case reflect.Int64, reflect.Uint64, reflect.Float64: self.align(8) case reflect.String: if t == typeSignature { self.align(1) } else { self.align(4) } case reflect.Struct: if t == typeVariant { self.align(1) } else { self.align(8) } default: return errors.New("Don't know how to align " + t.String()) } return nil } func (self *encoder) appendValue(v reflect.Value) error { signature, err := SignatureOf(v.Type()) if err != nil { return err } self.signature += signature // Convert ObjectPather values to ObjectPath strings if v.Type().AssignableTo(typeObjectPather) { path := v.Interface().(ObjectPather).ObjectPath() v = reflect.ValueOf(path) } // We want pointer values here, rather than the pointers themselves. for v.Kind() == reflect.Ptr { v = v.Elem() } self.alignForType(v.Type()) switch v.Kind() { case reflect.Uint8: self.data.WriteByte(byte(v.Uint())) return nil case reflect.Bool: var uintval uint32 if v.Bool() { uintval = 1 } else { uintval = 0 } binary.Write(&self.data, self.order, uintval) return nil case reflect.Int16: binary.Write(&self.data, self.order, int16(v.Int())) return nil case reflect.Uint16: binary.Write(&self.data, self.order, uint16(v.Uint())) return nil case reflect.Int32: binary.Write(&self.data, self.order, int32(v.Int())) return nil case reflect.Uint32: binary.Write(&self.data, self.order, uint32(v.Uint())) return nil case reflect.Int64: binary.Write(&self.data, self.order, int64(v.Int())) return nil case reflect.Uint64: binary.Write(&self.data, self.order, uint64(v.Uint())) return nil case reflect.Float64: binary.Write(&self.data, self.order, float64(v.Float())) return nil case reflect.String: s := v.String() // Signatures only use a single byte for the length. if v.Type() == typeSignature { self.data.WriteByte(byte(len(s))) } else { binary.Write(&self.data, self.order, uint32(len(s))) } self.data.Write([]byte(s)) self.data.WriteByte(0) return nil case reflect.Array, reflect.Slice: // Marshal array contents to a separate buffer so we // can find its length. var content encoder content.order = self.order for i := 0; i < v.Len(); i++ { if err := content.appendValue(v.Index(i)); err != nil { return err } } binary.Write(&self.data, self.order, uint32(content.data.Len())) self.alignForType(v.Type().Elem()) self.data.Write(content.data.Bytes()) return nil case reflect.Map: // Marshal array contents to a separate buffer so we // can find its length. var content encoder content.order = self.order for _, key := range v.MapKeys() { content.align(8) if err := content.appendValue(key); err != nil { return err } if err := content.appendValue(v.MapIndex(key)); err != nil { return err } } binary.Write(&self.data, self.order, uint32(content.data.Len())) self.align(8) // alignment of DICT_ENTRY self.data.Write(content.data.Bytes()) return nil case reflect.Struct: if v.Type() == typeVariant { variant := v.Interface().(Variant) variantSig, err := variant.GetVariantSignature() if err != nil { return err } // Save the signature, so we don't add the // typecodes for the variant value to the // signature. savedSig := self.signature if err := self.appendValue(reflect.ValueOf(variantSig)); err != nil { return err } if err := self.appendValue(reflect.ValueOf(variant.Value)); err != nil { return err } self.signature = savedSig return nil } // XXX: save and restore the signature, since we wrote // out the entire struct signature previously. savedSig := self.signature for i := 0; i != v.NumField(); i++ { if err := self.appendValue(v.Field(i)); err != nil { return err } } self.signature = savedSig return nil } return errors.New("Could not marshal " + v.Type().String()) } golang-go-dbus-1~bzr20140217/encoder_test.go000066400000000000000000000201501230051202400205460ustar00rootroot00000000000000package dbus import ( "encoding/binary" . "launchpad.net/gocheck" ) func (s *S) TestEncoderAlign(c *C) { enc := newEncoder("", nil, binary.LittleEndian) enc.data.WriteByte(1) enc.align(1) c.Check(enc.data.Bytes(), DeepEquals, []byte{1}) enc.align(2) c.Check(enc.data.Bytes(), DeepEquals, []byte{1, 0}) enc.align(4) c.Check(enc.data.Bytes(), DeepEquals, []byte{1, 0, 0, 0}) enc.align(8) c.Check(enc.data.Bytes(), DeepEquals, []byte{1, 0, 0, 0, 0, 0, 0, 0}) } func (s *S) TestEncoderAppendByte(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append(byte(42)); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("y")) c.Check(enc.data.Bytes(), DeepEquals, []byte{42}) } func (s *S) TestEncoderAppendBoolean(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append(true); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("b")) c.Check(enc.data.Bytes(), DeepEquals, []byte{1, 0, 0, 0}) } func (s *S) TestEncoderAppendInt16(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append(int16(42)); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("n")) c.Check(enc.data.Bytes(), DeepEquals, []byte{42, 0}) } func (s *S) TestEncoderAppendUint16(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append(uint16(42)); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("q")) c.Check(enc.data.Bytes(), DeepEquals, []byte{42, 0}) } func (s *S) TestEncoderAppendInt32(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append(int32(42)); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("i")) c.Check(enc.data.Bytes(), DeepEquals, []byte{42, 0, 0, 0}) } func (s *S) TestEncoderAppendUint32(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append(uint32(42)); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("u")) c.Check(enc.data.Bytes(), DeepEquals, []byte{42, 0, 0, 0}) } func (s *S) TestEncoderAppendInt64(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append(int64(42)); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("x")) c.Check(enc.data.Bytes(), DeepEquals, []byte{42, 0, 0, 0, 0, 0, 0, 0}) } func (s *S) TestEncoderAppendUint64(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append(uint64(42)); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("t")) c.Check(enc.data.Bytes(), DeepEquals, []byte{42, 0, 0, 0, 0, 0, 0, 0}) } func (s *S) TestEncoderAppendFloat64(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append(float64(42.0)); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("d")) c.Check(enc.data.Bytes(), DeepEquals, []byte{0, 0, 0, 0, 0, 0, 69, 64}) } func (s *S) TestEncoderAppendString(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append("hello"); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("s")) c.Check(enc.data.Bytes(), DeepEquals, []byte{ 5, 0, 0, 0, // Length 'h', 'e', 'l', 'l', 'o', // "hello" 0}) // nul termination } func (s *S) TestEncoderAppendObjectPath(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append(ObjectPath("/foo")); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("o")) c.Check(enc.data.Bytes(), DeepEquals, []byte{ 4, 0, 0, 0, // Length '/', 'f', 'o', 'o', // ObjectPath("/foo") 0}) // nul termination } type testObject struct{} func (f *testObject) ObjectPath() ObjectPath { return ObjectPath("/foo") } func (s *S) TestEncoderAppendObject(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append(&testObject{}); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("o")) c.Check(enc.data.Bytes(), DeepEquals, []byte{ 4, 0, 0, 0, // Length '/', 'f', 'o', 'o', // ObjectPath("/foo") 0}) // nul termination } func (s *S) TestEncoderAppendSignature(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append(Signature("a{si}")); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("g")) c.Check(enc.data.Bytes(), DeepEquals, []byte{ 5, // Length 'a', '{', 's', 'i', '}', // Signature("a{si}") 0}) // nul termination } func (s *S) TestEncoderAppendArray(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append([]int32{42, 420}); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("ai")) c.Check(enc.data.Bytes(), DeepEquals, []byte{ 8, 0, 0, 0, // Length 42, 0, 0, 0, // int32(42) 164, 1, 0, 0}) // int32(420) } func (s *S) TestEncoderAppendArrayLengthAlignment(c *C) { enc := newEncoder("", nil, binary.LittleEndian) // append a byte, which means we are no longer aligned. c.Assert(enc.Append(byte(1)), Equals, nil) // Now create an array. c.Check(enc.Append([]uint32{42}), Equals, nil) c.Check(enc.signature, Equals, Signature("yau")) c.Check(enc.data.Bytes(), DeepEquals, []byte{ 1, // byte(1) 0, 0, 0, // padding 4, 0, 0, 0, // array length 42, 0, 0, 0}) // uint32(42) } func (s *S) TestEncoderAppendArrayPaddingAfterLength(c *C) { enc := newEncoder("", nil, binary.LittleEndian) // Now create an array with alignment 8 values. c.Check(enc.Append([]int64{42}), Equals, nil) c.Check(enc.signature, Equals, Signature("ax")) c.Check(enc.data.Bytes(), DeepEquals, []byte{ 8, 0, 0, 0, // array length (not including padding) 0, 0, 0, 0, // padding 42, 0, 0, 0, 0, 0, 0, 0}) // int64(42) // The padding is needed, even if there are no elements in the array. enc = newEncoder("", nil, binary.LittleEndian) c.Check(enc.Append([]int64{}), Equals, nil) c.Check(enc.signature, Equals, Signature("ax")) c.Check(enc.data.Bytes(), DeepEquals, []byte{ 0, 0, 0, 0, // array length (not including padding) 0, 0, 0, 0}) // padding } func (s *S) TestEncoderAppendMap(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append(map[string]bool{"true": true}); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("a{sb}")) c.Check(enc.data.Bytes(), DeepEquals, []byte{ 16, 0, 0, 0, // array content length 0, 0, 0, 0, // padding to 8 bytes 4, 0, 0, 0, 't', 'r', 'u', 'e', 0, // "true" 0, 0, 0, // padding to 4 bytes 1, 0, 0, 0}) // true } func (s *S) TestEncoderAppendMapAlignment(c *C) { enc := newEncoder("", nil, binary.LittleEndian) // append a byte, which means we are no longer aligned. c.Assert(enc.Append(byte(1)), Equals, nil) c.Check(enc.Append(map[string]bool{"true": true}), Equals, nil) c.Check(enc.signature, Equals, Signature("ya{sb}")) c.Check(enc.data.Bytes(), DeepEquals, []byte{ 1, // byte(1) 0, 0, 0, // padding 16, 0, 0, 0, // array content length 4, 0, 0, 0, 't', 'r', 'u', 'e', 0, // "true" 0, 0, 0, // padding to 4 bytes 1, 0, 0, 0}) // true } func (s *S) TestEncoderAppendStruct(c *C) { enc := newEncoder("", nil, binary.LittleEndian) type sample struct { one int32 two string } if err := enc.Append(&sample{42, "hello"}); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("(is)")) c.Check(enc.data.Bytes(), DeepEquals, []byte{ 42, 0, 0, 0, 5, 0, 0, 0, 'h', 'e', 'l', 'l', 'o', 0}) } func (s *S) TestEncoderAppendVariant(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append(&Variant{int32(42)}); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("v")) c.Check(enc.data.Bytes(), DeepEquals, []byte{ 1, 'i', 0, // Signature("i") 0, // padding to 4 bytes 42, 0, 0, 0}) // int32(42) } func (s *S) TestEncoderAppendAlignment(c *C) { enc := newEncoder("", nil, binary.LittleEndian) if err := enc.Append(byte(42), int16(42), true, int32(42), int64(42)); err != nil { c.Error(err) } c.Check(enc.signature, Equals, Signature("ynbix")) c.Check(enc.data.Bytes(), DeepEquals, []byte{ 42, // byte(42) 0, // padding to 2 bytes 42, 0, // int16(42) 1, 0, 0, 0, // true 42, 0, 0, 0, // int32(42) 0, 0, 0, 0, // padding to 8 bytes 42, 0, 0, 0, 0, 0, 0, 0}) // int64(42) } golang-go-dbus-1~bzr20140217/introspect.go000066400000000000000000000052751230051202400202750ustar00rootroot00000000000000// +build ignore // // XXX: The method call logic no longer needs introspection data, so // this code is currently unused. I've kept it around since it may be // useful stub generation. package dbus import ( "bytes" "encoding/xml" "strings" ) type annotationData struct { Name string `xml:"name,attr"` Value string `xml:"value,attr"` } type argData struct { Name string `xml:"name,attr"` Type string `xml:"type,attr"` Direction string `xml:"direction,attr"` } type methodData struct { Name string `xml:"name,attr"` Arg []argData `xml:"arg"` Annotation annotationData `xml:"annotation"` } type signalData struct { Name string `xml:"name,attr"` Arg []argData `xml:"arg"` } type interfaceData struct { Name string `xml:"name,attr"` Method []methodData `xml:"method"` Signal []signalData `xml:"signal"` } type introspect struct { Name string `xml:"name,attr"` Interface []interfaceData `xml:"interface"` Node []*Introspect `xml:"node"` } type Introspect interface { GetInterfaceData(name string) InterfaceData } type InterfaceData interface { GetMethodData(name string) MethodData GetSignalData(name string) SignalData GetName() string } type MethodData interface { GetName() string GetInSignature() Signature GetOutSignature() Signature } type SignalData interface { GetName() string GetSignature() Signature } func NewIntrospect(xmlIntro string) (Introspect, error) { intro := new(introspect) buff := bytes.NewBufferString(xmlIntro) err := xml.Unmarshal(buff.Bytes(), intro) if err != nil { return nil, err } return intro, nil } func (p introspect) GetInterfaceData(name string) InterfaceData { for _, v := range p.Interface { if v.Name == name { return v } } return nil } func (p interfaceData) GetMethodData(name string) MethodData { for _, v := range p.Method { if v.GetName() == name { return v } } return nil } func (p interfaceData) GetSignalData(name string) SignalData { for _, v := range p.Signal { if v.GetName() == name { return v } } return nil } func (p interfaceData) GetName() string { return p.Name } func (p methodData) GetInSignature() (sig Signature) { for _, v := range p.Arg { if strings.ToUpper(v.Direction) == "IN" { sig += Signature(v.Type) } } return } func (p methodData) GetOutSignature() (sig Signature) { for _, v := range p.Arg { if strings.ToUpper(v.Direction) == "OUT" { sig += Signature(v.Type) } } return } func (p methodData) GetName() string { return p.Name } func (p signalData) GetSignature() (sig Signature) { for _, v := range p.Arg { sig += Signature(v.Type) } return } func (p signalData) GetName() string { return p.Name } golang-go-dbus-1~bzr20140217/introspect_test.go000066400000000000000000000040011230051202400213160ustar00rootroot00000000000000// +build ignore package dbus import ( . "launchpad.net/gocheck" ) var introStr = ` ` func (s *S) TestIntrospect(c *C) { intro, err := NewIntrospect(introStr) c.Assert(err, Equals, nil) c.Assert(intro, Not(Equals), nil) intf := intro.GetInterfaceData("org.freedesktop.SampleInterface") c.Assert(intf, Not(Equals), nil) c.Check(intf.GetName(), Equals, "org.freedesktop.SampleInterface") meth := intf.GetMethodData("Frobate") c.Assert(meth, Not(Equals), nil) c.Check(meth.GetOutSignature(), Equals, Signature("sa{us}")) nilmeth := intf.GetMethodData("Hoo") // unknown method name c.Check(nilmeth, Equals, nil) signal := intf.GetSignalData("Changed") c.Assert(signal, Not(Equals), nil) c.Check(signal.GetSignature(), Equals, Signature("b")) nilsignal := intf.GetSignalData("Hoo") // unknown signal name c.Check(nilsignal, Equals, nil) } golang-go-dbus-1~bzr20140217/matchrule.go000066400000000000000000000030761230051202400200640ustar00rootroot00000000000000package dbus import "fmt" import "strings" // Matches all messages with equal type, interface, member, or path. // Any missing/invalid fields are not matched against. type MatchRule struct { Type MessageType Sender string Path ObjectPath Interface string Member string Arg0 string senderNameOwner string } // A string representation af the MatchRule (D-Bus variant map). func (p *MatchRule) String() string { params := make([]string, 0, 6) if p.Type != TypeInvalid { params = append(params, fmt.Sprintf("type='%s'", p.Type)) } if p.Sender != "" { params = append(params, fmt.Sprintf("sender='%s'", p.Sender)) } if p.Path != "" { params = append(params, fmt.Sprintf("path='%s'", p.Path)) } if p.Interface != "" { params = append(params, fmt.Sprintf("interface='%s'", p.Interface)) } if p.Member != "" { params = append(params, fmt.Sprintf("member='%s'", p.Member)) } if p.Arg0 != "" { params = append(params, fmt.Sprintf("arg0='%s'", p.Arg0)) } return strings.Join(params, ",") } func (p *MatchRule) Match(msg *Message) bool { if p.Type != TypeInvalid && p.Type != msg.Type { return false } if p.Sender != "" { if !(p.Sender == msg.Sender || p.senderNameOwner == msg.Sender) { return false } } if p.Path != "" && p.Path != msg.Path { return false } if p.Interface != "" && p.Interface != msg.Interface { return false } if p.Member != "" && p.Member != msg.Member { return false } if p.Arg0 != "" { var arg0 string if err := msg.Args(&arg0); err != nil || arg0 != p.Arg0 { return false } } return true } golang-go-dbus-1~bzr20140217/matchrule_test.go000066400000000000000000000024361230051202400211220ustar00rootroot00000000000000package dbus import . "launchpad.net/gocheck" func (s *S) TestMatchRuleToString(c *C) { mr := MatchRule{ Type: TypeSignal, Interface: "org.freedesktop.DBus", Member: "Foo", Path: "/bar/foo"} c.Check(mr.String(), Equals, "type='signal',path='/bar/foo',interface='org.freedesktop.DBus',member='Foo'") // A rule that doesn't match the member mr = MatchRule{ Type: TypeSignal, Interface: "com.example.Foo", Member: "Bar"} c.Check(mr.String(), Equals, "type='signal',interface='com.example.Foo',member='Bar'") } func (s *S) TestMatchRuleMatch(c *C) { msg := NewSignalMessage("", "org.freedesktop.DBus", "NameOwnerChanged") _ = msg.AppendArgs("com.example.Foo", "", ":2.0") mr := MatchRule{ Type: TypeSignal, Interface: "org.freedesktop.DBus", Member: "NameOwnerChanged"} c.Check(mr.Match(msg), Equals, true) mr = MatchRule{ Type: TypeSignal, Interface: "org.freedesktop.DBus", Member: "NameAcquired"} c.Check(mr.Match(msg), Equals, false) // Check matching against first argument. mr = MatchRule{ Type: TypeSignal, Interface: "org.freedesktop.DBus", Member: "NameOwnerChanged", Arg0: "com.example.Foo"} c.Check(mr.Match(msg), Equals, true) mr.Arg0 = "com.example.Bar" c.Check(mr.Match(msg), Equals, false) } golang-go-dbus-1~bzr20140217/message.go000066400000000000000000000244131230051202400175220ustar00rootroot00000000000000package dbus import ( "encoding/binary" "errors" "io" ) // See the D-Bus tutorial for information about message types. // http://dbus.freedesktop.org/doc/dbus-tutorial.html#messages type MessageType uint8 const ( TypeInvalid MessageType = iota TypeMethodCall TypeMethodReturn TypeError TypeSignal ) var messageTypeString = map[MessageType]string{ TypeInvalid: "invalid", TypeMethodCall: "method_call", TypeMethodReturn: "method_return", TypeSignal: "signal", TypeError: "error", } func (t MessageType) String() string { return messageTypeString[t] } type MessageFlag uint8 const ( // When applied to method call messages, indicates that no // method return or error message is expected. FlagNoReplyExpected MessageFlag = 1 << iota // Indicates that the message should not autostart the service // if the destination service is not currently running. FlagNoAutoStart ) // Message represents a D-Bus message. // // It is used to both construct messages for sending on the bus, and // to represent messages received from the bus. // // There type does not use locks to protect its internal members. // Instead, it is expected that users either (a) only modify a message // from a single thread (usually the case when constructing a message // to send), or (b) treat the message as read only (usually the case // when processing a received message). type Message struct { order binary.ByteOrder Type MessageType Flags MessageFlag Protocol uint8 serial uint32 // header fields Path ObjectPath Interface string Member string ErrorName string replySerial uint32 Dest string Sender string sig Signature body []byte } // Create a new message with Flags == 0 and Protocol == 1. func newMessage() *Message { msg := new(Message) msg.order = binary.LittleEndian msg.serial = 0 msg.replySerial = 0 msg.Flags = 0 msg.Protocol = 1 msg.body = []byte{} return msg } // NewMethodCallMessage creates a method call message. // // Method arguments can be appended to the message via AppendArgs. func NewMethodCallMessage(destination string, path ObjectPath, iface string, member string) *Message { msg := newMessage() msg.Type = TypeMethodCall msg.Dest = destination msg.Path = path msg.Interface = iface msg.Member = member return msg } // NewMethodReturnMessage creates a method return message. // // This message type represents a successful reply to the method call // message passed as an argument. // // Return arguments should be appended to the message via AppendArgs. func NewMethodReturnMessage(methodCall *Message) *Message { if methodCall.serial == 0 { panic("methodCall.serial == 0") } if methodCall.Type != TypeMethodCall { panic("replies should be sent in response to method calls") } msg := newMessage() msg.Type = TypeMethodReturn msg.replySerial = methodCall.serial msg.Dest = methodCall.Sender return msg } // NewSignalMessage creates a signal message. // // Signal messages are used to broadcast messages to interested // listeners. // // Arguments can be appended to the signal with AppendArgs. func NewSignalMessage(path ObjectPath, iface string, member string) *Message { msg := newMessage() msg.Type = TypeSignal msg.Path = path msg.Interface = iface msg.Member = member return msg } // NewErrorMessage creates an error message. // // This message type should be sent in response to a method call // message in the case of a failure. func NewErrorMessage(methodCall *Message, errorName string, message string) *Message { if methodCall.serial == 0 { panic("methodCall.serial == 0") } if methodCall.Type != TypeMethodCall { panic("errors should be sent in response to method calls") } msg := newMessage() msg.Type = TypeError msg.replySerial = methodCall.serial msg.Dest = methodCall.Sender msg.ErrorName = errorName if err := msg.AppendArgs(message); err != nil { panic(err) } return msg } func (p *Message) setSerial(serial uint32) { if p.serial != 0 { panic("Message already has a serial number") } p.serial = serial } // AppendArgs appends arguments to a message. // // Native Go types are converted to equivalent D-Bus types: // - uint8 represents a byte. // - bool represents a boolean value. // - int16, uint16, int32, uint32, int64 and uint64 represent the // equivalent integer types. // - string represents a string. // - The dbus.ObjectPath type or any type conforming to the // dbus.ObjectPather interface represents an object path. // - arrays and slices represent arrays of the element type. // - maps represent equivalent D-Bus dictionaries. // - structures represent a structure comprising the public members. // - the dbus.Variant type represents a variant. // // If an argument can not be serialised in the message, an error is // returned. When multiple arguments are being appended, it is // possible for some arguments to be successfully appended before the // error is generated. func (p *Message) AppendArgs(args ...interface{}) error { enc := newEncoder(p.sig, p.body, p.order) if err := enc.Append(args...); err != nil { return err } p.sig = enc.signature p.body = enc.data.Bytes() return nil } // Args decodes one or more arguments from the message. // // The arguments should be pointers to variables used to hold the // arguments. If the type of the argument does not match the // corresponding argument in the message, then an error will be // raised. // // As a special case, arguments may be decoded into a blank interface // value. This may result in a less useful decoded version though // (e.g. an "ai" message argument would be decoded as []interface{} // instead of []int32). func (p *Message) Args(args ...interface{}) error { dec := newDecoder(p.sig, p.body, p.order) return dec.Decode(args...) } // AllArgs returns all arguments in the message. // // This method is equivalent to calling Args and passing pointers // to blank interface values for each message argument. func (p *Message) AllArgs() []interface{} { dec := newDecoder(p.sig, p.body, p.order) args := make([]interface{}, 0) for dec.HasMore() { var arg interface{} if err := dec.Decode(&arg); err != nil { panic(err) } args = append(args, arg) } return args } // AsError creates a Go error value corresponding to a message. // // This method should only be called on messages of the error type. func (p *Message) AsError() error { if p.Type != TypeError { panic("Only messages of type 'error' can be converted to an error") } var errorMessage string if err := p.Args(&errorMessage); err != nil { // Ignore error errorMessage = "" } return &Error{p.ErrorName, errorMessage} } type headerField struct { Code byte Value Variant } func readMessage(r io.Reader) (*Message, error) { header := make([]byte, 16) if n, err := r.Read(header); n < len(header) { if err == nil { err = errors.New("Could not read message header") } return nil, err } msg := newMessage() switch header[0] { case 'l': msg.order = binary.LittleEndian case 'B': msg.order = binary.BigEndian default: return nil, errors.New("Unknown message endianness: " + string(header[0])) } dec := newDecoder("yyyyuuu", header, msg.order) var msgOrder byte var msgBodyLength, headerFieldsLength uint32 if err := dec.Decode(&msgOrder, &msg.Type, &msg.Flags, &msg.Protocol, &msgBodyLength, &msg.serial, &headerFieldsLength); err != nil { return nil, err } // Read out and decode the header fields, plus the padding to // 8 bytes. padding := -(len(header) + int(headerFieldsLength)) % 8 if padding < 0 { padding += 8 } headerFields := make([]byte, 16+int(headerFieldsLength)+padding) copy(headerFields[:16], header) if n, err := r.Read(headerFields[16:]); n < len(headerFields)-16 { if err == nil { err = errors.New("Could not read message header fields") } return nil, err } dec = newDecoder("a(yv)", headerFields, msg.order) dec.dataOffset += 12 fields := make([]headerField, 0, 10) if err := dec.Decode(&fields); err != nil { return nil, err } for _, field := range fields { switch field.Code { case 1: msg.Path = field.Value.Value.(ObjectPath) case 2: msg.Interface = field.Value.Value.(string) case 3: msg.Member = field.Value.Value.(string) case 4: msg.ErrorName = field.Value.Value.(string) case 5: msg.replySerial = field.Value.Value.(uint32) case 6: msg.Dest = field.Value.Value.(string) case 7: msg.Sender = field.Value.Value.(string) case 8: msg.sig = field.Value.Value.(Signature) } } msg.body = make([]byte, msgBodyLength) if n, err := r.Read(msg.body); n < len(msg.body) { if err == nil { err = errors.New("Could not read message body") } return nil, err } return msg, nil } // WriteTo serialises the message and writes it to the given writer. func (p *Message) WriteTo(w io.Writer) (int64, error) { fields := make([]headerField, 0, 10) if p.Path != "" { fields = append(fields, headerField{1, Variant{p.Path}}) } if p.Interface != "" { fields = append(fields, headerField{2, Variant{p.Interface}}) } if p.Member != "" { fields = append(fields, headerField{3, Variant{p.Member}}) } if p.ErrorName != "" { fields = append(fields, headerField{4, Variant{p.ErrorName}}) } if p.replySerial != 0 { fields = append(fields, headerField{5, Variant{p.replySerial}}) } if p.Dest != "" { fields = append(fields, headerField{6, Variant{p.Dest}}) } if p.Sender != "" { fields = append(fields, headerField{7, Variant{p.Sender}}) } if p.sig != "" { fields = append(fields, headerField{8, Variant{p.sig}}) } var orderTag byte switch p.order { case binary.LittleEndian: orderTag = 'l' case binary.BigEndian: orderTag = 'B' default: return 0, errors.New("Unknown byte order: " + p.order.String()) } header := newEncoder("", nil, p.order) if err := header.Append(orderTag, byte(p.Type), byte(p.Flags), byte(p.Protocol), uint32(len(p.body)), p.serial, fields); err != nil { return 0, err } // Add alignment bytes for body header.align(8) m, err := w.Write(header.data.Bytes()) if err != nil { return int64(m), err } else if m != header.data.Len() { return int64(m), errors.New("Failed to write complete message header") } n, err := w.Write(p.body) if err != nil { return int64(m + n), err } else if n != len(p.body) { return int64(m + n), errors.New("Failed to write complete message body") } return int64(m + n), nil } golang-go-dbus-1~bzr20140217/message_test.go000066400000000000000000000102451230051202400205570ustar00rootroot00000000000000package dbus import ( "bytes" "io" . "launchpad.net/gocheck" ) var testMessage = []byte{ 'l', // Byte order 1, // Message type 0, // Flags 1, // Protocol 8, 0, 0, 0, // Body length 1, 0, 0, 0, // Serial 127, 0, 0, 0, // Header fields array length 1, 1, 'o', 0, // Path, type OBJECT_PATH 21, 0, 0, 0, '/', 'o', 'r', 'g', '/', 'f', 'r', 'e', 'e', 'd', 'e', 's', 'k', 't', 'o', 'p', '/', 'D', 'B', 'u', 's', 0, 0, 0, 2, 1, 's', 0, // Interface, type STRING 20, 0, 0, 0, 'o', 'r', 'g', '.', 'f', 'r', 'e', 'e', 'd', 'e', 's', 'k', 't', 'o', 'p', '.', 'D', 'B', 'u', 's', 0, 0, 0, 0, 3, 1, 's', 0, // Member, type STRING 12, 0, 0, 0, 'N', 'a', 'm', 'e', 'H', 'a', 's', 'O', 'w', 'n', 'e', 'r', 0, 0, 0, 0, 6, 1, 's', 0, // Destination, type STRING 20, 0, 0, 0, 'o', 'r', 'g', '.', 'f', 'r', 'e', 'e', 'd', 'e', 's', 'k', 't', 'o', 'p', '.', 'D', 'B', 'u', 's', 0, 0, 0, 0, 8, 1, 'g', 0, // Signature, type SIGNATURE 1, 's', 0, 0, // Message body 3, 0, 0, 0, 'x', 'y', 'z', 0} func (s *S) TestReadMessage(c *C) { r := bytes.NewReader(testMessage) msg, err := readMessage(r) if nil != err { c.Error(err) } c.Check(msg.Type, Equals, TypeMethodCall) c.Check(msg.Path, Equals, ObjectPath("/org/freedesktop/DBus")) c.Check(msg.Dest, Equals, "org.freedesktop.DBus") c.Check(msg.Interface, Equals, "org.freedesktop.DBus") c.Check(msg.Member, Equals, "NameHasOwner") c.Check(msg.sig, Equals, Signature("s")) var arg string if err := msg.Args(&arg); err != nil { c.Error(err) } c.Check(arg, Equals, "xyz") // Try reading a second message from the reader msg, err = readMessage(r) if err == nil { c.Error("Should not have been able to read a second message.") } else if err != io.EOF { c.Error(err) } } func (s *S) TestWriteMessage(c *C) { msg := newMessage() msg.Type = TypeMethodCall msg.Flags = MessageFlag(0) msg.serial = 1 msg.Path = "/org/freedesktop/DBus" msg.Dest = "org.freedesktop.DBus" msg.Interface = "org.freedesktop.DBus" msg.Member = "NameHasOwner" if err := msg.AppendArgs("xyz"); err != nil { c.Error(err) } buff := new(bytes.Buffer) n, err := msg.WriteTo(buff) c.Check(err, Equals, nil) c.Check(n, Equals, int64(len(testMessage))) c.Check(buff.Bytes(), DeepEquals, testMessage) } func (s *S) TestNewMethodCallMessage(c *C) { msg := NewMethodCallMessage("com.destination", "/path", "com.interface", "method") c.Check(msg.Type, Equals, TypeMethodCall) c.Check(msg.Dest, Equals, "com.destination") c.Check(msg.Path, Equals, ObjectPath("/path")) c.Check(msg.Interface, Equals, "com.interface") c.Check(msg.Member, Equals, "method") // No signature or data c.Check(msg.sig, Equals, Signature("")) c.Check(msg.body, DeepEquals, []byte{}) } func (s *S) TestNewMethodReturnMessage(c *C) { call := NewMethodCallMessage("com.destination", "/path", "com.interface", "method") call.serial = 42 call.Sender = ":1.2" reply := NewMethodReturnMessage(call) c.Check(reply.Type, Equals, TypeMethodReturn) c.Check(reply.Dest, Equals, ":1.2") c.Check(reply.replySerial, Equals, uint32(42)) // No signature or data c.Check(reply.sig, Equals, Signature("")) c.Check(reply.body, DeepEquals, []byte{}) } func (s *S) TestNewSignalMessage(c *C) { msg := NewSignalMessage("/path", "com.interface", "signal") c.Check(msg.Type, Equals, TypeSignal) c.Check(msg.Dest, Equals, "") c.Check(msg.Path, Equals, ObjectPath("/path")) c.Check(msg.Interface, Equals, "com.interface") c.Check(msg.Member, Equals, "signal") // No signature or data c.Check(msg.sig, Equals, Signature("")) c.Check(msg.body, DeepEquals, []byte{}) } func (s *S) TestNewErrorMessage(c *C) { call := NewMethodCallMessage("com.destination", "/path", "com.interface", "method") call.serial = 42 call.Sender = ":1.2" reply := NewErrorMessage(call, "com.interface.Error", "message") c.Check(reply.Type, Equals, TypeError) c.Check(reply.Dest, Equals, ":1.2") c.Check(reply.replySerial, Equals, uint32(42)) c.Check(reply.ErrorName, Equals, "com.interface.Error") // No signature or data c.Check(reply.sig, Equals, Signature("s")) var errorMessage string if err := reply.Args(&errorMessage); err != nil { c.Error(err) } c.Check(errorMessage, Equals, "message") } golang-go-dbus-1~bzr20140217/names.go000066400000000000000000000152411230051202400172000ustar00rootroot00000000000000package dbus import ( "errors" "log" ) type nameInfo struct { bus *Connection busName string currentOwner string signalWatch *SignalWatch watches []*NameWatch } type NameWatch struct { info *nameInfo C chan string cancelled bool } func newNameInfo(bus *Connection, busName string) (*nameInfo, error) { info := &nameInfo{ bus: bus, busName: busName, watches: []*NameWatch{}} watch, err := bus.WatchSignal(&MatchRule{ Type: TypeSignal, Sender: BUS_DAEMON_NAME, Path: BUS_DAEMON_PATH, Interface: BUS_DAEMON_IFACE, Member: "NameOwnerChanged", Arg0: busName}) if err != nil { return nil, err } go func() { for msg := range watch.C { var busName, oldOwner, newOwner string if err := msg.Args(&busName, &oldOwner, &newOwner); err != nil { log.Println("Could not decode NameOwnerChanged message:", err) continue } info.handleOwnerChange(newOwner) } }() info.signalWatch = watch // spawn a goroutine to find the current name owner go info.checkCurrentOwner() return info, nil } func (self *nameInfo) checkCurrentOwner() { currentOwner, err := self.bus.busProxy.GetNameOwner(self.busName) if err != nil { if dbusErr, ok := err.(*Error); !ok || dbusErr.Name != "org.freedesktop.DBus.Error.NameHasNoOwner" { log.Println("Unexpected error from GetNameOwner:", err) } } if self.currentOwner == "" { // Simulate an ownership change message. self.handleOwnerChange(currentOwner) } } func (self *nameInfo) handleOwnerChange(newOwner string) { for _, watch := range self.watches { watch.C <- newOwner } self.currentOwner = newOwner } func (p *Connection) WatchName(busName string) (watch *NameWatch, err error) { p.nameInfoMutex.Lock() defer p.nameInfoMutex.Unlock() info, ok := p.nameInfo[busName] if !ok { if info, err = newNameInfo(p, busName); err != nil { return } p.nameInfo[busName] = info } watch = &NameWatch{info: info, C: make(chan string, 1)} info.watches = append(info.watches, watch) // If we're hooking up to an existing nameOwner and it already // knows the current name owner, tell our callback. if ok && info.currentOwner != "" { watch.C <- info.currentOwner } return } func (watch *NameWatch) Cancel() error { if watch.cancelled { return nil } watch.cancelled = true close(watch.C) info := watch.info bus := info.bus bus.nameInfoMutex.Lock() defer bus.nameInfoMutex.Unlock() found := false for i, other := range info.watches { if other == watch { info.watches[i] = info.watches[len(info.watches)-1] info.watches = info.watches[:len(info.watches)-1] found = true break } } if !found { return errors.New("NameOwnerWatch already cancelled") } if len(info.watches) != 0 { // There are other watches interested in this name, so // leave the nameOwner in place. return nil } delete(bus.nameInfo, info.busName) return info.signalWatch.Cancel() } // BusName acts as a handle for a well known bus name owned by this client. type BusName struct { bus *Connection Name string Flags NameFlags C chan error cancelled bool needsRelease bool acquiredWatch *SignalWatch lostWatch *SignalWatch } type NameFlags uint32 const ( NameFlagAllowReplacement NameFlags = 1 << iota NameFlagReplaceExisting NameFlagDoNotQueue ) var ( ErrNameLost = errors.New("name ownership lost") ErrNameInQueue = errors.New("in queue for name ownership") ErrNameExists = errors.New("name exists") ErrNameAlreadyOwned = errors.New("name already owned") ) // RequestName requests ownership of a well known bus name. // // Name ownership is communicated over the the BusName's channel: a // nil value indicates that the name was successfully acquired, and a // non-nil value indicates that the name was lost or could not be // acquired. func (p *Connection) RequestName(busName string, flags NameFlags) *BusName { name := &BusName{ bus: p, Name: busName, Flags: flags, C: make(chan error, 1)} go name.request() return name } func (name *BusName) request() { if name.cancelled { return } result, err := name.bus.busProxy.RequestName(name.Name, uint32(name.Flags)) if err != nil { log.Println("Error requesting bus name", name.Name, "err =", err) return } subscribe := false switch result { case 1: // DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER name.C <- nil subscribe = true name.needsRelease = true case 2: // DBUS_REQUEST_NAME_REPLY_IN_QUEUE name.C <- ErrNameInQueue subscribe = true name.needsRelease = true case 3: // DBUS_REQUEST_NAME_REPLY_EXISTS name.C <- ErrNameExists name.Release() case 4: // DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER name.C <- ErrNameAlreadyOwned name.Release() default: // assume that other responses mean we couldn't own // the name name.C <- errors.New("Unknown error") name.Release() } if subscribe && !name.cancelled { watch, err := name.bus.WatchSignal(&MatchRule{ Type: TypeSignal, Sender: BUS_DAEMON_NAME, Path: BUS_DAEMON_PATH, Interface: BUS_DAEMON_IFACE, Member: "NameLost", Arg0: name.Name}) if err != nil { log.Println("Could not set up NameLost signal watch") name.Release() return } name.lostWatch = watch go func() { for _ = range name.lostWatch.C { if !name.cancelled { name.C <- ErrNameLost close(name.C) name.cancelled = true } } }() watch, err = name.bus.WatchSignal(&MatchRule{ Type: TypeSignal, Sender: BUS_DAEMON_NAME, Path: BUS_DAEMON_PATH, Interface: BUS_DAEMON_IFACE, Member: "NameAcquired", Arg0: name.Name}) if err != nil { log.Println("Could not set up NameLost signal watch") name.Release() return } name.acquiredWatch = watch go func() { for _ = range name.acquiredWatch.C { if !name.cancelled { name.C <- nil } } }() // XXX: if we disconnect from the bus, we should // report the name being lost. } } // Release releases well known name on the message bus. func (name *BusName) Release() error { if name.cancelled { return nil } name.cancelled = true close(name.C) if name.acquiredWatch != nil { if err := name.acquiredWatch.Cancel(); err != nil { return err } name.acquiredWatch = nil } if name.lostWatch != nil { if err := name.lostWatch.Cancel(); err != nil { return err } name.lostWatch = nil } if name.needsRelease { result, err := name.bus.busProxy.ReleaseName(name.Name) if err != nil { return err } if result != 1 { // DBUS_RELEASE_NAME_REPLY_RELEASED log.Println("Unexpected result when releasing name", name.Name, "result =", result) } name.needsRelease = false } return nil } golang-go-dbus-1~bzr20140217/names_test.go000066400000000000000000000063451230051202400202440ustar00rootroot00000000000000package dbus import ( . "launchpad.net/gocheck" ) func (s *S) TestConnectionWatchName(c *C) { bus, err := Connect(SessionBus) c.Assert(err, IsNil) defer bus.Close() // Set up the name watch nameChanged := make(chan int, 1) owners := []string{} watch, err := bus.WatchName("com.example.GoDbus") c.Assert(err, IsNil) defer watch.Cancel() go func() { for newOwner := range watch.C { owners = append(owners, newOwner) nameChanged <- 0 } }() // Our handler will be called once with the initial name owner <-nameChanged c.Check(owners, DeepEquals, []string{""}) // Acquire the name, and wait for the process to complete. name := bus.RequestName("com.example.GoDbus", NameFlagDoNotQueue) c.Check(<-name.C, IsNil) <-nameChanged c.Check(owners, DeepEquals, []string{"", bus.UniqueName}) err = name.Release() c.Assert(err, IsNil) <-nameChanged c.Check(owners, DeepEquals, []string{"", bus.UniqueName, ""}) } func (s *S) TestConnectionRequestName(c *C) { bus, err := Connect(SessionBus) c.Assert(err, IsNil) defer bus.Close() name := bus.RequestName("com.example.GoDbus", 0) c.Check(name, NotNil) c.Check(<-name.C, IsNil) owner, err := bus.busProxy.GetNameOwner("com.example.GoDbus") c.Check(err, IsNil) c.Check(owner, Equals, bus.UniqueName) c.Check(name.Release(), IsNil) } func (s *S) TestConnectionRequestNameQueued(c *C) { // Acquire the name on a second connection bus1, err := Connect(SessionBus) c.Assert(err, IsNil) defer bus1.Close() bus2, err := Connect(SessionBus) c.Assert(err, IsNil) defer bus2.Close() name1 := bus1.RequestName("com.example.GoDbus", 0) c.Check(<-name1.C, IsNil) c.Check(name1.needsRelease, Equals, true) name2 := bus2.RequestName("com.example.GoDbus", 0) c.Check(<-name2.C, Equals, ErrNameInQueue) c.Check(name2.needsRelease, Equals, true) // Release the name on the first connection c.Check(name1.Release(), IsNil) // And the second connection can now acquire it c.Check(<-name2.C, IsNil) c.Check(name2.Release(), IsNil) } func (s *S) TestConnectionRequestNameDoNotQueue(c *C) { // Acquire the name on a second connection bus1, err := Connect(SessionBus) c.Assert(err, IsNil) defer bus1.Close() bus2, err := Connect(SessionBus) c.Assert(err, IsNil) defer bus2.Close() name1 := bus1.RequestName("com.example.GoDbus", 0) defer name1.Release() c.Check(<-name1.C, IsNil) c.Check(name1.needsRelease, Equals, true) name2 := bus2.RequestName("com.example.GoDbus", NameFlagDoNotQueue) c.Check(<-name2.C, Equals, ErrNameExists) c.Check(name2.needsRelease, Equals, false) c.Check(name2.Release(), IsNil) } func (s *S) TestConnectionRequestNameAllowReplacement(c *C) { // Acquire the name on a second connection bus1, err := Connect(SessionBus) c.Assert(err, IsNil) defer bus1.Close() bus2, err := Connect(SessionBus) c.Assert(err, IsNil) defer bus2.Close() name1 := bus1.RequestName("com.example.GoDbus", NameFlagAllowReplacement) defer name1.Release() c.Check(<-name1.C, IsNil) c.Check(name1.needsRelease, Equals, true) name2 := bus2.RequestName("com.example.GoDbus", NameFlagReplaceExisting) defer name2.Release() c.Check(<-name2.C, IsNil) c.Check(name2.needsRelease, Equals, true) // The first name owner loses possession. c.Check(<-name1.C, Equals, ErrNameLost) } golang-go-dbus-1~bzr20140217/proxy.go000066400000000000000000000100171230051202400172520ustar00rootroot00000000000000package dbus // This is not yet finished: it is an idea for what statically generated object bindings could look like. type Introspectable struct { *ObjectProxy } func (o *Introspectable) Introspect() (data string, err error) { reply, err := o.Call("org.freedesktop.DBus.Introspectable", "Introspect") if err != nil { return } err = reply.Args(&data) return } type Properties struct { *ObjectProxy } func (o *Properties) Get(interfaceName string, propertyName string) (value interface{}, err error) { reply, err := o.Call("org.freedesktop.DBus.Properties", "Get", interfaceName, propertyName) if err != nil { return } var variant Variant err = reply.Args(&variant) value = variant.Value return } func (o *Properties) Set(interfaceName string, propertyName string, value interface{}) (err error) { _, err = o.Call("org.freedesktop.DBus.Properties", "Set", interfaceName, propertyName, Variant{value}) return } func (o *Properties) GetAll(interfaceName string) (props map[string]Variant, err error) { reply, err := o.Call("org.freedesktop.DBus.Properties", "GetAll", interfaceName) if err != nil { return } err = reply.Args(&props) return } type BusDaemon struct { *ObjectProxy } func (o *BusDaemon) Hello() (uniqueName string, err error) { reply, err := o.Call(BUS_DAEMON_IFACE, "Hello") if err != nil { return } err = reply.Args(&uniqueName) return } func (o *BusDaemon) RequestName(name string, flags uint32) (result uint32, err error) { reply, err := o.Call(BUS_DAEMON_IFACE, "RequestName", name, flags) if err != nil { return } err = reply.Args(&result) return } func (o *BusDaemon) ReleaseName(name string) (result uint32, err error) { reply, err := o.Call(BUS_DAEMON_IFACE, "ReleaseName", name) if err != nil { return } err = reply.Args(&result) return } func (o *BusDaemon) ListQueuedOwners(name string) (owners []string, err error) { reply, err := o.Call(BUS_DAEMON_IFACE, "ListQueuedOwners", name) if err != nil { return } err = reply.Args(&owners) return } func (o *BusDaemon) ListNames() (names []string, err error) { reply, err := o.Call(BUS_DAEMON_IFACE, "ListNames") if err != nil { return } err = reply.Args(&names) return } func (o *BusDaemon) ListActivatableNames() (names []string, err error) { reply, err := o.Call(BUS_DAEMON_IFACE, "ListActivatableNames") if err != nil { return } err = reply.Args(&names) return } func (o *BusDaemon) NameHasOwner(name string) (hasOwner bool, err error) { reply, err := o.Call(BUS_DAEMON_IFACE, "NameHasOwner", name) if err != nil { return } err = reply.Args(&hasOwner) return } func (o *BusDaemon) StartServiceByName(name string, flags uint32) (result uint32, err error) { reply, err := o.Call(BUS_DAEMON_IFACE, "StartServiceByName", name, flags) if err != nil { return } err = reply.Args(&result) return } func (o *BusDaemon) UpdateActivationEnvironment(env map[string]string) (err error) { _, err = o.Call(BUS_DAEMON_IFACE, "UpdateActivationEnvironment", env) return } func (o *BusDaemon) GetNameOwner(name string) (owner string, err error) { reply, err := o.Call(BUS_DAEMON_IFACE, "GetNameOwner", name) if err != nil { return } err = reply.Args(&owner) return } func (o *BusDaemon) GetConnectionUnixUser(busName string) (user uint32, err error) { reply, err := o.Call(BUS_DAEMON_IFACE, "GetConnectionUnixUser", busName) if err != nil { return } err = reply.Args(&user) return } func (o *BusDaemon) GetConnectionUnixProcessID(busName string) (process uint32, err error) { reply, err := o.Call(BUS_DAEMON_IFACE, "GetConnectionUnixProcessID", busName) if err != nil { return } err = reply.Args(&process) return } func (o *BusDaemon) AddMatch(rule string) (err error) { _, err = o.Call(BUS_DAEMON_IFACE, "AddMatch", rule) return } func (o *BusDaemon) RemoveMatch(rule string) (err error) { _, err = o.Call(BUS_DAEMON_IFACE, "RemoveMatch", rule) return } func (o *BusDaemon) GetId() (busId string, err error) { reply, err := o.Call(BUS_DAEMON_IFACE, "GetId") if err != nil { return } err = reply.Args(&busId) return } golang-go-dbus-1~bzr20140217/signal.go000066400000000000000000000075551230051202400173630ustar00rootroot00000000000000package dbus import ( "errors" ) // A structure to store the set of signal watches, keyed by object // path, interface and member. type signalWatchSet map[ObjectPath]map[string]map[string][]*SignalWatch func (self signalWatchSet) Add(watch *SignalWatch) { byInterface, ok := self[watch.rule.Path] if !ok { byInterface = make(map[string]map[string][]*SignalWatch) self[watch.rule.Path] = byInterface } byMember, ok := byInterface[watch.rule.Interface] if !ok { byMember = make(map[string][]*SignalWatch) byInterface[watch.rule.Interface] = byMember } watches, ok := byMember[watch.rule.Member] if !ok { watches = make([]*SignalWatch, 0, 1) } byMember[watch.rule.Member] = append(watches, watch) } func (self signalWatchSet) Remove(watch *SignalWatch) bool { byInterface, ok := self[watch.rule.Path] if !ok { return false } byMember, ok := byInterface[watch.rule.Interface] if !ok { return false } watches, ok := byMember[watch.rule.Member] if !ok { return false } for i, other := range watches { if other == watch { // Truncate the watch slice, moving the item // at the end to the new location. watches[i] = watches[len(watches)-1] byMember[watch.rule.Member] = watches[:len(watches)-1] return true } } return false } func (self signalWatchSet) FindMatches(msg *Message) (matches []*SignalWatch) { pathKeys := []ObjectPath{""} if msg.Path != ObjectPath("") { pathKeys = append(pathKeys, msg.Path) } ifaceKeys := []string{""} if msg.Interface != "" { ifaceKeys = append(ifaceKeys, msg.Interface) } memberKeys := []string{""} if msg.Member != "" { memberKeys = append(memberKeys, msg.Member) } for _, path := range pathKeys { byInterface, ok := self[path] if !ok { continue } for _, iface := range ifaceKeys { byMember, ok := byInterface[iface] if !ok { continue } for _, member := range memberKeys { watches, ok := byMember[member] if !ok { continue } for _, watch := range watches { if watch.rule.Match(msg) { matches = append(matches, watch) } } } } } return } type SignalWatch struct { bus *Connection rule MatchRule C chan *Message // If the rule tries to match against a bus name as the // sender, we need to track the current owner of that name. nameWatch *NameWatch cancelled bool } // Handle received signals. func (p *Connection) WatchSignal(rule *MatchRule) (*SignalWatch, error) { if rule.Type != TypeSignal { return nil, errors.New("Match rule is not for signals") } watch := &SignalWatch{ bus: p, rule: *rule, C: make(chan *Message)} // Does the rule match a bus name other than the daemon? if rule.Sender != "" && rule.Sender != BUS_DAEMON_NAME { nameWatch, err := p.WatchName(rule.Sender) if err != nil { return nil, err } watch.nameWatch = nameWatch if rule.Sender[0] == ':' { // For unique names, cancel the signal watch // when the name is lost. go func() { for newOwner := range nameWatch.C { if newOwner == "" { watch.Cancel() } } }() } else { // Otherwise, update the sender owner. go func() { for newOwner := range nameWatch.C { watch.rule.senderNameOwner = newOwner } }() } } if err := p.busProxy.AddMatch(rule.String()); err != nil { watch.nameWatch.Cancel() return nil, err } p.handlerMutex.Lock() p.signalMatchRules.Add(watch) p.handlerMutex.Unlock() return watch, nil } func (watch *SignalWatch) Cancel() error { if watch.cancelled { return nil } watch.cancelled = true close(watch.C) watch.bus.handlerMutex.Lock() foundMatch := watch.bus.signalMatchRules.Remove(watch) watch.bus.handlerMutex.Unlock() if foundMatch { if err := watch.bus.busProxy.RemoveMatch(watch.rule.String()); err != nil { return err } if watch.nameWatch != nil { if err := watch.nameWatch.Cancel(); err != nil { return err } } } return nil } golang-go-dbus-1~bzr20140217/signal_test.go000066400000000000000000000103711230051202400204100ustar00rootroot00000000000000package dbus import ( . "launchpad.net/gocheck" ) func (s *S) TestConnectionWatchSignal(c *C) { bus1, err := Connect(SessionBus) c.Assert(err, IsNil) defer bus1.Close() // Set up a second bus connection to receive a signal. watchReady := make(chan int) complete := make(chan *Message) go func(sender string, watchReady chan<- int, complete chan<- *Message) { bus2, err := Connect(SessionBus) if err != nil { c.Error(err) watchReady <- 0 complete <- nil return } defer bus2.Close() watch, err := bus2.WatchSignal(&MatchRule{ Type: TypeSignal, Sender: sender, Path: "/go/dbus/test", Interface: "com.example.GoDbus", Member: "TestSignal"}) watchReady <- 0 if err != nil { c.Error(err) bus2.Close() complete <- nil return } msg := <-watch.C if err := watch.Cancel(); err != nil { c.Error(err) } complete <- msg }(bus1.UniqueName, watchReady, complete) // Wait for the goroutine to configure the signal watch <-watchReady // Send the signal and wait for it to be received at the other end. signal := NewSignalMessage("/go/dbus/test", "com.example.GoDbus", "TestSignal") if err := bus1.Send(signal); err != nil { c.Fatal(err) } signal2 := <-complete c.Check(signal2, NotNil) } func (s *S) TestConnectionWatchSignalWithBusName(c *C) { bus, err := Connect(SessionBus) c.Assert(err, IsNil) defer bus.Close() // Request a bus name result, err := bus.busProxy.RequestName("com.example.GoDbus", 0x4) c.Assert(err, IsNil) c.Assert(result, Equals, uint32(1)) // We are Primary Owner // Set up a signal watch received := make(chan *Message, 1) watch, err := bus.WatchSignal(&MatchRule{ Type: TypeSignal, Sender: "com.example.GoDbus", Interface: "com.example.GoDbus", Member: "TestSignal"}) c.Assert(err, IsNil) defer watch.Cancel() // pump received signals messages into our bufferred channel go func() { for msg := range watch.C { received <- msg } }() // Send the signal, and wait to receive it. signal := NewSignalMessage("/go/dbus/test", "com.example.GoDbus", "TestSignal") if err := bus.Send(signal); err != nil { c.Fatal(err) } signal2 := <-received c.Check(signal2, NotNil) } func (s *S) TestSignalWatchSetAdd(c *C) { set := make(signalWatchSet) watch := SignalWatch{rule: MatchRule{ Type: TypeSignal, Sender: ":1.42", Path: "/foo", Interface: "com.example.Foo", Member: "Bar"}} set.Add(&watch) byInterface, ok := set["/foo"] c.Assert(ok, Equals, true) byMember, ok := byInterface["com.example.Foo"] c.Assert(ok, Equals, true) watches, ok := byMember["Bar"] c.Assert(ok, Equals, true) c.Check(watches, DeepEquals, []*SignalWatch{&watch}) } func (s *S) TestSignalWatchSetRemove(c *C) { set := make(signalWatchSet) watch1 := SignalWatch{rule: MatchRule{ Type: TypeSignal, Sender: ":1.42", Path: "/foo", Interface: "com.example.Foo", Member: "Bar"}} set.Add(&watch1) watch2 := SignalWatch{rule: MatchRule{ Type: TypeSignal, Sender: ":1.43", Path: "/foo", Interface: "com.example.Foo", Member: "Bar"}} set.Add(&watch2) c.Check(set.Remove(&watch1), Equals, true) c.Check(set["/foo"]["com.example.Foo"]["Bar"], DeepEquals, []*SignalWatch{&watch2}) // A second attempt at removal fails c.Check(set.Remove(&watch1), Equals, false) } func (s *S) TestSignalWatchSetFindMatches(c *C) { msg := NewSignalMessage("/foo", "com.example.Foo", "Bar") msg.Sender = ":1.42" set := make(signalWatchSet) watch := SignalWatch{rule: MatchRule{ Type: TypeSignal, Sender: ":1.42", Path: "/foo", Interface: "com.example.Foo", Member: "Bar"}} set.Add(&watch) c.Check(set.FindMatches(msg), DeepEquals, []*SignalWatch{&watch}) set.Remove(&watch) // An empty path also matches watch.rule.Path = "" set.Add(&watch) c.Check(set.FindMatches(msg), DeepEquals, []*SignalWatch{&watch}) set.Remove(&watch) // Or an empty interface watch.rule.Path = "/foo" watch.rule.Interface = "" set.Add(&watch) c.Check(set.FindMatches(msg), DeepEquals, []*SignalWatch{&watch}) set.Remove(&watch) // Or an empty member watch.rule.Interface = "com.example.Foo" watch.rule.Member = "" set.Add(&watch) c.Check(set.FindMatches(msg), DeepEquals, []*SignalWatch{&watch}) set.Remove(&watch) } golang-go-dbus-1~bzr20140217/suite_test.go000066400000000000000000000002221230051202400202560ustar00rootroot00000000000000package dbus import ( . "launchpad.net/gocheck" "testing" ) func TestAll(t *testing.T) { TestingT(t) } type S struct{} var _ = Suite(&S{}) golang-go-dbus-1~bzr20140217/transport.go000066400000000000000000000052001230051202400201230ustar00rootroot00000000000000package dbus import ( "errors" "io/ioutil" "net" "net/url" "strings" ) type transport interface { Dial() (net.Conn, error) } func newTransport(address string) (transport, error) { if len(address) == 0 { return nil, errors.New("Unknown address type") } // Split the address into transport type and options. transportType := address[:strings.Index(address, ":")] options := make(map[string]string) for _, option := range strings.Split(address[len(transportType)+1:], ",") { pair := strings.SplitN(option, "=", 2) key, err := url.QueryUnescape(pair[0]) if err != nil { return nil, err } value, err := url.QueryUnescape(pair[1]) if err != nil { return nil, err } options[key] = value } switch transportType { case "unix": if abstract, ok := options["abstract"]; ok { return &unixTransport{"@" + abstract}, nil } else if path, ok := options["path"]; ok { return &unixTransport{path}, nil } else { return nil, errors.New("unix transport requires 'path' or 'abstract' options") } case "tcp", "nonce-tcp": address := options["host"] + ":" + options["port"] var family string switch options["family"] { case "", "ipv4": family = "tcp4" case "ipv6": family = "tcp6" default: return nil, errors.New("Unknown family for tcp transport: " + options["family"]) } if transportType == "tcp" { return &tcpTransport{address, family}, nil } else { nonceFile := options["noncefile"] return &nonceTcpTransport{address, family, nonceFile}, nil } // These can be implemented later as needed case "launchd": // Perform newTransport() on contents of // options["env"] environment variable case "systemd": // Only used when systemd is starting the message bus, // so probably not needed in a client library. case "unixexec": // exec a process with a socket hooked to stdin/stdout } return nil, errors.New("Unhandled transport type " + transportType) } type unixTransport struct { Address string } func (trans *unixTransport) Dial() (net.Conn, error) { return net.Dial("unix", trans.Address) } type tcpTransport struct { Address, Family string } func (trans *tcpTransport) Dial() (net.Conn, error) { return net.Dial(trans.Family, trans.Address) } type nonceTcpTransport struct { Address, Family, NonceFile string } func (trans *nonceTcpTransport) Dial() (net.Conn, error) { data, err := ioutil.ReadFile(trans.NonceFile) if err != nil { return nil, err } conn, err := net.Dial(trans.Family, trans.Address) if err != nil { return nil, err } // Write the nonce data to the socket if _, err := conn.Write(data); err != nil { conn.Close() return nil, err } return conn, nil } golang-go-dbus-1~bzr20140217/transport_test.go000066400000000000000000000100531230051202400211640ustar00rootroot00000000000000package dbus import ( "bytes" "errors" "fmt" "io/ioutil" . "launchpad.net/gocheck" "net" "path" ) func (s *S) TestNewTransportUnix(c *C) { trans, err := newTransport("unix:path=/tmp/dbus%3dsock") c.Check(err, Equals, nil) unixTrans, ok := trans.(*unixTransport) c.Check(ok, Equals, true) c.Check(unixTrans.Address, Equals, "/tmp/dbus=sock") // And for abstract namespace sockets: trans, err = newTransport("unix:abstract=/tmp/dbus%3dsock") c.Check(err, Equals, nil) unixTrans, ok = trans.(*unixTransport) c.Check(ok, Equals, true) c.Check(unixTrans.Address, Equals, "@/tmp/dbus=sock") } func (s *S) TestUnixTransportDial(c *C) { socketFile := path.Join(c.MkDir(), "bus.sock") listener, err := net.Listen("unix", socketFile) c.Assert(err, IsNil) trans, err := newTransport(fmt.Sprintf("unix:path=%s", socketFile)) c.Assert(err, IsNil) errChan := make(chan error, 1) go func() { conn, err := listener.Accept() if err == nil { conn.Close() } errChan <- err }() conn, err := trans.Dial() c.Assert(err, IsNil) conn.Close() // Was the other end of the connection established correctly? err = <-errChan c.Check(err, IsNil) listener.Close() } func (s *S) TestNewTransportTcp(c *C) { trans, err := newTransport("tcp:host=localhost,port=4444") c.Check(err, Equals, nil) tcpTrans, ok := trans.(*tcpTransport) c.Check(ok, Equals, true) c.Check(tcpTrans.Address, Equals, "localhost:4444") c.Check(tcpTrans.Family, Equals, "tcp4") // And with explicit family: trans, err = newTransport("tcp:host=localhost,port=4444,family=ipv4") c.Check(err, Equals, nil) tcpTrans, ok = trans.(*tcpTransport) c.Check(ok, Equals, true) c.Check(tcpTrans.Address, Equals, "localhost:4444") c.Check(tcpTrans.Family, Equals, "tcp4") trans, err = newTransport("tcp:host=localhost,port=4444,family=ipv6") c.Check(err, Equals, nil) tcpTrans, ok = trans.(*tcpTransport) c.Check(ok, Equals, true) c.Check(tcpTrans.Address, Equals, "localhost:4444") c.Check(tcpTrans.Family, Equals, "tcp6") } func (s *S) TestTcpTransportDial(c *C) { listener, err := net.Listen("tcp", "127.0.0.1:0") c.Assert(err, IsNil) addr := listener.Addr().(*net.TCPAddr) address := fmt.Sprintf("tcp:host=%s,port=%d", addr.IP.String(), addr.Port) trans, err := newTransport(address) c.Assert(err, IsNil) errChan := make(chan error, 1) go func() { conn, err := listener.Accept() if err == nil { conn.Close() } errChan <- err }() conn, err := trans.Dial() c.Assert(err, IsNil) conn.Close() // Was the other end of the connection established correctly? err = <-errChan c.Check(err, IsNil) listener.Close() } func (s *S) TestNewTransportNonceTcp(c *C) { trans, err := newTransport("nonce-tcp:host=localhost,port=4444,noncefile=/tmp/foo") c.Check(err, Equals, nil) nonceTcpTrans, ok := trans.(*nonceTcpTransport) c.Check(ok, Equals, true) c.Check(nonceTcpTrans.Address, Equals, "localhost:4444") c.Check(nonceTcpTrans.Family, Equals, "tcp4") c.Check(nonceTcpTrans.NonceFile, Equals, "/tmp/foo") } func (s *S) TestNonceTcpTransportDial(c *C) { nonceFile := path.Join(c.MkDir(), "nonce-file") nonceData := []byte("nonce-data") c.Assert(ioutil.WriteFile(nonceFile, nonceData, 0600), IsNil) listener, err := net.Listen("tcp", "127.0.0.1:0") c.Assert(err, IsNil) addr := listener.Addr().(*net.TCPAddr) address := fmt.Sprintf("nonce-tcp:host=%s,port=%d,noncefile=%s", addr.IP.String(), addr.Port, nonceFile) trans, err := newTransport(address) c.Assert(err, IsNil) errChan := make(chan error, 1) go func() { conn, err := listener.Accept() if err != nil { errChan <- err return } // The client starts by writing the nonce data to the socket. data := make([]byte, 4096) n, err := conn.Read(data) if err != nil { conn.Close() errChan <- err return } if !bytes.Equal(data[:n], nonceData) { err = errors.New("Did not receive nonce data") } conn.Close() errChan <- err }() conn, err := trans.Dial() c.Assert(err, IsNil) conn.Close() // Was the other end of the connection established correctly? err = <-errChan c.Check(err, IsNil) listener.Close() } golang-go-dbus-1~bzr20140217/types.go000066400000000000000000000071531230051202400172440ustar00rootroot00000000000000package dbus import ( "errors" "fmt" "reflect" ) var ( typeObjectPather = reflect.TypeOf((*ObjectPather)(nil)).Elem() typeVariant = reflect.TypeOf(Variant{}) typeSignature = reflect.TypeOf(Signature("")) typeBlankInterface = reflect.TypeOf((*interface{})(nil)).Elem() ) type Signature string func SignatureOf(t reflect.Type) (Signature, error) { if t.AssignableTo(typeObjectPather) { return Signature("o"), nil } switch t.Kind() { case reflect.Uint8: return Signature("y"), nil case reflect.Bool: return Signature("b"), nil case reflect.Int16: return Signature("n"), nil case reflect.Uint16: return Signature("q"), nil case reflect.Int32: return Signature("i"), nil case reflect.Uint32: return Signature("u"), nil case reflect.Int64: return Signature("x"), nil case reflect.Uint64: return Signature("t"), nil case reflect.Float64: return Signature("d"), nil case reflect.String: if t == typeSignature { return Signature("g"), nil } return Signature("s"), nil case reflect.Array, reflect.Slice: valueSig, err := SignatureOf(t.Elem()) if err != nil { return Signature(""), err } return Signature("a") + valueSig, nil case reflect.Map: keySig, err := SignatureOf(t.Key()) if err != nil { return Signature(""), err } valueSig, err := SignatureOf(t.Elem()) if err != nil { return Signature(""), err } return Signature("a{") + keySig + valueSig + Signature("}"), nil case reflect.Struct: // Special case the variant structure if t == typeVariant { return Signature("v"), nil } sig := Signature("(") for i := 0; i != t.NumField(); i++ { fieldSig, err := SignatureOf(t.Field(i).Type) if err != nil { return Signature(""), err } sig += fieldSig } sig += Signature(")") return sig, nil case reflect.Ptr: // dereference pointers sig, err := SignatureOf(t.Elem()) return sig, err } return Signature(""), errors.New("Can not determine signature for " + t.String()) } func (sig Signature) NextType(offset int) (next int, err error) { if offset >= len(sig) { err = errors.New("No more types codes in signature") return } switch sig[offset] { case 'y', 'b', 'n', 'q', 'i', 'u', 'x', 't', 'd', 's', 'o', 'g', 'v', 'h': // A basic type code. next = offset + 1 case 'a': // An array: consume the embedded type code next, err = sig.NextType(offset + 1) case '{': // A pair used in maps: consume the two contained types next, err = sig.NextType(offset + 1) if err != nil { return } next, err = sig.NextType(next) if err != nil { return } if next >= len(sig) || sig[next] != '}' { err = errors.New("Pair does not end with '}'") return } next += 1 case '(': // A struct: consume types until we next = offset + 1 for { if next < len(sig) && sig[next] == ')' { next += 1 return } next, err = sig.NextType(next) if err != nil { return } } default: err = errors.New("Unknown type code " + string(sig[offset])) } return } // Validate that the signature is a valid string of type codes func (sig Signature) Validate() (err error) { offset := 0 for offset < len(sig) { offset, err = sig.NextType(offset) if err != nil { break } } return } type ObjectPath string type ObjectPather interface { ObjectPath() ObjectPath } func (o ObjectPath) ObjectPath() ObjectPath { return o } type Variant struct { Value interface{} } func (v *Variant) GetVariantSignature() (Signature, error) { return SignatureOf(reflect.TypeOf(v.Value)) } type Error struct { Name string Message string } func (e *Error) Error() string { return fmt.Sprint(e.Name, ": ", e.Message) } golang-go-dbus-1~bzr20140217/types_test.go000066400000000000000000000037061230051202400203030ustar00rootroot00000000000000package dbus import . "launchpad.net/gocheck" func (s *S) TestSignatureNextType(c *C) { // NextType() works for basic types for _, sig := range []Signature{"y", "b", "n", "q", "i", "u", "x", "t", "d", "s", "o", "g", "v", "h"} { next, err := sig.NextType(0) c.Check(next, Equals, 1) c.Check(err, Equals, nil) } // Unknown type code gives error next, err := Signature("_").NextType(0) c.Check(err, Not(Equals), nil) // Offset inside signature next, err = Signature("ii").NextType(1) c.Check(next, Equals, 2) c.Check(err, Equals, nil) // Error if there is no more type codes in signature next, err = Signature("i").NextType(1) c.Check(err, Not(Equals), nil) // Arrays consume their element type code next, err = Signature("ai").NextType(0) c.Check(next, Equals, 2) c.Check(err, Equals, nil) // Array without element type code gives error next, err = Signature("a").NextType(0) c.Check(err, Not(Equals), nil) // Structs are consumed entirely next, err = Signature("(isv)").NextType(0) c.Check(next, Equals, 5) c.Check(err, Equals, nil) // Incomplete struct gives error next, err = Signature("(isv").NextType(0) c.Check(err, Not(Equals), nil) // Dict entries have two contained type codes next, err = Signature("{ii}").NextType(0) c.Check(next, Equals, 4) c.Check(err, Equals, nil) next, err = Signature("{}").NextType(0) c.Check(err, Not(Equals), nil) next, err = Signature("{i}").NextType(0) c.Check(err, Not(Equals), nil) next, err = Signature("{iii}").NextType(0) c.Check(err, Not(Equals), nil) next, err = Signature("{ii").NextType(0) c.Check(err, Not(Equals), nil) // Now a recursive type combining the above. next, err = Signature("a{s(saax)}").NextType(0) c.Check(next, Equals, 10) c.Check(err, Equals, nil) } func (s *S) TestSignatureValidate(c *C) { c.Check(Signature("a{s(sax)}aav").Validate(), Equals, nil) c.Check(Signature("a").Validate(), Not(Equals), nil) c.Check(Signature("a(ii").Validate(), Not(Equals), nil) }