go-tg-screenshot-bot
996 строк · 26.8 Кб
1package dbus
2
3import (
4"context"
5"errors"
6"io"
7"os"
8"strings"
9"sync"
10)
11
12var (
13systemBus *Conn
14systemBusLck sync.Mutex
15sessionBus *Conn
16sessionBusLck sync.Mutex
17)
18
19// ErrClosed is the error returned by calls on a closed connection.
20var ErrClosed = errors.New("dbus: connection closed by user")
21
22// Conn represents a connection to a message bus (usually, the system or
23// session bus).
24//
25// Connections are either shared or private. Shared connections
26// are shared between calls to the functions that return them. As a result,
27// the methods Close, Auth and Hello must not be called on them.
28//
29// Multiple goroutines may invoke methods on a connection simultaneously.
30type Conn struct {
31transport
32
33ctx context.Context
34cancelCtx context.CancelFunc
35
36closeOnce sync.Once
37closeErr error
38
39busObj BusObject
40unixFD bool
41uuid string
42
43handler Handler
44signalHandler SignalHandler
45serialGen SerialGenerator
46inInt Interceptor
47outInt Interceptor
48auth []Auth
49
50names *nameTracker
51calls *callTracker
52outHandler *outputHandler
53
54eavesdropped chan<- *Message
55eavesdroppedLck sync.Mutex
56}
57
58// SessionBus returns a shared connection to the session bus, connecting to it
59// if not already done.
60func SessionBus() (conn *Conn, err error) {
61sessionBusLck.Lock()
62defer sessionBusLck.Unlock()
63if sessionBus != nil &&
64sessionBus.Connected() {
65return sessionBus, nil
66}
67defer func() {
68if conn != nil {
69sessionBus = conn
70}
71}()
72conn, err = ConnectSessionBus()
73return
74}
75
76func getSessionBusAddress(autolaunch bool) (string, error) {
77if address := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); address != "" && address != "autolaunch:" {
78return address, nil
79
80} else if address := tryDiscoverDbusSessionBusAddress(); address != "" {
81os.Setenv("DBUS_SESSION_BUS_ADDRESS", address)
82return address, nil
83}
84if !autolaunch {
85return "", errors.New("dbus: couldn't determine address of session bus")
86}
87return getSessionBusPlatformAddress()
88}
89
90// SessionBusPrivate returns a new private connection to the session bus.
91func SessionBusPrivate(opts ...ConnOption) (*Conn, error) {
92address, err := getSessionBusAddress(true)
93if err != nil {
94return nil, err
95}
96
97return Dial(address, opts...)
98}
99
100// SessionBusPrivate returns a new private connection to the session bus. If
101// the session bus is not already open, do not attempt to launch it.
102func SessionBusPrivateNoAutoStartup(opts ...ConnOption) (*Conn, error) {
103address, err := getSessionBusAddress(false)
104if err != nil {
105return nil, err
106}
107
108return Dial(address, opts...)
109}
110
111// SessionBusPrivate returns a new private connection to the session bus.
112//
113// Deprecated: use SessionBusPrivate with options instead.
114func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) {
115return SessionBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler))
116}
117
118// SystemBus returns a shared connection to the system bus, connecting to it if
119// not already done.
120func SystemBus() (conn *Conn, err error) {
121systemBusLck.Lock()
122defer systemBusLck.Unlock()
123if systemBus != nil &&
124systemBus.Connected() {
125return systemBus, nil
126}
127defer func() {
128if conn != nil {
129systemBus = conn
130}
131}()
132conn, err = ConnectSystemBus()
133return
134}
135
136// ConnectSessionBus connects to the session bus.
137func ConnectSessionBus(opts ...ConnOption) (*Conn, error) {
138address, err := getSessionBusAddress(true)
139if err != nil {
140return nil, err
141}
142return Connect(address, opts...)
143}
144
145// ConnectSystemBus connects to the system bus.
146func ConnectSystemBus(opts ...ConnOption) (*Conn, error) {
147return Connect(getSystemBusPlatformAddress(), opts...)
148}
149
150// Connect connects to the given address.
151//
152// Returned connection is ready to use and doesn't require calling
153// Auth and Hello methods to make it usable.
154func Connect(address string, opts ...ConnOption) (*Conn, error) {
155conn, err := Dial(address, opts...)
156if err != nil {
157return nil, err
158}
159if err = conn.Auth(conn.auth); err != nil {
160_ = conn.Close()
161return nil, err
162}
163if err = conn.Hello(); err != nil {
164_ = conn.Close()
165return nil, err
166}
167return conn, nil
168}
169
170// SystemBusPrivate returns a new private connection to the system bus.
171// Note: this connection is not ready to use. One must perform Auth and Hello
172// on the connection before it is usable.
173func SystemBusPrivate(opts ...ConnOption) (*Conn, error) {
174return Dial(getSystemBusPlatformAddress(), opts...)
175}
176
177// SystemBusPrivateHandler returns a new private connection to the system bus, using the provided handlers.
178//
179// Deprecated: use SystemBusPrivate with options instead.
180func SystemBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) {
181return SystemBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler))
182}
183
184// Dial establishes a new private connection to the message bus specified by address.
185func Dial(address string, opts ...ConnOption) (*Conn, error) {
186tr, err := getTransport(address)
187if err != nil {
188return nil, err
189}
190return newConn(tr, opts...)
191}
192
193// DialHandler establishes a new private connection to the message bus specified by address, using the supplied handlers.
194//
195// Deprecated: use Dial with options instead.
196func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) {
197return Dial(address, WithHandler(handler), WithSignalHandler(signalHandler))
198}
199
200// ConnOption is a connection option.
201type ConnOption func(conn *Conn) error
202
203// WithHandler overrides the default handler.
204func WithHandler(handler Handler) ConnOption {
205return func(conn *Conn) error {
206conn.handler = handler
207return nil
208}
209}
210
211// WithSignalHandler overrides the default signal handler.
212func WithSignalHandler(handler SignalHandler) ConnOption {
213return func(conn *Conn) error {
214conn.signalHandler = handler
215return nil
216}
217}
218
219// WithSerialGenerator overrides the default signals generator.
220func WithSerialGenerator(gen SerialGenerator) ConnOption {
221return func(conn *Conn) error {
222conn.serialGen = gen
223return nil
224}
225}
226
227// WithAuth sets authentication methods for the auth conversation.
228func WithAuth(methods ...Auth) ConnOption {
229return func(conn *Conn) error {
230conn.auth = methods
231return nil
232}
233}
234
235// Interceptor intercepts incoming and outgoing messages.
236type Interceptor func(msg *Message)
237
238// WithIncomingInterceptor sets the given interceptor for incoming messages.
239func WithIncomingInterceptor(interceptor Interceptor) ConnOption {
240return func(conn *Conn) error {
241conn.inInt = interceptor
242return nil
243}
244}
245
246// WithOutgoingInterceptor sets the given interceptor for outgoing messages.
247func WithOutgoingInterceptor(interceptor Interceptor) ConnOption {
248return func(conn *Conn) error {
249conn.outInt = interceptor
250return nil
251}
252}
253
254// WithContext overrides the default context for the connection.
255func WithContext(ctx context.Context) ConnOption {
256return func(conn *Conn) error {
257conn.ctx = ctx
258return nil
259}
260}
261
262// NewConn creates a new private *Conn from an already established connection.
263func NewConn(conn io.ReadWriteCloser, opts ...ConnOption) (*Conn, error) {
264return newConn(genericTransport{conn}, opts...)
265}
266
267// NewConnHandler creates a new private *Conn from an already established connection, using the supplied handlers.
268//
269// Deprecated: use NewConn with options instead.
270func NewConnHandler(conn io.ReadWriteCloser, handler Handler, signalHandler SignalHandler) (*Conn, error) {
271return NewConn(genericTransport{conn}, WithHandler(handler), WithSignalHandler(signalHandler))
272}
273
274// newConn creates a new *Conn from a transport.
275func newConn(tr transport, opts ...ConnOption) (*Conn, error) {
276conn := new(Conn)
277conn.transport = tr
278for _, opt := range opts {
279if err := opt(conn); err != nil {
280return nil, err
281}
282}
283if conn.ctx == nil {
284conn.ctx = context.Background()
285}
286conn.ctx, conn.cancelCtx = context.WithCancel(conn.ctx)
287
288conn.calls = newCallTracker()
289if conn.handler == nil {
290conn.handler = NewDefaultHandler()
291}
292if conn.signalHandler == nil {
293conn.signalHandler = NewDefaultSignalHandler()
294}
295if conn.serialGen == nil {
296conn.serialGen = newSerialGenerator()
297}
298conn.outHandler = &outputHandler{conn: conn}
299conn.names = newNameTracker()
300conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
301
302go func() {
303<-conn.ctx.Done()
304conn.Close()
305}()
306return conn, nil
307}
308
309// BusObject returns the object owned by the bus daemon which handles
310// administrative requests.
311func (conn *Conn) BusObject() BusObject {
312return conn.busObj
313}
314
315// Close closes the connection. Any blocked operations will return with errors
316// and the channels passed to Eavesdrop and Signal are closed. This method must
317// not be called on shared connections.
318func (conn *Conn) Close() error {
319conn.closeOnce.Do(func() {
320conn.outHandler.close()
321if term, ok := conn.signalHandler.(Terminator); ok {
322term.Terminate()
323}
324
325if term, ok := conn.handler.(Terminator); ok {
326term.Terminate()
327}
328
329conn.eavesdroppedLck.Lock()
330if conn.eavesdropped != nil {
331close(conn.eavesdropped)
332}
333conn.eavesdroppedLck.Unlock()
334
335conn.cancelCtx()
336
337conn.closeErr = conn.transport.Close()
338})
339return conn.closeErr
340}
341
342// Context returns the context associated with the connection. The
343// context will be cancelled when the connection is closed.
344func (conn *Conn) Context() context.Context {
345return conn.ctx
346}
347
348// Connected returns whether conn is connected
349func (conn *Conn) Connected() bool {
350return conn.ctx.Err() == nil
351}
352
353// Eavesdrop causes conn to send all incoming messages to the given channel
354// without further processing. Method replies, errors and signals will not be
355// sent to the appropriate channels and method calls will not be handled. If nil
356// is passed, the normal behaviour is restored.
357//
358// The caller has to make sure that ch is sufficiently buffered;
359// if a message arrives when a write to ch is not possible, the message is
360// discarded.
361func (conn *Conn) Eavesdrop(ch chan<- *Message) {
362conn.eavesdroppedLck.Lock()
363conn.eavesdropped = ch
364conn.eavesdroppedLck.Unlock()
365}
366
367// getSerial returns an unused serial.
368func (conn *Conn) getSerial() uint32 {
369return conn.serialGen.GetSerial()
370}
371
372// Hello sends the initial org.freedesktop.DBus.Hello call. This method must be
373// called after authentication, but before sending any other messages to the
374// bus. Hello must not be called for shared connections.
375func (conn *Conn) Hello() error {
376var s string
377err := conn.busObj.Call("org.freedesktop.DBus.Hello", 0).Store(&s)
378if err != nil {
379return err
380}
381conn.names.acquireUniqueConnectionName(s)
382return nil
383}
384
385// inWorker runs in an own goroutine, reading incoming messages from the
386// transport and dispatching them appropriately.
387func (conn *Conn) inWorker() {
388sequenceGen := newSequenceGenerator()
389for {
390msg, err := conn.ReadMessage()
391if err != nil {
392if _, ok := err.(InvalidMessageError); !ok {
393// Some read error occurred (usually EOF); we can't really do
394// anything but to shut down all stuff and returns errors to all
395// pending replies.
396conn.Close()
397conn.calls.finalizeAllWithError(sequenceGen, err)
398return
399}
400// invalid messages are ignored
401continue
402}
403conn.eavesdroppedLck.Lock()
404if conn.eavesdropped != nil {
405select {
406case conn.eavesdropped <- msg:
407default:
408}
409conn.eavesdroppedLck.Unlock()
410continue
411}
412conn.eavesdroppedLck.Unlock()
413dest, _ := msg.Headers[FieldDestination].value.(string)
414found := dest == "" ||
415!conn.names.uniqueNameIsKnown() ||
416conn.names.isKnownName(dest)
417if !found {
418// Eavesdropped a message, but no channel for it is registered.
419// Ignore it.
420continue
421}
422
423if conn.inInt != nil {
424conn.inInt(msg)
425}
426sequence := sequenceGen.next()
427switch msg.Type {
428case TypeError:
429conn.serialGen.RetireSerial(conn.calls.handleDBusError(sequence, msg))
430case TypeMethodReply:
431conn.serialGen.RetireSerial(conn.calls.handleReply(sequence, msg))
432case TypeSignal:
433conn.handleSignal(sequence, msg)
434case TypeMethodCall:
435go conn.handleCall(msg)
436}
437
438}
439}
440
441func (conn *Conn) handleSignal(sequence Sequence, msg *Message) {
442iface := msg.Headers[FieldInterface].value.(string)
443member := msg.Headers[FieldMember].value.(string)
444// as per http://dbus.freedesktop.org/doc/dbus-specification.html ,
445// sender is optional for signals.
446sender, _ := msg.Headers[FieldSender].value.(string)
447if iface == "org.freedesktop.DBus" && sender == "org.freedesktop.DBus" {
448if member == "NameLost" {
449// If we lost the name on the bus, remove it from our
450// tracking list.
451name, ok := msg.Body[0].(string)
452if !ok {
453panic("Unable to read the lost name")
454}
455conn.names.loseName(name)
456} else if member == "NameAcquired" {
457// If we acquired the name on the bus, add it to our
458// tracking list.
459name, ok := msg.Body[0].(string)
460if !ok {
461panic("Unable to read the acquired name")
462}
463conn.names.acquireName(name)
464}
465}
466signal := &Signal{
467Sender: sender,
468Path: msg.Headers[FieldPath].value.(ObjectPath),
469Name: iface + "." + member,
470Body: msg.Body,
471Sequence: sequence,
472}
473conn.signalHandler.DeliverSignal(iface, member, signal)
474}
475
476// Names returns the list of all names that are currently owned by this
477// connection. The slice is always at least one element long, the first element
478// being the unique name of the connection.
479func (conn *Conn) Names() []string {
480return conn.names.listKnownNames()
481}
482
483// Object returns the object identified by the given destination name and path.
484func (conn *Conn) Object(dest string, path ObjectPath) BusObject {
485return &Object{conn, dest, path}
486}
487
488func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) {
489if msg.serial == 0 {
490msg.serial = conn.getSerial()
491}
492if conn.outInt != nil {
493conn.outInt(msg)
494}
495err := conn.outHandler.sendAndIfClosed(msg, ifClosed)
496if err != nil {
497conn.handleSendError(msg, err)
498} else if msg.Type != TypeMethodCall {
499conn.serialGen.RetireSerial(msg.serial)
500}
501}
502
503func (conn *Conn) handleSendError(msg *Message, err error) {
504if msg.Type == TypeMethodCall {
505conn.calls.handleSendError(msg, err)
506} else if msg.Type == TypeMethodReply {
507if _, ok := err.(FormatError); ok {
508conn.sendError(err, msg.Headers[FieldDestination].value.(string), msg.Headers[FieldReplySerial].value.(uint32))
509}
510}
511conn.serialGen.RetireSerial(msg.serial)
512}
513
514// Send sends the given message to the message bus. You usually don't need to
515// use this; use the higher-level equivalents (Call / Go, Emit and Export)
516// instead. If msg is a method call and NoReplyExpected is not set, a non-nil
517// call is returned and the same value is sent to ch (which must be buffered)
518// once the call is complete. Otherwise, ch is ignored and a Call structure is
519// returned of which only the Err member is valid.
520func (conn *Conn) Send(msg *Message, ch chan *Call) *Call {
521return conn.send(context.Background(), msg, ch)
522}
523
524// SendWithContext acts like Send but takes a context
525func (conn *Conn) SendWithContext(ctx context.Context, msg *Message, ch chan *Call) *Call {
526return conn.send(ctx, msg, ch)
527}
528
529func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call {
530if ctx == nil {
531panic("nil context")
532}
533if ch == nil {
534ch = make(chan *Call, 1)
535} else if cap(ch) == 0 {
536panic("dbus: unbuffered channel passed to (*Conn).Send")
537}
538
539var call *Call
540ctx, canceler := context.WithCancel(ctx)
541msg.serial = conn.getSerial()
542if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 {
543call = new(Call)
544call.Destination, _ = msg.Headers[FieldDestination].value.(string)
545call.Path, _ = msg.Headers[FieldPath].value.(ObjectPath)
546iface, _ := msg.Headers[FieldInterface].value.(string)
547member, _ := msg.Headers[FieldMember].value.(string)
548call.Method = iface + "." + member
549call.Args = msg.Body
550call.Done = ch
551call.ctx = ctx
552call.ctxCanceler = canceler
553conn.calls.track(msg.serial, call)
554if ctx.Err() != nil {
555// short path: don't even send the message if context already cancelled
556conn.calls.handleSendError(msg, ctx.Err())
557return call
558}
559go func() {
560<-ctx.Done()
561conn.calls.handleSendError(msg, ctx.Err())
562}()
563conn.sendMessageAndIfClosed(msg, func() {
564conn.calls.handleSendError(msg, ErrClosed)
565canceler()
566})
567} else {
568canceler()
569call = &Call{Err: nil, Done: ch}
570ch <- call
571conn.sendMessageAndIfClosed(msg, func() {
572call = &Call{Err: ErrClosed}
573})
574}
575return call
576}
577
578// sendError creates an error message corresponding to the parameters and sends
579// it to conn.out.
580func (conn *Conn) sendError(err error, dest string, serial uint32) {
581var e *Error
582switch em := err.(type) {
583case Error:
584e = &em
585case *Error:
586e = em
587case DBusError:
588name, body := em.DBusError()
589e = NewError(name, body)
590default:
591e = MakeFailedError(err)
592}
593msg := new(Message)
594msg.Type = TypeError
595msg.Headers = make(map[HeaderField]Variant)
596if dest != "" {
597msg.Headers[FieldDestination] = MakeVariant(dest)
598}
599msg.Headers[FieldErrorName] = MakeVariant(e.Name)
600msg.Headers[FieldReplySerial] = MakeVariant(serial)
601msg.Body = e.Body
602if len(e.Body) > 0 {
603msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...))
604}
605conn.sendMessageAndIfClosed(msg, nil)
606}
607
608// sendReply creates a method reply message corresponding to the parameters and
609// sends it to conn.out.
610func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
611msg := new(Message)
612msg.Type = TypeMethodReply
613msg.Headers = make(map[HeaderField]Variant)
614if dest != "" {
615msg.Headers[FieldDestination] = MakeVariant(dest)
616}
617msg.Headers[FieldReplySerial] = MakeVariant(serial)
618msg.Body = values
619if len(values) > 0 {
620msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
621}
622conn.sendMessageAndIfClosed(msg, nil)
623}
624
625// AddMatchSignal registers the given match rule to receive broadcast
626// signals based on their contents.
627func (conn *Conn) AddMatchSignal(options ...MatchOption) error {
628return conn.AddMatchSignalContext(context.Background(), options...)
629}
630
631// AddMatchSignalContext acts like AddMatchSignal but takes a context.
632func (conn *Conn) AddMatchSignalContext(ctx context.Context, options ...MatchOption) error {
633options = append([]MatchOption{withMatchType("signal")}, options...)
634return conn.busObj.CallWithContext(
635ctx,
636"org.freedesktop.DBus.AddMatch", 0,
637formatMatchOptions(options),
638).Store()
639}
640
641// RemoveMatchSignal removes the first rule that matches previously registered with AddMatchSignal.
642func (conn *Conn) RemoveMatchSignal(options ...MatchOption) error {
643return conn.RemoveMatchSignalContext(context.Background(), options...)
644}
645
646// RemoveMatchSignalContext acts like RemoveMatchSignal but takes a context.
647func (conn *Conn) RemoveMatchSignalContext(ctx context.Context, options ...MatchOption) error {
648options = append([]MatchOption{withMatchType("signal")}, options...)
649return conn.busObj.CallWithContext(
650ctx,
651"org.freedesktop.DBus.RemoveMatch", 0,
652formatMatchOptions(options),
653).Store()
654}
655
656// Signal registers the given channel to be passed all received signal messages.
657//
658// Multiple of these channels can be registered at the same time. The channel is
659// closed if the Conn is closed; it should not be closed by the caller before
660// RemoveSignal was called on it.
661//
662// These channels are "overwritten" by Eavesdrop; i.e., if there currently is a
663// channel for eavesdropped messages, this channel receives all signals, and
664// none of the channels passed to Signal will receive any signals.
665//
666// Panics if the signal handler is not a `SignalRegistrar`.
667func (conn *Conn) Signal(ch chan<- *Signal) {
668handler, ok := conn.signalHandler.(SignalRegistrar)
669if !ok {
670panic("cannot use this method with a non SignalRegistrar handler")
671}
672handler.AddSignal(ch)
673}
674
675// RemoveSignal removes the given channel from the list of the registered channels.
676//
677// Panics if the signal handler is not a `SignalRegistrar`.
678func (conn *Conn) RemoveSignal(ch chan<- *Signal) {
679handler, ok := conn.signalHandler.(SignalRegistrar)
680if !ok {
681panic("cannot use this method with a non SignalRegistrar handler")
682}
683handler.RemoveSignal(ch)
684}
685
686// SupportsUnixFDs returns whether the underlying transport supports passing of
687// unix file descriptors. If this is false, method calls containing unix file
688// descriptors will return an error and emitted signals containing them will
689// not be sent.
690func (conn *Conn) SupportsUnixFDs() bool {
691return conn.unixFD
692}
693
694// Error represents a D-Bus message of type Error.
695type Error struct {
696Name string
697Body []interface{}
698}
699
700func NewError(name string, body []interface{}) *Error {
701return &Error{name, body}
702}
703
704func (e Error) Error() string {
705if len(e.Body) >= 1 {
706s, ok := e.Body[0].(string)
707if ok {
708return s
709}
710}
711return e.Name
712}
713
714// Signal represents a D-Bus message of type Signal. The name member is given in
715// "interface.member" notation, e.g. org.freedesktop.D-Bus.NameLost.
716type Signal struct {
717Sender string
718Path ObjectPath
719Name string
720Body []interface{}
721Sequence Sequence
722}
723
724// transport is a D-Bus transport.
725type transport interface {
726// Read and Write raw data (for example, for the authentication protocol).
727io.ReadWriteCloser
728
729// Send the initial null byte used for the EXTERNAL mechanism.
730SendNullByte() error
731
732// Returns whether this transport supports passing Unix FDs.
733SupportsUnixFDs() bool
734
735// Signal the transport that Unix FD passing is enabled for this connection.
736EnableUnixFDs()
737
738// Read / send a message, handling things like Unix FDs.
739ReadMessage() (*Message, error)
740SendMessage(*Message) error
741}
742
743var (
744transports = make(map[string]func(string) (transport, error))
745)
746
747func getTransport(address string) (transport, error) {
748var err error
749var t transport
750
751addresses := strings.Split(address, ";")
752for _, v := range addresses {
753i := strings.IndexRune(v, ':')
754if i == -1 {
755err = errors.New("dbus: invalid bus address (no transport)")
756continue
757}
758f := transports[v[:i]]
759if f == nil {
760err = errors.New("dbus: invalid bus address (invalid or unsupported transport)")
761continue
762}
763t, err = f(v[i+1:])
764if err == nil {
765return t, nil
766}
767}
768return nil, err
769}
770
771// getKey gets a key from a the list of keys. Returns "" on error / not found...
772func getKey(s, key string) string {
773for _, keyEqualsValue := range strings.Split(s, ",") {
774keyValue := strings.SplitN(keyEqualsValue, "=", 2)
775if len(keyValue) == 2 && keyValue[0] == key {
776val, err := UnescapeBusAddressValue(keyValue[1])
777if err != nil {
778// No way to return an error.
779return ""
780}
781return val
782}
783}
784return ""
785}
786
787type outputHandler struct {
788conn *Conn
789sendLck sync.Mutex
790closed struct {
791isClosed bool
792lck sync.RWMutex
793}
794}
795
796func (h *outputHandler) sendAndIfClosed(msg *Message, ifClosed func()) error {
797h.closed.lck.RLock()
798defer h.closed.lck.RUnlock()
799if h.closed.isClosed {
800if ifClosed != nil {
801ifClosed()
802}
803return nil
804}
805h.sendLck.Lock()
806defer h.sendLck.Unlock()
807return h.conn.SendMessage(msg)
808}
809
810func (h *outputHandler) close() {
811h.closed.lck.Lock()
812defer h.closed.lck.Unlock()
813h.closed.isClosed = true
814}
815
816type serialGenerator struct {
817lck sync.Mutex
818nextSerial uint32
819serialUsed map[uint32]bool
820}
821
822func newSerialGenerator() *serialGenerator {
823return &serialGenerator{
824serialUsed: map[uint32]bool{0: true},
825nextSerial: 1,
826}
827}
828
829func (gen *serialGenerator) GetSerial() uint32 {
830gen.lck.Lock()
831defer gen.lck.Unlock()
832n := gen.nextSerial
833for gen.serialUsed[n] {
834n++
835}
836gen.serialUsed[n] = true
837gen.nextSerial = n + 1
838return n
839}
840
841func (gen *serialGenerator) RetireSerial(serial uint32) {
842gen.lck.Lock()
843defer gen.lck.Unlock()
844delete(gen.serialUsed, serial)
845}
846
847type nameTracker struct {
848lck sync.RWMutex
849unique string
850names map[string]struct{}
851}
852
853func newNameTracker() *nameTracker {
854return &nameTracker{names: map[string]struct{}{}}
855}
856func (tracker *nameTracker) acquireUniqueConnectionName(name string) {
857tracker.lck.Lock()
858defer tracker.lck.Unlock()
859tracker.unique = name
860}
861func (tracker *nameTracker) acquireName(name string) {
862tracker.lck.Lock()
863defer tracker.lck.Unlock()
864tracker.names[name] = struct{}{}
865}
866func (tracker *nameTracker) loseName(name string) {
867tracker.lck.Lock()
868defer tracker.lck.Unlock()
869delete(tracker.names, name)
870}
871
872func (tracker *nameTracker) uniqueNameIsKnown() bool {
873tracker.lck.RLock()
874defer tracker.lck.RUnlock()
875return tracker.unique != ""
876}
877func (tracker *nameTracker) isKnownName(name string) bool {
878tracker.lck.RLock()
879defer tracker.lck.RUnlock()
880_, ok := tracker.names[name]
881return ok || name == tracker.unique
882}
883func (tracker *nameTracker) listKnownNames() []string {
884tracker.lck.RLock()
885defer tracker.lck.RUnlock()
886out := make([]string, 0, len(tracker.names)+1)
887out = append(out, tracker.unique)
888for k := range tracker.names {
889out = append(out, k)
890}
891return out
892}
893
894type callTracker struct {
895calls map[uint32]*Call
896lck sync.RWMutex
897}
898
899func newCallTracker() *callTracker {
900return &callTracker{calls: map[uint32]*Call{}}
901}
902
903func (tracker *callTracker) track(sn uint32, call *Call) {
904tracker.lck.Lock()
905tracker.calls[sn] = call
906tracker.lck.Unlock()
907}
908
909func (tracker *callTracker) handleReply(sequence Sequence, msg *Message) uint32 {
910serial := msg.Headers[FieldReplySerial].value.(uint32)
911tracker.lck.RLock()
912_, ok := tracker.calls[serial]
913tracker.lck.RUnlock()
914if ok {
915tracker.finalizeWithBody(serial, sequence, msg.Body)
916}
917return serial
918}
919
920func (tracker *callTracker) handleDBusError(sequence Sequence, msg *Message) uint32 {
921serial := msg.Headers[FieldReplySerial].value.(uint32)
922tracker.lck.RLock()
923_, ok := tracker.calls[serial]
924tracker.lck.RUnlock()
925if ok {
926name, _ := msg.Headers[FieldErrorName].value.(string)
927tracker.finalizeWithError(serial, sequence, Error{name, msg.Body})
928}
929return serial
930}
931
932func (tracker *callTracker) handleSendError(msg *Message, err error) {
933if err == nil {
934return
935}
936tracker.lck.RLock()
937_, ok := tracker.calls[msg.serial]
938tracker.lck.RUnlock()
939if ok {
940tracker.finalizeWithError(msg.serial, NoSequence, err)
941}
942}
943
944// finalize was the only func that did not strobe Done
945func (tracker *callTracker) finalize(sn uint32) {
946tracker.lck.Lock()
947defer tracker.lck.Unlock()
948c, ok := tracker.calls[sn]
949if ok {
950delete(tracker.calls, sn)
951c.ContextCancel()
952}
953}
954
955func (tracker *callTracker) finalizeWithBody(sn uint32, sequence Sequence, body []interface{}) {
956tracker.lck.Lock()
957c, ok := tracker.calls[sn]
958if ok {
959delete(tracker.calls, sn)
960}
961tracker.lck.Unlock()
962if ok {
963c.Body = body
964c.ResponseSequence = sequence
965c.done()
966}
967}
968
969func (tracker *callTracker) finalizeWithError(sn uint32, sequence Sequence, err error) {
970tracker.lck.Lock()
971c, ok := tracker.calls[sn]
972if ok {
973delete(tracker.calls, sn)
974}
975tracker.lck.Unlock()
976if ok {
977c.Err = err
978c.ResponseSequence = sequence
979c.done()
980}
981}
982
983func (tracker *callTracker) finalizeAllWithError(sequenceGen *sequenceGenerator, err error) {
984tracker.lck.Lock()
985closedCalls := make([]*Call, 0, len(tracker.calls))
986for sn := range tracker.calls {
987closedCalls = append(closedCalls, tracker.calls[sn])
988}
989tracker.calls = map[uint32]*Call{}
990tracker.lck.Unlock()
991for _, call := range closedCalls {
992call.Err = err
993call.ResponseSequence = sequenceGen.next()
994call.done()
995}
996}
997