Created
October 2, 2012 11:14
-
-
Save mvidner/3818256 to your computer and use it in GitHub Desktop.
D-Bus example from http://www.matthew.ath.cx/misc/dbus
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define DBUS_API_SUBJECT_TO_CHANGE | |
#include <dbus/dbus.h> | |
#include <stdbool.h> | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
/** | |
* Connect to the DBUS bus and send a broadcast signal | |
*/ | |
void sendsignal(const char* sigvalue) | |
{ | |
DBusMessage* msg; | |
DBusMessageIter args; | |
DBusConnection* conn; | |
DBusError err; | |
int ret; | |
dbus_uint32_t serial = 0; | |
printf("Sending signal with value %s\n", sigvalue); | |
// initialise the error value | |
dbus_error_init(&err); | |
// connect to the DBUS session bus, and check for errors | |
conn = dbus_bus_get(DBUS_BUS_SESSION, &err); | |
if (dbus_error_is_set(&err)) { | |
fprintf(stderr, "Connection Error (%s)\n", err.message); | |
dbus_error_free(&err); | |
} | |
if (NULL == conn) { | |
exit(1); | |
} | |
// register our name on the bus, and check for errors | |
ret = dbus_bus_request_name(conn, "test.signal.source", DBUS_NAME_FLAG_REPLACE_EXISTING , &err); | |
if (dbus_error_is_set(&err)) { | |
fprintf(stderr, "Name Error (%s)\n", err.message); | |
dbus_error_free(&err); | |
} | |
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { | |
exit(1); | |
} | |
// create a signal & check for errors | |
msg = dbus_message_new_signal("/test/signal/Object", // object name of the signal | |
"test.signal.Type", // interface name of the signal | |
"Test"); // name of the signal | |
if (NULL == msg) | |
{ | |
fprintf(stderr, "Message Null\n"); | |
exit(1); | |
} | |
// append arguments onto signal | |
dbus_message_iter_init_append(msg, &args); | |
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &sigvalue)) { | |
fprintf(stderr, "Out Of Memory!\n"); | |
exit(1); | |
} | |
// send the message and flush the connection | |
if (!dbus_connection_send(conn, msg, &serial)) { | |
fprintf(stderr, "Out Of Memory!\n"); | |
exit(1); | |
} | |
dbus_connection_flush(conn); | |
printf("Signal Sent\n"); | |
// free the message and unref the connection | |
dbus_message_unref(msg); | |
dbus_connection_unref(conn); | |
} | |
/** | |
* Call a method on a remote object | |
*/ | |
void query(const char* param) | |
{ | |
DBusMessage* msg; | |
DBusMessageIter args; | |
DBusConnection* conn; | |
DBusError err; | |
DBusPendingCall* pending; | |
int ret; | |
dbus_bool_t stat; | |
dbus_uint32_t level; | |
printf("Calling remote method with %s\n", param); | |
// initialiset the errors | |
dbus_error_init(&err); | |
// connect to the session bus and check for errors | |
conn = dbus_bus_get(DBUS_BUS_SESSION, &err); | |
if (dbus_error_is_set(&err)) { | |
fprintf(stderr, "Connection Error (%s)\n", err.message); | |
dbus_error_free(&err); | |
} | |
if (NULL == conn) { | |
exit(1); | |
} | |
// request our name on the bus | |
ret = dbus_bus_request_name(conn, "test.method.caller", DBUS_NAME_FLAG_REPLACE_EXISTING , &err); | |
if (dbus_error_is_set(&err)) { | |
fprintf(stderr, "Name Error (%s)\n", err.message); | |
dbus_error_free(&err); | |
} | |
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { | |
exit(1); | |
} | |
// create a new method call and check for errors | |
msg = dbus_message_new_method_call("test.method.server", // target for the method call | |
"/test/method/Object", // object to call on | |
"test.method.Type", // interface to call on | |
"Method"); // method name | |
if (NULL == msg) { | |
fprintf(stderr, "Message Null\n"); | |
exit(1); | |
} | |
// append arguments | |
dbus_message_iter_init_append(msg, &args); | |
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, ¶m)) { | |
fprintf(stderr, "Out Of Memory!\n"); | |
exit(1); | |
} | |
// send message and get a handle for a reply | |
if (!dbus_connection_send_with_reply (conn, msg, &pending, -1)) { // -1 is default timeout | |
fprintf(stderr, "Out Of Memory!\n"); | |
exit(1); | |
} | |
if (NULL == pending) { | |
fprintf(stderr, "Pending Call Null\n"); | |
exit(1); | |
} | |
dbus_connection_flush(conn); | |
printf("Request Sent\n"); | |
// free message | |
dbus_message_unref(msg); | |
// block until we recieve a reply | |
dbus_pending_call_block(pending); | |
// get the reply message | |
msg = dbus_pending_call_steal_reply(pending); | |
if (NULL == msg) { | |
fprintf(stderr, "Reply Null\n"); | |
exit(1); | |
} | |
// free the pending message handle | |
dbus_pending_call_unref(pending); | |
// read the parameters | |
if (!dbus_message_iter_init(msg, &args)) | |
fprintf(stderr, "Message has no arguments!\n"); | |
else if (DBUS_TYPE_BOOLEAN != dbus_message_iter_get_arg_type(&args)) | |
fprintf(stderr, "Argument is not boolean!\n"); | |
else | |
dbus_message_iter_get_basic(&args, &stat); | |
if (!dbus_message_iter_next(&args)) | |
fprintf(stderr, "Message has too few arguments!\n"); | |
else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args)) | |
fprintf(stderr, "Argument is not int!\n"); | |
else | |
dbus_message_iter_get_basic(&args, &level); | |
printf("Got Reply: %d, %d\n", stat, level); | |
// free reply and unref connection | |
dbus_message_unref(msg); | |
dbus_connection_unref(conn); | |
} | |
void reply_to_method_call(DBusMessage* msg, DBusConnection* conn) | |
{ | |
DBusMessage* reply; | |
DBusMessageIter args; | |
dbus_bool_t stat = true; | |
dbus_uint32_t level = 21614; | |
dbus_uint32_t serial = 0; | |
const char* param = ""; | |
// read the arguments | |
if (!dbus_message_iter_init(msg, &args)) | |
fprintf(stderr, "Message has no arguments!\n"); | |
else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) | |
fprintf(stderr, "Argument is not string!\n"); | |
else | |
dbus_message_iter_get_basic(&args, ¶m); | |
printf("Method called with %s\n", param); | |
// create a reply from the message | |
reply = dbus_message_new_method_return(msg); | |
// add the arguments to the reply | |
dbus_message_iter_init_append(reply, &args); | |
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &stat)) { | |
fprintf(stderr, "Out Of Memory!\n"); | |
exit(1); | |
} | |
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &level)) { | |
fprintf(stderr, "Out Of Memory!\n"); | |
exit(1); | |
} | |
// send the reply && flush the connection | |
if (!dbus_connection_send(conn, reply, &serial)) { | |
fprintf(stderr, "Out Of Memory!\n"); | |
exit(1); | |
} | |
dbus_connection_flush(conn); | |
// free the reply | |
dbus_message_unref(reply); | |
} | |
/** | |
* Server that exposes a method call and waits for it to be called | |
*/ | |
void listen() | |
{ | |
DBusMessage* msg; | |
DBusConnection* conn; | |
DBusError err; | |
int ret; | |
printf("Listening for method calls\n"); | |
// initialise the error | |
dbus_error_init(&err); | |
// connect to the bus and check for errors | |
conn = dbus_bus_get(DBUS_BUS_SESSION, &err); | |
if (dbus_error_is_set(&err)) { | |
fprintf(stderr, "Connection Error (%s)\n", err.message); | |
dbus_error_free(&err); | |
} | |
if (NULL == conn) { | |
fprintf(stderr, "Connection Null\n"); | |
exit(1); | |
} | |
// request our name on the bus and check for errors | |
ret = dbus_bus_request_name(conn, "test.method.server", DBUS_NAME_FLAG_REPLACE_EXISTING , &err); | |
if (dbus_error_is_set(&err)) { | |
fprintf(stderr, "Name Error (%s)\n", err.message); | |
dbus_error_free(&err); | |
} | |
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { | |
fprintf(stderr, "Not Primary Owner (%d)\n", ret); | |
exit(1); | |
} | |
// loop, testing for new messages | |
while (true) { | |
// non blocking read of the next available message | |
dbus_connection_read_write(conn, 0); | |
msg = dbus_connection_pop_message(conn); | |
// loop again if we haven't got a message | |
if (NULL == msg) { | |
sleep(1); | |
continue; | |
} | |
// check this is a method call for the right interface & method | |
if (dbus_message_is_method_call(msg, "test.method.Type", "Method")) | |
reply_to_method_call(msg, conn); | |
// free the message | |
dbus_message_unref(msg); | |
} | |
// unref the connection | |
dbus_connection_unref(conn); | |
} | |
/** | |
* Listens for signals on the bus | |
*/ | |
void receive() | |
{ | |
DBusMessage* msg; | |
DBusMessageIter args; | |
DBusConnection* conn; | |
DBusError err; | |
int ret; | |
char* sigvalue; | |
printf("Listening for signals\n"); | |
// initialise the errors | |
dbus_error_init(&err); | |
// connect to the bus and check for errors | |
conn = dbus_bus_get(DBUS_BUS_SESSION, &err); | |
if (dbus_error_is_set(&err)) { | |
fprintf(stderr, "Connection Error (%s)\n", err.message); | |
dbus_error_free(&err); | |
} | |
if (NULL == conn) { | |
exit(1); | |
} | |
// request our name on the bus and check for errors | |
ret = dbus_bus_request_name(conn, "test.signal.sink", DBUS_NAME_FLAG_REPLACE_EXISTING , &err); | |
if (dbus_error_is_set(&err)) { | |
fprintf(stderr, "Name Error (%s)\n", err.message); | |
dbus_error_free(&err); | |
} | |
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { | |
exit(1); | |
} | |
// add a rule for which messages we want to see | |
dbus_bus_add_match(conn, "type='signal',interface='test.signal.Type'", &err); // see signals from the given interface | |
dbus_connection_flush(conn); | |
if (dbus_error_is_set(&err)) { | |
fprintf(stderr, "Match Error (%s)\n", err.message); | |
exit(1); | |
} | |
printf("Match rule sent\n"); | |
// loop listening for signals being emmitted | |
while (true) { | |
// non blocking read of the next available message | |
dbus_connection_read_write(conn, 0); | |
msg = dbus_connection_pop_message(conn); | |
// loop again if we haven't read a message | |
if (NULL == msg) { | |
sleep(1); | |
continue; | |
} | |
// check if the message is a signal from the correct interface and with the correct name | |
if (dbus_message_is_signal(msg, "test.signal.Type", "Test")) { | |
// read the parameters | |
if (!dbus_message_iter_init(msg, &args)) | |
fprintf(stderr, "Message Has No Parameters\n"); | |
else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) | |
fprintf(stderr, "Argument is not string!\n"); | |
else | |
dbus_message_iter_get_basic(&args, &sigvalue); | |
printf("Got Signal with value %s\n", sigvalue); | |
} | |
// free the message | |
dbus_message_unref(msg); | |
} | |
// unref the connection | |
dbus_connection_unref(conn); | |
} | |
int main(int argc, char** argv) | |
{ | |
if (2 > argc) { | |
printf ("Syntax: dbus-example [send|receive|listen|query] [<param>]\n"); | |
return 1; | |
} | |
const char* param = "no param"; | |
if (3 >= argc && NULL != argv[2]) param = argv[2]; | |
if (0 == strcmp(argv[1], "send")) | |
sendsignal(param); | |
else if (0 == strcmp(argv[1], "receive")) | |
receive(); | |
else if (0 == strcmp(argv[1], "listen")) | |
listen(); | |
else if (0 == strcmp(argv[1], "query")) | |
query(param); | |
else { | |
printf ("Syntax: dbus-example [send|receive|listen|query] [<param>]\n"); | |
return 1; | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CFLAGS=`pkg-config --cflags dbus-1` -Wall | |
LDFLAGS=`pkg-config --libs dbus-1` | |
all: dbus-example |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment