New sd-bus API from systemd

In the new release of systemd v221, we are introducing the sd-bus API that ships with the stable release of systemd . sd-bus is our minimal D-Bus IPC C library , supporting both classic socket-based D-Bus and kdbus as backends . The library has been part of systemd for some time, but it was only used internally as we wanted to freely make changes to the API without affecting external users. However, now, starting with v221, we are confident that we have made a stable API.





In this post, I provide an overview of the sd-bus library, a brief recap of the basics of D-Bus and its concepts, and some simple examples of how to write D-Bus clients and services using it.





What is D-Bus?

Let's start with a quick reminder of what D-Bus really is. It is a powerful general purpose IPC system for Linux and other operating systems. It defines concepts such as buses, objects, interfaces, methods, signals, properties. It provides you with granular access control, a rich type system, easy discovery, self-diagnostics, monitoring, reliable multicasting, service startup, file descriptor transfers, and more. There are bindings for many of the programming languages ​​that are used in Linux.





D-Bus has been a core component of Linux systems for over 10 years. It is by far the most widely used high-level local IPC system in Linux. Since its inception, systemd has been the IPC system in which it exposes its interfaces. And even before systemd, it was the IPC system that Upstart used for its interfaces. It is used by GNOME, KDE and many system components.





D-Bus refers to both the specification and the reference implementation . The reference implementation provides both a bus server component and a client library. Although there are many other popular subsequent implementations of the client library, both for C and other programming languages, the only widely used server side is the one specified in the reference implementation. (However, the kdbus project is working to provide an alternative to this server implementation as a kernel component.)





D-Bus IPC AF_UNIX. TCP/IP. , D-Bus TCP . D-Bus , ssh, . systemd , API .





D-Bus: , , AF_UNIX FIFO UNIX . , D-Bus -: AF_UNIX/FIFO D-Bus , TCP HTTP/REST. , AF_UNIX/FIFO , D-Bus , , , , .





10- D-Bus , , , - ( , kdbus, sd-bus), , , . IPC, , D-Bus, , , D-Bus.





: D-Bus . Linux IPC, . , D-Bus , , , .





sd-bus?

, sd-bus, D-Bus .





D-Bus: libdbus, D-Bus, GDBus, GLib, GNOME.





libdbus , . , . , API , API , . , , . , (, OOM , ) , Windows UNIX.





GDBus - . GLib/GObject libdbus. GDBus , libdbus. libdbus, , GObject D-Bus GObject. D-Bus GVariant, GLib. GLib, , D-Bus , libdbus.





sd-bus , libdbus, GDBus. libdbus GDBus: , , , , , , , GDBus/GLib/GObject/GVariant. systemd, OOM. , , kdbus D-Bus («dbus1»). , kdbus, dbus1, - , . libdbus GDBus, sd-bus, Linux Linux , . , ( ): libdbus, GDBus . ( ), . , : , kdbus , , , libdbus GDBus.





, , API :





  • GLib/GObject, GDBus .





  • , Linux, Windows, Mac OS UNIX, GDBus ( GLib/GObject), libdbus ( ).





  • sd-bus.





( C++, . : Qt, QtDBus API D-Bus, libdbus.)





D-Bus

D-Bus . , . . :





  • - , IPC. : , , ; , , , . ( , , , , , , , .)





  • - , IPC API . . , org.freedesktop.NetworkManager



    - , API- NetworkManager, org.freedesktop.login1



    - , API- systemd-logind



    .





  • - , IPC API . , , , . , . .





  • - . , , - . - , , . , D-Bus , , . : /org/freedesktop/login1



    - «» org.freedesktop.login1



    (, , systemd-logind). , . , , systemd-logind



    /org/freedesktop/login1/session



    , : /org/freedesktop/login1/session/_7



    , /org/freedesktop/login1/session./_55



    . , .





  • , , . - , ( ), . D-Bus , , Java, . , . , . (, , , , .) , , , . , org.freedesktop.DBus.Introspectable



    , org.freedesktop.DBus.Peer



    org.freedesktop.DBus.Properties



    .





  • . «» «», - , Java. D-Bus , . D-Bus . , , . ( ) CamelCase. , systemd-logind



    ActivateSession



    org.freedesktop.login1.Manager



    , /org/freedesktop/login1



    org.freedesktop.login1



    .





  • , ( , , . ). , . . , , s



    u



    32- , , as



    a(sb)



    , . . D-Bus, . ActivateSession



    ( , , s



    ) ( , , ). , , . .





  • - , D-Bus. , . . , , . , , - . , . / --, -- ( , , --). : systemd-logind



    SessionNew



    - , , SessionRemoved



    , .





  • - , D-Bus. , , C#. . , , . : systemd-logind



    Docked



    b



    ( ). , systemd-logind



    , - ( ).





D-Bus . , . . , -, HTTP REST. HTTP- D-Bus:





  • HTTP-, . , VPN. , , . «» D-Bus.





  • HTTP- . .





  • HTTP- URL-. URL-, ( , «/») D-Bus.





  • «» URL- ( , , , ), , . D-Bus .





  • , HTTP- «?», D-Bus.





, HTTP- D-Bus . , , , .





. , , .





systemd busctl, D-Bus. , . ( --user, ):





$ busctl
NAME                                       PID PROCESS         USER             CONNECTION    UNIT                      SESSION    DESCRIPTION
:1.1                                         1 systemd         root             :1.1          -                         -          -
:1.11                                      705 NetworkManager  root             :1.11         NetworkManager.service    -          -
:1.14                                      744 gdm             root             :1.14         gdm.service               -          -
:1.4                                       708 systemd-logind  root             :1.4          systemd-logind.service    -          -
:1.7200                                  17563 busctl          lennart          :1.7200       session-1.scope           1          -
[…]
org.freedesktop.NetworkManager             705 NetworkManager  root             :1.11         NetworkManager.service    -          -
org.freedesktop.login1                     708 systemd-logind  root             :1.4          systemd-logind.service    -          -
org.freedesktop.systemd1                     1 systemd         root             :1.1          -                         -          -
org.gnome.DisplayManager                   744 gdm             root             :1.14         gdm.service               -          -
[…]
      
      



( , ).





, . , ":1.11". D-Bus . , , , . , IP-. , , busctl, . , ( ; , ). DNS, , IP- , , . , , IP-, , . ( , , , IP- , ).





, . , (, , systemd).





. , org.freedesktop.login1:





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



, ? , , : TAB, . D-Bus!





, . . , , , :





$ busctl introspect org.freedesktop.login1 /org/freedesktop/login1/session/_31
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         -                                        -
.TakeControl                        method    b         -                                        -
.TakeDevice                         method    uu        hb                                       -
.Terminate                          method    -         -                                        -
.Unlock                             method    -         -                                        -
.Active                             property  b         true                                     emits-change
.Audit                              property  u         1                                        const
.Class                              property  s         "user"                                   const
.Desktop                            property  s         ""                                       const
.Display                            property  s         ""                                       const
.Id                                 property  s         "1"                                      const
.IdleHint                           property  b         true                                     emits-change
.IdleSinceHint                      property  t         1434494624206001                         emits-change
.IdleSinceHintMonotonic             property  t         0                                        emits-change
.Leader                             property  u         762                                      const
.Name                               property  s         "lennart"                                const
.Remote                             property  b         false                                    const
.RemoteHost                         property  s         ""                                       const
.RemoteUser                         property  s         ""                                       const
.Scope                              property  s         "session-1.scope"                        const
.Seat                               property  (so)      "seat0" "/org/freedesktop/login1/seat... const
.Service                            property  s         "gdm-autologin"                          const
.State                              property  s         "active"                                 -
.TTY                                property  s         "/dev/tty1"                              const
.Timestamp                          property  t         1434494630344367                         const
.TimestampMonotonic                 property  t         34814579                                 const
.Type                               property  s         "x11"                                    const
.User                               property  (uo)      1000 "/org/freedesktop/login1/user/_1... const
.VTNr                               property  u         1                                        const
.Lock                               signal    -         -                                        -
.PauseDevice                        signal    uus       -                                        -
.ResumeDevice                       signal    uuh       -                                        -
.Unlock                             signal    -         -                                        -
      
      



, busctl , , TAB. , , , systemd-logind



. , . . . , . . .





. : - :





# busctl call org.freedesktop.login1 /org/freedesktop/login1/session/_31 org.freedesktop.login1.Session Lock
      
      



, , : . - , - , TAB. Lock



, . , , Enter , ( , systemd-logind. GNOME , KDE ).





Lock



, . , . , systemd :





# busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager StartUnit ss "cups.service" "replace"
o "/org/freedesktop/systemd1/job/42684"
      
      



, , ( , , ). - . , , . StartUnit systemd , , . . , : ( o ), .





, , busctl



. . .





busctl



. , D-Bus ( .cap



Wireshark!) . , sd-bus, busctl



, , .





busctl



( ) API sd-bus. , sd-bus. , . kdbus, D-Bus, !





sd-bus

! , sd-bus.





API sd-bus sd-bus.h.





, .





  • kdbus, dbus1 .





  • ssh .





  • . 34 , PID .





  • , , , .





  • , , .





  • D-Bus UNIX ( ), D-Bus Linux.





  • , . .





API , . , sd_bus_



.





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;
}
      
      



bus-client.c



, :





$ gcc bus-client.c -o bus-client `pkg-config --cflags --libs libsystemd`
      
      



bus-client



, . root, StartUnit



:





# ./bus-client
Queued service job as /org/freedesktop/systemd1/job/3586.
      
      



. , . busctl



, . , . , D-Bus sd-bus. , , , sd-bus.





sd-bus

, - . , . . , : 64- , 64- .





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

static int method_multiply(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
  int64_t x, y;
  int r;

  /* Read the parameters */
  r = sd_bus_message_read(m, "xx", &x, &y);
  if (r < 0) {
    fprintf(stderr, "Failed to parse parameters: %s\n", strerror(-r));
    return r;
  }

  /* Reply with the response */
  return sd_bus_reply_method_return(m, "x", x * y);
}

static int method_divide(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
  int64_t x, y;
  int r;

  /* Read the parameters */
  r = sd_bus_message_read(m, "xx", &x, &y);
  if (r < 0) {
    fprintf(stderr, "Failed to parse parameters: %s\n", strerror(-r));
    return r;
  }

  /* Return an error on division by zero */
  if (y == 0) {
    sd_bus_error_set_const(ret_error, "net.poettering.DivisionByZero", "Sorry, can't allow division by zero.");
    return -EINVAL;
  }

  return sd_bus_reply_method_return(m, "x", x / y);
}

/* The vtable of our little object, implements the net.poettering.Calculator interface */
static const sd_bus_vtable calculator_vtable[] = {
  SD_BUS_VTABLE_START(0),
  SD_BUS_METHOD("Multiply", "xx", "x", method_multiply, SD_BUS_VTABLE_UNPRIVILEGED),
  SD_BUS_METHOD("Divide",   "xx", "x", method_divide,   SD_BUS_VTABLE_UNPRIVILEGED),
  SD_BUS_VTABLE_END
};

int main(int argc, char *argv[]) {
  sd_bus_slot *slot = NULL;
  sd_bus *bus = NULL;
  int r;

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

  /* Install the object */
  r = sd_bus_add_object_vtable(bus,
                               &slot,
                               "/net/poettering/Calculator",  /* object path */
                               "net.poettering.Calculator",   /* interface name */
                               calculator_vtable,
                               NULL);
  if (r < 0) {
    fprintf(stderr, "Failed to issue method call: %s\n", strerror(-r));
    goto finish;
  }

  /* Take a well-known service name so that clients can find us */
  r = sd_bus_request_name(bus, "net.poettering.Calculator", 0);
  if (r < 0) {
    fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-r));
    goto finish;
  }

  for (;;) {
    /* Process requests */
    r = sd_bus_process(bus, NULL);
    if (r < 0) {
      fprintf(stderr, "Failed to process bus: %s\n", strerror(-r));
      goto finish;
    }
    if (r > 0) /* we processed a request, try to process another one, right-away */
      continue;

    /* Wait for the next request to process */
    r = sd_bus_wait(bus, (uint64_t) -1);
    if (r < 0) {
      fprintf(stderr, "Failed to wait on bus: %s\n", strerror(-r));
      goto finish;
    }
  }

finish:
  sd_bus_slot_unref(slot);
  sd_bus_unref(bus);

  return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
      
      



bus-service.c



, :





$ gcc bus-service.c -o bus-service `pkg-config --cflags --libs libsystemd`
      
      



:





$ ./bus-service
      
      



. , , , . : , . : , , , . , --user busctl. .





$ busctl --user tree net.poettering.Calculator
└─/net/poettering/Calculator
      
      



, , , , . , :





$ busctl --user introspect net.poettering.Calculator /net/poettering/Calculator
NAME                                TYPE      SIGNATURE RESULT/VALUE FLAGS
net.poettering.Calculator           interface -         -            -
.Divide                             method    xx        x            -
.Multiply                           method    xx        x            -
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  -            -
      
      



, sd-bus . , , , ! , «xx» ( 64- ) «x». ! ?





$ busctl --user call net.poettering.Calculator /net/poettering/Calculator net.poettering.Calculator Multiply xx 5 7
x 35
      
      



! 5 7, 35! :





$ busctl --user call net.poettering.Calculator /net/poettering/Calculator net.poettering.Calculator Divide xx 99 17
x 5
      
      



! ! ! :





$ busctl --user call net.poettering.Calculator /net/poettering/Calculator net.poettering.Calculator Divide xx 43 0
Sorry, can't allow division by zero.
      
      



! . , , .





, . , , , , , . D-Bus sd-bus, ...





Hope this post was helpful to you. If you are interested in using sd-bus for your own programs, I hope it helps you. If you have further questions, take a look at the (incomplete) man pages and ask us on IRC or the systemd mailing list. If you need more examples, take a look at the systemd source tree, all of systemd's many bus services use sd-bus extensively.








All Articles