11. Application bus

POSIX API (signals, messages, shared memory): Disadvantages

History:

D-Bus

Concepts:

Architecture

TODO

Linux

D-Bus programming

Useful software:

Overview

  1. Run 'd-feet' to see the installed services:
    andrewt@comp-core-i7-3615qm-0dbf32 ~ $ d-feet

    1

  2. See list of dbus command-line tools (press Tab after dbus- to get completion work):

    andrewt@comp-core-i7-3615qm-0dbf32 ~ $ dbus-
    dbus-cleanup-sockets   dbus-launch    dbus-run-session   dbus-update-activation-environment
    dbus-daemon            dbus-monitor   dbus-send          dbus-uuidgen
    • Use the 'dbus-send' tool to introspect the properties of NetworkManager:

       1 andrewt@comp-core-i7-3615qm-0dbf32 ~ $ dbus-send --system --print-reply --dest=org.freedesktop.NetworkManager /org/freedesktop/NetworkManager/Devices/1 org.freedesktop.DBus.Introspectable.Introspect
       2 method return time=1590384778.681292 sender=:1.6 -> destination=:1.141 serial=3362 reply_serial=2
       3    string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
       4                       "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
       5 <!-- GDBus 2.60.7 -->
       6 <node>
       7   <interface name="org.freedesktop.DBus.Properties">
       8     <method name="Get">
       9       <arg type="s" name="interface_name" direction="in"/>
      10       <arg type="s" name="property_name" direction="in"/>
      11       <arg type="v" name="value" direction="out"/>
      12     </method>
      13     <method name="GetAll">
      14       <arg type="s" name="interface_name" direction="in"/>
      15       <arg type="a{sv}" name="properties" direction="out"/>
      16     </method>
      17     <method name="Set">
      18       <arg type="s" name="interface_name" direction="in"/>
      19       <arg type="s" name="property_name" direction="in"/>
      20       <arg type="v" name="value" direction="in"/>
      21     </method>
      22     <signal name="PropertiesChanged">
      23       <arg type="s" name="interface_name"/>
      24       <arg type="a{sv}" name="changed_properties"/>
      25       <arg type="as" name="invalidated_properties"/>
      26     </signal>
      27   </interface>
      28   <interface name="org.freedesktop.DBus.Introspectable">
      29     <method name="Introspect">
      30       <arg type="s" name="xml_data" direction="out"/>
      31     </method>
      32   </interface>
      33   <interface name="org.freedesktop.DBus.Peer">
      34     <method name="Ping"/>
      35     <method name="GetMachineId">
      36       <arg type="s" name="machine_uuid" direction="out"/>
      37     </method>
      38   </interface>
      39   <interface name="org.freedesktop.NetworkManager.Device.Statistics">
      40     <signal name="PropertiesChanged">
      41       <arg type="a{sv}" name="properties"/>
      42     </signal>
      43     <property type="u" name="RefreshRateMs" access="readwrite"/>
      44     <property type="t" name="TxBytes" access="read"/>
      45     <property type="t" name="RxBytes" access="read"/>
      46   </interface>
      47   <interface name="org.freedesktop.NetworkManager.Device.Generic">
      48     <signal name="PropertiesChanged">
      49       <arg type="a{sv}" name="properties"/>
      50     </signal>
      51     <property type="s" name="HwAddress" access="read"/>
      52     <property type="s" name="TypeDescription" access="read"/>
      53   </interface>
      54   <interface name="org.freedesktop.NetworkManager.Device">
      55     <method name="Reapply">
      56       <arg type="a{sa{sv}}" name="connection" direction="in"/>
      57       <arg type="t" name="version_id" direction="in"/>
      58       <arg type="u" name="flags" direction="in"/>
      59     </method>
      60     <method name="GetAppliedConnection">
      61       <arg type="u" name="flags" direction="in"/>
      62       <arg type="a{sa{sv}}" name="connection" direction="out"/>
      63       <arg type="t" name="version_id" direction="out"/>
      64     </method>
      65     <method name="Disconnect"/>
      66     <method name="Delete"/>
      67     <signal name="StateChanged">
      68       <arg type="u" name="new_state"/>
      69       <arg type="u" name="old_state"/>
      70       <arg type="u" name="reason"/>
      71     </signal>
      72     <property type="s" name="Udi" access="read"/>
      73     <property type="s" name="Interface" access="read"/>
      74     <property type="s" name="IpInterface" access="read"/>
      75     <property type="s" name="Driver" access="read"/>
      76     <property type="s" name="DriverVersion" access="read"/>
      77     <property type="s" name="FirmwareVersion" access="read"/>
      78     <property type="u" name="Capabilities" access="read"/>
      79     <property type="u" name="Ip4Address" access="read"/>
      80     <property type="u" name="State" access="read"/>
      81     <property type="(uu)" name="StateReason" access="read"/>
      82     <property type="o" name="ActiveConnection" access="read"/>
      83     <property type="o" name="Ip4Config" access="read"/>
      84     <property type="o" name="Dhcp4Config" access="read"/>
      85     <property type="o" name="Ip6Config" access="read"/>
      86     <property type="o" name="Dhcp6Config" access="read"/>
      87     <property type="b" name="Managed" access="readwrite"/>
      88     <property type="b" name="Autoconnect" access="readwrite"/>
      89     <property type="b" name="FirmwareMissing" access="read"/>
      90     <property type="b" name="NmPluginMissing" access="read"/>
      91     <property type="u" name="DeviceType" access="read"/>
      92     <property type="ao" name="AvailableConnections" access="read"/>
      93     <property type="s" name="PhysicalPortId" access="read"/>
      94     <property type="u" name="Mtu" access="read"/>
      95     <property type="u" name="Metered" access="read"/>
      96     <property type="aa{sv}" name="LldpNeighbors" access="read"/>
      97     <property type="b" name="Real" access="read"/>
      98     <property type="u" name="Ip4Connectivity" access="read"/>
      99     <property type="u" name="Ip6Connectivity" access="read"/>
     100   </interface>
     101 </node>
    
  3. More convenient facilities to manage D-Bus are provided by the 'qdbus' tool.

    andrewt@comp-core-i7-3615qm-0dbf32 ~ $ qdbusviewer

    2

    • How to use command-line tool 'qdbus':
      andrewt@comp-core-i7-3615qm-0dbf32 ~ $ qdbus --help
      Usage: qdbus [--system] [--bus busaddress] [--literal] [servicename] [path] [method] [args]
      
       servicename       the service to connect to (e.g., org.freedesktop.DBus)
       path              the path to the object (e.g., /)
       method            the method to call, with or without the interface
       args              arguments to pass to the call
      With 0 arguments, qdbus will list the services available on the bus
      With just the servicename, qdbus will list the object paths available on the service
      With service name and object path, qdbus will list the methods, signals and properties available on the object
      
      Options:
       --system          connect to the system bus
       --bus busaddress  connect to a custom bus
       --literal         print replies literally
    • See all system services registered in D-Bus:
      andrewt@comp-core-i7-3615qm-0dbf32 ~ $ qdbus --system
      :1.0
       org.freedesktop.systemd1
      :1.10
       org.freedesktop.Accounts
      :1.113
      :1.116
       com.redhat.NewPrinterNotification
       com.redhat.PrinterDriversInstaller
      :1.12
      :1.14
       org.freedesktop.ModemManager1
      :1.15
       org.freedesktop.ColorManager
      :1.154
      :1.3
       org.freedesktop.Avahi
      :1.35
      :1.4
       org.freedesktop.login1
      :1.41
      :1.47
      :1.49
      :1.5
       org.freedesktop.PolicyKit1
      :1.50
      :1.52
      :1.53
       org.freedesktop.UPower
      :1.54
      :1.6
       org.freedesktop.NetworkManager
      :1.67
      :1.68
       org.freedesktop.UDisks2
      :1.80
      :1.9
       org.freedesktop.DisplayManager
      :1.93
      :1.94
      org.freedesktop.DBus
    • See all objects provided by a specific service (completion works!):
      andrewt@comp-core-i7-3615qm-0dbf32 ~ $ qdbus --system org.freedesktop.NetworkManager
      /
      /org
      /org/freedesktop
      /org/freedesktop/NetworkManager
      /org/freedesktop/NetworkManager/IP4Config
      /org/freedesktop/NetworkManager/IP4Config/5
      /org/freedesktop/NetworkManager/IP4Config/3
      /org/freedesktop/NetworkManager/IP4Config/4
      /org/freedesktop/NetworkManager/ActiveConnection
      /org/freedesktop/NetworkManager/ActiveConnection/1
      /org/freedesktop/NetworkManager/ActiveConnection/6
      /org/freedesktop/NetworkManager/AgentManager
      /org/freedesktop/NetworkManager/Devices
      /org/freedesktop/NetworkManager/Devices/2
      /org/freedesktop/NetworkManager/Devices/3
      /org/freedesktop/NetworkManager/Devices/1
      /org/freedesktop/NetworkManager/DHCP4Config
      /org/freedesktop/NetworkManager/DHCP4Config/6
      /org/freedesktop/NetworkManager/DnsManager
      /org/freedesktop/NetworkManager/IP6Config
      /org/freedesktop/NetworkManager/IP6Config/9
      /org/freedesktop/NetworkManager/IP6Config/3
      /org/freedesktop/NetworkManager/IP6Config/4
      /org/freedesktop/NetworkManager/Settings
      /org/freedesktop/NetworkManager/Settings/2
      /org/freedesktop/NetworkManager/Settings/3
      /org/freedesktop/NetworkManager/Settings/1
    • See methods and properties provided by a specific object (commpletion works again!):
      andrewt@comp-core-i7-3615qm-0dbf32 ~ $ qdbus --system org.freedesktop.NetworkManager /org/freedesktop/NetworkManager/Devices/1
      signal void org.freedesktop.DBus.Properties.PropertiesChanged(QString interface_name, QVariantMap changed_properties, QStringList invalidated_properties)
      method QDBusVariant org.freedesktop.DBus.Properties.Get(QString interface_name, QString property_name)
      method QVariantMap org.freedesktop.DBus.Properties.GetAll(QString interface_name)
      method void org.freedesktop.DBus.Properties.Set(QString interface_name, QString property_name, QDBusVariant value)
      method QString org.freedesktop.DBus.Introspectable.Introspect()
      method QString org.freedesktop.DBus.Peer.GetMachineId()
      method void org.freedesktop.DBus.Peer.Ping()
      property readwrite uint org.freedesktop.NetworkManager.Device.Statistics.RefreshRateMs
      property read qulonglong org.freedesktop.NetworkManager.Device.Statistics.RxBytes
      property read qulonglong org.freedesktop.NetworkManager.Device.Statistics.TxBytes
      signal void org.freedesktop.NetworkManager.Device.Statistics.PropertiesChanged(QVariantMap properties)
      property read QString org.freedesktop.NetworkManager.Device.Generic.HwAddress
      property read QString org.freedesktop.NetworkManager.Device.Generic.TypeDescription
      signal void org.freedesktop.NetworkManager.Device.Generic.PropertiesChanged(QVariantMap properties)
      property read QDBusObjectPath org.freedesktop.NetworkManager.Device.ActiveConnection
      property readwrite bool org.freedesktop.NetworkManager.Device.Autoconnect
      property read QList<QDBusObjectPath> org.freedesktop.NetworkManager.Device.AvailableConnections
      property read uint org.freedesktop.NetworkManager.Device.Capabilities
      property read uint org.freedesktop.NetworkManager.Device.DeviceType
      property read QDBusObjectPath org.freedesktop.NetworkManager.Device.Dhcp4Config
      property read QDBusObjectPath org.freedesktop.NetworkManager.Device.Dhcp6Config
      property read QString org.freedesktop.NetworkManager.Device.Driver
      property read QString org.freedesktop.NetworkManager.Device.DriverVersion
      property read bool org.freedesktop.NetworkManager.Device.FirmwareMissing
      property read QString org.freedesktop.NetworkManager.Device.FirmwareVersion
      property read QString org.freedesktop.NetworkManager.Device.Interface
      property read uint org.freedesktop.NetworkManager.Device.Ip4Address
      property read QDBusObjectPath org.freedesktop.NetworkManager.Device.Ip4Config
      property read uint org.freedesktop.NetworkManager.Device.Ip4Connectivity
      property read QDBusObjectPath org.freedesktop.NetworkManager.Device.Ip6Config
      property read uint org.freedesktop.NetworkManager.Device.Ip6Connectivity
      property read QString org.freedesktop.NetworkManager.Device.IpInterface
      property read {D-Bus type "aa{sv}"} org.freedesktop.NetworkManager.Device.LldpNeighbors
      property readwrite bool org.freedesktop.NetworkManager.Device.Managed
      property read uint org.freedesktop.NetworkManager.Device.Metered
      property read uint org.freedesktop.NetworkManager.Device.Mtu
      property read bool org.freedesktop.NetworkManager.Device.NmPluginMissing
      property read QString org.freedesktop.NetworkManager.Device.PhysicalPortId
      property read bool org.freedesktop.NetworkManager.Device.Real
      property read uint org.freedesktop.NetworkManager.Device.State
      property read {D-Bus type "(uu)"} org.freedesktop.NetworkManager.Device.StateReason
      property read QString org.freedesktop.NetworkManager.Device.Udi
      signal void org.freedesktop.NetworkManager.Device.StateChanged(uint new_state, uint old_state, uint reason)
      method void org.freedesktop.NetworkManager.Device.Delete()
      method void org.freedesktop.NetworkManager.Device.Disconnect()
      method {D-Bus type "a{sa{sv}}"} org.freedesktop.NetworkManager.Device.GetAppliedConnection(uint flags, qulonglong& version_id)
      method void org.freedesktop.NetworkManager.Device.Reapply({D-Bus type "a{sa{sv}}"} connection, qulonglong version_id, uint flags)
    • Use qdbus to request information on network interfaces (complete… ok, You got it):

      andrewt@comp-core-i7-3615qm-0dbf32 ~ $ qdbus --system org.freedesktop.NetworkManager /org/freedesktop/NetworkManager/Devices/1 org.freedesktop.NetworkManager.Device.Interface
      lo
      andrewt@comp-core-i7-3615qm-0dbf32 ~ $ qdbus --system org.freedesktop.NetworkManager /org/freedesktop/NetworkManager/Devices/2 org.freedesktop.NetworkManager.Device.Interface
      eth0
      andrewt@comp-core-i7-3615qm-0dbf32 ~ $ qdbus --system org.freedesktop.NetworkManager /org/freedesktop/NetworkManager/Devices/3 org.freedesktop.NetworkManager.Device.Interface
      eth1
    In the same way, it is possible to manage network interfaces via other properties and methods.
  4. busctl is probably the best commandline utility:

    • try busctl tree

    • try busctl --user introspect with lot of Tab completion tries

      • e. g. busctl --user introspect org.freedesktop.Notifications /org/freedesktop/Notifications org.freedesktop.Notifications:

        NAME                          TYPE      SIGNATURE     RESULT/VALUE FLAGS
        .CloseNotification            method    u             -            -
        .GetCapabilities              method    -             as           -
        .GetServerInformation         method    -             ssss         -
        .Notify                       method    susssasa{sv}i u            -
        .ActionInvoked                signal    us            -            -
        .NotificationClosed           signal    uu            -            -
        • Thank goodness, no XML here!
        • This queer susssasa{sv}i designates method input parameters:

          1. s — string (char * with zero)

          2. u — uint32

          3. s — string (char * with zero)

          4. s — string (char * with zero)

          5. s — string (char * with zero)

          6. as — array of strings

          7. a{sv} — dictionary with string indexes and variable object values

          8. i — int32

        • More on signatures

  5. It is possible to manage D-Bus from programs in high-level programming languages. For example, a library called pydbus allows doing it from Python.

       1 andrewt@comp-core-i7-3615qm-0dbf32 ~ $ python3
       2 Python 3.7.4 (default, Apr 17 2020, 12:15:50)
       3 [GCC 8.4.1 20200305 (ALT p9 8.4.1-alt0.p9.1)] on linux
       4 Type "help", "copyright", "credits" or "license" for more information.
       5 >>> from pydbus import SessionBus
       6 >>>
       7 >>> bus = SessionBus()
       8 >>> notifications = bus.get('org.freedesktop.Notifications')
       9 >>>
      10 >>> help(notifications)
      11 >>>
      12 >>> notifications.Notify('test', 0, 'dialog-information', "Hello World!", "pydbus works :)", [], {}, 5000)
    
    • Note how help() works!

    • A Python program that lists running systemd units:
         1 from pydbus import SystemBus
         2 
         3 bus = SystemBus()
         4 systemd = bus.get(".systemd1")
         5 
         6 for unit in systemd.ListUnits():
         7     print(*unit)
      
  6. Systemd is providing excellent D-Dus interface. Manage systemd services from pydbus.

    • Create a simple service:
      •    andrewt@comp-core-i7-3615qm-0dbf32 ~ $ systemctl edit --user --force --full xtermtop.service
        • With the following content:
        [Unit]
        Description=Xterm top
        
        [Service]
        ExecStart=xterm -e top
      • See its' status:
         andrewt@comp-core-i7-3615qm-0dbf32 ~ $ systemctl --user status xtermtop.service
         ● xtermtop.service
            Loaded: loaded (/home/andrewt/.config/systemd/user/xtermtop.service; static; vendor preset: enabled)
            Active: inactive (dead)
      • Start and stop it manually:

   andrewt@comp-core-i7-3615qm-0dbf32 ~ $ systemctl --user start xtermtop.service
   andrewt@comp-core-i7-3615qm-0dbf32 ~ $ systemctl --user stop xtermtop.service
  1. A D-Bus service in Python.

    • server.py

      •    1 # Python DBUS Test Server # runs until the Quit() method is called via DBUS
           2 
           3 from gi.repository import GLib from pydbus import SessionBus
           4 
           5 loop = GLib.MainLoop()
           6 
           7 class MyDBUSService(object):
           8 
           9   """
          10     <node>
          11      <interface name='net.lew21.pydbus.ClientServerExample'>
          12       <method name='Hello'>
          13        <arg type='s' name='response' direction='out'/>
          14     </method> <method name='EchoString'>
          15        <arg type='s' name='a' direction='in'/> <arg type='s' name='response' direction='out'/>
          16     </method> <method name='Quit'/>
          17    </interface>
          18   </node>
          19   """
          20 
          21   def Hello(self):
          22     """returns the string 'Hello, World!'"""
          23     return "Hello, World!"
          24 
          25   def EchoString(self, s):
          26     """returns whatever is passed to it"""
          27     return s
          28 
          29   def Quit(self):
          30     """removes this object from the DBUS connection and exits"""
          31     loop.quit()
          32 
          33 bus = SessionBus()
          34 bus.publish("net.lew21.pydbus.ClientServerExample", MyDBUSService())
          35 loop.run()
        
      • Docstring here is valuable: it implements introspection

      • Note parameter sinatures (described here)

    • Run server.py with python3:
      andrewt@comp-core-i7-3615qm-0dbf32 ~ $ python3 server.py
    • See the registered service with 'd-feet':
      andrewt@comp-core-i7-3615qm-0dbf32 ~ $ d-feet

    3

    • Call methods of the service from 'd-feet':

    4 5

    • Call methods of the running server.py service with 'qdbus':
    andrewt@comp-core-i7-3615qm-0dbf32 ~ $ qdbus net.lew21.pydbus.ClientServerExample /net/lew21/pydbus/ClientServerExample net.lew21.pydbus.ClientServerExample.Hello
    Hello, World!
    andrewt@comp-core-i7-3615qm-0dbf32 ~ $ qdbus net.lew21.pydbus.ClientServerExample /net/lew21/pydbus/ClientServerExample net.lew21.pydbus.ClientServerExample.EchoString "QQ"
    QQ
    • Call the same methods with 'dbus-send':
    andrewt@comp-core-i7-3615qm-0dbf32 ~ $ dbus-send --print-reply --session --dest=net.lew21.pydbus.ClientServerExample /net/lew21/pydbus/ClientServerExample net.lew21.pydbus.ClientServerExample.Hello
    method return time=1590411234.525504 sender=:1.174 -> destination=:1.193 serial=74 reply_serial=2
       string "Hello, World!"
    andrewt@comp-core-i7-3615qm-0dbf32 ~ $ dbus-send --print-reply --session --dest=net.lew21.pydbus.ClientServerExample /net/lew21/pydbus/ClientServerExample net.lew21.pydbus.ClientServerExample.EchoString string:QQ
    method return time=1590411291.496958 sender=:1.174 -> destination=:1.194 serial=75 reply_serial=2
       string "QQ"
    • Call the 'Quit' method to stop the service:
    andrewt@comp-core-i7-3615qm-0dbf32 ~ $ dbus-send --print-reply --session --dest=net.lew21.pydbus.ClientServerExample /net/lew21/pydbus/ClientServerExample net.lew21.pydbus.ClientServerExample.Quit
    method return time=1590411398.034527 sender=:1.174 -> destination=:1.195 serial=76 reply_serial=2

HSE/ArchitectureOS/11_ApplicationBus (последним исправлял пользователь FrBrGeorge 2021-04-13 11:31:27)