D-Bus

D-Bus is a message bus system, a simple way for applications to talk to one another. In addition to interprocess communication, D-Bus helps coordinate process lifecycle; it makes it simple and reliable to code a "single instance" application or daemon, and to launch applications and daemons on demand when their services are needed.

In computing, D-Bus or DBus (for “Desktop Bus”), a software bus, is an inter-process communication (IPC) and remote procedure call (RPC) mechanism that allows communication between multiple computer programs (that is, processes) concurrently running on the same machine. [Wikipedia]

D-Bus allows different processes to communicate indirectly through a known interface. As a short analogy would be that D-Bus is to unix sockets what HTTP/REST is to TCP.

D-Bus is a service daemon that runs in the background, we use it to interact with applications and their functionalities. The bus daemon sends/receives messages to and from applications.

There are two types of daemons:

  • SystemBus: one per system, for system services

  • SessionBus: one per user, for user services

  • bus: is where you look for IPC services.

  • service: is a program that offers an IPC API on a bus. Services are identified by a reverse domain name, e.g. org.freedesktop.login1 exposes systemd-logind's APIs.

  • client: Program that makes uise of some IPC API on a bus- talking to or monitoring a service. Doesn't (need to) provide any services of their own.

  • peer: Generalization used to refer to either a service or a client.

  • object path: Identifier for an object on a given service. Comparable to a C pointer in that you used to reference an object. Is a memory address meaningful outside the service. /org/freedesktop/login1 is the object path of the "manager" object of the org.freedesktop.login1 service.

  • An object identified by object path has one or more interfaces. An interface is a collection of members; signals, methods, and properties. Interface names are in reverse domain notation as well, like service names. Some interfaces are standardized:

    • org.freedesktop.DBus.Peer
    • org.freedesktop.DBus.Properties
    • org.freedesktop.DBus.Instrospectable
  • method: Function that can be invoked through the API. A method call a single client issues a request on a signle service, the service sends back a response to the client. systemd-logind exposes an ActivateSession method on the org.freedesktop.login1.Manager interface available on the /org/freedesktop/login1 object of the org.freedesktop.login1 service.

  • signal: Member type of D-Bus object sytem used for asynchronous notification of peers or broadcasting over the bus. systemd-logind broadcasts a SessionNew signal from its manager object each time a user logs in, and a SessionRemoved every time a user logs out.

  • property: Similar to OOP concept of properties. A variable exposed by the object that can be read or altered by clients. sytemd-logind exposes the Docked property of signature b.

  • signature: Set of parameters a function, signal, or property takes or returns. Series of characters that each encode one parameter by its type. e.g. s for string, u for 32bit int, as array of strings, a(sb) array of structures consiting of one string and one bolean each.

D-Bus services work well with systemd services.

D-Bus offers to messaging patterns:

  • Methods
  • Signals

Method calls go to a single destination and get a reply- either method return or error. Signals are sent to anyone that is interested. They have no response.

Four message types:

  • methods
  • signals
  • returns
  • errors

They can carry different data types:

  • Numbers
  • UTF-8 strings
  • Arrays
  • Dictionaries
  • File descriptors

For a full list of data types see the D-Bus specification.

The bus is the hub that brokers messages to consumers. Programs using D-Bus send and receive messages through the bus. You can also send messages to the bus itself, to tell it who you are or to subscribe to a signal.

If you send a message to a bus name which isn't claimed, the bus may be able to start a program to handle it. This is called D-Bus activation, and it's governed by simple files saying which program to start for which name.

System services like wpa_supplicant describe an API available over D-Bus.

Cheat sheet

To list all peers connected to the bus use busctl. Peer names like :1.2 are known as unique names, they are much like an internal IP address. Names like org.freedesktop.login1 are called well-known names, similar to DNS host names.

$ busctl
NAME                                   PID PROCESS         USER             CONNECTION    UNIT                      SESSION    DESCRIPTION
:1.0                                     1 systemd         root             :1.0          init.scope                -          -
:1.1                                   320 avahi-daemon    avahi            :1.1          avahi-daemon.service      -          -
:1.16                                31577 polkitd         root             :1.16         polkit.service            -          -
:1.196                               30270 busctl          pi               :1.196        session-c73.scope         c73        -
:1.2                                   326 systemd-logind  root             :1.2          systemd-logind.service    -          -
:1.24                                32348 bluetoothd      root             :1.24         bluetooth.service         -          -
fi.epitest.hostap.WPASupplicant          - -               -                (activatable) -                         -
fi.w1.wpa_supplicant1                    - -               -                (activatable) -                         -
org.blueman.Mechanism                    - -               -                (activatable) -                         -
org.bluez                            32348 bluetoothd      root             :1.24         bluetooth.service         -          -
org.freedesktop.Avahi                  320 avahi-daemon    avahi            :1.1          avahi-daemon.service      -          -
org.freedesktop.DBus                   321 dbus-daemon     messagebus       org.freedesktop.DBus dbus.service              -          -
org.freedesktop.PolicyKit1           31577 polkitd         root             :1.16         polkit.service            -          -
org.freedesktop.hello                    - -               -                (activatable) -                         -
org.freedesktop.hostname1                - -               -                (activatable) -                         -
org.freedesktop.locale1                  - -               -                (activatable) -                         -
org.freedesktop.login1                 326 systemd-logind  root             :1.2          systemd-logind.service    -          -
org.freedesktop.network1                 - -               -                (activatable) -                         -
org.freedesktop.resolve1                 - -               -                (activatable) -                         -
org.freedesktop.systemd1                 1 systemd         root             :1.0          init.scope                -          -
org.freedesktop.timedate1                - -               -                (activatable) -                         -

To list objets exposed by the org.freedesktop.login1 service:

$ busctl tree org.freedesktop.login1
└─/org
  └─/org/freedesktop
    └─/org/freedesktop/login1
      ├─/org/freedesktop/login1/seat
      │ └─/org/freedesktop/login1/seat/seat0
      ├─/org/freedesktop/login1/session
      │ ├─/org/freedesktop/login1/session/c1
      │ ├─/org/freedesktop/login1/session/c73
      │ └─/org/freedesktop/login1/session/self
      └─/org/freedesktop/login1/user
        ├─/org/freedesktop/login1/user/_1000
        └─/org/freedesktop/login1/user/self

To instrospect an object and show the interfaces, methods, signals and properties exposed:

$ busctl introspect org.freedesktop.login1 /org/freedesktop/login1/session/c73
NAME                                TYPE      SIGNATURE RESULT/VALUE                             FLAGS
org.freedesktop.DBus.Introspectable interface -         -                                        -
.Introspect                         method    -         s                                        -
org.freedesktop.DBus.Peer           interface -         -                                        -
.GetMachineId                       method    -         s                                        -
.Ping                               method    -         -                                        -
org.freedesktop.DBus.Properties     interface -         -                                        -
.Get                                method    ss        v                                        -
.GetAll                             method    s         a{sv}                                    -
.Set                                method    ssv       -                                        -
.PropertiesChanged                  signal    sa{sv}as  -                                        -
org.freedesktop.login1.Session      interface -         -                                        -
.Activate                           method    -         -                                        -
.Kill                               method    si        -                                        -
.Lock                               method    -         -                                        -
.PauseDeviceComplete                method    uu        -                                        -
.ReleaseControl                     method    -         -                                        -
.ReleaseDevice                      method    uu        -                                        -
.SetIdleHint                        method    b         -                                        -
.SetLockedHint                      method    b         -                                        -
.TakeControl                        method    b         -                                        -
.TakeDevice                         method    uu        hb                                       -
.Terminate                          method    -         -                                        -
.Unlock                             method    -         -                                        -
.Active                             property  b         true                                     emits-change
.Audit                              property  u         0                                        const
.Class                              property  s         "user"                                   const
.Desktop                            property  s         ""                                       const
.Display                            property  s         ""                                       const
.Id                                 property  s         "c73"                                    const
.IdleHint                           property  b         false                                    emits-change
.IdleSinceHint                      property  t         0                                        emits-change
.IdleSinceHintMonotonic             property  t         0                                        emits-change
.Leader                             property  u         30007                                    const
.LockedHint                         property  b         false                                    emits-change
.Name                               property  s         "pi"                                     const
.Remote                             property  b         true                                     const
.RemoteHost                         property  s         "192.168.10.104"                         const
.RemoteUser                         property  s         ""                                       const
.Scope                              property  s         "session-c73.scope"                      const
.Seat                               property  (so)      "" "/"                                   const
.Service                            property  s         "sshd"                                   const
.State                              property  s         "active"                                 -
.TTY                                property  s         ""                                       const
.Timestamp                          property  t         1558206890617603                         const
.TimestampMonotonic                 property  t         13873648709262                           const
.Type                               property  s         "tty"                                    const
.User                               property  (uo)      1000 "/org/freedesktop/login1/user/_1…0" const
.VTNr                               property  u         0                                        const
.Lock                               signal    -         -                                        -
.PauseDevice                        signal    uus       -                                        -
.ResumeDevice                       signal    uuh       -                                        -
.Unlock                             signal    -         -                                        -

To call a method:

$ busctl call org.freedesktop.login1 /org/freedesktop/login1/session/c73 org.freedesktop.DBus.Peer GetMachineId
137f05d485c24a764b39a6cf5ce0634b

You can monitor services, in this case systemd-logind. This will fire events when you ssh in a new terminal:

$ busctl monitor org.freedesktop.login1
Monitoring bus message stream.
‣ Type=signal  Endian=l  Flags=1  Version=1  Priority=0 Cookie=2
  Sender=org.freedesktop.DBus  Destination=:1.275  Path=/org/freedesktop/DBus  Interface=org.freedesktop.DBus  Member=NameAcquired
  MESSAGE "s" {
          STRING ":1.275";
  };

‣ Type=signal  Endian=l  Flags=1  Version=1  Priority=0 Cookie=4
  Sender=org.freedesktop.DBus  Destination=:1.275  Path=/org/freedesktop/DBus  Interface=org.freedesktop.DBus  Member=NameLost
  MESSAGE "s" {
          STRING ":1.275";
  };

‣ Type=method_call  Endian=l  Flags=0  Version=1  Priority=0 Cookie=2
  Sender=:1.276  Destination=org.freedesktop.login1  Path=/org/freedesktop/login1  Interface=org.freedesktop.login1.Manager  Member=CreateSession
  UniqueName=:1.276
  MESSAGE "uusssssussbssa(sv)" {
          UINT32 1000;
          UINT32 31029;
          STRING "sshd";
          STRING "tty";
          STRING "user";
          STRING "";
          STRING "";
          UINT32 0;
          STRING "";
          STRING "";
          BOOLEAN true;
          STRING "";
          STRING "192.168.10.104";
          ARRAY "(sv)" {
          };
  };

‣ Type=method_call  Endian=l  Flags=0  Version=1  Priority=0 Cookie=1218
  Sender=:1.2  Destination=org.freedesktop.DBus  Path=/org/freedesktop/DBus  Interface=org.freedesktop.DBus  Member=GetConnectionUnixUser
  UniqueName=:1.2
  MESSAGE "s" {
          STRING ":1.276";
  };

‣ Type=method_return  Endian=l  Flags=1  Version=1  Priority=0 Cookie=299  ReplyCookie=1218
  Sender=org.freedesktop.DBus  Destination=:1.2
  MESSAGE "u" {
          UINT32 0;
  };

‣ Type=method_call  Endian=l  Flags=0  Version=1  Priority=0 Cookie=1219
  Sender=:1.2  Destination=org.freedesktop.systemd1  Path=/org/freedesktop/systemd1  Interface=org.freedesktop.systemd1.Manager  Member=StartTransientUnit
  UniqueName=:1.2
  MESSAGE "ssa(sv)a(sa(sv))" {
          STRING "session-c74.scope";
          STRING "fail";
          ARRAY "(sv)" {
                  STRUCT "sv" {
                          STRING "Slice";
                          VARIANT "s" {
                                  STRING "user-1000.slice";
                          };
                  };
                  STRUCT "sv" {
                          STRING "Description";
                          VARIANT "s" {
                                  STRING "Session c74 of user pi";
                          };
                  };
                  STRUCT "sv" {
                          STRING "After";
                          VARIANT "as" {
                                  ARRAY "s" {
                                          STRING "systemd-logind.service";
                                  };
                          };
                  };
                  STRUCT "sv" {
                          STRING "After";
                          VARIANT "as" {
                                  ARRAY "s" {
                                          STRING "systemd-user-sessions.service";
                                  };
                          };
                  };
                  STRUCT "sv" {
                          STRING "SendSIGHUP";
                          VARIANT "b" {
                                  BOOLEAN true;
                          };
                  };
                  STRUCT "sv" {
                          STRING "PIDs";
                          VARIANT "au" {
                                  ARRAY "u" {
                                          UINT32 31029;
                                  };
                          };
                  };
                  STRUCT "sv" {
                          STRING "TasksMax";
                          VARIANT "t" {
                                  UINT64 18446744073709551615;
                          };
                  };
          };
          ARRAY "(sa(sv))" {
          };
  };

‣ Type=method_return  Endian=l  Flags=1  Version=1  Priority=0 Cookie=30469  ReplyCookie=1219
  Sender=:1.0  Destination=:1.2
  UniqueName=:1.0
  MESSAGE "o" {
          OBJECT_PATH "/org/freedesktop/systemd1/job/33886";
  };

‣ Type=signal  Endian=l  Flags=1  Version=1  Priority=0 Cookie=1220
  Sender=:1.2  Path=/org/freedesktop/login1  Interface=org.freedesktop.login1.Manager  Member=SessionNew
  UniqueName=:1.2
  MESSAGE "so" {
          STRING "c74";
          OBJECT_PATH "/org/freedesktop/login1/session/c74";
  };

‣ Type=signal  Endian=l  Flags=1  Version=1  Priority=0 Cookie=1221
  Sender=:1.2  Path=/org/freedesktop/login1/user/_1000  Interface=org.freedesktop.DBus.Properties  Member=PropertiesChanged
  UniqueName=:1.2
  MESSAGE "sa{sv}as" {
          STRING "org.freedesktop.login1.User";
          ARRAY "{sv}" {
                  DICT_ENTRY "sv" {
                          STRING "Display";
                          VARIANT "(so)" {
                                  STRUCT "so" {
                                          STRING "c1";
                                          OBJECT_PATH "/org/freedesktop/login1/session/c1";
                                  };
                          };
                  };
          };
          ARRAY "s" {
          };
  };

‣ Type=method_return  Endian=l  Flags=1  Version=1  Priority=0 Cookie=1222  ReplyCookie=2
  Sender=:1.2  Destination=:1.276
  UniqueName=:1.2
  MESSAGE "soshusub" {
          STRING "c74";
          OBJECT_PATH "/org/freedesktop/login1/session/c74";
          STRING "/run/user/1000";
          UNIX_FD 4;
          UINT32 1000;
          STRING "";
          UINT32 0;
          BOOLEAN false;
  };

List Registered Services:

# List system services
dbus-send --system --dest=org.freedesktop.DBus --type=method_call --print-reply \
/org/freedesktop/DBus org.freedesktop.DBus.ListNames | grep -v '":'

# List session services
dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply \
/org/freedesktop/DBus org.freedesktop.DBus.ListNames | grep -v '":'

Registry Locations:

/usr/share/dbus-1/services/*.service
/usr/share/dbus-1/system-services/*.service
/usr/share/dbus-1/interfaces/*.xml

Call RPC:

dbus-send --session --dest=<class> <namespace> <method> [<parameters>]

Example:

dbus-send --session --dest=org.gnome.feed.Reader \
  /org/gnome/feed/Reader \
  org.gnome.feed.Reader.Subscribe \
  string:http://osnews.com/files/recent.rdf

Go d-bus

The tcd project exposes an object both over gRPC and D-Bus.

Library interfacing with Ubuntu upstart to manage jobs.

The ble-adapter-go project uses godbus to interact with BLE.

Examples

client.go:

package main

import (
	"github.com/guelfey/go.dbus"
)

func main() {
	conn, err := dbus.SessionBus()
	if err != nil {
		panic(err)
	}

	// func (conn *Conn) Object(dest string, path ObjectPath) *Object
	obj := conn.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")

	// Interface from the specification:
	// UINT32 org.freedesktop.Notifications.Notify (STRING app_name, UINT32 replaces_id, STRING app_icon, STRING summary, STRING body, ARRAY actions, DICT hints, INT32 expire_timeout);

	// func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call
	call := obj.Call("org.freedesktop.Notifications.Notify", 0, "c¼h", uint32(0), "", "Hallo Chaostreff!", "Ich begrüße euch herzlich zu meiner c¼h!", []string{}, map[string]dbus.Variant{}, int32(1000))
	if call.Err != nil {
		panic(call.Err)
	}
}

server.go:

package main

import (
	"fmt"
	"github.com/guelfey/go.dbus"
)

type Server struct {
	id uint32
}

func (s Server) Notify(appName string, replacesId uint32, appIcon string, summary string, body string, actions []string, hints map[string]dbus.Variant, expireTimeout int32) (ret uint32, err *dbus.Error) {
	fmt.Printf("Got Notification from %s:\n", appName)
	fmt.Printf("==== %s ====\n", summary)
	fmt.Println(body)
	fmt.Printf("==== END %s ====\n", summary)
	s.id++
	return s.id, nil
}

func main() {
	conn, err := dbus.SessionBus()
	if err != nil {
		panic(err)
	}

	reply, err := conn.RequestName("org.freedesktop.Notifications", dbus.NameFlagDoNotQueue)
	if err != nil {
		panic(err)
	}
	if reply != dbus.RequestNameReplyPrimaryOwner {
		panic("Name already taken")
	}

	s := Server{ id: 0 }

	conn.Export(s, "/org/freedesktop/Notifications", "org.freedesktop.Notifications")
	select {}
}

Registering a service with Avahi using D-Bus:

package main

import (
        "github.com/guelfey/go.dbus"
        "log"
        "bufio"
        "os"
)

func main() {
        var dconn *dbus.Conn
        var obj *dbus.Object
        var path dbus.ObjectPath
        var err error

        dconn, err = dbus.SystemBus()
        if err != nil {
                log.Fatal("Fatal error ", err.Error())
        }

        obj = dconn.Object("org.freedesktop.Avahi", "/")
        obj.Call("org.freedesktop.Avahi.Server.EntryGroupNew", 0).Store(&path)

        obj = dconn.Object("org.freedesktop.Avahi", path)

        var AAY [][]byte
        for _, s := range []string{"email=lemenkov@gmail.com", "jid=lemenkov@gmail.com", "status=avail"} {
                AAY = append(AAY, []byte(s))
        }

        // http://www.dns-sd.org/ServiceTypes.html
        obj.Call("org.freedesktop.Avahi.EntryGroup.AddService", 0,
                int32(-1),      // avahi.IF_UNSPEC
                int32(-1),      // avahi.PROTO_UNSPEC
                uint32(0),      // flags
                "epmd@Hostname",// sname
                "_epmd._tcp",   // stype
                "local",        // sdomain
                "work.local",   // shost
                uint16(4369),   // port
                AAY)            // text record
        obj.Call("org.freedesktop.Avahi.EntryGroup.Commit", 0)

        // Wait for getch and exit
        bufio.NewReader(os.Stdin).ReadString('\n')
}

Python D-Bus

Examples

C D-Bus

C has three established D-Bus libraries:

  • libdbus: shipped in the reference implementation of D-Bus, OOM.
  • GDBus: part of GLib, the low-level tool library of GNOME
  • sd-bus: Support for kdbus, better performance, shipped with systemd.

Examples

Using sd-bus:

#include <stdio.h>
#include <stdlib.h>
#include <systemd/sd-bus.h>

int main(int argc, char *argv[]) {
        sd_bus_error error = SD_BUS_ERROR_NULL;
        sd_bus_message *m = NULL;
        sd_bus *bus = NULL;
        const char *path;
        int r;

        /* Connect to the system bus */
        r = sd_bus_open_system(&bus);
        if (r < 0) {
                fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-r));
                goto finish;
        }

        /* Issue the method call and store the respons message in m */
        r = sd_bus_call_method(bus,
                               "org.freedesktop.systemd1",           /* service to contact */
                               "/org/freedesktop/systemd1",          /* object path */
                               "org.freedesktop.systemd1.Manager",   /* interface name */
                               "StartUnit",                          /* method name */
                               &error,                               /* object to return error in */
                               &m,                                   /* return message on success */
                               "ss",                                 /* input signature */
                               "cups.service",                       /* first argument */
                               "replace");                           /* second argument */
        if (r < 0) {
                fprintf(stderr, "Failed to issue method call: %s\n", error.message);
                goto finish;
        }

        /* Parse the response message */
        r = sd_bus_message_read(m, "o", &path);
        if (r < 0) {
                fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r));
                goto finish;
        }

        printf("Queued service job as %s.\n", path);

finish:
        sd_bus_error_free(&error);
        sd_bus_message_unref(m);
        sd_bus_unref(bus);

        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

See Invoking a Method, from C, with sd-bus.

GDBus is a newer implementation.

Using GDBus:

/**
 * Define enumerations for the different signals that we can generate
 * (so that we can refer to them within the signals-array [below]
 * using symbolic names). These are not the same as the signal name
 * strings.
 *
 * NOTE: E_SIGNAL_COUNT is NOT a signal enum. We use it as a
 *       convenient constant giving the number of signals defined so
 *       far. It needs to be listed last.
 */
typedef enum {
  E_SIGNAL_CHANGED_VALUE1,
  E_SIGNAL_CHANGED_VALUE2,
  E_SIGNAL_OUTOFRANGE_VALUE1,
  E_SIGNAL_OUTOFRANGE_VALUE2,
  E_SIGNAL_COUNT
} ValueSignalNumber;

  /*... Listing cut for brevity ...*/

typedef struct {
  /* The parent class state. */
  GObjectClass parent;
  /* The minimum number under which values will cause signals to be
     emitted. */
  gint thresholdMin;
  /* The maximum number over which values will cause signals to be
     emitted. */
  gint thresholdMax;
  /* Signals created for this class. */
  guint signals[E_SIGNAL_COUNT];
} ValueObjectClass;

  /*... Listing cut for brevity ...*/

/**
 * Per class initializer
 *
 * Sets up the thresholds (-100 .. 100), creates the signals that we
 * can emit from any object of this class and finally registers the
 * type into the GLib/D-Bus wrapper so that it may add its own magic.
 */
static void value_object_class_init(ValueObjectClass* klass) {

  /* Since all signals have the same prototype (each will get one
     string as a parameter), we create them in a loop below. The only
     difference between them is the index into the klass->signals
     array, and the signal name.

     Since the index goes from 0 to E_SIGNAL_COUNT-1, we just specify
     the signal names into an array and iterate over it.

     Note that the order here must correspond to the order of the
     enumerations before. */
  const gchar* signalNames[E_SIGNAL_COUNT] = {
    SIGNAL_CHANGED_VALUE1,
    SIGNAL_CHANGED_VALUE2,
    SIGNAL_OUTOFRANGE_VALUE1,
    SIGNAL_OUTOFRANGE_VALUE2 };
  /* Loop variable */
  int i;

  dbg("Called");
  g_assert(klass != NULL);

  /* Setup sane minimums and maximums for the thresholds. There is no
     way to change these afterwards (currently), so you can consider
     them as constants. */
  klass->thresholdMin = -100;
  klass->thresholdMax = 100;

  dbg("Creating signals");

  /* Create the signals in one loop, since they all are similar
     (except for the names). */
  for (i = 0; i < E_SIGNAL_COUNT; i++) {
    guint signalId;

    /* Most of the time you will encounter the following code without
       comments. This is why all the parameters are documented
       directly below. */
    signalId =
      g_signal_new(signalNames[i], /* str name of the signal */
                   /* GType to which signal is bound to */
                   G_OBJECT_CLASS_TYPE(klass),
                   /* Combination of GSignalFlags which tell the
                      signal dispatch machinery how and when to
                      dispatch this signal. The most common is the
                      G_SIGNAL_RUN_LAST specification. */
                   G_SIGNAL_RUN_LAST,
                   /* Offset into the class structure for the type
                      function pointer. Since we're implementing a
                      simple class/type, we'll leave this at zero. */
                   0,
                   /* GSignalAccumulator to use. We don't need one. */
                   NULL,
                   /* User-data to pass to the accumulator. */
                   NULL,
                   /* Function to use to marshal the signal data into
                      the parameters of the signal call. Luckily for
                      us, GLib (GCClosure) already defines just the
                      function that we want for a signal handler that
                      we don't expect any return values (void) and
                      one that will accept one string as parameter
                      (besides the instance pointer and pointer to
                      user-data).

                      If no such function would exist, you would need
                      to create a new one (by using glib-genmarshal
                      tool). */
                   g_cclosure_marshal_VOID__STRING,
                   /* Return GType of the return value. The handler
                      does not return anything, so we use G_TYPE_NONE
                      to mark that. */
                   G_TYPE_NONE,
                   /* Number of parameter GTypes to follow. */
                   1,
                   /* GType(s) of the parameters. We only have one. */
                   G_TYPE_STRING);
    /* Store the signal Id into the class state, so that we can use
       it later. */
    klass->signals[i] = signalId;

    /* Proceed with the next signal creation. */
  }
  /* All signals created. */

  dbg("Binding to GLib/D-Bus");

  /*... Listing cut for brevity ...*/

}

Node D-Bus

D-Bus over Network

This tutorial explains how to use gabriel to connect over the network using SSH. Might be outdated.

dbus-remote

There's a C library, dbus-daemon-proxy, that can be used to proxy two machines over the network.

Resources