summaryrefslogtreecommitdiff
path: root/vendor/github.com/godbus
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/godbus')
-rw-r--r--vendor/github.com/godbus/dbus/.travis.yml46
-rw-r--r--vendor/github.com/godbus/dbus/CONTRIBUTING.md50
-rw-r--r--vendor/github.com/godbus/dbus/MAINTAINERS3
-rw-r--r--vendor/github.com/godbus/dbus/README.markdown2
-rw-r--r--vendor/github.com/godbus/dbus/auth.go1
-rw-r--r--vendor/github.com/godbus/dbus/auth_anonymous.go16
-rw-r--r--vendor/github.com/godbus/dbus/call.go26
-rw-r--r--vendor/github.com/godbus/dbus/conn.go616
-rw-r--r--vendor/github.com/godbus/dbus/conn_darwin.go4
-rw-r--r--vendor/github.com/godbus/dbus/conn_other.go63
-rw-r--r--vendor/github.com/godbus/dbus/conn_unix.go18
-rw-r--r--vendor/github.com/godbus/dbus/conn_windows.go15
-rw-r--r--vendor/github.com/godbus/dbus/decoder.go9
-rw-r--r--vendor/github.com/godbus/dbus/default_handler.go52
-rw-r--r--vendor/github.com/godbus/dbus/export.go17
-rw-r--r--vendor/github.com/godbus/dbus/go.mod1
-rw-r--r--vendor/github.com/godbus/dbus/object.go118
-rw-r--r--vendor/github.com/godbus/dbus/server_interfaces.go10
-rw-r--r--vendor/github.com/godbus/dbus/transport_generic.go2
-rw-r--r--vendor/github.com/godbus/dbus/transport_nonce_tcp.go39
-rw-r--r--vendor/github.com/godbus/dbus/transport_unix.go30
21 files changed, 851 insertions, 287 deletions
diff --git a/vendor/github.com/godbus/dbus/.travis.yml b/vendor/github.com/godbus/dbus/.travis.yml
new file mode 100644
index 000000000..9cd57f432
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/.travis.yml
@@ -0,0 +1,46 @@
+dist: precise
+language: go
+go_import_path: github.com/godbus/dbus
+sudo: true
+
+go:
+ - 1.7.3
+ - 1.8.7
+ - 1.9.5
+ - 1.10.1
+ - tip
+
+env:
+ global:
+ matrix:
+ - TARGET=amd64
+ - TARGET=arm64
+ - TARGET=arm
+ - TARGET=386
+ - TARGET=ppc64le
+
+matrix:
+ fast_finish: true
+ allow_failures:
+ - go: tip
+ exclude:
+ - go: tip
+ env: TARGET=arm
+ - go: tip
+ env: TARGET=arm64
+ - go: tip
+ env: TARGET=386
+ - go: tip
+ env: TARGET=ppc64le
+
+addons:
+ apt:
+ packages:
+ - dbus
+ - dbus-x11
+
+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
diff --git a/vendor/github.com/godbus/dbus/CONTRIBUTING.md b/vendor/github.com/godbus/dbus/CONTRIBUTING.md
new file mode 100644
index 000000000..c88f9b2bd
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/CONTRIBUTING.md
@@ -0,0 +1,50 @@
+# How to Contribute
+
+## Getting Started
+
+- Fork the repository on GitHub
+- Read the [README](README.markdown) for build and test instructions
+- Play with the project, submit bugs, submit patches!
+
+## Contribution Flow
+
+This is a rough outline of what a contributor's workflow looks like:
+
+- Create a topic branch from where you want to base your work (usually master).
+- Make commits of logical units.
+- Make sure your commit messages are in the proper format (see below).
+- Push your changes to a topic branch in your fork of the repository.
+- Make sure the tests pass, and add any new tests as appropriate.
+- Submit a pull request to the original repository.
+
+Thanks for your contributions!
+
+### Format of the Commit Message
+
+We follow a rough convention for commit messages that is designed to answer two
+questions: what changed and why. The subject line should feature the what and
+the body of the commit should describe the why.
+
+```
+scripts: add the test-cluster command
+
+this uses tmux to setup a test cluster that you can easily kill and
+start for debugging.
+
+Fixes #38
+```
+
+The format can be described more formally as follows:
+
+```
+<subsystem>: <what changed>
+<BLANK LINE>
+<why this change was made>
+<BLANK LINE>
+<footer>
+```
+
+The first line is the subject and should be no longer than 70 characters, the
+second line is always blank, and other lines should be wrapped at 80 characters.
+This allows the message to be easier to read on GitHub as well as in various
+git tools.
diff --git a/vendor/github.com/godbus/dbus/MAINTAINERS b/vendor/github.com/godbus/dbus/MAINTAINERS
new file mode 100644
index 000000000..27618c9cd
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/MAINTAINERS
@@ -0,0 +1,3 @@
+Brandon Philips <brandon@ifup.org> (@philips)
+Brian Waldon <brian@waldon.cc> (@bcwaldon)
+John Southworth <jsouthwo@brocade.com> (@jsouthworth)
diff --git a/vendor/github.com/godbus/dbus/README.markdown b/vendor/github.com/godbus/dbus/README.markdown
index d37f4e2ed..fd2964875 100644
--- a/vendor/github.com/godbus/dbus/README.markdown
+++ b/vendor/github.com/godbus/dbus/README.markdown
@@ -14,7 +14,7 @@ D-Bus message bus system.
### 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
diff --git a/vendor/github.com/godbus/dbus/auth.go b/vendor/github.com/godbus/dbus/auth.go
index 98017b693..b0dcb54e6 100644
--- a/vendor/github.com/godbus/dbus/auth.go
+++ b/vendor/github.com/godbus/dbus/auth.go
@@ -116,7 +116,6 @@ func (conn *Conn) Auth(methods []Auth) error {
return err
}
go conn.inWorker()
- go conn.outWorker()
return nil
}
}
diff --git a/vendor/github.com/godbus/dbus/auth_anonymous.go b/vendor/github.com/godbus/dbus/auth_anonymous.go
new file mode 100644
index 000000000..75f3ad34d
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/auth_anonymous.go
@@ -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
+}
diff --git a/vendor/github.com/godbus/dbus/call.go b/vendor/github.com/godbus/dbus/call.go
index ba6e73f60..2cb189012 100644
--- a/vendor/github.com/godbus/dbus/call.go
+++ b/vendor/github.com/godbus/dbus/call.go
@@ -1,9 +1,12 @@
package dbus
import (
+ "context"
"errors"
)
+var errSignature = errors.New("dbus: mismatched signature")
+
// Call represents a pending or completed method call.
type Call struct {
Destination string
@@ -20,9 +23,25 @@ type Call struct {
// Holds the response once the call is done.
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
// 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...)
}
+
+func (c *Call) done() {
+ c.Done <- c
+ c.ContextCancel()
+}
diff --git a/vendor/github.com/godbus/dbus/conn.go b/vendor/github.com/godbus/dbus/conn.go
index 5720e2ebb..b38920baf 100644
--- a/vendor/github.com/godbus/dbus/conn.go
+++ b/vendor/github.com/godbus/dbus/conn.go
@@ -1,6 +1,7 @@
package dbus
import (
+ "context"
"errors"
"io"
"os"
@@ -14,7 +15,6 @@ var (
systemBusLck sync.Mutex
sessionBus *Conn
sessionBusLck sync.Mutex
- sessionEnvLck sync.Mutex
)
// ErrClosed is the error returned by calls on a closed connection.
@@ -35,23 +35,13 @@ type Conn struct {
unixFD bool
uuid string
- names []string
- 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
-
+ handler Handler
signalHandler SignalHandler
+ serialGen SerialGenerator
+
+ names *nameTracker
+ calls *callTracker
+ outHandler *outputHandler
eavesdropped chan<- *Message
eavesdroppedLck sync.Mutex
@@ -87,32 +77,31 @@ func SessionBus() (conn *Conn, err error) {
}
func getSessionBusAddress() (string, error) {
- sessionEnvLck.Lock()
- defer sessionEnvLck.Unlock()
- address := os.Getenv("DBUS_SESSION_BUS_ADDRESS")
- if address != "" && address != "autolaunch:" {
+ if address := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); address != "" && address != "autolaunch:" {
+ return address, nil
+
+ } else if address := tryDiscoverDbusSessionBusAddress(); address != "" {
+ os.Setenv("DBUS_SESSION_BUS_ADDRESS", address)
return address, nil
}
return getSessionBusPlatformAddress()
}
// SessionBusPrivate returns a new private connection to the session bus.
-func SessionBusPrivate() (*Conn, error) {
+func SessionBusPrivate(opts ...ConnOption) (*Conn, error) {
address, err := getSessionBusAddress()
if err != nil {
return nil, err
}
- return Dial(address)
+ return Dial(address, opts...)
}
// SessionBusPrivate returns a new private connection to the session bus.
+//
+// Deprecated: use SessionBusPrivate with options instead.
func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) {
- address, err := getSessionBusAddress()
- if err != nil {
- return nil, err
- }
- return DialHandler(address, handler, signalHandler)
+ return SessionBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler))
}
// 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.
-func SystemBusPrivate() (*Conn, error) {
- return Dial(getSystemBusPlatformAddress())
+func SystemBusPrivate(opts ...ConnOption) (*Conn, error) {
+ return Dial(getSystemBusPlatformAddress(), opts...)
}
// 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) {
- return DialHandler(getSystemBusPlatformAddress(), handler, signalHandler)
+ return SystemBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler))
}
// 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)
if err != nil {
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.
+//
+// Deprecated: use Dial with options instead.
func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) {
- tr, err := getTransport(address)
- if err != nil {
- return nil, err
+ return Dial(address, WithSignalHandler(signalHandler))
+}
+
+// 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.
-func NewConn(conn io.ReadWriteCloser) (*Conn, error) {
- return NewConnHandler(conn, NewDefaultHandler(), NewDefaultSignalHandler())
+func NewConn(conn io.ReadWriteCloser, opts ...ConnOption) (*Conn, error) {
+ return newConn(genericTransport{conn}, opts...)
}
// 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) {
- return newConn(genericTransport{conn}, handler, signalHandler)
+ return NewConn(genericTransport{conn}, WithHandler(handler), WithSignalHandler(signalHandler))
}
// 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.transport = tr
- conn.calls = make(map[uint32]*Call)
- conn.out = make(chan *Message, 10)
- conn.handler = handler
- conn.signalHandler = signalHandler
- conn.nextSerial = 1
- conn.serialUsed = map[uint32]bool{0: true}
+ for _, opt := range opts {
+ if err := opt(conn); err != nil {
+ return nil, err
+ }
+ }
+ 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")
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
// not be called on shared connections.
func (conn *Conn) Close() error {
- conn.outLck.Lock()
- 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()
-
+ conn.outHandler.close()
if term, ok := conn.signalHandler.(Terminator); ok {
term.Terminate()
}
@@ -249,17 +267,9 @@ func (conn *Conn) Eavesdrop(ch chan<- *Message) {
conn.eavesdroppedLck.Unlock()
}
-// getSerial returns an unused serial.
+// GetSerial returns an unused serial.
func (conn *Conn) getSerial() uint32 {
- conn.serialLck.Lock()
- defer conn.serialLck.Unlock()
- n := conn.nextSerial
- for conn.serialUsed[n] {
- n++
- }
- conn.serialUsed[n] = true
- conn.nextSerial = n + 1
- return n
+ return conn.serialGen.GetSerial()
}
// 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 {
return err
}
- conn.namesLck.Lock()
- conn.names = make([]string, 1)
- conn.names[0] = s
- conn.namesLck.Unlock()
+ conn.names.acquireUniqueConnectionName(s)
return nil
}
@@ -283,109 +290,48 @@ func (conn *Conn) Hello() error {
func (conn *Conn) inWorker() {
for {
msg, err := conn.ReadMessage()
- if err == nil {
- conn.eavesdroppedLck.Lock()
- if conn.eavesdropped != nil {
- select {
- case conn.eavesdropped <- msg:
- default:
- }
- conn.eavesdroppedLck.Unlock()
- continue
- }
- conn.eavesdroppedLck.Unlock()
- dest, _ := msg.Headers[FieldDestination].value.(string)
- 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)
+ if err != nil {
+ 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.calls.finalizeAllWithError(err)
+ return
}
- } 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
+ // invalid messages are ignored
+ continue
+ }
+ conn.eavesdroppedLck.Lock()
+ if conn.eavesdropped != nil {
+ select {
+ case conn.eavesdropped <- msg:
+ default:
}
- conn.callsLck.RUnlock()
- return
+ conn.eavesdroppedLck.Unlock()
+ continue
+ }
+ 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)
}
- // invalid messages are ignored
+
}
}
@@ -395,6 +341,25 @@ func (conn *Conn) handleSignal(msg *Message) {
// 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.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{
Sender: sender,
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
// being the unique name of the connection.
func (conn *Conn) Names() []string {
- conn.namesLck.RLock()
- // copy the slice so it can't be modified
- s := make([]string, len(conn.names))
- copy(s, conn.names)
- conn.namesLck.RUnlock()
- return s
+ return conn.names.listKnownNames()
}
// 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
// sent to conn.out.
-func (conn *Conn) outWorker() {
- for msg := range conn.out {
- err := conn.SendMessage(msg)
- conn.callsLck.RLock()
- if err != nil {
- if c := conn.calls[msg.serial]; c != nil {
- c.Err = err
- c.Done <- c
- }
- conn.serialLck.Lock()
- delete(conn.serialUsed, msg.serial)
- conn.serialLck.Unlock()
- } else if msg.Type != TypeMethodCall {
- conn.serialLck.Lock()
- delete(conn.serialUsed, msg.serial)
- conn.serialLck.Unlock()
- }
- conn.callsLck.RUnlock()
+func (conn *Conn) sendMessage(msg *Message) {
+ conn.sendMessageAndIfClosed(msg, func() {})
+}
+
+func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) {
+ err := conn.outHandler.sendAndIfClosed(msg, ifClosed)
+ conn.calls.handleSendError(msg, err)
+ if err != nil {
+ conn.serialGen.RetireSerial(msg.serial)
+ } else if msg.Type != TypeMethodCall {
+ conn.serialGen.RetireSerial(msg.serial)
}
}
@@ -451,8 +404,21 @@ func (conn *Conn) outWorker() {
// once the call is complete. Otherwise, ch is ignored and a Call structure is
// returned of which only the Err member is valid.
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()
if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 {
if ch == nil {
@@ -468,26 +434,23 @@ func (conn *Conn) Send(msg *Message, ch chan *Call) *Call {
call.Method = iface + "." + member
call.Args = msg.Body
call.Done = ch
- conn.callsLck.Lock()
- conn.calls[msg.serial] = call
- conn.callsLck.Unlock()
- conn.outLck.RLock()
- if conn.closed {
- call.Err = ErrClosed
- call.Done <- call
- } else {
- conn.out <- msg
- }
- conn.outLck.RUnlock()
+ call.ctx = ctx
+ call.ctxCanceler = canceler
+ conn.calls.track(msg.serial, call)
+ go func() {
+ <-ctx.Done()
+ conn.calls.handleSendError(msg, ctx.Err())
+ }()
+ conn.sendMessageAndIfClosed(msg, func() {
+ conn.calls.handleSendError(msg, ErrClosed)
+ canceler()
+ })
} else {
- conn.outLck.RLock()
- if conn.closed {
+ canceler()
+ call = &Call{Err: nil}
+ conn.sendMessageAndIfClosed(msg, func() {
call = &Call{Err: ErrClosed}
- } else {
- conn.out <- msg
- call = &Call{Err: nil}
- }
- conn.outLck.RUnlock()
+ })
}
return call
}
@@ -520,11 +483,7 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) {
if len(e.Body) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...))
}
- conn.outLck.RLock()
- if !conn.closed {
- conn.out <- msg
- }
- conn.outLck.RUnlock()
+ conn.sendMessage(msg)
}
// 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 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
}
- conn.outLck.RLock()
- if !conn.closed {
- conn.out <- msg
- }
- conn.outLck.RUnlock()
+ conn.sendMessage(msg)
}
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 ""
}
+
+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()
+ }
+}
diff --git a/vendor/github.com/godbus/dbus/conn_darwin.go b/vendor/github.com/godbus/dbus/conn_darwin.go
index c015f80ce..6e2e40202 100644
--- a/vendor/github.com/godbus/dbus/conn_darwin.go
+++ b/vendor/github.com/godbus/dbus/conn_darwin.go
@@ -31,3 +31,7 @@ func getSystemBusPlatformAddress() string {
}
return defaultSystemBusAddress
}
+
+func tryDiscoverDbusSessionBusAddress() string {
+ return ""
+}
diff --git a/vendor/github.com/godbus/dbus/conn_other.go b/vendor/github.com/godbus/dbus/conn_other.go
index 254c9f2ef..289044a44 100644
--- a/vendor/github.com/godbus/dbus/conn_other.go
+++ b/vendor/github.com/godbus/dbus/conn_other.go
@@ -6,12 +6,14 @@ import (
"bytes"
"errors"
"fmt"
+ "io/ioutil"
"os"
"os/exec"
+ "os/user"
+ "path"
+ "strings"
)
-const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket"
-
func getSessionBusPlatformAddress() (string, error) {
cmd := exec.Command("dbus-launch")
b, err := cmd.CombinedOutput()
@@ -33,10 +35,57 @@ func getSessionBusPlatformAddress() (string, error) {
return addr, nil
}
-func getSystemBusPlatformAddress() string {
- address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS")
- if address != "" {
- return fmt.Sprintf("unix:path=%s", address)
+// tryDiscoverDbusSessionBusAddress tries to discover an existing dbus session
+// and return the value of its DBUS_SESSION_BUS_ADDRESS.
+// It tries different techniques employed by different operating systems,
+// 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
}
diff --git a/vendor/github.com/godbus/dbus/conn_unix.go b/vendor/github.com/godbus/dbus/conn_unix.go
new file mode 100644
index 000000000..4cba8ae8e
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/conn_unix.go
@@ -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
+} \ No newline at end of file
diff --git a/vendor/github.com/godbus/dbus/conn_windows.go b/vendor/github.com/godbus/dbus/conn_windows.go
new file mode 100644
index 000000000..4291e4519
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/conn_windows.go
@@ -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
+}
diff --git a/vendor/github.com/godbus/dbus/decoder.go b/vendor/github.com/godbus/dbus/decoder.go
index ef50dcab9..5c27d3b51 100644
--- a/vendor/github.com/godbus/dbus/decoder.go
+++ b/vendor/github.com/godbus/dbus/decoder.go
@@ -191,7 +191,14 @@ func (dec *decoder) decode(s string, depth int) interface{} {
length := dec.decode("u", depth).(uint32)
v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length))
// 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
for dec.pos < spos+int(length) {
ev := dec.decode(s[1:], depth+1)
diff --git a/vendor/github.com/godbus/dbus/default_handler.go b/vendor/github.com/godbus/dbus/default_handler.go
index e81f73ac5..81dbcc7e4 100644
--- a/vendor/github.com/godbus/dbus/default_handler.go
+++ b/vendor/github.com/godbus/dbus/default_handler.go
@@ -21,6 +21,8 @@ func newIntrospectIntf(h *defaultHandler) *exportedIntf {
//NewDefaultHandler returns an instance of the default
//call handler. This is useful if you want to implement only
//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 {
h := &defaultHandler{
objects: make(map[ObjectPath]*exportedObj),
@@ -161,6 +163,7 @@ func newExportedObject() *exportedObj {
}
type exportedObj struct {
+ mu sync.RWMutex
interfaces map[string]*exportedIntf
}
@@ -168,19 +171,27 @@ func (obj *exportedObj) LookupInterface(name string) (Interface, bool) {
if name == "" {
return obj, true
}
+ obj.mu.RLock()
+ defer obj.mu.RUnlock()
intf, exists := obj.interfaces[name]
return intf, exists
}
func (obj *exportedObj) AddInterface(name string, iface *exportedIntf) {
+ obj.mu.Lock()
+ defer obj.mu.Unlock()
obj.interfaces[name] = iface
}
func (obj *exportedObj) DeleteInterface(name string) {
+ obj.mu.Lock()
+ defer obj.mu.Unlock()
delete(obj.interfaces, name)
}
func (obj *exportedObj) LookupMethod(name string) (Method, bool) {
+ obj.mu.RLock()
+ defer obj.mu.RUnlock()
for _, intf := range obj.interfaces {
method, exists := intf.LookupMethod(name)
if exists {
@@ -220,8 +231,12 @@ func (obj *exportedIntf) isFallbackInterface() bool {
//NewDefaultSignalHandler returns an instance of the default
//signal handler. This is useful if you want to implement only
//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 {
- return &defaultSignalHandler{}
+ return &defaultSignalHandler{
+ closeChan: make(chan struct{}),
+ }
}
func isDefaultSignalHandler(handler SignalHandler) bool {
@@ -231,32 +246,47 @@ func isDefaultSignalHandler(handler SignalHandler) bool {
type defaultSignalHandler struct {
sync.RWMutex
- closed bool
- signals []chan<- *Signal
+ closed bool
+ signals []chan<- *Signal
+ closeChan chan struct{}
}
func (sh *defaultSignalHandler) DeliverSignal(intf, name string, signal *Signal) {
- go func() {
- sh.RLock()
- defer sh.RUnlock()
- if sh.closed {
+ sh.RLock()
+ defer sh.RUnlock()
+ if sh.closed {
+ return
+ }
+ for _, ch := range sh.signals {
+ select {
+ case ch <- signal:
+ case <-sh.closeChan:
return
+ default:
+ go func() {
+ select {
+ case ch <- signal:
+ case <-sh.closeChan:
+ return
+ }
+ }()
}
- for _, ch := range sh.signals {
- ch <- signal
- }
- }()
+ }
}
func (sh *defaultSignalHandler) Init() error {
sh.Lock()
sh.signals = make([]chan<- *Signal, 0)
+ sh.closeChan = make(chan struct{})
sh.Unlock()
return nil
}
func (sh *defaultSignalHandler) Terminate() {
sh.Lock()
+ if !sh.closed {
+ close(sh.closeChan)
+ }
sh.closed = true
for _, ch := range sh.signals {
close(ch)
diff --git a/vendor/github.com/godbus/dbus/export.go b/vendor/github.com/godbus/dbus/export.go
index aae970881..95d0e2958 100644
--- a/vendor/github.com/godbus/dbus/export.go
+++ b/vendor/github.com/godbus/dbus/export.go
@@ -170,11 +170,8 @@ func (conn *Conn) handleCall(msg *Message) {
reply.Body[i] = ret[i]
}
reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...))
- conn.outLck.RLock()
- if !conn.closed {
- conn.out <- reply
- }
- conn.outLck.RUnlock()
+
+ conn.sendMessage(reply)
}
}
@@ -207,12 +204,14 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro
if len(values) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
}
- conn.outLck.RLock()
- defer conn.outLck.RUnlock()
- if conn.closed {
+
+ var closed bool
+ conn.sendMessageAndIfClosed(msg, func() {
+ closed = true
+ })
+ if closed {
return ErrClosed
}
- conn.out <- msg
return nil
}
diff --git a/vendor/github.com/godbus/dbus/go.mod b/vendor/github.com/godbus/dbus/go.mod
new file mode 100644
index 000000000..bdcd12598
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/go.mod
@@ -0,0 +1 @@
+module github.com/godbus/dbus
diff --git a/vendor/github.com/godbus/dbus/object.go b/vendor/github.com/godbus/dbus/object.go
index 6d95583d7..f27ffe144 100644
--- a/vendor/github.com/godbus/dbus/object.go
+++ b/vendor/github.com/godbus/dbus/object.go
@@ -1,6 +1,7 @@
package dbus
import (
+ "context"
"errors"
"strings"
)
@@ -9,7 +10,11 @@ import (
// invoked.
type BusObject interface {
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
+ 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)
Destination() string
Path() ObjectPath
@@ -24,16 +29,73 @@ type Object struct {
// Call calls a method with (*Object).Go and waits for its reply.
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
-// method (member).
-func (o *Object) AddMatchSignal(iface, member string) *Call {
- return o.Call(
+// CallWithContext acts like Call but takes a context
+func (o *Object) CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call {
+ return <-o.createCall(ctx, method, flags, make(chan *Call, 1), args...).Done
+}
+
+// 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",
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
// specifies the interface on which the method is called.
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 := ""
i := strings.LastIndex(method, ".")
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 {
panic("dbus: unbuffered channel passed to (*Object).Go")
}
+ ctx, cancel := context.WithCancel(ctx)
call := &Call{
Destination: o.dest,
Path: o.path,
Method: method,
Args: args,
Done: ch,
+ ctxCanceler: cancel,
+ ctx: ctx,
}
- o.conn.callsLck.Lock()
- o.conn.calls[msg.serial] = call
- o.conn.callsLck.Unlock()
- o.conn.outLck.RLock()
- if o.conn.closed {
- call.Err = ErrClosed
- call.Done <- call
- } else {
- o.conn.out <- msg
- }
- o.conn.outLck.RUnlock()
+ o.conn.calls.track(msg.serial, call)
+ o.conn.sendMessageAndIfClosed(msg, func() {
+ o.conn.calls.handleSendError(msg, ErrClosed)
+ cancel()
+ })
+ go func() {
+ <-ctx.Done()
+ o.conn.calls.handleSendError(msg, ctx.Err())
+ }()
+
return call
}
- o.conn.outLck.RLock()
- defer o.conn.outLck.RUnlock()
done := make(chan *Call, 1)
call := &Call{
Err: nil,
@@ -107,11 +181,9 @@ func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface
call.Done <- call
close(done)
}()
- if o.conn.closed {
+ o.conn.sendMessageAndIfClosed(msg, func() {
call.Err = ErrClosed
- return call
- }
- o.conn.out <- msg
+ })
return call
}
diff --git a/vendor/github.com/godbus/dbus/server_interfaces.go b/vendor/github.com/godbus/dbus/server_interfaces.go
index 091948aef..01166f0bd 100644
--- a/vendor/github.com/godbus/dbus/server_interfaces.go
+++ b/vendor/github.com/godbus/dbus/server_interfaces.go
@@ -87,3 +87,13 @@ type SignalHandler interface {
type DBusError 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)
+}
diff --git a/vendor/github.com/godbus/dbus/transport_generic.go b/vendor/github.com/godbus/dbus/transport_generic.go
index 3fad859a6..718a1ff02 100644
--- a/vendor/github.com/godbus/dbus/transport_generic.go
+++ b/vendor/github.com/godbus/dbus/transport_generic.go
@@ -11,7 +11,7 @@ var nativeEndian binary.ByteOrder
func detectEndianness() binary.ByteOrder {
var x uint32 = 0x01020304
- if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
+ if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
return binary.BigEndian
}
return binary.LittleEndian
diff --git a/vendor/github.com/godbus/dbus/transport_nonce_tcp.go b/vendor/github.com/godbus/dbus/transport_nonce_tcp.go
new file mode 100644
index 000000000..697739efa
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/transport_nonce_tcp.go
@@ -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)
+}
diff --git a/vendor/github.com/godbus/dbus/transport_unix.go b/vendor/github.com/godbus/dbus/transport_unix.go
index e56d5ca90..f000c6b5d 100644
--- a/vendor/github.com/godbus/dbus/transport_unix.go
+++ b/vendor/github.com/godbus/dbus/transport_unix.go
@@ -31,6 +31,7 @@ func (o *oobReader) Read(b []byte) (n int, err error) {
type unixTransport struct {
*net.UnixConn
+ rdr *oobReader
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
// reader that uses ReadUnix on the underlying connection instead of Read
// 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),
// 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
}
switch csheader[0] {
@@ -104,7 +110,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
// decode headers and look for unix fds
headerdata := make([]byte, hlen+4)
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
}
dec := newDecoder(bytes.NewBuffer(headerdata), order)
@@ -122,7 +128,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
all := make([]byte, 16+hlen+blen)
copy(all, csheader[:])
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
}
if unixfds != 0 {
@@ -130,7 +136,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
return nil, errors.New("dbus: got unix fds on unsupported transport")
}
// read the fds from the OOB data
- scms, err := syscall.ParseSocketControlMessage(rd.oob)
+ scms, err := syscall.ParseSocketControlMessage(t.rdr.oob)
if err != nil {
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
// array receiver via OOB) with the actual values
for i, v := range msg.Body {
- if j, ok := v.(UnixFDIndex); ok {
+ switch v.(type) {
+ case UnixFDIndex:
+ j := v.(UnixFDIndex)
if uint32(j) >= unixfds {
return nil, InvalidMessageError("invalid index for unix fd")
}
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