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