Bump dependency github.com/godbus/dbus@v19 (2ff6f7ffd60f)

This commit is contained in:
Odin Ugedal 2019-10-05 14:37:48 +02:00
parent c07408380d
commit 42d1238962
No known key found for this signature in database
GPG Key ID: AFF9C8242CF7A7AF
23 changed files with 768 additions and 293 deletions

4
go.mod
View File

@ -61,7 +61,7 @@ require (
github.com/go-openapi/strfmt v0.19.0 github.com/go-openapi/strfmt v0.19.0
github.com/go-openapi/validate v0.19.2 github.com/go-openapi/validate v0.19.2
github.com/go-ozzo/ozzo-validation v3.5.0+incompatible // indirect github.com/go-ozzo/ozzo-validation v3.5.0+incompatible // indirect
github.com/godbus/dbus v4.1.0+incompatible // indirect github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f // indirect
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903
github.com/golang/mock v1.2.0 github.com/golang/mock v1.2.0
@ -275,7 +275,7 @@ replace (
github.com/go-openapi/validate => github.com/go-openapi/validate v0.19.2 github.com/go-openapi/validate => github.com/go-openapi/validate v0.19.2
github.com/go-ozzo/ozzo-validation => github.com/go-ozzo/ozzo-validation v3.5.0+incompatible github.com/go-ozzo/ozzo-validation => github.com/go-ozzo/ozzo-validation v3.5.0+incompatible
github.com/go-stack/stack => github.com/go-stack/stack v1.8.0 github.com/go-stack/stack => github.com/go-stack/stack v1.8.0
github.com/godbus/dbus => github.com/godbus/dbus v4.1.0+incompatible github.com/godbus/dbus => github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f
github.com/gogo/protobuf => github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d github.com/gogo/protobuf => github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d
github.com/golang/glog => github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/glog => github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/groupcache => github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 github.com/golang/groupcache => github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903

4
go.sum
View File

@ -185,8 +185,8 @@ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2K
github.com/go-ozzo/ozzo-validation v3.5.0+incompatible h1:sUy/in/P6askYr16XJgTKq/0SZhiWsdg4WZGaLsGQkM= github.com/go-ozzo/ozzo-validation v3.5.0+incompatible h1:sUy/in/P6askYr16XJgTKq/0SZhiWsdg4WZGaLsGQkM=
github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4= github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f h1:zlOR3rOlPAVvtfuxGKoghCmop5B0TRyu/ZieziZuGiM=
github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=

View File

@ -4,8 +4,10 @@ go_import_path: github.com/godbus/dbus
sudo: true sudo: true
go: go:
- 1.6.3
- 1.7.3 - 1.7.3
- 1.8.7
- 1.9.5
- 1.10.1
- tip - tip
env: env:
@ -38,3 +40,7 @@ addons:
- dbus-x11 - dbus-x11
before_install: before_install:
script:
- go test -v -race ./... # Run all the tests with the race detector enabled
- go vet ./... # go vet is the official Go static analyzer

View File

@ -4,12 +4,15 @@ go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"auth.go", "auth.go",
"auth_anonymous.go",
"auth_external.go", "auth_external.go",
"auth_sha1.go", "auth_sha1.go",
"call.go", "call.go",
"conn.go", "conn.go",
"conn_darwin.go", "conn_darwin.go",
"conn_other.go", "conn_other.go",
"conn_unix.go",
"conn_windows.go",
"dbus.go", "dbus.go",
"decoder.go", "decoder.go",
"default_handler.go", "default_handler.go",
@ -24,6 +27,7 @@ go_library(
"sig.go", "sig.go",
"transport_darwin.go", "transport_darwin.go",
"transport_generic.go", "transport_generic.go",
"transport_nonce_tcp.go",
"transport_tcp.go", "transport_tcp.go",
"transport_unix.go", "transport_unix.go",
"transport_unixcred_dragonfly.go", "transport_unixcred_dragonfly.go",

View File

@ -14,7 +14,7 @@ D-Bus message bus system.
### Installation ### Installation
This packages requires Go 1.1. If you installed it and set up your GOPATH, just run: This packages requires Go 1.7. If you installed it and set up your GOPATH, just run:
``` ```
go get github.com/godbus/dbus go get github.com/godbus/dbus

View File

@ -116,7 +116,6 @@ func (conn *Conn) Auth(methods []Auth) error {
return err return err
} }
go conn.inWorker() go conn.inWorker()
go conn.outWorker()
return nil return nil
} }
} }

16
vendor/github.com/godbus/dbus/auth_anonymous.go generated vendored Normal file
View File

@ -0,0 +1,16 @@
package dbus
// AuthAnonymous returns an Auth that uses the ANONYMOUS mechanism.
func AuthAnonymous() Auth {
return &authAnonymous{}
}
type authAnonymous struct{}
func (a *authAnonymous) FirstData() (name, resp []byte, status AuthStatus) {
return []byte("ANONYMOUS"), nil, AuthOk
}
func (a *authAnonymous) HandleData(data []byte) (resp []byte, status AuthStatus) {
return nil, AuthError
}

View File

@ -1,9 +1,12 @@
package dbus package dbus
import ( import (
"context"
"errors" "errors"
) )
var errSignature = errors.New("dbus: mismatched signature")
// Call represents a pending or completed method call. // Call represents a pending or completed method call.
type Call struct { type Call struct {
Destination string Destination string
@ -20,9 +23,25 @@ type Call struct {
// Holds the response once the call is done. // Holds the response once the call is done.
Body []interface{} Body []interface{}
// tracks context and canceler
ctx context.Context
ctxCanceler context.CancelFunc
} }
var errSignature = errors.New("dbus: mismatched signature") func (c *Call) Context() context.Context {
if c.ctx == nil {
return context.Background()
}
return c.ctx
}
func (c *Call) ContextCancel() {
if c.ctxCanceler != nil {
c.ctxCanceler()
}
}
// Store stores the body of the reply into the provided pointers. It returns // Store stores the body of the reply into the provided pointers. It returns
// an error if the signatures of the body and retvalues don't match, or if // an error if the signatures of the body and retvalues don't match, or if
@ -34,3 +53,8 @@ func (c *Call) Store(retvalues ...interface{}) error {
return Store(c.Body, retvalues...) return Store(c.Body, retvalues...)
} }
func (c *Call) done() {
c.Done <- c
c.ContextCancel()
}

616
vendor/github.com/godbus/dbus/conn.go generated vendored
View File

@ -1,6 +1,7 @@
package dbus package dbus
import ( import (
"context"
"errors" "errors"
"io" "io"
"os" "os"
@ -14,7 +15,6 @@ var (
systemBusLck sync.Mutex systemBusLck sync.Mutex
sessionBus *Conn sessionBus *Conn
sessionBusLck sync.Mutex sessionBusLck sync.Mutex
sessionEnvLck sync.Mutex
) )
// ErrClosed is the error returned by calls on a closed connection. // ErrClosed is the error returned by calls on a closed connection.
@ -35,23 +35,13 @@ type Conn struct {
unixFD bool unixFD bool
uuid string uuid string
names []string handler Handler
namesLck sync.RWMutex
serialLck sync.Mutex
nextSerial uint32
serialUsed map[uint32]bool
calls map[uint32]*Call
callsLck sync.RWMutex
handler Handler
out chan *Message
closed bool
outLck sync.RWMutex
signalHandler SignalHandler signalHandler SignalHandler
serialGen SerialGenerator
names *nameTracker
calls *callTracker
outHandler *outputHandler
eavesdropped chan<- *Message eavesdropped chan<- *Message
eavesdroppedLck sync.Mutex eavesdroppedLck sync.Mutex
@ -87,32 +77,31 @@ func SessionBus() (conn *Conn, err error) {
} }
func getSessionBusAddress() (string, error) { func getSessionBusAddress() (string, error) {
sessionEnvLck.Lock() if address := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); address != "" && address != "autolaunch:" {
defer sessionEnvLck.Unlock() return address, nil
address := os.Getenv("DBUS_SESSION_BUS_ADDRESS")
if address != "" && address != "autolaunch:" { } else if address := tryDiscoverDbusSessionBusAddress(); address != "" {
os.Setenv("DBUS_SESSION_BUS_ADDRESS", address)
return address, nil return address, nil
} }
return getSessionBusPlatformAddress() return getSessionBusPlatformAddress()
} }
// SessionBusPrivate returns a new private connection to the session bus. // SessionBusPrivate returns a new private connection to the session bus.
func SessionBusPrivate() (*Conn, error) { func SessionBusPrivate(opts ...ConnOption) (*Conn, error) {
address, err := getSessionBusAddress() address, err := getSessionBusAddress()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return Dial(address) return Dial(address, opts...)
} }
// SessionBusPrivate returns a new private connection to the session bus. // SessionBusPrivate returns a new private connection to the session bus.
//
// Deprecated: use SessionBusPrivate with options instead.
func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) { func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) {
address, err := getSessionBusAddress() return SessionBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler))
if err != nil {
return nil, err
}
return DialHandler(address, handler, signalHandler)
} }
// SystemBus returns a shared connection to the system bus, connecting to it if // SystemBus returns a shared connection to the system bus, connecting to it if
@ -145,53 +134,93 @@ func SystemBus() (conn *Conn, err error) {
} }
// SystemBusPrivate returns a new private connection to the system bus. // SystemBusPrivate returns a new private connection to the system bus.
func SystemBusPrivate() (*Conn, error) { func SystemBusPrivate(opts ...ConnOption) (*Conn, error) {
return Dial(getSystemBusPlatformAddress()) return Dial(getSystemBusPlatformAddress(), opts...)
} }
// SystemBusPrivateHandler returns a new private connection to the system bus, using the provided handlers. // SystemBusPrivateHandler returns a new private connection to the system bus, using the provided handlers.
//
// Deprecated: use SystemBusPrivate with options instead.
func SystemBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) { func SystemBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) {
return DialHandler(getSystemBusPlatformAddress(), handler, signalHandler) return SystemBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler))
} }
// Dial establishes a new private connection to the message bus specified by address. // Dial establishes a new private connection to the message bus specified by address.
func Dial(address string) (*Conn, error) { func Dial(address string, opts ...ConnOption) (*Conn, error) {
tr, err := getTransport(address) tr, err := getTransport(address)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newConn(tr, NewDefaultHandler(), NewDefaultSignalHandler()) return newConn(tr, opts...)
} }
// DialHandler establishes a new private connection to the message bus specified by address, using the supplied handlers. // DialHandler establishes a new private connection to the message bus specified by address, using the supplied handlers.
//
// Deprecated: use Dial with options instead.
func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) { func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) {
tr, err := getTransport(address) return Dial(address, WithSignalHandler(signalHandler))
if err != nil { }
return nil, err
// ConnOption is a connection option.
type ConnOption func(conn *Conn) error
// WithHandler overrides the default handler.
func WithHandler(handler Handler) ConnOption {
return func(conn *Conn) error {
conn.handler = handler
return nil
}
}
// WithSignalHandler overrides the default signal handler.
func WithSignalHandler(handler SignalHandler) ConnOption {
return func(conn *Conn) error {
conn.signalHandler = handler
return nil
}
}
// WithSerialGenerator overrides the default signals generator.
func WithSerialGenerator(gen SerialGenerator) ConnOption {
return func(conn *Conn) error {
conn.serialGen = gen
return nil
} }
return newConn(tr, handler, signalHandler)
} }
// NewConn creates a new private *Conn from an already established connection. // NewConn creates a new private *Conn from an already established connection.
func NewConn(conn io.ReadWriteCloser) (*Conn, error) { func NewConn(conn io.ReadWriteCloser, opts ...ConnOption) (*Conn, error) {
return NewConnHandler(conn, NewDefaultHandler(), NewDefaultSignalHandler()) return newConn(genericTransport{conn}, opts...)
} }
// NewConnHandler creates a new private *Conn from an already established connection, using the supplied handlers. // NewConnHandler creates a new private *Conn from an already established connection, using the supplied handlers.
//
// Deprecated: use NewConn with options instead.
func NewConnHandler(conn io.ReadWriteCloser, handler Handler, signalHandler SignalHandler) (*Conn, error) { func NewConnHandler(conn io.ReadWriteCloser, handler Handler, signalHandler SignalHandler) (*Conn, error) {
return newConn(genericTransport{conn}, handler, signalHandler) return NewConn(genericTransport{conn}, WithHandler(handler), WithSignalHandler(signalHandler))
} }
// newConn creates a new *Conn from a transport. // newConn creates a new *Conn from a transport.
func newConn(tr transport, handler Handler, signalHandler SignalHandler) (*Conn, error) { func newConn(tr transport, opts ...ConnOption) (*Conn, error) {
conn := new(Conn) conn := new(Conn)
conn.transport = tr conn.transport = tr
conn.calls = make(map[uint32]*Call) for _, opt := range opts {
conn.out = make(chan *Message, 10) if err := opt(conn); err != nil {
conn.handler = handler return nil, err
conn.signalHandler = signalHandler }
conn.nextSerial = 1 }
conn.serialUsed = map[uint32]bool{0: true} conn.calls = newCallTracker()
if conn.handler == nil {
conn.handler = NewDefaultHandler()
}
if conn.signalHandler == nil {
conn.signalHandler = NewDefaultSignalHandler()
}
if conn.serialGen == nil {
conn.serialGen = newSerialGenerator()
}
conn.outHandler = &outputHandler{conn: conn}
conn.names = newNameTracker()
conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
return conn, nil return conn, nil
} }
@ -206,18 +235,7 @@ func (conn *Conn) BusObject() BusObject {
// and the channels passed to Eavesdrop and Signal are closed. This method must // and the channels passed to Eavesdrop and Signal are closed. This method must
// not be called on shared connections. // not be called on shared connections.
func (conn *Conn) Close() error { func (conn *Conn) Close() error {
conn.outLck.Lock() conn.outHandler.close()
if conn.closed {
// inWorker calls Close on read error, the read error may
// be caused by another caller calling Close to shutdown the
// dbus connection, a double-close scenario we prevent here.
conn.outLck.Unlock()
return nil
}
close(conn.out)
conn.closed = true
conn.outLck.Unlock()
if term, ok := conn.signalHandler.(Terminator); ok { if term, ok := conn.signalHandler.(Terminator); ok {
term.Terminate() term.Terminate()
} }
@ -249,17 +267,9 @@ func (conn *Conn) Eavesdrop(ch chan<- *Message) {
conn.eavesdroppedLck.Unlock() conn.eavesdroppedLck.Unlock()
} }
// getSerial returns an unused serial. // GetSerial returns an unused serial.
func (conn *Conn) getSerial() uint32 { func (conn *Conn) getSerial() uint32 {
conn.serialLck.Lock() return conn.serialGen.GetSerial()
defer conn.serialLck.Unlock()
n := conn.nextSerial
for conn.serialUsed[n] {
n++
}
conn.serialUsed[n] = true
conn.nextSerial = n + 1
return n
} }
// Hello sends the initial org.freedesktop.DBus.Hello call. This method must be // Hello sends the initial org.freedesktop.DBus.Hello call. This method must be
@ -271,10 +281,7 @@ func (conn *Conn) Hello() error {
if err != nil { if err != nil {
return err return err
} }
conn.namesLck.Lock() conn.names.acquireUniqueConnectionName(s)
conn.names = make([]string, 1)
conn.names[0] = s
conn.namesLck.Unlock()
return nil return nil
} }
@ -283,109 +290,48 @@ func (conn *Conn) Hello() error {
func (conn *Conn) inWorker() { func (conn *Conn) inWorker() {
for { for {
msg, err := conn.ReadMessage() msg, err := conn.ReadMessage()
if err == nil { if err != nil {
conn.eavesdroppedLck.Lock() if _, ok := err.(InvalidMessageError); !ok {
if conn.eavesdropped != nil { // Some read error occured (usually EOF); we can't really do
select { // anything but to shut down all stuff and returns errors to all
case conn.eavesdropped <- msg: // pending replies.
default: conn.Close()
} conn.calls.finalizeAllWithError(err)
conn.eavesdroppedLck.Unlock() return
continue }
// invalid messages are ignored
continue
}
conn.eavesdroppedLck.Lock()
if conn.eavesdropped != nil {
select {
case conn.eavesdropped <- msg:
default:
} }
conn.eavesdroppedLck.Unlock() conn.eavesdroppedLck.Unlock()
dest, _ := msg.Headers[FieldDestination].value.(string) continue
found := false
if dest == "" {
found = true
} else {
conn.namesLck.RLock()
if len(conn.names) == 0 {
found = true
}
for _, v := range conn.names {
if dest == v {
found = true
break
}
}
conn.namesLck.RUnlock()
}
if !found {
// Eavesdropped a message, but no channel for it is registered.
// Ignore it.
continue
}
switch msg.Type {
case TypeMethodReply, TypeError:
serial := msg.Headers[FieldReplySerial].value.(uint32)
conn.callsLck.Lock()
if c, ok := conn.calls[serial]; ok {
if msg.Type == TypeError {
name, _ := msg.Headers[FieldErrorName].value.(string)
c.Err = Error{name, msg.Body}
} else {
c.Body = msg.Body
}
c.Done <- c
conn.serialLck.Lock()
delete(conn.serialUsed, serial)
conn.serialLck.Unlock()
delete(conn.calls, serial)
}
conn.callsLck.Unlock()
case TypeSignal:
iface := msg.Headers[FieldInterface].value.(string)
member := msg.Headers[FieldMember].value.(string)
// as per http://dbus.freedesktop.org/doc/dbus-specification.html ,
// sender is optional for signals.
sender, _ := msg.Headers[FieldSender].value.(string)
if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" {
if member == "NameLost" {
// If we lost the name on the bus, remove it from our
// tracking list.
name, ok := msg.Body[0].(string)
if !ok {
panic("Unable to read the lost name")
}
conn.namesLck.Lock()
for i, v := range conn.names {
if v == name {
conn.names = append(conn.names[:i],
conn.names[i+1:]...)
}
}
conn.namesLck.Unlock()
} else if member == "NameAcquired" {
// If we acquired the name on the bus, add it to our
// tracking list.
name, ok := msg.Body[0].(string)
if !ok {
panic("Unable to read the acquired name")
}
conn.namesLck.Lock()
conn.names = append(conn.names, name)
conn.namesLck.Unlock()
}
}
conn.handleSignal(msg)
case TypeMethodCall:
go conn.handleCall(msg)
}
} else if _, ok := err.(InvalidMessageError); !ok {
// Some read error occured (usually EOF); we can't really do
// anything but to shut down all stuff and returns errors to all
// pending replies.
conn.Close()
conn.callsLck.RLock()
for _, v := range conn.calls {
v.Err = err
v.Done <- v
}
conn.callsLck.RUnlock()
return
} }
// invalid messages are ignored conn.eavesdroppedLck.Unlock()
dest, _ := msg.Headers[FieldDestination].value.(string)
found := dest == "" ||
!conn.names.uniqueNameIsKnown() ||
conn.names.isKnownName(dest)
if !found {
// Eavesdropped a message, but no channel for it is registered.
// Ignore it.
continue
}
switch msg.Type {
case TypeError:
conn.serialGen.RetireSerial(conn.calls.handleDBusError(msg))
case TypeMethodReply:
conn.serialGen.RetireSerial(conn.calls.handleReply(msg))
case TypeSignal:
conn.handleSignal(msg)
case TypeMethodCall:
go conn.handleCall(msg)
}
} }
} }
@ -395,6 +341,25 @@ func (conn *Conn) handleSignal(msg *Message) {
// as per http://dbus.freedesktop.org/doc/dbus-specification.html , // as per http://dbus.freedesktop.org/doc/dbus-specification.html ,
// sender is optional for signals. // sender is optional for signals.
sender, _ := msg.Headers[FieldSender].value.(string) sender, _ := msg.Headers[FieldSender].value.(string)
if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" {
if member == "NameLost" {
// If we lost the name on the bus, remove it from our
// tracking list.
name, ok := msg.Body[0].(string)
if !ok {
panic("Unable to read the lost name")
}
conn.names.loseName(name)
} else if member == "NameAcquired" {
// If we acquired the name on the bus, add it to our
// tracking list.
name, ok := msg.Body[0].(string)
if !ok {
panic("Unable to read the acquired name")
}
conn.names.acquireName(name)
}
}
signal := &Signal{ signal := &Signal{
Sender: sender, Sender: sender,
Path: msg.Headers[FieldPath].value.(ObjectPath), Path: msg.Headers[FieldPath].value.(ObjectPath),
@ -408,12 +373,7 @@ func (conn *Conn) handleSignal(msg *Message) {
// connection. The slice is always at least one element long, the first element // connection. The slice is always at least one element long, the first element
// being the unique name of the connection. // being the unique name of the connection.
func (conn *Conn) Names() []string { func (conn *Conn) Names() []string {
conn.namesLck.RLock() return conn.names.listKnownNames()
// copy the slice so it can't be modified
s := make([]string, len(conn.names))
copy(s, conn.names)
conn.namesLck.RUnlock()
return s
} }
// Object returns the object identified by the given destination name and path. // Object returns the object identified by the given destination name and path.
@ -423,24 +383,17 @@ func (conn *Conn) Object(dest string, path ObjectPath) BusObject {
// outWorker runs in an own goroutine, encoding and sending messages that are // outWorker runs in an own goroutine, encoding and sending messages that are
// sent to conn.out. // sent to conn.out.
func (conn *Conn) outWorker() { func (conn *Conn) sendMessage(msg *Message) {
for msg := range conn.out { conn.sendMessageAndIfClosed(msg, func() {})
err := conn.SendMessage(msg) }
conn.callsLck.RLock()
if err != nil { func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) {
if c := conn.calls[msg.serial]; c != nil { err := conn.outHandler.sendAndIfClosed(msg, ifClosed)
c.Err = err conn.calls.handleSendError(msg, err)
c.Done <- c if err != nil {
} conn.serialGen.RetireSerial(msg.serial)
conn.serialLck.Lock() } else if msg.Type != TypeMethodCall {
delete(conn.serialUsed, msg.serial) conn.serialGen.RetireSerial(msg.serial)
conn.serialLck.Unlock()
} else if msg.Type != TypeMethodCall {
conn.serialLck.Lock()
delete(conn.serialUsed, msg.serial)
conn.serialLck.Unlock()
}
conn.callsLck.RUnlock()
} }
} }
@ -451,8 +404,21 @@ func (conn *Conn) outWorker() {
// once the call is complete. Otherwise, ch is ignored and a Call structure is // once the call is complete. Otherwise, ch is ignored and a Call structure is
// returned of which only the Err member is valid. // returned of which only the Err member is valid.
func (conn *Conn) Send(msg *Message, ch chan *Call) *Call { func (conn *Conn) Send(msg *Message, ch chan *Call) *Call {
var call *Call return conn.send(context.Background(), msg, ch)
}
// SendWithContext acts like Send but takes a context
func (conn *Conn) SendWithContext(ctx context.Context, msg *Message, ch chan *Call) *Call {
return conn.send(ctx, msg, ch)
}
func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call {
if ctx == nil {
panic("nil context")
}
var call *Call
ctx, canceler := context.WithCancel(ctx)
msg.serial = conn.getSerial() msg.serial = conn.getSerial()
if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 { if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 {
if ch == nil { if ch == nil {
@ -468,26 +434,23 @@ func (conn *Conn) Send(msg *Message, ch chan *Call) *Call {
call.Method = iface + "." + member call.Method = iface + "." + member
call.Args = msg.Body call.Args = msg.Body
call.Done = ch call.Done = ch
conn.callsLck.Lock() call.ctx = ctx
conn.calls[msg.serial] = call call.ctxCanceler = canceler
conn.callsLck.Unlock() conn.calls.track(msg.serial, call)
conn.outLck.RLock() go func() {
if conn.closed { <-ctx.Done()
call.Err = ErrClosed conn.calls.handleSendError(msg, ctx.Err())
call.Done <- call }()
} else { conn.sendMessageAndIfClosed(msg, func() {
conn.out <- msg conn.calls.handleSendError(msg, ErrClosed)
} canceler()
conn.outLck.RUnlock() })
} else { } else {
conn.outLck.RLock() canceler()
if conn.closed { call = &Call{Err: nil}
conn.sendMessageAndIfClosed(msg, func() {
call = &Call{Err: ErrClosed} call = &Call{Err: ErrClosed}
} else { })
conn.out <- msg
call = &Call{Err: nil}
}
conn.outLck.RUnlock()
} }
return call return call
} }
@ -520,11 +483,7 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) {
if len(e.Body) > 0 { if len(e.Body) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...)) msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...))
} }
conn.outLck.RLock() conn.sendMessage(msg)
if !conn.closed {
conn.out <- msg
}
conn.outLck.RUnlock()
} }
// sendReply creates a method reply message corresponding to the parameters and // sendReply creates a method reply message corresponding to the parameters and
@ -542,11 +501,7 @@ func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
if len(values) > 0 { if len(values) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
} }
conn.outLck.RLock() conn.sendMessage(msg)
if !conn.closed {
conn.out <- msg
}
conn.outLck.RUnlock()
} }
func (conn *Conn) defaultSignalAction(fn func(h *defaultSignalHandler, ch chan<- *Signal), ch chan<- *Signal) { func (conn *Conn) defaultSignalAction(fn func(h *defaultSignalHandler, ch chan<- *Signal), ch chan<- *Signal) {
@ -681,3 +636,212 @@ func getKey(s, key string) string {
} }
return "" return ""
} }
type outputHandler struct {
conn *Conn
sendLck sync.Mutex
closed struct {
isClosed bool
lck sync.RWMutex
}
}
func (h *outputHandler) sendAndIfClosed(msg *Message, ifClosed func()) error {
h.closed.lck.RLock()
defer h.closed.lck.RUnlock()
if h.closed.isClosed {
ifClosed()
return nil
}
h.sendLck.Lock()
defer h.sendLck.Unlock()
return h.conn.SendMessage(msg)
}
func (h *outputHandler) close() {
h.closed.lck.Lock()
defer h.closed.lck.Unlock()
h.closed.isClosed = true
}
type serialGenerator struct {
lck sync.Mutex
nextSerial uint32
serialUsed map[uint32]bool
}
func newSerialGenerator() *serialGenerator {
return &serialGenerator{
serialUsed: map[uint32]bool{0: true},
nextSerial: 1,
}
}
func (gen *serialGenerator) GetSerial() uint32 {
gen.lck.Lock()
defer gen.lck.Unlock()
n := gen.nextSerial
for gen.serialUsed[n] {
n++
}
gen.serialUsed[n] = true
gen.nextSerial = n + 1
return n
}
func (gen *serialGenerator) RetireSerial(serial uint32) {
gen.lck.Lock()
defer gen.lck.Unlock()
delete(gen.serialUsed, serial)
}
type nameTracker struct {
lck sync.RWMutex
unique string
names map[string]struct{}
}
func newNameTracker() *nameTracker {
return &nameTracker{names: map[string]struct{}{}}
}
func (tracker *nameTracker) acquireUniqueConnectionName(name string) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
tracker.unique = name
}
func (tracker *nameTracker) acquireName(name string) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
tracker.names[name] = struct{}{}
}
func (tracker *nameTracker) loseName(name string) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
delete(tracker.names, name)
}
func (tracker *nameTracker) uniqueNameIsKnown() bool {
tracker.lck.RLock()
defer tracker.lck.RUnlock()
return tracker.unique != ""
}
func (tracker *nameTracker) isKnownName(name string) bool {
tracker.lck.RLock()
defer tracker.lck.RUnlock()
_, ok := tracker.names[name]
return ok || name == tracker.unique
}
func (tracker *nameTracker) listKnownNames() []string {
tracker.lck.RLock()
defer tracker.lck.RUnlock()
out := make([]string, 0, len(tracker.names)+1)
out = append(out, tracker.unique)
for k := range tracker.names {
out = append(out, k)
}
return out
}
type callTracker struct {
calls map[uint32]*Call
lck sync.RWMutex
}
func newCallTracker() *callTracker {
return &callTracker{calls: map[uint32]*Call{}}
}
func (tracker *callTracker) track(sn uint32, call *Call) {
tracker.lck.Lock()
tracker.calls[sn] = call
tracker.lck.Unlock()
}
func (tracker *callTracker) handleReply(msg *Message) uint32 {
serial := msg.Headers[FieldReplySerial].value.(uint32)
tracker.lck.RLock()
_, ok := tracker.calls[serial]
tracker.lck.RUnlock()
if ok {
tracker.finalizeWithBody(serial, msg.Body)
}
return serial
}
func (tracker *callTracker) handleDBusError(msg *Message) uint32 {
serial := msg.Headers[FieldReplySerial].value.(uint32)
tracker.lck.RLock()
_, ok := tracker.calls[serial]
tracker.lck.RUnlock()
if ok {
name, _ := msg.Headers[FieldErrorName].value.(string)
tracker.finalizeWithError(serial, Error{name, msg.Body})
}
return serial
}
func (tracker *callTracker) handleSendError(msg *Message, err error) {
if err == nil {
return
}
tracker.lck.RLock()
_, ok := tracker.calls[msg.serial]
tracker.lck.RUnlock()
if ok {
tracker.finalizeWithError(msg.serial, err)
}
}
// finalize was the only func that did not strobe Done
func (tracker *callTracker) finalize(sn uint32) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
c, ok := tracker.calls[sn]
if ok {
delete(tracker.calls, sn)
c.ContextCancel()
}
return
}
func (tracker *callTracker) finalizeWithBody(sn uint32, body []interface{}) {
tracker.lck.Lock()
c, ok := tracker.calls[sn]
if ok {
delete(tracker.calls, sn)
}
tracker.lck.Unlock()
if ok {
c.Body = body
c.done()
}
return
}
func (tracker *callTracker) finalizeWithError(sn uint32, err error) {
tracker.lck.Lock()
c, ok := tracker.calls[sn]
if ok {
delete(tracker.calls, sn)
}
tracker.lck.Unlock()
if ok {
c.Err = err
c.done()
}
return
}
func (tracker *callTracker) finalizeAllWithError(err error) {
tracker.lck.Lock()
closedCalls := make([]*Call, 0, len(tracker.calls))
for sn := range tracker.calls {
closedCalls = append(closedCalls, tracker.calls[sn])
}
tracker.calls = map[uint32]*Call{}
tracker.lck.Unlock()
for _, call := range closedCalls {
call.Err = err
call.done()
}
}

View File

@ -31,3 +31,7 @@ func getSystemBusPlatformAddress() string {
} }
return defaultSystemBusAddress return defaultSystemBusAddress
} }
func tryDiscoverDbusSessionBusAddress() string {
return ""
}

View File

@ -6,12 +6,14 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"os/user"
"path"
"strings"
) )
const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket"
func getSessionBusPlatformAddress() (string, error) { func getSessionBusPlatformAddress() (string, error) {
cmd := exec.Command("dbus-launch") cmd := exec.Command("dbus-launch")
b, err := cmd.CombinedOutput() b, err := cmd.CombinedOutput()
@ -33,10 +35,57 @@ func getSessionBusPlatformAddress() (string, error) {
return addr, nil return addr, nil
} }
func getSystemBusPlatformAddress() string { // tryDiscoverDbusSessionBusAddress tries to discover an existing dbus session
address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS") // and return the value of its DBUS_SESSION_BUS_ADDRESS.
if address != "" { // It tries different techniques employed by different operating systems,
return fmt.Sprintf("unix:path=%s", address) // returning the first valid address it finds, or an empty string.
//
// * /run/user/<uid>/bus if this exists, it *is* the bus socket. present on
// Ubuntu 18.04
// * /run/user/<uid>/dbus-session: if this exists, it can be parsed for the bus
// address. present on Ubuntu 16.04
//
// See https://dbus.freedesktop.org/doc/dbus-launch.1.html
func tryDiscoverDbusSessionBusAddress() string {
if runtimeDirectory, err := getRuntimeDirectory(); err == nil {
if runUserBusFile := path.Join(runtimeDirectory, "bus"); fileExists(runUserBusFile) {
// if /run/user/<uid>/bus exists, that file itself
// *is* the unix socket, so return its path
return fmt.Sprintf("unix:path=%s", runUserBusFile)
}
if runUserSessionDbusFile := path.Join(runtimeDirectory, "dbus-session"); fileExists(runUserSessionDbusFile) {
// if /run/user/<uid>/dbus-session exists, it's a
// text file // containing the address of the socket, e.g.:
// DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-E1c73yNqrG
if f, err := ioutil.ReadFile(runUserSessionDbusFile); err == nil {
fileContent := string(f)
prefix := "DBUS_SESSION_BUS_ADDRESS="
if strings.HasPrefix(fileContent, prefix) {
address := strings.TrimRight(strings.TrimPrefix(fileContent, prefix), "\n\r")
return address
}
}
}
}
return ""
}
func getRuntimeDirectory() (string, error) {
if currentUser, err := user.Current(); err != nil {
return "", err
} else {
return fmt.Sprintf("/run/user/%s", currentUser.Uid), nil
}
}
func fileExists(filename string) bool {
if _, err := os.Stat(filename); !os.IsNotExist(err) {
return true
} else {
return false
} }
return defaultSystemBusAddress
} }

18
vendor/github.com/godbus/dbus/conn_unix.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
//+build !windows,!solaris,!darwin
package dbus
import (
"os"
"fmt"
)
const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket"
func getSystemBusPlatformAddress() string {
address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS")
if address != "" {
return fmt.Sprintf("unix:path=%s", address)
}
return defaultSystemBusAddress
}

15
vendor/github.com/godbus/dbus/conn_windows.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
//+build windows
package dbus
import "os"
const defaultSystemBusAddress = "tcp:host=127.0.0.1,port=12434"
func getSystemBusPlatformAddress() string {
address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS")
if address != "" {
return address
}
return defaultSystemBusAddress
}

View File

@ -191,7 +191,14 @@ func (dec *decoder) decode(s string, depth int) interface{} {
length := dec.decode("u", depth).(uint32) length := dec.decode("u", depth).(uint32)
v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length)) v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length))
// Even for empty arrays, the correct padding must be included // Even for empty arrays, the correct padding must be included
dec.align(alignment(typeFor(s[1:]))) align := alignment(typeFor(s[1:]))
if len(s) > 1 && s[1] == '(' {
//Special case for arrays of structs
//structs decode as a slice of interface{} values
//but the dbus alignment does not match this
align = 8
}
dec.align(align)
spos := dec.pos spos := dec.pos
for dec.pos < spos+int(length) { for dec.pos < spos+int(length) {
ev := dec.decode(s[1:], depth+1) ev := dec.decode(s[1:], depth+1)

View File

@ -21,6 +21,8 @@ func newIntrospectIntf(h *defaultHandler) *exportedIntf {
//NewDefaultHandler returns an instance of the default //NewDefaultHandler returns an instance of the default
//call handler. This is useful if you want to implement only //call handler. This is useful if you want to implement only
//one of the two handlers but not both. //one of the two handlers but not both.
//
// Deprecated: this is the default value, don't use it, it will be unexported.
func NewDefaultHandler() *defaultHandler { func NewDefaultHandler() *defaultHandler {
h := &defaultHandler{ h := &defaultHandler{
objects: make(map[ObjectPath]*exportedObj), objects: make(map[ObjectPath]*exportedObj),
@ -161,6 +163,7 @@ func newExportedObject() *exportedObj {
} }
type exportedObj struct { type exportedObj struct {
mu sync.RWMutex
interfaces map[string]*exportedIntf interfaces map[string]*exportedIntf
} }
@ -168,19 +171,27 @@ func (obj *exportedObj) LookupInterface(name string) (Interface, bool) {
if name == "" { if name == "" {
return obj, true return obj, true
} }
obj.mu.RLock()
defer obj.mu.RUnlock()
intf, exists := obj.interfaces[name] intf, exists := obj.interfaces[name]
return intf, exists return intf, exists
} }
func (obj *exportedObj) AddInterface(name string, iface *exportedIntf) { func (obj *exportedObj) AddInterface(name string, iface *exportedIntf) {
obj.mu.Lock()
defer obj.mu.Unlock()
obj.interfaces[name] = iface obj.interfaces[name] = iface
} }
func (obj *exportedObj) DeleteInterface(name string) { func (obj *exportedObj) DeleteInterface(name string) {
obj.mu.Lock()
defer obj.mu.Unlock()
delete(obj.interfaces, name) delete(obj.interfaces, name)
} }
func (obj *exportedObj) LookupMethod(name string) (Method, bool) { func (obj *exportedObj) LookupMethod(name string) (Method, bool) {
obj.mu.RLock()
defer obj.mu.RUnlock()
for _, intf := range obj.interfaces { for _, intf := range obj.interfaces {
method, exists := intf.LookupMethod(name) method, exists := intf.LookupMethod(name)
if exists { if exists {
@ -220,8 +231,12 @@ func (obj *exportedIntf) isFallbackInterface() bool {
//NewDefaultSignalHandler returns an instance of the default //NewDefaultSignalHandler returns an instance of the default
//signal handler. This is useful if you want to implement only //signal handler. This is useful if you want to implement only
//one of the two handlers but not both. //one of the two handlers but not both.
//
// Deprecated: this is the default value, don't use it, it will be unexported.
func NewDefaultSignalHandler() *defaultSignalHandler { func NewDefaultSignalHandler() *defaultSignalHandler {
return &defaultSignalHandler{} return &defaultSignalHandler{
closeChan: make(chan struct{}),
}
} }
func isDefaultSignalHandler(handler SignalHandler) bool { func isDefaultSignalHandler(handler SignalHandler) bool {
@ -231,32 +246,47 @@ func isDefaultSignalHandler(handler SignalHandler) bool {
type defaultSignalHandler struct { type defaultSignalHandler struct {
sync.RWMutex sync.RWMutex
closed bool closed bool
signals []chan<- *Signal signals []chan<- *Signal
closeChan chan struct{}
} }
func (sh *defaultSignalHandler) DeliverSignal(intf, name string, signal *Signal) { func (sh *defaultSignalHandler) DeliverSignal(intf, name string, signal *Signal) {
go func() { sh.RLock()
sh.RLock() defer sh.RUnlock()
defer sh.RUnlock() if sh.closed {
if sh.closed { return
}
for _, ch := range sh.signals {
select {
case ch <- signal:
case <-sh.closeChan:
return return
default:
go func() {
select {
case ch <- signal:
case <-sh.closeChan:
return
}
}()
} }
for _, ch := range sh.signals { }
ch <- signal
}
}()
} }
func (sh *defaultSignalHandler) Init() error { func (sh *defaultSignalHandler) Init() error {
sh.Lock() sh.Lock()
sh.signals = make([]chan<- *Signal, 0) sh.signals = make([]chan<- *Signal, 0)
sh.closeChan = make(chan struct{})
sh.Unlock() sh.Unlock()
return nil return nil
} }
func (sh *defaultSignalHandler) Terminate() { func (sh *defaultSignalHandler) Terminate() {
sh.Lock() sh.Lock()
if !sh.closed {
close(sh.closeChan)
}
sh.closed = true sh.closed = true
for _, ch := range sh.signals { for _, ch := range sh.signals {
close(ch) close(ch)

View File

@ -170,11 +170,8 @@ func (conn *Conn) handleCall(msg *Message) {
reply.Body[i] = ret[i] reply.Body[i] = ret[i]
} }
reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...)) reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...))
conn.outLck.RLock()
if !conn.closed { conn.sendMessage(reply)
conn.out <- reply
}
conn.outLck.RUnlock()
} }
} }
@ -207,12 +204,14 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro
if len(values) > 0 { if len(values) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
} }
conn.outLck.RLock()
defer conn.outLck.RUnlock() var closed bool
if conn.closed { conn.sendMessageAndIfClosed(msg, func() {
closed = true
})
if closed {
return ErrClosed return ErrClosed
} }
conn.out <- msg
return nil return nil
} }

1
vendor/github.com/godbus/dbus/go.mod generated vendored Normal file
View File

@ -0,0 +1 @@
module github.com/godbus/dbus

View File

@ -1,6 +1,7 @@
package dbus package dbus
import ( import (
"context"
"errors" "errors"
"strings" "strings"
) )
@ -9,7 +10,11 @@ import (
// invoked. // invoked.
type BusObject interface { type BusObject interface {
Call(method string, flags Flags, args ...interface{}) *Call Call(method string, flags Flags, args ...interface{}) *Call
CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call
Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call
GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call
AddMatchSignal(iface, member string, options ...MatchOption) *Call
RemoveMatchSignal(iface, member string, options ...MatchOption) *Call
GetProperty(p string) (Variant, error) GetProperty(p string) (Variant, error)
Destination() string Destination() string
Path() ObjectPath Path() ObjectPath
@ -24,16 +29,73 @@ type Object struct {
// Call calls a method with (*Object).Go and waits for its reply. // Call calls a method with (*Object).Go and waits for its reply.
func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call { func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call {
return <-o.Go(method, flags, make(chan *Call, 1), args...).Done return <-o.createCall(context.Background(), method, flags, make(chan *Call, 1), args...).Done
} }
// AddMatchSignal subscribes BusObject to signals from specified interface and // CallWithContext acts like Call but takes a context
// method (member). func (o *Object) CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call {
func (o *Object) AddMatchSignal(iface, member string) *Call { return <-o.createCall(ctx, method, flags, make(chan *Call, 1), args...).Done
return o.Call( }
// MatchOption specifies option for dbus routing match rule. Options can be constructed with WithMatch* helpers.
// For full list of available options consult
// https://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing-match-rules
type MatchOption struct {
key string
value string
}
// WithMatchOption creates match option with given key and value
func WithMatchOption(key, value string) MatchOption {
return MatchOption{key, value}
}
// WithMatchObjectPath creates match option that filters events based on given path
func WithMatchObjectPath(path ObjectPath) MatchOption {
return MatchOption{"path", string(path)}
}
func formatMatchOptions(options []MatchOption) string {
items := make([]string, 0, len(options))
for _, option := range options {
items = append(items, option.key+"='"+option.value+"'")
}
return strings.Join(items, ",")
}
// AddMatchSignal subscribes BusObject to signals from specified interface,
// method (member). Additional filter rules can be added via WithMatch* option constructors.
// Note: To filter events by object path you have to specify this path via an option.
func (o *Object) AddMatchSignal(iface, member string, options ...MatchOption) *Call {
base := []MatchOption{
{"type", "signal"},
{"interface", iface},
{"member", member},
}
options = append(base, options...)
return o.conn.BusObject().Call(
"org.freedesktop.DBus.AddMatch", "org.freedesktop.DBus.AddMatch",
0, 0,
"type='signal',interface='"+iface+"',member='"+member+"'", formatMatchOptions(options),
)
}
// RemoveMatchSignal unsubscribes BusObject from signals from specified interface,
// method (member). Additional filter rules can be added via WithMatch* option constructors
func (o *Object) RemoveMatchSignal(iface, member string, options ...MatchOption) *Call {
base := []MatchOption{
{"type", "signal"},
{"interface", iface},
{"member", member},
}
options = append(base, options...)
return o.conn.BusObject().Call(
"org.freedesktop.DBus.RemoveMatch",
0,
formatMatchOptions(options),
) )
} }
@ -49,6 +111,18 @@ func (o *Object) AddMatchSignal(iface, member string) *Call {
// If the method parameter contains a dot ('.'), the part before the last dot // If the method parameter contains a dot ('.'), the part before the last dot
// specifies the interface on which the method is called. // specifies the interface on which the method is called.
func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call { func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
return o.createCall(context.Background(), method, flags, ch, args...)
}
// GoWithContext acts like Go but takes a context
func (o *Object) GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
return o.createCall(ctx, method, flags, ch, args...)
}
func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
if ctx == nil {
panic("nil context")
}
iface := "" iface := ""
i := strings.LastIndex(method, ".") i := strings.LastIndex(method, ".")
if i != -1 { if i != -1 {
@ -76,28 +150,28 @@ func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface
} else if cap(ch) == 0 { } else if cap(ch) == 0 {
panic("dbus: unbuffered channel passed to (*Object).Go") panic("dbus: unbuffered channel passed to (*Object).Go")
} }
ctx, cancel := context.WithCancel(ctx)
call := &Call{ call := &Call{
Destination: o.dest, Destination: o.dest,
Path: o.path, Path: o.path,
Method: method, Method: method,
Args: args, Args: args,
Done: ch, Done: ch,
ctxCanceler: cancel,
ctx: ctx,
} }
o.conn.callsLck.Lock() o.conn.calls.track(msg.serial, call)
o.conn.calls[msg.serial] = call o.conn.sendMessageAndIfClosed(msg, func() {
o.conn.callsLck.Unlock() o.conn.calls.handleSendError(msg, ErrClosed)
o.conn.outLck.RLock() cancel()
if o.conn.closed { })
call.Err = ErrClosed go func() {
call.Done <- call <-ctx.Done()
} else { o.conn.calls.handleSendError(msg, ctx.Err())
o.conn.out <- msg }()
}
o.conn.outLck.RUnlock()
return call return call
} }
o.conn.outLck.RLock()
defer o.conn.outLck.RUnlock()
done := make(chan *Call, 1) done := make(chan *Call, 1)
call := &Call{ call := &Call{
Err: nil, Err: nil,
@ -107,11 +181,9 @@ func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface
call.Done <- call call.Done <- call
close(done) close(done)
}() }()
if o.conn.closed { o.conn.sendMessageAndIfClosed(msg, func() {
call.Err = ErrClosed call.Err = ErrClosed
return call })
}
o.conn.out <- msg
return call return call
} }

View File

@ -87,3 +87,13 @@ type SignalHandler interface {
type DBusError interface { type DBusError interface {
DBusError() (string, []interface{}) DBusError() (string, []interface{})
} }
// SerialGenerator is responsible for serials generation.
//
// Different approaches for the serial generation can be used,
// maintaining a map guarded with a mutex (the standard way) or
// simply increment an atomic counter.
type SerialGenerator interface {
GetSerial() uint32
RetireSerial(serial uint32)
}

View File

@ -11,7 +11,7 @@ var nativeEndian binary.ByteOrder
func detectEndianness() binary.ByteOrder { func detectEndianness() binary.ByteOrder {
var x uint32 = 0x01020304 var x uint32 = 0x01020304
if *(*byte)(unsafe.Pointer(&x)) == 0x01 { if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
return binary.BigEndian return binary.BigEndian
} }
return binary.LittleEndian return binary.LittleEndian

39
vendor/github.com/godbus/dbus/transport_nonce_tcp.go generated vendored Normal file
View File

@ -0,0 +1,39 @@
//+build !windows
package dbus
import (
"errors"
"io/ioutil"
"net"
)
func init() {
transports["nonce-tcp"] = newNonceTcpTransport
}
func newNonceTcpTransport(keys string) (transport, error) {
host := getKey(keys, "host")
port := getKey(keys, "port")
noncefile := getKey(keys, "noncefile")
if host == "" || port == "" || noncefile == "" {
return nil, errors.New("dbus: unsupported address (must set host, port and noncefile)")
}
protocol, err := tcpFamily(keys)
if err != nil {
return nil, err
}
socket, err := net.Dial(protocol, net.JoinHostPort(host, port))
if err != nil {
return nil, err
}
b, err := ioutil.ReadFile(noncefile)
if err != nil {
return nil, err
}
_, err = socket.Write(b)
if err != nil {
return nil, err
}
return NewConn(socket)
}

View File

@ -31,6 +31,7 @@ func (o *oobReader) Read(b []byte) (n int, err error) {
type unixTransport struct { type unixTransport struct {
*net.UnixConn *net.UnixConn
rdr *oobReader
hasUnixFDs bool hasUnixFDs bool
} }
@ -79,10 +80,15 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
// To be sure that all bytes of out-of-band data are read, we use a special // To be sure that all bytes of out-of-band data are read, we use a special
// reader that uses ReadUnix on the underlying connection instead of Read // reader that uses ReadUnix on the underlying connection instead of Read
// and gathers the out-of-band data in a buffer. // and gathers the out-of-band data in a buffer.
rd := &oobReader{conn: t.UnixConn} if t.rdr == nil {
t.rdr = &oobReader{conn: t.UnixConn}
} else {
t.rdr.oob = nil
}
// read the first 16 bytes (the part of the header that has a constant size), // read the first 16 bytes (the part of the header that has a constant size),
// from which we can figure out the length of the rest of the message // from which we can figure out the length of the rest of the message
if _, err := io.ReadFull(rd, csheader[:]); err != nil { if _, err := io.ReadFull(t.rdr, csheader[:]); err != nil {
return nil, err return nil, err
} }
switch csheader[0] { switch csheader[0] {
@ -104,7 +110,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
// decode headers and look for unix fds // decode headers and look for unix fds
headerdata := make([]byte, hlen+4) headerdata := make([]byte, hlen+4)
copy(headerdata, csheader[12:]) copy(headerdata, csheader[12:])
if _, err := io.ReadFull(t, headerdata[4:]); err != nil { if _, err := io.ReadFull(t.rdr, headerdata[4:]); err != nil {
return nil, err return nil, err
} }
dec := newDecoder(bytes.NewBuffer(headerdata), order) dec := newDecoder(bytes.NewBuffer(headerdata), order)
@ -122,7 +128,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
all := make([]byte, 16+hlen+blen) all := make([]byte, 16+hlen+blen)
copy(all, csheader[:]) copy(all, csheader[:])
copy(all[16:], headerdata[4:]) copy(all[16:], headerdata[4:])
if _, err := io.ReadFull(rd, all[16+hlen:]); err != nil { if _, err := io.ReadFull(t.rdr, all[16+hlen:]); err != nil {
return nil, err return nil, err
} }
if unixfds != 0 { if unixfds != 0 {
@ -130,7 +136,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
return nil, errors.New("dbus: got unix fds on unsupported transport") return nil, errors.New("dbus: got unix fds on unsupported transport")
} }
// read the fds from the OOB data // read the fds from the OOB data
scms, err := syscall.ParseSocketControlMessage(rd.oob) scms, err := syscall.ParseSocketControlMessage(t.rdr.oob)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -148,11 +154,23 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
// substitute the values in the message body (which are indices for the // substitute the values in the message body (which are indices for the
// array receiver via OOB) with the actual values // array receiver via OOB) with the actual values
for i, v := range msg.Body { for i, v := range msg.Body {
if j, ok := v.(UnixFDIndex); ok { switch v.(type) {
case UnixFDIndex:
j := v.(UnixFDIndex)
if uint32(j) >= unixfds { if uint32(j) >= unixfds {
return nil, InvalidMessageError("invalid index for unix fd") return nil, InvalidMessageError("invalid index for unix fd")
} }
msg.Body[i] = UnixFD(fds[j]) msg.Body[i] = UnixFD(fds[j])
case []UnixFDIndex:
idxArray := v.([]UnixFDIndex)
fdArray := make([]UnixFD, len(idxArray))
for k, j := range idxArray {
if uint32(j) >= unixfds {
return nil, InvalidMessageError("invalid index for unix fd")
}
fdArray[k] = UnixFD(fds[j])
}
msg.Body[i] = fdArray
} }
} }
return msg, nil return msg, nil

2
vendor/modules.txt vendored
View File

@ -388,7 +388,7 @@ github.com/go-openapi/validate
# github.com/go-ozzo/ozzo-validation v3.5.0+incompatible => github.com/go-ozzo/ozzo-validation v3.5.0+incompatible # github.com/go-ozzo/ozzo-validation v3.5.0+incompatible => github.com/go-ozzo/ozzo-validation v3.5.0+incompatible
github.com/go-ozzo/ozzo-validation github.com/go-ozzo/ozzo-validation
github.com/go-ozzo/ozzo-validation/is github.com/go-ozzo/ozzo-validation/is
# github.com/godbus/dbus v4.1.0+incompatible => github.com/godbus/dbus v4.1.0+incompatible # github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f => github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f
github.com/godbus/dbus github.com/godbus/dbus
# github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d => github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d # github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d => github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d
github.com/gogo/protobuf/gogoproto github.com/gogo/protobuf/gogoproto