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