User Tools

Site Tools


Sidebar

Network and communication

k24:k24.9:k24.9.5:k24.9.5.1:start

24.9.5.1 Project 1 - DBusObserver - Part 1

In the programme presented, it is to be determined whether a USB stick has been inserted, which name (label) the USB stick has and under which path the USB stick can be reached.

If you want to develop a project for a D-Bus observer that is to observe a method or a signal, then you must obtain the answers to the following questions in advance:

  • Which d-bus-enabled application is sending the message to be intercepted?
  • Is the method or signal sent on the session bus or on the system bus?
  • What type does the message represent?
  • Which D-Bus object is used?
  • Is the object path known?
  • What is the name of the method or the signal (member) to be observed?
  • What is the signature of the message?
  • What is the name of the interface - if one exists?

The answers to the questions can be given if you use the two programmes d-feet and dbus-monitor and carefully analyse their output when inserting a USB stick in relation to the above task. The use of the programme d-feet is presented in the chapter D-Bus-Introspection.

The console programme dbus-send is also very useful for introspection:

$ dbus-send --session --print-reply –dest=org.gtk.Private.UDisks2VolumeMonitor \
 /org/gtk/Private/RemoteVolumeMonitor \
 org.freedesktop.DBus.Introspectable.Introspect > volumemonitor.introspection.xml

Here is an excerpt from the XML file:

...
  <signal name="VolumeAdded">
    <arg type="s" name="dbus_name"/>
    <arg type="s" name="id"/>
    <arg type="(ssssssbbssa{ss}sa{sv})" name="volume"/>
  </signal>
...

In addition, here is an excerpt of the output of the dbus-monitor programme when a USB stick has been inserted and, among other things, the D-Bus signal “VolumeAdded” of the object /org/gtk/Private/RemoteVolumeMonitor triggered then is displayed with the values of its arguments:

signal sender=:1.10 -> dest=(null destination) serial=53 path=/org/gtk/Private/RemoteVolumeMonitor;
   interface=org.gtk.Private.RemoteVolumeMonitor; member=VolumeAdded
   string "org.gtk.Private.UDisks2VolumeMonitor"
   string "0x2493c70"
   struct {
      string "0x2493c70"
      string "2_GB_P"
      string ". GThemedIcon drive-removable-media-usb drive-removable-media drive-removable drive"
      string ". GThemedIcon drive-removable-media-usb-symbolic ... drive-removable drive"
      string ""
      string ""
      boolean true
      boolean true
      string "0x24b4d90"
      string ""
      array [
         dict entry(
            string "class"
            string "device"
         )
         dict entry(
            string "unix-device"
            string "/dev/sdd1"
         )
         dict entry(
            string "label"
            string "2_GB_P"
         )
         dict entry(
            string "uuid"
            string "38ea6e0b-a161-401d-a673-11c06cf1229e"
         )
      ]
      string "gvfs.time_detected_usec.1519387042284411"
      array [
      ]
   }

With this, and also after looking at the output of the d-feet console programme, the following concrete answers emerged for the applicable application:

  • Application (D-Bus name): org.gtk.Private.UDisks2VolumeMonitor
  • D-Bus: Session Bus
  • Message type: Signal
  • D-Bus object path: /org/gtk/Private/RemoteVolumeMonitor
  • Name of the signal (member): VolumeAdded
  • The message has three arguments. The signature can be read from the above extract from the XML file. Argument1: String, Argument2: String, Argument3: ComplexType
  • Name of the interface: org.gtk.Private.UDisks2VolumeMonitor

24.9.5.1.1 Signature of the signal 'VolumeAdded'

Interesting in relation to the above task is the following section on the signal named 'VolumeAdded' from the very extensive contents of the XML document:

<signal name="VolumeAdded">
  <arg type="s" name="dbus_name"/>
  <arg type="s" name="id"/>
  <arg type="(ssssssbbssa{ss}sa{sv})" name="volume"/>
</signal>

The following can be noted:

  • The signal has a name that points in the right direction - VolumeAdded.
  • The signal has exactly three arguments.
  • A (data) type is specified for each argument.
  • Each argument has a name.

To describe the number and types of arguments required by methods and signals, D-Bus uses string encoding in the form of signatures.

  • The Arg1 and Arg2 arguments have the native data type string.
  • The argument 3 has a complex data type: Readable are 6 consecutive strings followed by 2 truth values. Then come two more strings. These strings are followed by a collection (Collection1 with KeyTyp = String and DatenTyp = String). Collection1 is followed by a string, which is followed by another collection (Collection2 with KeyType = String and DataType = Variant).

A simple and expressive format! Now it becomes interesting for the DBusObserver1 project how the data types of the 3rd argument can also be mapped to a complex data type in Gambas. Right - there is a simple way by using the Struct data type for this:

Public Struct StructVariant
  String1 As String
  String2 As String
  String3 As String
  String4 As String
  String5 As String
  String6 As String
  Boolean1 As Boolean
  Boolean2 As Boolean
  String7 As String
  String8 As String
  Collection1 As Collection
  String9 As String
  Collection2 As Collection
End Struct

Public structSignalArgument3 As New StructVariant

24.9.5.1.2 Project 1 - Part 2

The source code for the project is manageable, so it is given in full and then commented on:

[1] ' Gambas class file
[2]
[3] Public Struct StructVariant
[4]   String1 As String
[5]   String2 As String
[6]   String3 As String
[7]   String4 As String
[8]   String5 As String
[9]   String6 As String
[10]   Boolean1 As Boolean
[11]   Boolean2 As Boolean
[12]   String7 As String
[13]   String8 As String
[14]   Collection1 As Collection
[15]   String9 As String
[16]   Collection2 As Collection
[17] End Struct
[18]
[19] Public structSignalArgument3 As New StructVariant
[20] Public hDBusObserver As DBusObserver
[21]
[22] Private $cDBus As DBusConnection
[23] Private $iOSMessageType As Integer
[24] Private $sOSObjectPath As String
[25] Private $sOSMember As String
[26] Private $sOSInterface As String
[27] Private $sOSDestination As String
[28]
[29] Public Sub Form_Open()
[30]
[31]   FMain.Resizable = True
[32]
[33]   $cDBus = DBus.Session
[34]   $iOSMessageType = DBus.Signal
[35]   $sOSObjectPath = "/org/gtk/Private/RemoteVolumeMonitor"
[36]   $sOSMember = "VolumeAdded" ' Member -> DBus-SignalName
[37]   $sOSInterface = "org.gtk.Private.RemoteVolumeMonitor"
[38]   $sOSDestination = "*"
[39]
[40]   hDBusObserver = New DBusObserver($cDBus, $iOSMessageType, $sOSObjectPath, $sOSMember, $sOSInterface, $sOSDestination) As "hDBusObserver"
[41]
[42]   FMain.Caption = "DBus-Observer:  Signal" & " ==> " & $sOSMember
[43]
[44] End
[45]
[46] Public Sub hDBusObserver_Message()
[47]
[48]   Dim k As Integer = 1
[49]   Dim vElement As Variant
[50]   Dim aArguments As Variant[]
[51]   Dim sDestination As String
[52]   Dim aObserverMessageTypes As String[] = ["DBus.Method", "DBus.Reply", "DBus.Error", "DBus.Signal"]
[53]
[54]   aArguments = hDBusObserver.Message.Arguments
[55]
[56]   structSignalArgument3.String1 = aArguments[2][0]
[57]   structSignalArgument3.String2 = aArguments[2][1]
[58]   structSignalArgument3.String3 = aArguments[2][2]
[59]   structSignalArgument3.String4 = aArguments[2][3]
[60]   structSignalArgument3.String5 = aArguments[2][4]
[61]   structSignalArgument3.String6 = aArguments[2][5]
[62]   structSignalArgument3.Boolean1 = aArguments[2][6]
[63]   structSignalArgument3.Boolean2 = aArguments[2][7]
[64]   structSignalArgument3.String7 = aArguments[2][8]
[65]   structSignalArgument3.String8 = aArguments[2][9]
[66]   structSignalArgument3.Collection1 = aArguments[2][10]
[67]   structSignalArgument3.String9 = aArguments[2][11]
[68]   structSignalArgument3.Collection2 = aArguments[2][12]
[69]
[70]   If Not hDBusObserver.Message.Destination Then
[71]      sDestination = "All Applications"
[72]   Else
[73]      sDestination = hDBusObserver.Message.Destination
[74]   Endif
[75]
[76]   txaResults.Insert(gb.NewLine)
[77]   txaResults.Insert("Message-Destination = " & sDestination & gb.NewLine)
[78]   txaResults.Insert("Message-Interface = " & hDBusObserver.Message.Interface & gb.NewLine)
[79]   txaResults.Insert("Message-Member = " & hDBusObserver.Message.Member & gb.NewLine)
[80]   txaResults.Insert("Message-Object = " & hDBusObserver.Message.Object & gb.NewLine)
[81]   txaResults.Insert("Message-Sender (ID) = " & hDBusObserver.Message.Sender & gb.NewLine)
[82]   txaResults.Insert("Message-Number = " & hDBusObserver.Message.Serial & gb.NewLine)
[83]   txaResults.Insert("Message-Type = " & aObserverMessageTypes[hDBusObserver.Message.Type - 1])
[84]   txaResults.Insert(gb.NewLine & gb.NewLine)
[85]
[86]   txaResults.Insert("Arguments of the \"VolumeAdded\" Signal:" & gb.NewLine)
[87]   txaResults.Insert(String$(61, "-") & gb.NewLine)
[88]   txaResults.Insert("<signal name=\"VolumeAdded\"" & gb.NewLine)
[89]   txaResults.Insert("  <arg type=\"s\" name=\"dbus_name\"/>" & gb.NewLine)
[90]   txaResults.Insert("  <arg type=\"s\" name=\"id\"/>" & gb.NewLine)
[91]   txaResults.Insert("  <arg type=\"(ssssssbbssa{ss}sa{sv})\" name=\"volume\"/>" & gb.NewLine)
[92]   txaResults.Insert("</signal>" & gb.NewLine & gb.NewLine)
[93]
[94]   txaResults.Insert("Number of arguments for Variant-Array 'Arguments' = " & aArguments.Count &
gb.NewLine)
[95]   txaResults.Insert(gb.NewLine)
[96]   txaResults.Insert("String:" & gb.NewLine)
[97]   txaResults.Insert("Arguments[0] = " & aArguments[0] & gb.NewLine)
[98]   txaResults.Insert("String:" & gb.NewLine)
[99]   txaResults.Insert("Arguments[1] = " & aArguments[1] & gb.NewLine)
[100]
[101]   txaResults.Insert("Data-Type Struct:" & gb.NewLine)
[102] ' 6x String
[103]   txaResults.Insert("Arguments[2][0] = " & aArguments[2][0] & gb.NewLine)
[104]   txaResults.Insert("Arguments[2][1] = " & aArguments[2][1] & gb.NewLine)
[105]   txaResults.Insert("Arguments[2][2] = " & aArguments[2][2] & gb.NewLine)
[106]   txaResults.Insert("Arguments[2][3] = " & aArguments[2][3] & gb.NewLine)
[107]   txaResults.Insert("Arguments[2][4] = " & aArguments[2][4] & gb.NewLine)
[108]   txaResults.Insert("Arguments[2][5] = " & aArguments[2][5] & gb.NewLine)
[109] ' 2x Boolean
[110]   txaResults.Insert("Arguments[2][6] = " & aArguments[2][6] & gb.NewLine)
[111]   txaResults.Insert("Arguments[2][7] = " & aArguments[2][7] & gb.NewLine)
[112] ' 2x String
[113]   txaResults.Insert("Arguments[2][8] = " & aArguments[2][8] & gb.NewLine)
[114]   txaResults.Insert("Arguments[2][9] = " & aArguments[2][9] & gb.NewLine)
[115] ' Collection 1 -> KeyType = String and DataType = String
[116]   txaResults.Insert("Collection 1 = Arguments[2][10]" & gb.NewLine)
[117]   If structSignalArgument3.Collection1.Count > 0 Then
[118]      For Each vElement In structSignalArgument3.Collection1
[119]        txaResults.Insert("Element " & Str(k) & "  :   " & structSignalArgument3.Collection1.Key)
[120]        txaResults.Insert(" = " & vElement & gb.NewLine)
[121]        Inc k
[122]      Next
[123]     Else
[124]      txaResults.Insert("Attention: The collection 1 is empty!" & gb.NewLine)
[125]   Endif
[126] ' 1x String
[127]   txaResults.Insert("Arguments[2][11] = " & aArguments[2][11] & gb.NewLine)
[128]   k = 1
[129] ' Collection 2 -> KeyType = String and DataType = Variant
[130]   txaResults.Insert("Collection 2 = Arguments[2][12]" & gb.NewLine)
[131]   If structSignalArgument3.Collection2.Count > 0 Then
[132]      For Each vElement In structSignalArgument3.Collection2
[133]        txaResults.Insert("Element " & Str(k) & "  :   " & structSignalArgument3.Collection2.Key)
[134]        txaResults.Insert(" = " & vElement & gb.NewLine)
[135]        Inc k
[136]      Next
[137]   Else
[138]      txaResults.Insert("Attention: The collection 2 is empty!" & gb.NewLine)
[139]   Endif
[140]
[141] End
[142]
[143] Public Sub Form_Close()
[144]   hDBusObserver = Null
[145]   FMain.Close()
[146] End

Comment:

  • Lines 3 to 27 declare the necessary variables.
  • The assignment of the arguments for the creation of a DBusObserver object is done in lines 33 to 38.
  • Alternatively, you can also intercept other signals (DriveConnected, DriveChanged, VolumeChanged, VolumeRemoved, MountAdded, DriveEject, MountPreUnmount, MountChanged). However, you must then determine the signatures for these signals, because a simple exchange of $sOSMember = “VolumeAdded” for $sOSMember = “MountAdded” leads to an error!
  • The message event in line 46 is triggered when the signal to be observed is detected on the D-Bus. The complete message is stored in the properties of the virtual class DBusObserver.Message.
  • In line 54, all three arguments of the property hDBusObserver.Message.Arguments are stored in a variant array.
  • In lines 56 to 68, the elements of the defined structure (structSignalArgument3) are filled with the values whose data type was previously read from the signature for the third argument.
  • The values of all properties of the class DBusObserver.Message - but without the property Arguments of the data type VariantArray are assigned in lines 77 to 84 and displayed in a TextArea.
  • In lines 97 and 99, the values of Argument 1 and Argument 2 of the Arguments property are displayed. After that, the values of the complex argument 3 are displayed in the lines from 102.

The result of observing the “VolumeAdded” signal of the object of the org.gtk.Private.UDisks2VolumeMonitor object can be seen:


Figure 24.9.5.1.1: Evaluation of the observation of the signal 'VolumeAdded' (Message-Member)

You can adapt the presented project to other messages to be observed. However, you will only succeed without problems if you re-run the introspection for the selected message type with the recommended programmes with care to determine, among other things, the signature of the messages.

24.9.5.1.3 Project 2 - ObserverDBus - Signal 'MountAdded'

In another project, an observer for the signal 'MountAdded' is provided for testing. Here, the data type Struct is dispensed with and only the Gambas data types Integer, String, Array and Collection are used, as a look at the definition list shows:

Dim k As Integer = 1
Dim vElement As Variant
Dim cCollection As Collection
Dim aArray As String[]
Dim aArguments As Variant[]
Dim sDestination As String
Dim aObserverMessageTypes As String[] = ["DBus.Method", "DBus.Reply", "DBus.Error", "DBus.Signal"]

The signature of the message - compared to project 1 - is completely different:

<signal name="MountAdded">
  <arg type="s" name="dbus_name"/>
  <arg type="s" name="id"/>
  <arg type="(ssssssbsassa{sv})" name="mount"/>
</signal>

This is the output when the signal 'MountAdded' has been intercepted and evaluated:


Figure 24.9.5.1.2: Evaluation of the observation of the signal 'MountAdded'.

In chapter 24.9.8.0 you are introduced to the two classes DBusVariant and DBusValues, which can be used to generate the appropriate dbus-appropriate data for your own messages for self-declared signatures from the data with Gambas data types. Two projects in which Gambas programs (server/client) export D-Bus objects and provide or use services complement the theory described.

Download

The website uses a temporary session cookie. This technically necessary cookie is deleted when the browser is closed. You can find information on cookies in our privacy policy.
k24/k24.9/k24.9.5/k24.9.5.1/start.txt · Last modified: 16.08.2022 (external edit)

Page Tools