Search code examples
cdbus

DBus, C - send/receive binary data


Looking for a simple tutorial.

I need to send and receive binary data through DBus (pure C).

All tutorial I found are using DBUS_TYPE_STRING, but I have a binary data blocks.

Thinking about usage like this:

void write_msg(DbusConnection *conn, void *data, size_t datasize) {
   DBusMessage *msg = dbus_message_new(DBUS_TYPE_ARRAY); // Is it DBUS_TYPE_ARRAY?

   // how to convert data of datasize into msg?

   dbus_connection_send(conn, msg, NULL);

   dbus_free(msg); // there is no dbus_message_free() function?
}

void read_msg(DbusConnection *conn, void *data, size_t datasize) {
   DBusMessage *msg = dbus_connection_pop_message(conn);

   // how to convert msg to data of datasize?

   dbus_free(msg);
}

// And to use it as:
struct my_struct st;
write_msg(conn, &st, sizeof(st));

So how to write/read an untyped memory block into DBusMessage? To make it as easy as write/read datagrams in sockets?


Solution

  • dbus_message_new(DBUS_TYPE_ARRAY); // Is it DBUS_TYPE_ARRAY
    

    No, that's the message type, not the data type. D-Bus has "method call" and "signal" as the two major message types – if you are calling a function (method) via D-Bus, you should be specifying DBUS_MESSAGE_TYPE_METHOD_CALL, or using the dbus_message_new_method_call() function.

    So how to write/read an untyped memory block into DBusMessage?

    Binary data in D-Bus is usually transferred as type ay – "array of byte".

    While I'm not very familiar with dbus-glib, I looked at wpa_supplicant's source code (hostap.git) for an example, and I think you're looking for:

    1. Begin the array with dbus_message_iter_open_container(&val, DBUS_TYPE_ARRAY, "y", &iter),

    2. Write data using dbus_message_iter_append_fixed_array()

      (Alternatively, you could loop dbus_message_iter_append_basic(&iter, DBUS_TYPE_BYTE, &(val[i])) for each byte of your memory block),

    3. Finish using dbus_message_iter_close_container(&iter)

    To make it as easy as write/read datagrams in sockets?

    If all you need is datagrams over a socket, D-Bus is probably not for you. You can't fully get away from its structure (the method call/return format and the object & interface system) – and if you do, then what's the point of using D-Bus?

    However, do try out either GLib2 (GDBus) or systemd's "sd-bus" as an easier-to-use C library. (The dbus-glib library you're using is mostly considered deprecated in favor of GDBus via GLib; it will keep working forever but is not really maintained anymore.)

    Additionally, keep in mind that D-Bus is not meant for high-volume traffic. Over a private socket it's fine but the shared system (or session) bus will have limits on what's acceptable.

    If you really need a raw Unix socket, then use a socket – for example, you can create a socketpair(), pass one of the file descriptors via D-Bus call (using a h value), then continue all communications over the socket. This is already done by some programs and is even recommended by dbus-daemon maintainers for programs that need high traffic volumes or unstructured communications.