1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

vendor: github.com/godbus/dbus/v5 v5.0.4

full diff: https://github.com/godbus/dbus/compare/v5.0.3...v5.0.4

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2021-04-04 23:21:36 +02:00
parent 7a956d1342
commit 3987dc264b
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
15 changed files with 382 additions and 131 deletions

View file

@ -101,7 +101,7 @@ github.com/coreos/go-systemd 39ca1b05acc7ad1220e09f133283
# systemd integration (journald, daemon/listeners, containerd/cgroups) # systemd integration (journald, daemon/listeners, containerd/cgroups)
github.com/coreos/go-systemd/v22 256724e3db397c5ca4287b8f0c78e9e8492fdb01 # v22.3.1 github.com/coreos/go-systemd/v22 256724e3db397c5ca4287b8f0c78e9e8492fdb01 # v22.3.1
github.com/godbus/dbus/v5 37bf87eef99d69c4f1d3528bd66e3a87dc201472 # v5.0.3 github.com/godbus/dbus/v5 c88335c0b1d28a30e7fc76d526a06154b85e5d97 # v5.0.4
# gelf logging driver deps # gelf logging driver deps
github.com/Graylog2/go-gelf 1550ee647df0510058c9d67a45c56f18911d80b8 # v2 branch github.com/Graylog2/go-gelf 1550ee647df0510058c9d67a45c56f18911d80b8 # v2 branch

View file

@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.org/godbus/dbus.svg?branch=master)](https://travis-ci.org/godbus/dbus) ![Build Status](https://github.com/godbus/dbus/workflows/Go/badge.svg)
dbus dbus
---- ----
@ -32,6 +32,8 @@ gives a short overview over the basic usage.
#### Projects using godbus #### Projects using godbus
- [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library. - [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library.
- [go-bluetooth](https://github.com/muka/go-bluetooth) provides a bluetooth client over bluez dbus API. - [go-bluetooth](https://github.com/muka/go-bluetooth) provides a bluetooth client over bluez dbus API.
- [playerbm](https://github.com/altdesktop/playerbm) a bookmark utility for media players.
- [iwd](https://github.com/shibumi/iwd) go bindings for the internet wireless daemon "iwd".
Please note that the API is considered unstable for now and may change without Please note that the API is considered unstable for now and may change without
further notice. further notice.

View file

@ -37,7 +37,7 @@ const (
// Auth defines the behaviour of an authentication mechanism. // Auth defines the behaviour of an authentication mechanism.
type Auth interface { type Auth interface {
// Return the name of the mechnism, the argument to the first AUTH command // Return the name of the mechanism, the argument to the first AUTH command
// and the next status. // and the next status.
FirstData() (name, resp []byte, status AuthStatus) FirstData() (name, resp []byte, status AuthStatus)

View file

@ -24,6 +24,15 @@ type Call struct {
// Holds the response once the call is done. // Holds the response once the call is done.
Body []interface{} Body []interface{}
// ResponseSequence stores the sequence number of the DBus message containing
// the call response (or error). This can be compared to the sequence number
// of other call responses and signals on this connection to determine their
// relative ordering on the underlying DBus connection.
// For errors, ResponseSequence is populated only if the error came from a
// DBusMessage that was received or if there was an error receiving. In case of
// failure to make the call, ResponseSequence will be NoSequence.
ResponseSequence Sequence
// tracks context and canceler // tracks context and canceler
ctx context.Context ctx context.Context
ctxCanceler context.CancelFunc ctxCanceler context.CancelFunc

View file

@ -45,6 +45,7 @@ type Conn struct {
serialGen SerialGenerator serialGen SerialGenerator
inInt Interceptor inInt Interceptor
outInt Interceptor outInt Interceptor
auth []Auth
names *nameTracker names *nameTracker
calls *callTracker calls *callTracker
@ -59,7 +60,8 @@ type Conn struct {
func SessionBus() (conn *Conn, err error) { func SessionBus() (conn *Conn, err error) {
sessionBusLck.Lock() sessionBusLck.Lock()
defer sessionBusLck.Unlock() defer sessionBusLck.Unlock()
if sessionBus != nil { if sessionBus != nil &&
sessionBus.Connected() {
return sessionBus, nil return sessionBus, nil
} }
defer func() { defer func() {
@ -67,19 +69,7 @@ func SessionBus() (conn *Conn, err error) {
sessionBus = conn sessionBus = conn
} }
}() }()
conn, err = SessionBusPrivate() conn, err = ConnectSessionBus()
if err != nil {
return
}
if err = conn.Auth(nil); err != nil {
conn.Close()
conn = nil
return
}
if err = conn.Hello(); err != nil {
conn.Close()
conn = nil
}
return return
} }
@ -116,7 +106,8 @@ func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Co
func SystemBus() (conn *Conn, err error) { func SystemBus() (conn *Conn, err error) {
systemBusLck.Lock() systemBusLck.Lock()
defer systemBusLck.Unlock() defer systemBusLck.Unlock()
if systemBus != nil { if systemBus != nil &&
systemBus.Connected() {
return systemBus, nil return systemBus, nil
} }
defer func() { defer func() {
@ -124,20 +115,42 @@ func SystemBus() (conn *Conn, err error) {
systemBus = conn systemBus = conn
} }
}() }()
conn, err = SystemBusPrivate() conn, err = ConnectSystemBus()
return
}
// ConnectSessionBus connects to the session bus.
func ConnectSessionBus(opts ...ConnOption) (*Conn, error) {
address, err := getSessionBusAddress()
if err != nil { if err != nil {
return return nil, err
} }
if err = conn.Auth(nil); err != nil { return Connect(address, opts...)
conn.Close() }
conn = nil
return // ConnectSystemBus connects to the system bus.
func ConnectSystemBus(opts ...ConnOption) (*Conn, error) {
return Connect(getSystemBusPlatformAddress(), opts...)
}
// Connect connects to the given address.
//
// Returned connection is ready to use and doesn't require calling
// Auth and Hello methods to make it usable.
func Connect(address string, opts ...ConnOption) (*Conn, error) {
conn, err := Dial(address, opts...)
if err != nil {
return nil, err
}
if err = conn.Auth(conn.auth); err != nil {
_ = conn.Close()
return nil, err
} }
if err = conn.Hello(); err != nil { if err = conn.Hello(); err != nil {
conn.Close() _ = conn.Close()
conn = nil return nil, err
} }
return return conn, nil
} }
// SystemBusPrivate returns a new private connection to the system bus. // SystemBusPrivate returns a new private connection to the system bus.
@ -197,6 +210,14 @@ func WithSerialGenerator(gen SerialGenerator) ConnOption {
} }
} }
// WithAuth sets authentication methods for the auth conversation.
func WithAuth(methods ...Auth) ConnOption {
return func(conn *Conn) error {
conn.auth = methods
return nil
}
}
// Interceptor intercepts incoming and outgoing messages. // Interceptor intercepts incoming and outgoing messages.
type Interceptor func(msg *Message) type Interceptor func(msg *Message)
@ -309,6 +330,11 @@ func (conn *Conn) Context() context.Context {
return conn.ctx return conn.ctx
} }
// Connected returns whether conn is connected
func (conn *Conn) Connected() bool {
return conn.ctx.Err() == nil
}
// Eavesdrop causes conn to send all incoming messages to the given channel // Eavesdrop causes conn to send all incoming messages to the given channel
// without further processing. Method replies, errors and signals will not be // without further processing. Method replies, errors and signals will not be
// sent to the appropriate channels and method calls will not be handled. If nil // sent to the appropriate channels and method calls will not be handled. If nil
@ -342,8 +368,9 @@ func (conn *Conn) Hello() error {
} }
// inWorker runs in an own goroutine, reading incoming messages from the // inWorker runs in an own goroutine, reading incoming messages from the
// transport and dispatching them appropiately. // transport and dispatching them appropriately.
func (conn *Conn) inWorker() { func (conn *Conn) inWorker() {
sequenceGen := newSequenceGenerator()
for { for {
msg, err := conn.ReadMessage() msg, err := conn.ReadMessage()
if err != nil { if err != nil {
@ -352,7 +379,7 @@ func (conn *Conn) inWorker() {
// anything but to shut down all stuff and returns errors to all // anything but to shut down all stuff and returns errors to all
// pending replies. // pending replies.
conn.Close() conn.Close()
conn.calls.finalizeAllWithError(err) conn.calls.finalizeAllWithError(sequenceGen, err)
return return
} }
// invalid messages are ignored // invalid messages are ignored
@ -381,13 +408,14 @@ func (conn *Conn) inWorker() {
if conn.inInt != nil { if conn.inInt != nil {
conn.inInt(msg) conn.inInt(msg)
} }
sequence := sequenceGen.next()
switch msg.Type { switch msg.Type {
case TypeError: case TypeError:
conn.serialGen.RetireSerial(conn.calls.handleDBusError(msg)) conn.serialGen.RetireSerial(conn.calls.handleDBusError(sequence, msg))
case TypeMethodReply: case TypeMethodReply:
conn.serialGen.RetireSerial(conn.calls.handleReply(msg)) conn.serialGen.RetireSerial(conn.calls.handleReply(sequence, msg))
case TypeSignal: case TypeSignal:
conn.handleSignal(msg) conn.handleSignal(sequence, msg)
case TypeMethodCall: case TypeMethodCall:
go conn.handleCall(msg) go conn.handleCall(msg)
} }
@ -395,7 +423,7 @@ func (conn *Conn) inWorker() {
} }
} }
func (conn *Conn) handleSignal(msg *Message) { func (conn *Conn) handleSignal(sequence Sequence, msg *Message) {
iface := msg.Headers[FieldInterface].value.(string) iface := msg.Headers[FieldInterface].value.(string)
member := msg.Headers[FieldMember].value.(string) member := msg.Headers[FieldMember].value.(string)
// as per http://dbus.freedesktop.org/doc/dbus-specification.html , // as per http://dbus.freedesktop.org/doc/dbus-specification.html ,
@ -421,10 +449,11 @@ func (conn *Conn) handleSignal(msg *Message) {
} }
} }
signal := &Signal{ signal := &Signal{
Sender: sender, Sender: sender,
Path: msg.Headers[FieldPath].value.(ObjectPath), Path: msg.Headers[FieldPath].value.(ObjectPath),
Name: iface + "." + member, Name: iface + "." + member,
Body: msg.Body, Body: msg.Body,
Sequence: sequence,
} }
conn.signalHandler.DeliverSignal(iface, member, signal) conn.signalHandler.DeliverSignal(iface, member, signal)
} }
@ -442,6 +471,9 @@ func (conn *Conn) Object(dest string, path ObjectPath) BusObject {
} }
func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) { func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) {
if msg.serial == 0 {
msg.serial = conn.getSerial()
}
if conn.outInt != nil { if conn.outInt != nil {
conn.outInt(msg) conn.outInt(msg)
} }
@ -473,16 +505,16 @@ func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call {
if ctx == nil { if ctx == nil {
panic("nil context") panic("nil context")
} }
if ch == nil {
ch = make(chan *Call, 1)
} else if cap(ch) == 0 {
panic("dbus: unbuffered channel passed to (*Conn).Send")
}
var call *Call var call *Call
ctx, canceler := context.WithCancel(ctx) 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 {
ch = make(chan *Call, 5)
} else if cap(ch) == 0 {
panic("dbus: unbuffered channel passed to (*Conn).Send")
}
call = new(Call) call = new(Call)
call.Destination, _ = msg.Headers[FieldDestination].value.(string) call.Destination, _ = msg.Headers[FieldDestination].value.(string)
call.Path, _ = msg.Headers[FieldPath].value.(ObjectPath) call.Path, _ = msg.Headers[FieldPath].value.(ObjectPath)
@ -504,7 +536,8 @@ func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call {
}) })
} else { } else {
canceler() canceler()
call = &Call{Err: nil} call = &Call{Err: nil, Done: ch}
ch <- call
conn.sendMessageAndIfClosed(msg, func() { conn.sendMessageAndIfClosed(msg, func() {
call = &Call{Err: ErrClosed} call = &Call{Err: ErrClosed}
}) })
@ -529,7 +562,6 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) {
} }
msg := new(Message) msg := new(Message)
msg.Type = TypeError msg.Type = TypeError
msg.serial = conn.getSerial()
msg.Headers = make(map[HeaderField]Variant) msg.Headers = make(map[HeaderField]Variant)
if dest != "" { if dest != "" {
msg.Headers[FieldDestination] = MakeVariant(dest) msg.Headers[FieldDestination] = MakeVariant(dest)
@ -548,7 +580,6 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) {
func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) { func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
msg := new(Message) msg := new(Message)
msg.Type = TypeMethodReply msg.Type = TypeMethodReply
msg.serial = conn.getSerial()
msg.Headers = make(map[HeaderField]Variant) msg.Headers = make(map[HeaderField]Variant)
if dest != "" { if dest != "" {
msg.Headers[FieldDestination] = MakeVariant(dest) msg.Headers[FieldDestination] = MakeVariant(dest)
@ -564,8 +595,14 @@ func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
// AddMatchSignal registers the given match rule to receive broadcast // AddMatchSignal registers the given match rule to receive broadcast
// signals based on their contents. // signals based on their contents.
func (conn *Conn) AddMatchSignal(options ...MatchOption) error { func (conn *Conn) AddMatchSignal(options ...MatchOption) error {
return conn.AddMatchSignalContext(context.Background(), options...)
}
// AddMatchSignalContext acts like AddMatchSignal but takes a context.
func (conn *Conn) AddMatchSignalContext(ctx context.Context, options ...MatchOption) error {
options = append([]MatchOption{withMatchType("signal")}, options...) options = append([]MatchOption{withMatchType("signal")}, options...)
return conn.busObj.Call( return conn.busObj.CallWithContext(
ctx,
"org.freedesktop.DBus.AddMatch", 0, "org.freedesktop.DBus.AddMatch", 0,
formatMatchOptions(options), formatMatchOptions(options),
).Store() ).Store()
@ -573,8 +610,14 @@ func (conn *Conn) AddMatchSignal(options ...MatchOption) error {
// RemoveMatchSignal removes the first rule that matches previously registered with AddMatchSignal. // RemoveMatchSignal removes the first rule that matches previously registered with AddMatchSignal.
func (conn *Conn) RemoveMatchSignal(options ...MatchOption) error { func (conn *Conn) RemoveMatchSignal(options ...MatchOption) error {
return conn.RemoveMatchSignalContext(context.Background(), options...)
}
// RemoveMatchSignalContext acts like RemoveMatchSignal but takes a context.
func (conn *Conn) RemoveMatchSignalContext(ctx context.Context, options ...MatchOption) error {
options = append([]MatchOption{withMatchType("signal")}, options...) options = append([]MatchOption{withMatchType("signal")}, options...)
return conn.busObj.Call( return conn.busObj.CallWithContext(
ctx,
"org.freedesktop.DBus.RemoveMatch", 0, "org.freedesktop.DBus.RemoveMatch", 0,
formatMatchOptions(options), formatMatchOptions(options),
).Store() ).Store()
@ -639,10 +682,11 @@ func (e Error) Error() string {
// Signal represents a D-Bus message of type Signal. The name member is given in // Signal represents a D-Bus message of type Signal. The name member is given in
// "interface.member" notation, e.g. org.freedesktop.D-Bus.NameLost. // "interface.member" notation, e.g. org.freedesktop.D-Bus.NameLost.
type Signal struct { type Signal struct {
Sender string Sender string
Path ObjectPath Path ObjectPath
Name string Name string
Body []interface{} Body []interface{}
Sequence Sequence
} }
// transport is a D-Bus transport. // transport is a D-Bus transport.
@ -825,25 +869,25 @@ func (tracker *callTracker) track(sn uint32, call *Call) {
tracker.lck.Unlock() tracker.lck.Unlock()
} }
func (tracker *callTracker) handleReply(msg *Message) uint32 { func (tracker *callTracker) handleReply(sequence Sequence, msg *Message) uint32 {
serial := msg.Headers[FieldReplySerial].value.(uint32) serial := msg.Headers[FieldReplySerial].value.(uint32)
tracker.lck.RLock() tracker.lck.RLock()
_, ok := tracker.calls[serial] _, ok := tracker.calls[serial]
tracker.lck.RUnlock() tracker.lck.RUnlock()
if ok { if ok {
tracker.finalizeWithBody(serial, msg.Body) tracker.finalizeWithBody(serial, sequence, msg.Body)
} }
return serial return serial
} }
func (tracker *callTracker) handleDBusError(msg *Message) uint32 { func (tracker *callTracker) handleDBusError(sequence Sequence, msg *Message) uint32 {
serial := msg.Headers[FieldReplySerial].value.(uint32) serial := msg.Headers[FieldReplySerial].value.(uint32)
tracker.lck.RLock() tracker.lck.RLock()
_, ok := tracker.calls[serial] _, ok := tracker.calls[serial]
tracker.lck.RUnlock() tracker.lck.RUnlock()
if ok { if ok {
name, _ := msg.Headers[FieldErrorName].value.(string) name, _ := msg.Headers[FieldErrorName].value.(string)
tracker.finalizeWithError(serial, Error{name, msg.Body}) tracker.finalizeWithError(serial, sequence, Error{name, msg.Body})
} }
return serial return serial
} }
@ -856,7 +900,7 @@ func (tracker *callTracker) handleSendError(msg *Message, err error) {
_, ok := tracker.calls[msg.serial] _, ok := tracker.calls[msg.serial]
tracker.lck.RUnlock() tracker.lck.RUnlock()
if ok { if ok {
tracker.finalizeWithError(msg.serial, err) tracker.finalizeWithError(msg.serial, NoSequence, err)
} }
} }
@ -871,7 +915,7 @@ func (tracker *callTracker) finalize(sn uint32) {
} }
} }
func (tracker *callTracker) finalizeWithBody(sn uint32, body []interface{}) { func (tracker *callTracker) finalizeWithBody(sn uint32, sequence Sequence, body []interface{}) {
tracker.lck.Lock() tracker.lck.Lock()
c, ok := tracker.calls[sn] c, ok := tracker.calls[sn]
if ok { if ok {
@ -880,11 +924,12 @@ func (tracker *callTracker) finalizeWithBody(sn uint32, body []interface{}) {
tracker.lck.Unlock() tracker.lck.Unlock()
if ok { if ok {
c.Body = body c.Body = body
c.ResponseSequence = sequence
c.done() c.done()
} }
} }
func (tracker *callTracker) finalizeWithError(sn uint32, err error) { func (tracker *callTracker) finalizeWithError(sn uint32, sequence Sequence, err error) {
tracker.lck.Lock() tracker.lck.Lock()
c, ok := tracker.calls[sn] c, ok := tracker.calls[sn]
if ok { if ok {
@ -893,11 +938,12 @@ func (tracker *callTracker) finalizeWithError(sn uint32, err error) {
tracker.lck.Unlock() tracker.lck.Unlock()
if ok { if ok {
c.Err = err c.Err = err
c.ResponseSequence = sequence
c.done() c.done()
} }
} }
func (tracker *callTracker) finalizeAllWithError(err error) { func (tracker *callTracker) finalizeAllWithError(sequenceGen *sequenceGenerator, err error) {
tracker.lck.Lock() tracker.lck.Lock()
closedCalls := make([]*Call, 0, len(tracker.calls)) closedCalls := make([]*Call, 0, len(tracker.calls))
for sn := range tracker.calls { for sn := range tracker.calls {
@ -907,6 +953,7 @@ func (tracker *callTracker) finalizeAllWithError(err error) {
tracker.lck.Unlock() tracker.lck.Unlock()
for _, call := range closedCalls { for _, call := range closedCalls {
call.Err = err call.Err = err
call.ResponseSequence = sequenceGen.next()
call.done() call.done()
} }
} }

View file

@ -28,6 +28,7 @@ var (
interfaceType = reflect.TypeOf((*interface{})(nil)).Elem() interfaceType = reflect.TypeOf((*interface{})(nil)).Elem()
unixFDType = reflect.TypeOf(UnixFD(0)) unixFDType = reflect.TypeOf(UnixFD(0))
unixFDIndexType = reflect.TypeOf(UnixFDIndex(0)) unixFDIndexType = reflect.TypeOf(UnixFDIndex(0))
errType = reflect.TypeOf((*error)(nil)).Elem()
) )
// An InvalidTypeError signals that a value which cannot be represented in the // An InvalidTypeError signals that a value which cannot be represented in the
@ -63,6 +64,9 @@ func storeInterfaces(src, dest interface{}) error {
func store(dest, src reflect.Value) error { func store(dest, src reflect.Value) error {
if dest.Kind() == reflect.Ptr { if dest.Kind() == reflect.Ptr {
if dest.IsNil() {
dest.Set(reflect.New(dest.Type().Elem()))
}
return store(dest.Elem(), src) return store(dest.Elem(), src)
} }
switch src.Kind() { switch src.Kind() {

View file

@ -126,14 +126,28 @@ func (m exportedMethod) Call(args ...interface{}) ([]interface{}, error) {
} }
ret := m.Value.Call(params) ret := m.Value.Call(params)
var err error
err := ret[t.NumOut()-1].Interface().(*Error) nilErr := false // The reflection will find almost-nils, let's only pass back clean ones!
ret = ret[:t.NumOut()-1] if t.NumOut() > 0 {
if e, ok := ret[t.NumOut()-1].Interface().(*Error); ok { // godbus *Error
nilErr = ret[t.NumOut()-1].IsNil()
ret = ret[:t.NumOut()-1]
err = e
} else if ret[t.NumOut()-1].Type().Implements(errType) { // Go error
i := ret[t.NumOut()-1].Interface()
if i == nil {
nilErr = ret[t.NumOut()-1].IsNil()
} else {
err = i.(error)
}
ret = ret[:t.NumOut()-1]
}
}
out := make([]interface{}, len(ret)) out := make([]interface{}, len(ret))
for i, val := range ret { for i, val := range ret {
out[i] = val.Interface() out[i] = val.Interface()
} }
if err == nil { if nilErr || err == nil {
//concrete type to interface nil is a special case //concrete type to interface nil is a special case
return out, nil return out, nil
} }

View file

@ -69,6 +69,22 @@ func getMethods(in interface{}, mapping map[string]string) map[string]reflect.Va
return methods return methods
} }
func getAllMethods(in interface{}, mapping map[string]string) map[string]reflect.Value {
if in == nil {
return nil
}
methods := make(map[string]reflect.Value)
val := reflect.ValueOf(in)
typ := val.Type()
for i := 0; i < typ.NumMethod(); i++ {
methtype := typ.Method(i)
method := val.Method(i)
// map names while building table
methods[computeMethodName(methtype.Name, mapping)] = method
}
return methods
}
func standardMethodArgumentDecode(m Method, sender string, msg *Message, body []interface{}) ([]interface{}, error) { func standardMethodArgumentDecode(m Method, sender string, msg *Message, body []interface{}) ([]interface{}, error) {
pointers := make([]interface{}, m.NumArguments()) pointers := make([]interface{}, m.NumArguments())
decode := make([]interface{}, 0, len(body)) decode := make([]interface{}, 0, len(body))
@ -159,7 +175,6 @@ func (conn *Conn) handleCall(msg *Message) {
if msg.Flags&FlagNoReplyExpected == 0 { if msg.Flags&FlagNoReplyExpected == 0 {
reply := new(Message) reply := new(Message)
reply.Type = TypeMethodReply reply.Type = TypeMethodReply
reply.serial = conn.getSerial()
reply.Headers = make(map[HeaderField]Variant) reply.Headers = make(map[HeaderField]Variant)
if hasSender { if hasSender {
reply.Headers[FieldDestination] = msg.Headers[FieldSender] reply.Headers[FieldDestination] = msg.Headers[FieldSender]
@ -195,7 +210,6 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro
} }
msg := new(Message) msg := new(Message)
msg.Type = TypeSignal msg.Type = TypeSignal
msg.serial = conn.getSerial()
msg.Headers = make(map[HeaderField]Variant) msg.Headers = make(map[HeaderField]Variant)
msg.Headers[FieldInterface] = MakeVariant(iface) msg.Headers[FieldInterface] = MakeVariant(iface)
msg.Headers[FieldMember] = MakeVariant(member) msg.Headers[FieldMember] = MakeVariant(member)
@ -247,6 +261,18 @@ func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error {
return conn.ExportWithMap(v, nil, path, iface) return conn.ExportWithMap(v, nil, path, iface)
} }
// ExportAll registers all exported methods defined by the given object on
// the message bus.
//
// Unlike Export there is no requirement to have the last parameter as type
// *Error. If you want to be able to return error then you can append an error
// type parameter to your method signature. If the error returned is not nil,
// it is sent back to the caller as an error. Otherwise, a method reply is
// sent with the other return values as its body.
func (conn *Conn) ExportAll(v interface{}, path ObjectPath, iface string) error {
return conn.export(getAllMethods(v, nil), path, iface, false)
}
// ExportWithMap works exactly like Export but provides the ability to remap // ExportWithMap works exactly like Export but provides the ability to remap
// method names (e.g. export a lower-case method). // method names (e.g. export a lower-case method).
// //
@ -299,19 +325,22 @@ func (conn *Conn) ExportSubtreeMethodTable(methods map[string]interface{}, path
} }
func (conn *Conn) exportMethodTable(methods map[string]interface{}, path ObjectPath, iface string, includeSubtree bool) error { func (conn *Conn) exportMethodTable(methods map[string]interface{}, path ObjectPath, iface string, includeSubtree bool) error {
out := make(map[string]reflect.Value) var out map[string]reflect.Value
for name, method := range methods { if methods != nil {
rval := reflect.ValueOf(method) out = make(map[string]reflect.Value)
if rval.Kind() != reflect.Func { for name, method := range methods {
continue rval := reflect.ValueOf(method)
if rval.Kind() != reflect.Func {
continue
}
t := rval.Type()
// only track valid methods must return *Error as last arg
if t.NumOut() == 0 ||
t.Out(t.NumOut()-1) != reflect.TypeOf(&ErrMsgInvalidArg) {
continue
}
out[name] = rval
} }
t := rval.Type()
// only track valid methods must return *Error as last arg
if t.NumOut() == 0 ||
t.Out(t.NumOut()-1) != reflect.TypeOf(&ErrMsgInvalidArg) {
continue
}
out[name] = rval
} }
return conn.export(out, path, iface, includeSubtree) return conn.export(out, path, iface, includeSubtree)
} }
@ -327,12 +356,12 @@ func (conn *Conn) unexport(h *defaultHandler, path ObjectPath, iface string) err
return nil return nil
} }
// exportWithMap is the worker function for all exports/registrations. // export is the worker function for all exports/registrations.
func (conn *Conn) export(methods map[string]reflect.Value, path ObjectPath, iface string, includeSubtree bool) error { func (conn *Conn) export(methods map[string]reflect.Value, path ObjectPath, iface string, includeSubtree bool) error {
h, ok := conn.handler.(*defaultHandler) h, ok := conn.handler.(*defaultHandler)
if !ok { if !ok {
return fmt.Errorf( return fmt.Errorf(
`dbus: export only allowed on the default hander handler have %T"`, `dbus: export only allowed on the default handler. Received: %T"`,
conn.handler) conn.handler)
} }

View file

@ -1,6 +1,7 @@
package dbus package dbus
import ( import (
"strconv"
"strings" "strings"
) )
@ -60,3 +61,29 @@ func WithMatchPathNamespace(namespace ObjectPath) MatchOption {
func WithMatchDestination(destination string) MatchOption { func WithMatchDestination(destination string) MatchOption {
return WithMatchOption("destination", destination) return WithMatchOption("destination", destination)
} }
// WithMatchArg sets argN match option, range of N is 0 to 63.
func WithMatchArg(argIdx int, value string) MatchOption {
if argIdx < 0 || argIdx > 63 {
panic("range of argument index is 0 to 63")
}
return WithMatchOption("arg"+strconv.Itoa(argIdx), value)
}
// WithMatchArgPath sets argN path match option, range of N is 0 to 63.
func WithMatchArgPath(argIdx int, path string) MatchOption {
if argIdx < 0 || argIdx > 63 {
panic("range of argument index is 0 to 63")
}
return WithMatchOption("arg"+strconv.Itoa(argIdx)+"path", path)
}
// WithMatchArg0Namespace sets arg0namespace match option.
func WithMatchArg0Namespace(arg0Namespace string) MatchOption {
return WithMatchOption("arg0namespace", arg0Namespace)
}
// WithMatchEavesdrop sets eavesdrop match option.
func WithMatchEavesdrop(eavesdrop bool) MatchOption {
return WithMatchOption("eavesdrop", strconv.FormatBool(eavesdrop))
}

View file

@ -16,6 +16,7 @@ type BusObject interface {
AddMatchSignal(iface, member string, options ...MatchOption) *Call AddMatchSignal(iface, member string, options ...MatchOption) *Call
RemoveMatchSignal(iface, member string, options ...MatchOption) *Call RemoveMatchSignal(iface, member string, options ...MatchOption) *Call
GetProperty(p string) (Variant, error) GetProperty(p string) (Variant, error)
StoreProperty(p string, value interface{}) error
SetProperty(p string, v interface{}) error SetProperty(p string, v interface{}) error
Destination() string Destination() string
Path() ObjectPath Path() ObjectPath
@ -109,7 +110,6 @@ func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch
method = method[i+1:] method = method[i+1:]
msg := new(Message) msg := new(Message)
msg.Type = TypeMethodCall msg.Type = TypeMethodCall
msg.serial = o.conn.getSerial()
msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected) msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected)
msg.Headers = make(map[HeaderField]Variant) msg.Headers = make(map[HeaderField]Variant)
msg.Headers[FieldPath] = MakeVariant(o.path) msg.Headers[FieldPath] = MakeVariant(o.path)
@ -122,68 +122,31 @@ func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch
if len(args) > 0 { if len(args) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...)) msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...))
} }
if msg.Flags&FlagNoReplyExpected == 0 { return o.conn.SendWithContext(ctx, msg, ch)
if ch == nil {
ch = make(chan *Call, 1)
} 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.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
}
done := make(chan *Call, 1)
call := &Call{
Err: nil,
Done: done,
}
defer func() {
call.Done <- call
close(done)
}()
o.conn.sendMessageAndIfClosed(msg, func() {
call.Err = ErrClosed
})
return call
} }
// GetProperty calls org.freedesktop.DBus.Properties.Get on the given // GetProperty calls org.freedesktop.DBus.Properties.Get on the given
// object. The property name must be given in interface.member notation. // object. The property name must be given in interface.member notation.
func (o *Object) GetProperty(p string) (Variant, error) { func (o *Object) GetProperty(p string) (Variant, error) {
var result Variant
err := o.StoreProperty(p, &result)
return result, err
}
// StoreProperty calls org.freedesktop.DBus.Properties.Get on the given
// object. The property name must be given in interface.member notation.
// It stores the returned property into the provided value.
func (o *Object) StoreProperty(p string, value interface{}) error {
idx := strings.LastIndex(p, ".") idx := strings.LastIndex(p, ".")
if idx == -1 || idx+1 == len(p) { if idx == -1 || idx+1 == len(p) {
return Variant{}, errors.New("dbus: invalid property " + p) return errors.New("dbus: invalid property " + p)
} }
iface := p[:idx] iface := p[:idx]
prop := p[idx+1:] prop := p[idx+1:]
result := Variant{} return o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).
err := o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).Store(&result) Store(value)
if err != nil {
return Variant{}, err
}
return result, nil
} }
// SetProperty calls org.freedesktop.DBus.Properties.Set on the given // SetProperty calls org.freedesktop.DBus.Properties.Set on the given

24
vendor/github.com/godbus/dbus/v5/sequence.go generated vendored Normal file
View file

@ -0,0 +1,24 @@
package dbus
// Sequence represents the value of a monotonically increasing counter.
type Sequence uint64
const (
// NoSequence indicates the absence of a sequence value.
NoSequence Sequence = 0
)
// sequenceGenerator represents a monotonically increasing counter.
type sequenceGenerator struct {
nextSequence Sequence
}
func (generator *sequenceGenerator) next() Sequence {
result := generator.nextSequence
generator.nextSequence++
return result
}
func newSequenceGenerator() *sequenceGenerator {
return &sequenceGenerator{nextSequence: 1}
}

125
vendor/github.com/godbus/dbus/v5/sequential_handler.go generated vendored Normal file
View file

@ -0,0 +1,125 @@
package dbus
import (
"sync"
)
// NewSequentialSignalHandler returns an instance of a new
// signal handler that guarantees sequential processing of signals. It is a
// guarantee of this signal handler that signals will be written to
// channels in the order they are received on the DBus connection.
func NewSequentialSignalHandler() SignalHandler {
return &sequentialSignalHandler{}
}
type sequentialSignalHandler struct {
mu sync.RWMutex
closed bool
signals []*sequentialSignalChannelData
}
func (sh *sequentialSignalHandler) DeliverSignal(intf, name string, signal *Signal) {
sh.mu.RLock()
defer sh.mu.RUnlock()
if sh.closed {
return
}
for _, scd := range sh.signals {
scd.deliver(signal)
}
}
func (sh *sequentialSignalHandler) Terminate() {
sh.mu.Lock()
defer sh.mu.Unlock()
if sh.closed {
return
}
for _, scd := range sh.signals {
scd.close()
close(scd.ch)
}
sh.closed = true
sh.signals = nil
}
func (sh *sequentialSignalHandler) AddSignal(ch chan<- *Signal) {
sh.mu.Lock()
defer sh.mu.Unlock()
if sh.closed {
return
}
sh.signals = append(sh.signals, newSequentialSignalChannelData(ch))
}
func (sh *sequentialSignalHandler) RemoveSignal(ch chan<- *Signal) {
sh.mu.Lock()
defer sh.mu.Unlock()
if sh.closed {
return
}
for i := len(sh.signals) - 1; i >= 0; i-- {
if ch == sh.signals[i].ch {
sh.signals[i].close()
copy(sh.signals[i:], sh.signals[i+1:])
sh.signals[len(sh.signals)-1] = nil
sh.signals = sh.signals[:len(sh.signals)-1]
}
}
}
type sequentialSignalChannelData struct {
ch chan<- *Signal
in chan *Signal
done chan struct{}
}
func newSequentialSignalChannelData(ch chan<- *Signal) *sequentialSignalChannelData {
scd := &sequentialSignalChannelData{
ch: ch,
in: make(chan *Signal),
done: make(chan struct{}),
}
go scd.bufferSignals()
return scd
}
func (scd *sequentialSignalChannelData) bufferSignals() {
defer close(scd.done)
// Ensure that signals are delivered to scd.ch in the same
// order they are received from scd.in.
var queue []*Signal
for {
if len(queue) == 0 {
signal, ok := <- scd.in
if !ok {
return
}
queue = append(queue, signal)
}
select {
case scd.ch <- queue[0]:
copy(queue, queue[1:])
queue[len(queue)-1] = nil
queue = queue[:len(queue)-1]
case signal, ok := <-scd.in:
if !ok {
return
}
queue = append(queue, signal)
}
}
}
func (scd *sequentialSignalChannelData) deliver(signal *Signal) {
scd.in <- signal
}
func (scd *sequentialSignalChannelData) close() {
close(scd.in)
// Ensure that bufferSignals() has exited and won't attempt
// any future sends on scd.ch
<-scd.done
}

View file

@ -137,7 +137,7 @@ func ParseSignatureMust(s string) Signature {
return sig return sig
} }
// Empty retruns whether the signature is the empty signature. // Empty returns whether the signature is the empty signature.
func (s Signature) Empty() bool { func (s Signature) Empty() bool {
return s.str == "" return s.str == ""
} }

View file

@ -10,6 +10,7 @@ package dbus
/* /*
const int sizeofPtr = sizeof(void*); const int sizeofPtr = sizeof(void*);
#define _WANT_UCRED #define _WANT_UCRED
#include <sys/types.h>
#include <sys/ucred.h> #include <sys/ucred.h>
*/ */
import "C" import "C"

View file

@ -142,3 +142,9 @@ func (v Variant) String() string {
func (v Variant) Value() interface{} { func (v Variant) Value() interface{} {
return v.value return v.value
} }
// Store converts the variant into a native go type using the same
// mechanism as the "Store" function.
func (v Variant) Store(value interface{}) error {
return storeInterfaces(v.value, value)
}