[RFC][Patch] DBus Service C library
Shahar Frank
shaharf at qumranet.com
Thu Aug 9 05:28:51 PDT 2007
Hi all,
I needed to implement a DBus front-end to an application we use.
I played a little with the Glib and the Python bindings and they both
worked well, but they seem unsuitable for my application which is a very
low level C application. In particular, the Glib binding code doesn't
fit into this application, which is very old stylish system application,
non object oriented. On the other hand, as it is stated in the DBus web
pages, the direct C binding is very low level. So, I decided to
implement simple and more "traditional" C oriented Server library. The
library is not yet finished but I decided to contribute it hoping that I
can get some valuable feedback, advices, comments, idea, etc.
It is in working condition (as I can check) and support:
- Single threaded server
- Multiple hierarchical objects
- Multiple interfaces
- Methods (method call handlers)
- Signal handlers
- Signal emitters (methods)
- Hierarchical introspection
- Automatic in/out parameters handling (limited to basic types
right now)
Still missing:
- Non basic parameter handing
- Properties handling
- Proper documentation
- Test client (I am using dbus-viewer for now)
I made an effort to do things in the "dbus way", but as I learned dbus
low level only while writing this library, I missed many mechanisms and
I have made quiet a few implementation mistakes. For example I
implemented a new logging system, didn't use dbus portable function
wrappers, and didn't use dbus internal abstract data structures, such as
dbus link lists. I really want to have your opinions on these subjects
(or any other).
If you feel it may interest others, I will happy to move the project to
your repository and work on it from there.
Shahar
diff -Naur /tmp/dbus/dbus-service.c dbus/dbus-service.c
--- /tmp/dbus/dbus-service.c 1970-01-01 02:00:00.000000000 +0200
+++ dbus/dbus-service.c 2007-08-09 12:14:52.000000000 +0300
@@ -0,0 +1,1033 @@
+/* DBus Service library.
+
+ Copyright (C) 2007 Qumranet, Inc., Shahar Frank
<shaharf at qumranet.com>
+
+ This Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ Theis Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <dbus-service.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+
+int dbus_log_level = DBUS_SERVICE_LOG_ERROR;
+
+static void dbus_interface_method_add(DBusInterface *interface,
DBusMethod *method);
+static void dbus_interface_signal_add(DBusInterface *interface,
DBusMethod *signal);
+static void dbus_object_interface_add(DBusObject *object, DBusInterface
*interface);
+static void dbus_service_object_add(DBusService *service, DBusObject
*object);
+static char *dbus_object_child_add(DBusObject *parent, DBusObject
*child);
+
+struct dbus_type {
+ char c;
+ int size;
+ int basic;
+} dbus_types[] = {
+ ['y']{ 'y', sizeof (unsigned char), 1 },
+ ['b']{ 'b', sizeof (bool), 1 },
+ ['n']{ 'n', sizeof (dbus_int16_t), 1 },
+ ['q']{ 'q', sizeof (dbus_uint16_t), 1 },
+ ['i']{ 'i', sizeof (dbus_int32_t), 1 },
+ ['u']{ 'u', sizeof (dbus_uint32_t), 1 },
+ ['x']{ 'x', sizeof (dbus_int64_t), 1 },
+ ['t']{ 't', sizeof (dbus_uint64_t), 1 },
+ ['d']{ 'd', sizeof (double), 1 },
+ ['s']{ 's', 0, 1 },
+ ['o']{ 'o', 0, 1 },
+ ['g']{ 'g', 0, 1 },
+ ['a']{ 'a', 0, 0 }, // array
+ ['r']{ 'r', 0, 0 }, // struct
+ ['(']{ '(', 0, 0 }, // struct
+ ['v']{ 'v', 0, 0 }, // variant
+ ['e']{ 'e', 0, 0 }, // dict
+ ['{']{ '{', 0, 0 }, // dict
+
+ [127]{0}, // last
+};
+
+char *dbus_introspect_xml_header =
DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE;
+char *bus_introspect_xml_interface =
+ " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
+ " <method name=\"Introspect\">\n"
+ " <arg name=\"xml\" type=\"s\"
direction=\"out\"/>\n"
+ " </method>\n"
+ " </interface>\n";
+
+
+static char *log_level_str[] = {
+ [DBUS_SERVICE_LOG_NONE] "NONE",
+ [DBUS_SERVICE_LOG_FATAL] "FATAL",
+ [DBUS_SERVICE_LOG_ERROR] "ERROR",
+ [DBUS_SERVICE_LOG_WARN] "WARN",
+ [DBUS_SERVICE_LOG_INFO] "INFO",
+ [DBUS_SERVICE_LOG_DEBUG] "DEBUG",
+ [DBUS_SERVICE_LOG_VERBOSE] "VERBOSE",
+};
+
+inline char *dbus_log_level_str(int level)
+{
+ if (level < 0 || level >= DBUS_SERVICE_LOG_LAST_)
+ return "???";
+ return log_level_str[level];
+}
+
+void dbus_log(DBusService *service, int level, char *msg, ...)
+{
+ char buf[8192], *id;
+ va_list va;
+ int n;
+
+ va_start(va, msg);
+ n = vsnprintf(buf, sizeof(buf), msg, va);
+ buf[n] = 0;
+ va_end(va);
+
+ if (service && service->id)
+ id = service->id;
+ else
+ id = "";
+ fprintf(stderr, "[%d:%s]: %s: %s\n", getpid(), id,
dbus_log_level_str(level), buf);
+}
+
+/**
+ * Set a service error to err str and return the error message.
+ */
+char *dbus_service_error_str(DBusService *service, char *msg)
+{
+ /* For now only single message is supported. */
+ if (service->err)
+ free(service->err);
+ service->err = strdup(msg);
+ return service->err;
+}
+
+/**
+ * Set a service error, free 'err' and return the error message.
+ */
+char *dbus_service_error(DBusService *service, DBusError *err)
+{
+ char *errstr;
+ errstr = dbus_service_error_str(service, strdup(err->message));
+ dbus_error_free(err);
+ return errstr;
+}
+
+DBusParam *dbus_method_lookup_param(DBusMethod *method, int in, char
*name)
+{
+ DBusParam **pp = in ? method->inparam : method->outparam, **ee;
+
+ for (ee = pp + DBUS_PARAM_MAX; pp < ee && *pp; pp++)
+ if (!strcmp(name, (*pp)->name))
+ return *pp;
+ return NULL;
+}
+
+static int dbus_type_size(char const *sig)
+{
+ char c = sig[0];
+
+ if (c < 1)
+ return -1;
+ return dbus_types[(int)c].size;
+}
+
+char *dbus_method_get_param(DBusMethod *method, char *name, int in,
void *value)
+{
+ DBusParam *p = dbus_method_lookup_param(method, in, name);
+ int sz;
+
+ if (!p)
+ return "no such parameter";
+ sz = dbus_type_size(p->signature);
+ if (sz > 0)
+ memcpy(value, p->data, sz);
+ else if (sz == 0)
+ *(void **)value = p->data;
+ else
+ return "bad signature for param";
+
+ return NULL;
+}
+
+char *dbus_method_set_param(DBusMethod *method, char *name, int in,
void *value)
+{
+ DBusParam *p = dbus_method_lookup_param(method, in, name);
+ int sz;
+
+ if (!p)
+ return "no such parameter";
+ sz = dbus_type_size(p->signature);
+ if (sz > 0)
+ memcpy(p->data, value, sz);
+ else if (sz == 0)
+ if (p->signature[0] == 's')
+ strncpy(p->data, value, p->len);
+ else
+ return "parameter type not supported yet";
+ else
+ return "bad signature for param";
+
+ return NULL;
+}
+
+DBusParam *dbus_param_new(char *name, char *signature, void *data, int
len)
+{
+ DBusParam *param;
+ DBusError error;
+ int sz;
+
+ if (!(param = calloc(1, sizeof (*param))))
+ return NULL;
+
+ if (!dbus_signature_validate_single(signature, &error)) {
+ DBUS_LOG(NULL, DBUS_SERVICE_LOG_WARN,
+ "param %s sig %s is not a valid single complete
type",
+ name, signature);
+ return NULL;
+ }
+ if (!data) {
+ if (!(data = calloc(1, (unsigned short)len))) {
+ free(param);
+ return NULL;
+ }
+ } else
+ param->userdata = 1;
+
+ param->name = strdup(name);
+ param->signature = strdup(signature);
+ param->data = data;
+ sz = dbus_type_size(signature);
+ if (!sz)
+ param->len = (unsigned short)len;
+ else
+ param->len = sz;
+
+ return param;
+}
+
+char *dbus_method_param_add(DBusMethod *method, DBusParam *param, int
in)
+{
+ DBusParam **pp = in ? method->inparam : method->outparam, **e;
+
+ if (!param || !param->name)
+ return "NULL/unassigned param";
+
+ for (e = pp + DBUS_PARAM_MAX; pp < e; pp++)
+ if (!*pp)
+ break;
+
+ if (pp >= e)
+ return "No more param space";
+
+ *pp = param;
+ param->in = in;
+
+ if (in) // strncat may write size + 1 char !!!
+ strncat(method->insig, param->signature,
sizeof(method->insig) -1);
+ else
+ strncat(method->outsig, param->signature,
sizeof(method->insig) -1);
+
+ return NULL;
+}
+
+#define _UPDATE_BUF(b, s, left) do {\
+ int _l = strlen(s);\
+ if (left <= _l) return "buffer
to small";\
+ strncpy(b, s, left); left -= _l;
b += _l;\
+ } while (0)
+
+static char *dbus_method_param_xml(DBusMethod *method, char *buf, int
n)
+{
+ DBusParam **pp, **e;
+ char nbuf[256];
+ int l;
+
+ l = snprintf(nbuf, sizeof(nbuf)-1, "\t\t<method name =
\"%s\">\n", method->name);
+ nbuf[l] = 0;
+ _UPDATE_BUF(buf, nbuf, n);
+
+ for (pp = method->inparam, e = pp + DBUS_PARAM_MAX; pp < e &&
*pp; pp++) {
+ int l = snprintf(nbuf, sizeof(nbuf)-1,
+ "\t\t\t<arg name = \"%s\" type = \"%s\"
direction = \"in\" />\n",
+ (*pp)->name, (*pp)->signature);
+ nbuf[l] = 0;
+ _UPDATE_BUF(buf, nbuf, n);
+ }
+
+ for (pp = method->outparam, e = pp + DBUS_PARAM_MAX; pp < e &&
*pp; pp++) {
+ int l = snprintf(nbuf, sizeof(nbuf)-1,
+ "\t\t\t<arg name = \"%s\" type = \"%s\"
direction = \"out\" />\n",
+ (*pp)->name, (*pp)->signature);
+ nbuf[l] = 0;
+ _UPDATE_BUF(buf, nbuf, n);
+ }
+
+ _UPDATE_BUF(buf, "\t\t</method>\n", n);
+
+ return NULL;
+}
+
+static char *dbus_signal_param_xml(DBusMethod *method, char *buf, int
n)
+{
+ DBusParam **pp, **e;
+ char nbuf[256];
+ int l;
+
+ l = snprintf(nbuf, sizeof(nbuf)-1, "\t\t<signal name =
\"%s\">\n", method->name);
+ nbuf[l] = 0;
+ _UPDATE_BUF(buf, nbuf, n);
+
+ for (pp = method->outparam, e = pp + DBUS_PARAM_MAX; pp < e &&
*pp; pp++) {
+ int l = snprintf(nbuf, sizeof(nbuf)-1,
+ "\t\t\t<arg name = \"%s\" type = \"%s\" />\n",
+ (*pp)->name, (*pp)->signature);
+ nbuf[l] = 0;
+ _UPDATE_BUF(buf, nbuf, n);
+ }
+
+ _UPDATE_BUF(buf, "\t\t</signal>\n", n);
+
+ return NULL;
+
+}
+
+static char *dbus_object_introspect(DBusObject *object, char *buf, int
n)
+{
+ char nbuf[32*1024];
+ DBusObject *o;
+ DBusInterface *ifc;
+ DBusMethod *m;
+
+ _UPDATE_BUF(buf, dbus_introspect_xml_header, n);
+ _UPDATE_BUF(buf, "<node>\n", n);
+ _UPDATE_BUF(buf, bus_introspect_xml_interface, n);
+
+ for (ifc = object->interfaces; ifc; ifc = ifc->next) {
+ int l = snprintf(nbuf, sizeof(nbuf)-1,
+ "\t<interface name = \"%s\">\n",
ifc->name);
+ nbuf[l] = 0;
+ _UPDATE_BUF(buf, nbuf, n);
+ for (m = ifc->methods; m; m = m->next) {
+ dbus_method_param_xml(m, nbuf, sizeof(nbuf));
+ _UPDATE_BUF(buf, nbuf, n);
+ }
+ for (m = ifc->signals; m; m = m->next) {
+ dbus_signal_param_xml(m, nbuf, sizeof(nbuf));
+ _UPDATE_BUF(buf, nbuf, n);
+ }
+ _UPDATE_BUF(buf, "\t</interface>\n", n);
+ }
+
+ for (o = object->childs; o; o = o->nextchild) {
+ int l = snprintf(nbuf, sizeof(nbuf)-1,
+ "<node name = \"%s\">\n", o->relpath);
+ nbuf[l] = 0;
+ _UPDATE_BUF(buf, nbuf, n);
+ }
+
+ _UPDATE_BUF(buf, "</node>\n", n);
+
+ return NULL;
+}
+
+dbus_uint32_t dbus_service_send(DBusService *service, DBusMessage *msg,
int flush)
+{
+ DBusConnection *conn = service->conn;
+ dbus_uint32_t serial = 0;
+
+ // send the msg && flush the connection
+ if (!dbus_connection_send(conn, msg, &serial)) {
+ DBUS_LOG(service, DBUS_SERVICE_LOG_ERROR, "send failed:
Out Of Memory!\n");
+ dbus_message_unref(msg);
+ return 0;
+ }
+ if (flush)
+ dbus_connection_flush(conn);
+
+ // free the msg
+ dbus_message_unref(msg);
+
+ return serial;
+}
+
+static char *dbus_service_introspect(DBusService *service, DBusMessage
*msg, DBusObject *object)
+{
+ DBusMessage *reply;
+ DBusMessageIter args;
+ char xmlbuf[8192], *err, *buf = xmlbuf;
+
+ DBUS_LOG(service, DBUS_SERVICE_LOG_INFO, "Introspection called
on %s\n", object->path);
+
+ // create a reply from the message
+ reply = dbus_message_new_method_return(msg);
+
+ if ((err = dbus_object_introspect(object, xmlbuf,
sizeof(xmlbuf)))) {
+ DBUS_LOG(service, DBUS_SERVICE_LOG_ERROR, "introspection
error %s", err);
+ return err;
+ }
+ DBUS_LOG(service, DBUS_SERVICE_LOG_VERBOSE, "Introspect:\n%s\n",
xmlbuf);
+ // add the arguments to the reply
+ dbus_message_iter_init_append(reply, &args);
+ if (!dbus_message_iter_append_basic
+ (&args, DBUS_TYPE_STRING, &buf)) {
+ DBUS_LOG(service, DBUS_SERVICE_LOG_ERROR, "introspection
out of mem");
+ dbus_message_unref(msg);
+ return "introspection out of mem";
+ }
+
+ dbus_service_send(service, reply, 1);
+ return NULL;
+}
+
+static char *dbus_param_read_basic(DBusParam *param, int ptype,
DBusMessageIter *args)
+{
+ // TODO: should we copy also type 'o' and 'g'???
+ if (ptype == DBUS_TYPE_STRING) {
+ char *s;
+ dbus_message_iter_get_basic(args, &s);
+ strncpy(param->data, s, param->len);
+ ((char *)param->data)[param->len-1] = 0;
+ } else
+ dbus_message_iter_get_basic(args, param->data);
+ return NULL;
+}
+
+static char *dbus_param_read_container(DBusParam *param, int ptype,
DBusMessageIter *args)
+{
+ //TODO: implement
+ return "not implemented yet";
+}
+
+static char *dbus_param_write_basic(DBusParam *param, int ptype,
DBusMessageIter *args)
+{
+ if (ptype == DBUS_TYPE_STRING) {
+ if (!dbus_message_iter_append_basic(args, ptype,
¶m->data))
+ return "appendig basic failed: Out Of Memory";
+ } else if (!dbus_message_iter_append_basic(args, ptype,
param->data))
+ return "appendig basic failed: Out Of Memory";
+ return NULL;
+}
+
+static char *dbus_param_write_container(DBusParam *param, int ptype,
DBusMessageIter *args)
+{
+ //TODO: implement
+ return "not implemented yet";
+}
+
+static char *dbus_method_read_args(DBusMethod *method, DBusMessage
*msg)
+{
+ DBusMessageIter args;
+ DBusParam **pp, **e;
+ char const *sig;
+ int more = 1;
+
+ sig = dbus_message_get_signature(msg);
+ DBUS_LOG(dbus_method_service(method), DBUS_SERVICE_LOG_DEBUG,
+ "%s called with args sig: %s (%s)",
+ method->name, sig, method->insig);
+
+ if (strcmp(sig, method->insig)) {
+ DBUS_LOG(dbus_method_service(method),
DBUS_SERVICE_LOG_WARN,
+ "bad call signature: %s (!=%s)", sig,
method->insig);
+ return "Method call has incorrect argument signature";
+ }
+
+ if (!method->insig || method->insig[0] == 0)
+ return NULL; // no args to parse - silently ignore
given ones
+
+ if (!dbus_message_iter_init(msg, &args))
+ return "Missing required arguments";
+
+ for (pp = method->inparam, e = pp + DBUS_PARAM_MAX; pp < e &&
*pp;
+ pp++, more =
dbus_message_iter_next(&args)) {
+ DBusSignatureIter sigiter;
+ int ptype, mtype;
+ char *err = NULL;
+
+ if (!more)
+ return "Missing argument";
+
+ dbus_signature_iter_init(&sigiter, (*pp)->signature);
+ ptype = dbus_signature_iter_get_current_type (&sigiter);
+ mtype = dbus_message_iter_get_arg_type(&args);
+
+ if (ptype != mtype) {
+ /*
+ * If fact this is sanity -
+ * the sig check in the beginning should cover
this too.
+ */
+ DBUS_LOG(dbus_method_service(method),
DBUS_SERVICE_LOG_WARN,
+ "method %s called with bad param %s
type: %d (!=%d)",
+ method->name, (*pp)->name, mtype,
ptype);
+ return "argument type mismatch";
+ }
+ if (dbus_type_is_basic(ptype))
+ err = dbus_param_read_basic(*pp, ptype, &args);
+ else
+ err = dbus_param_read_container(*pp, ptype,
&args);
+
+ if (err) {
+ DBUS_LOG(dbus_method_service(method),
DBUS_SERVICE_LOG_WARN,
+ "method %s: reading param %s type %d
failed - err: %s",
+ method->name, (*pp)->name, ptype, err);
+ return err;
+ }
+ }
+
+ return NULL;
+}
+
+static char *dbus_method_write_args(DBusMethod *method, DBusMessage
*msg)
+{
+ DBusMessageIter args;
+ DBusParam **pp, **e;
+
+ DBUS_LOG(dbus_method_service(method), DBUS_SERVICE_LOG_DEBUG,
+ "%s start writing args sig: %s", method->name,
method->outsig);
+
+ // add the arguments to the message
+ dbus_message_iter_init_append(msg, &args);
+
+ for (pp = method->outparam, e = pp + DBUS_PARAM_MAX; pp < e &&
*pp; pp++) {
+ DBusSignatureIter sigiter;
+ int ptype;
+ char *err = NULL;
+
+ dbus_signature_iter_init(&sigiter, (*pp)->signature);
+ ptype = dbus_signature_iter_get_current_type (&sigiter);
+
+ if (dbus_type_is_basic(ptype))
+ err = dbus_param_write_basic(*pp, ptype, &args);
+ else
+ err = dbus_param_write_container(*pp, ptype,
&args);
+
+ if (err) {
+ DBUS_LOG(dbus_method_service(method),
DBUS_SERVICE_LOG_WARN,
+ "method %s: writing param %s type %d
failed - err: %s",
+ method->name, (*pp)->name, ptype, err);
+ return err;
+ }
+ }
+
+ DBUS_LOG(dbus_method_service(method), DBUS_SERVICE_LOG_DEBUG,
+ "%s wrote args sig: %s (%s)", method->name,
+ dbus_message_get_signature(msg),
method->outsig);
+ return NULL;
+}
+
+static char *dbus_service_do_method(DBusService *service, DBusMessage
*msg, DBusMethod *method)
+{
+ DBusMessage *reply;
+ char *err = NULL;
+
+ if ((err = dbus_method_read_args(method, msg)))
+ return err;
+
+ // call method handler
+ if (method->handler && (err = method->handler(method, msg,
method->user)))
+ return err;
+
+ if (method->flags & DBUS_METHOD_SIGNAL_RECIEVER)
+ return NULL;
+
+ // create a reply from the message
+ if (!(reply = dbus_message_new_method_return(msg)))
+ return "No mem for reply message";
+
+ if ((err = dbus_method_write_args(method, reply))) {
+ dbus_message_unref(reply);
+ return err;
+ }
+
+ dbus_service_send(service, reply, 1);
+ return NULL;
+}
+
+char *dbus_service_emit_signal(DBusService *service, DBusMethod
*method)
+{
+ DBusMessage *signal;
+ char *err = NULL;
+
+ if (!(method->flags & DBUS_METHOD_SIGNAL))
+ return "not an emitter method";
+
+ // create a reply from the message
+ if (!(signal =
dbus_message_new_signal(dbus_method_object(method)->path,
+ dbus_method_interface(method)->name,
method->name)))
+ return "No mem for signal message";
+
+ if ((err = dbus_method_write_args(method, signal))) {
+ dbus_message_unref(signal);
+ return err;
+ }
+
+ dbus_service_send(service, signal, 1);
+ return NULL;
+}
+
+static void dbus_interface_method_add(DBusInterface *interface,
DBusMethod *method)
+{
+ method->interface = interface;
+ method->next = interface->methods;
+ interface->methods = method;
+}
+
+static void dbus_interface_signal_add(DBusInterface *interface,
DBusMethod *signal)
+{
+ signal->interface = interface;
+ signal->next = interface->signals;
+ interface->signals = signal;
+}
+
+static void dbus_object_interface_add(DBusObject *object, DBusInterface
*interface)
+{
+ interface->object = object;
+ interface->next = object->interfaces;
+ object->interfaces = interface;
+}
+
+static void dbus_service_object_add(DBusService *service, DBusObject
*object)
+{
+ object->service = service;
+ object->next = service->objects;
+ service->objects = object;
+}
+
+static char *dbus_object_child_add(DBusObject *parent, DBusObject
*child)
+{
+ char path[512];
+ int n;
+
+ if (child->parent)
+ return "Child already has parent";
+ n = strlen(parent->path);
+ if (n + strlen(child->relpath) + 2 >= sizeof path)
+ return "Absolute path is too long";
+ child->parent = parent;
+ if (child->path)
+ free(child->path);
+ strncpy(path, parent->path, sizeof(path));
+ if (path[n-1] != '/')
+ path[n++] = '/';
+ strncpy(path + n, child->relpath, sizeof path - n);
+ child->path = strdup(path);
+ child->nextchild = parent->childs;
+ parent->childs = child;
+ return NULL;
+}
+
+DBusService *dbus_service_new(char *name)
+{
+ DBusService *service;
+
+ if (!( service = calloc(1, sizeof(*service))))
+ return NULL;
+
+ service->name = strdup(name);
+ service->rootobject = dbus_object_new(service, NULL, "/");
+ service->rootobject->path = strdup("/");
+ return service;
+}
+
+DBusObject *dbus_object_new(DBusService *service, DBusObject *parent,
char *relpath)
+{
+ DBusObject *object;
+
+ if (!( object = calloc(1, sizeof(*object))))
+ return NULL;
+ while (relpath && *relpath == '/')
+ relpath++;
+ object->relpath = strdup(relpath);
+ object->service = service;
+ if (service)
+ dbus_service_object_add(service, object);
+ if (parent)
+ dbus_object_child_add(parent, object);
+ else if (service && service->rootobject)
+ dbus_object_child_add(service->rootobject, object);
+ DBUS_LOG(service, DBUS_SERVICE_LOG_DEBUG, "new object %s (%s)",
object->path, object->relpath);
+ return object;
+}
+
+DBusInterface *dbus_interface_new(DBusObject *object, char *name)
+{
+ DBusInterface *interface;
+
+ if (!( interface = calloc(1, sizeof(*interface))))
+ return NULL;
+ interface->name = strdup(name);
+ interface->object = object;
+
+ if (object)
+ dbus_object_interface_add(object, interface);
+
+ return interface;
+}
+
+static DBusMethod *_dbus_method_new(char *name, dbus_method_handler
*handler, void *user)
+{
+ DBusMethod *method;
+
+ if (!( method = calloc(1, sizeof(*method))))
+ return NULL;
+ if (name)
+ method->name = strdup(name);
+ method->handler = handler;
+ method->user = user;
+ return method;
+}
+
+DBusMethod *dbus_method_new(DBusInterface *interface, char *name,
dbus_method_handler *handler, void *user)
+{
+ DBusMethod *method = _dbus_method_new(name, handler, user);
+
+ //assert(name && interface);
+
+ if (!method)
+ return NULL;
+ dbus_interface_method_add(interface, method);
+ return method;
+}
+
+DBusMethod *dbus_signal_handler_new(dbus_method_handler *handler, void
*user)
+{
+ DBusMethod *method = _dbus_method_new(NULL, handler, user);
+
+ if (!method)
+ return NULL;
+ method->flags |= DBUS_METHOD_SIGNAL_RECIEVER;
+ return method;
+}
+
+DBusMethod *dbus_signal_emitter_new(DBusInterface *interface, char
*name)
+{
+ DBusMethod *method = _dbus_method_new(name, NULL, NULL);
+
+ if (!method)
+ return NULL;
+ method->flags |= DBUS_METHOD_SIGNAL;
+ dbus_interface_signal_add(interface, method);
+ return method;
+}
+
+DBusSignal *dbus_signal_catcher_new(char *name, char *interface, char
*path, DBusMethod *handler)
+{
+ DBusSignal *signal;
+ char match[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
+ char pathmatch[256];
+
+ //_dbus_assert(name && interface && handler);
+
+ if (!(signal = calloc(1, sizeof (*signal))))
+ return NULL;
+
+ signal->interface = strdup(interface);
+ if (path && path[0] != 0) // path is allowed to be null
+ signal->path = strdup(path);
+ signal->name = strdup(name);
+ handler->name = strdup(name);
+ handler->signal = signal;
+ signal->method = handler;
+
+ if (signal->path) {
+ snprintf(pathmatch, sizeof pathmatch - 1, ",path='%s'",
signal->path);
+ pathmatch[sizeof pathmatch - 1] = 0;
+ } else
+ pathmatch[0] = 0;
+
+ snprintf(match, sizeof(match) - 1,
"type='signal',interface='%s',member=%s%s",
+ interface, name, pathmatch);
+ match[sizeof match - 1] = 0;
+ signal->match = strdup(match);
+
+ return signal;
+}
+
+char *dbus_service_signal_register(DBusService *service, DBusSignal
*signal)
+{
+ DBusConnection *conn;
+ DBusError err;
+
+ if (!(conn = service->conn))
+ return "Service not connected";
+
+ DBUS_LOG(service, DBUS_SERVICE_LOG_DEBUG, "registering signal
[%s:](%s)%s",
+ signal->interface, signal->path, signal->name);
+ dbus_error_init(&err);
+ dbus_bus_add_match(conn, signal->match, &err);
+ dbus_connection_flush(conn);
+ if (dbus_error_is_set(&err))
+ return dbus_service_error(service, &err);
+
+ return NULL;
+}
+
+char *dbus_service_signal_listen(DBusService *service, DBusSignal
*signal)
+{
+ if (signal->service)
+ return "signal is already used by a service";
+ signal->next = service->signals;
+ service->signals = signal;
+ signal->service = service;
+
+ if (service->conn) // we are online
+ return dbus_service_signal_register(service, signal);
+ return NULL;
+}
+
+/**
+ * Create a connection and register a DBus service to the bus daemon.
+ */
+char *dbus_service_connect(DBusService * service, int bus_session)
+{
+ DBusConnection *conn;
+ DBusSignal *signal;
+ DBusError err;
+ char *errstr;
+ int ret;
+
+ // initialise the error
+ dbus_error_init(&err);
+
+ // connect to the bus and check for errors
+ conn = dbus_bus_get(bus_session ? DBUS_BUS_SESSION :
DBUS_BUS_SYSTEM, &err);
+ if (dbus_error_is_set(&err))
+ return dbus_service_error(service, &err);
+ if (NULL == conn)
+ return dbus_service_error_str(service, "Connection
Null");
+
+ // request our name on the bus and check for errors
+ ret = dbus_bus_request_name(conn, service->name,
+ DBUS_NAME_FLAG_REPLACE_EXISTING,
&err);
+ if (dbus_error_is_set(&err))
+ return dbus_service_error(service, &err);
+
+ if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "Not Primary Owner (%d)\n",
ret);
+ return dbus_service_error_str(service, buf);
+ }
+
+ service->conn = conn;
+ service->id = strdup(dbus_bus_get_unique_name(conn));
+
+ for (signal = service->signals; signal; signal = signal->next)
+ if ((errstr = dbus_service_signal_register(service,
signal)))
+ DBUS_LOG(service, DBUS_SERVICE_LOG_ERROR,
"signal receive registration failed for signal [%s:]%s - %s",
+ signal->interface, signal->name,
errstr);
+
+ return NULL;
+}
+
+DBusMethod *dbus_interface_find_method(DBusInterface *interface, const
char *name)
+{
+ DBusMethod *method;
+
+ for (method = interface->methods; method; method = method->next)
+ if (!strcmp(method->name, name))
+ return method;
+ return NULL;
+}
+
+DBusInterface *dbus_object_find_interface(DBusObject *object, const
char *name)
+{
+ DBusInterface *interface;
+
+ for (interface = object->interfaces; interface; interface =
interface->next)
+ if (!strcmp(interface->name, name))
+ return interface;
+ return NULL;
+}
+
+DBusMethod *dbus_object_find_method(DBusObject *object, const char
*name)
+{
+ DBusInterface *interface;
+ DBusMethod *method;
+
+ for (interface = object->interfaces; interface; interface =
interface->next)
+ if ((method = dbus_interface_find_method(interface,
name)))
+ return method;
+ return NULL;
+}
+
+
+DBusObject *dbus_service_find_object(DBusService *service, const char
*path)
+{
+ DBusObject *object;
+
+ DBUS_LOG(service, DBUS_SERVICE_LOG_DEBUG, "find object %s",
path);
+
+ for (object = service->objects; object; object = object->next)
+ if (!strcmp(object->path, path))
+ return object;
+ return NULL;
+}
+
+DBusSignal *dbus_service_find_signal(DBusService *service, const char
*path, const char *interface, const char *member)
+{
+ DBusSignal *signal;
+
+ for (signal = service->signals; signal; signal = signal->next) {
+ if (signal->path && strcmp(signal->path, path))
+ continue;
+ if (strcmp(signal->interface, interface))
+ continue;
+ if (strcmp(signal->name, member))
+ continue;
+ return signal;
+ }
+ return NULL;
+}
+
+char *dbus_service_send_error(DBusService *service, DBusMessage *msg,
char *err)
+{
+ DBusConnection *conn = service->conn;
+ dbus_uint32_t serial = 0;
+ DBusMessage *reply;
+
+ DBUS_LOG(service, DBUS_SERVICE_LOG_WARN, "sending error %s\n",
err);
+
+ // create a reply from the message
+ reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, err);
+
+ // send the reply && flush the connection
+ if (!dbus_connection_send(conn, reply, &serial)) {
+ dbus_message_unref(reply);
+ return "out of mem";
+ }
+ dbus_connection_flush(conn);
+
+ // free the reply
+ dbus_message_unref(reply);
+ return err;
+}
+
+char *dbus_service_handle_once(DBusService * service)
+{
+ DBusConnection *conn;
+ DBusMessage *msg;
+ const char *objpath, *interface_name, *member;
+ DBusObject *object;
+ DBusInterface *interface;
+ DBusMethod *method = NULL;
+ char *err = NULL;
+ int msgtype;
+
+ if (!(conn = service->conn))
+ return "Service not connected";
+
+ DBUS_LOG(service, DBUS_SERVICE_LOG_INFO, "dispatch: --");
+
+ dbus_connection_read_write(conn, 0);
+
+ // non blocking read of the next available message
+ if (!(msg = dbus_connection_pop_message(conn)))
+ return NULL;
+
+ msgtype = dbus_message_get_type(msg);
+ objpath = dbus_message_get_path(msg);
+ interface_name = dbus_message_get_interface(msg);
+ member = dbus_message_get_member(msg);
+
+ DBUS_LOG(service, DBUS_SERVICE_LOG_DEBUG, "%s: %s [%s].%s(%s)",
+ dbus_message_type_to_string(msgtype),
+ objpath,
+ interface_name,
+ member,
+ dbus_message_get_signature(msg));
+
+ // We can handle only method calls and signals
+ if (msgtype != DBUS_MESSAGE_TYPE_METHOD_CALL &&
+ msgtype != DBUS_MESSAGE_TYPE_SIGNAL) {
+ DBUS_LOG(service, DBUS_SERVICE_LOG_INFO, "drop message
(type %s)",
+ dbus_message_type_to_string(msgtype));
+ return NULL;
+ }
+
+ if (msgtype == DBUS_MESSAGE_TYPE_SIGNAL) {
+ DBusSignal *signal;
+ DBUS_LOG(service, DBUS_SERVICE_LOG_INFO, "received
signal %s", member);
+ if (!(signal = dbus_service_find_signal(service,
objpath,
+ interface_name,
member)))
+ return NULL;
+ DBUS_LOG(service, DBUS_SERVICE_LOG_INFO, "found hander
for signal %s", signal->name);
+ if (signal->method &&
+ (err = dbus_service_do_method(service, msg,
signal->method)))
+ DBUS_LOG(service, DBUS_SERVICE_LOG_WARN,
+ "signal '%s' handling failed: %s",
signal->name, err);
+ return NULL;
+ }
+
+ object = dbus_service_find_object(service, objpath);
+ if (!object && msgtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
+ return dbus_service_send_error(service, msg, "unknown
object (path)");
+
+ // Built-in methods checks:
+
+ // check this is a method call for the right interface & method
+ if (dbus_message_is_method_call(msg,
+ "org.freedesktop.DBus.Introspectable",
"Introspect")) {
+ if ((err = dbus_service_introspect(service, msg,
object)))
+ return dbus_service_send_error(service, msg,
err);
+ goto out;
+ }
+
+ if (interface_name) {
+ interface = dbus_object_find_interface(object,
interface_name);
+ if (!interface)
+ return dbus_service_send_error(service, msg,
+ "unknown
interface for that object");
+ method = dbus_interface_find_method(interface, member);
+ } else
+ method = dbus_object_find_method(object, member);
+
+ if (!method)
+ return dbus_service_send_error(service, msg, "unknown
method/signal");
+
+ DBUS_LOG(service, DBUS_SERVICE_LOG_DEBUG, "found member %s
(%x)", member, method);
+
+ // TODO: call member handler
+
+ if (msgtype == DBUS_MESSAGE_TYPE_METHOD_CALL &&
+ (err = dbus_service_do_method(service, msg, method)))
+ return dbus_service_send_error(service, msg, err);
+
+out:
+ // free the message
+ dbus_message_unref(msg);
+ return NULL;
+}
+
+char *dbus_service_serve(DBusService *service)
+{
+ DBusConnection *conn;
+ char *err;
+
+ if (!(conn = service->conn))
+ return "Service not connected";
+
+ // Start serving
+ while(dbus_connection_read_write_dispatch(conn, -1))
+ if ((err = dbus_service_handle_once(service)))
+ return err;
+
+ return "Connection broken";
+}
diff -Naur /tmp/dbus/dbus-service.h dbus/dbus-service.h
--- /tmp/dbus/dbus-service.h 1970-01-01 02:00:00.000000000 +0200
+++ dbus/dbus-service.h 2007-08-09 14:52:25.000000000 +0300
@@ -0,0 +1,253 @@
+/* DBus Service library.
+
+ Copyright (C) 2007 Qumranet, Inc.
+
+ This Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ Theis Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _DBUS_SERVER_H
+#define _DBUS_SERVER_H
+
+/* TODO:
+ * +implemet service new
+ * +implement objects (paths)
+ * +implement objects service interfaces
+ * +implement Introspection for objects.
+ * +implement main dispatch loop (for multiple services???, service per
thread?)
+ * +implement type checking for method (signal)
+ * +implement library (make)
+ * Check bool var - dbus-viewer bug?
+ * implement argument marshaling/de-marshling:
+ * +basic arguments
+ * containers
+ * arrays
+ * struct
+ * var
+ * dict
+ * +implement signals:
+ * +listen
+ * +emit
+ * implement object propertires
+ * implement default handler
+ * implement change notifications on prop
+ * implement remove functions for prop, interface, objects, methods,
signals
+*/
+
+#include <dbus/dbus.h>
+#include <unistd.h> // DBUS_PANIC.exit
+
+enum {
+ DBUS_SERVICE_LOG_NONE,
+ DBUS_SERVICE_LOG_FATAL,
+ DBUS_SERVICE_LOG_ERROR,
+ DBUS_SERVICE_LOG_WARN,
+ DBUS_SERVICE_LOG_INFO,
+ DBUS_SERVICE_LOG_DEBUG,
+ DBUS_SERVICE_LOG_VERBOSE,
+
+ DBUS_SERVICE_LOG_LAST_
+};
+extern int dbus_log_level;
+#define DBUS_LOG_ACTIVE(lvl) ((lvl) <= dbus_log_level)
+#define DBUS_LOG(srv, lvl, msg, args...) \
+ do { \
+ if (!DBUS_LOG_ACTIVE(lvl))\
+ break;\
+ dbus_log((srv), (lvl), (msg), ## args);\
+ } while (0)
+#define DBUS_PANIC(srv, msg, args...) \
+ do {\
+ dbus_log((srv), DBUS_SERVICE_LOG_FATAL, (msg), ##
args);\
+ exit(-1);\
+ } while (0)
+
+typedef struct DBusMethod DBusMethod;
+typedef struct DBusInterface DBusInterface;
+typedef struct DBusService DBusService;
+typedef struct DBusObject DBusObject;
+typedef struct DBusParam DBusParam;
+typedef struct DBusSignal DBusSignal;
+typedef char *(dbus_method_handler)(DBusMethod *method, DBusMessage
*msg, void *user);
+
+struct DBusParam {
+ char *name; // argument name (used for by
name access)
+ char *signature; // single complete signature
+ char in; // flag:in param?
+ char userdata; // flag: user allocated variable
space?
+ unsigned short len; // variable allocation size
+ void *handler; // unused
+ void *data; // user data pointer
+};
+
+#define DBUS_PARAM_MAX 5
+#define DBUS_SIG_STR_MAX 32
+
+enum {
+ DBUS_METHOD_NORMAL = 0,
+ DBUS_METHOD_SIGNAL = 1 << 0,
+ DBUS_METHOD_SIGNAL_RECIEVER = 1 << 1,
+};
+
+struct DBusMethod {
+ char *name; // method member name
+ DBusParam *inparam[DBUS_PARAM_MAX]; // in arguments
+ DBusParam *outparam[DBUS_PARAM_MAX]; // return paramenters
+
+ char insig[DBUS_SIG_STR_MAX]; // method arguments signature
+ char outsig[DBUS_SIG_STR_MAX]; // method return signature
+ unsigned flags; // type flags
+ dbus_method_handler *handler; // user handler function
+ DBusInterface *interface; // back pointer
+ DBusSignal *signal; // back pointer for signal
methods
+ void *user; // user pointer
+ struct DBusMethod *next; // used by interface's methods
list
+};
+
+struct DBusSignal {
+ char *name; // signal member name
+ char *interface; // signal interface
+ char *path; // object path - may be NULL
+
+ DBusMethod *method; // signal handler method
+ char *match; // dbus match rule
+ DBusService *service; // back pointer
+ DBusSignal *next; // used by service signals
+};
+
+struct DBusInterface {
+ char *name;
+ DBusMethod *methods; // interface methods
+ DBusMethod *signals; // emitter signal list
+
+ DBusObject *object; // parent object
+ DBusInterface *next; // used by parent interfaces
list
+};
+
+struct DBusObject {
+ char *relpath; // relative path (to parent)
+ char *path; // absolute path (from service)
+ DBusInterface *interfaces; // object interfaces
+ DBusObject *childs; // child objects list
+
+ DBusObject *parent; // patet object, NULL for root
+ DBusService *service; // back pointer
+ DBusObject *next; // used by service objects list
+ DBusObject *nextchild; // user by parent childs list
+};
+
+struct DBusService {
+ char *name;
+ DBusObject *objects; // all object list
+ DBusSignal *signals; // receive signal list
+
+ char *id; // dbus id
+ char *err; // last service error
+ DBusObject *rootobject; // default root "/" object
+ DBusConnection *conn; // connected if non NULL
+};
+
+void dbus_log(DBusService *service, int level, char *msg, ...);
+
+DBusService *dbus_service_new(char *name);
+DBusObject *dbus_object_new(DBusService *service, DBusObject *parent,
char *relpath);
+DBusInterface *dbus_interface_new(DBusObject *object, char *name);
+DBusMethod *dbus_method_new(DBusInterface *interface, char *name,
dbus_method_handler *handler, void *user);
+DBusParam *dbus_param_new(char *name, char *signature, void *data, int
len);
+char *dbus_method_param_add(DBusMethod *method, DBusParam *param, int
in);
+DBusMethod *dbus_signal_handler_new(dbus_method_handler *handler, void
*user);
+DBusMethod *dbus_signal_emitter_new(DBusInterface *interface, char
*name);
+DBusSignal *dbus_signal_catcher_new(char *name, char *interface, char
*path, DBusMethod *handler);
+char *dbus_service_signal_listen(DBusService *service, DBusSignal
*signal);
+char *dbus_service_emit_signal(DBusService *service, DBusMethod
*emitter);
+
+char *dbus_service_connect(DBusService * service, int bus_session);
+char *dbus_service_handle_once(DBusService * service);
+char *dbus_service_serve(DBusService *service);
+
+char *dbus_method_get_param(DBusMethod *method, char *name, int in,
void *value);
+char *dbus_method_set_param(DBusMethod *method, char *name, int in,
void *value);
+
+static inline char *dbus_method_arg(DBusMethod *method, char *name,
void *value)
+{
+ return dbus_method_get_param(method, name, 1, value);
+}
+
+static inline char *dbus_method_get_return(DBusMethod *method, char
*name, void *value)
+{
+ return dbus_method_get_param(method, name, 0, value);
+}
+
+static inline char *dbus_method_set_arg(DBusMethod *method, char *name,
void *value)
+{
+ return dbus_method_set_param(method, name, 1, value);
+}
+
+static inline char *dbus_method_return(DBusMethod *method, char *name,
void *value)
+{
+ return dbus_method_set_param(method, name, 0, value);
+}
+
+static inline char *dbus_signal_set_arg(DBusMethod *method, char *name,
void *value)
+{
+ return dbus_method_set_param(method, name, 0, value);
+}
+
+static inline char *dbus_signal_get_arg(DBusMethod *method, char *name,
void *value)
+{
+ return dbus_method_get_param(method, name, 0, value);
+}
+
+static inline DBusService *dbus_method_service(DBusMethod *method)
+{
+ if (method->flags & DBUS_METHOD_SIGNAL_RECIEVER)
+ return method->signal->service;
+ return method->interface->object->service;
+}
+
+static inline DBusObject *dbus_method_object(DBusMethod *method)
+{
+ if (method->flags & DBUS_METHOD_SIGNAL_RECIEVER)
+ return NULL;
+ return method->interface->object;
+}
+
+static inline DBusInterface *dbus_method_interface(DBusMethod *method)
+{
+ if (method->flags & DBUS_METHOD_SIGNAL_RECIEVER)
+ return NULL;
+ return method->interface;
+}
+
+static inline void *dbus_method_get_userdata(DBusMethod *method)
+{
+ return method->user;
+}
+
+static inline char *dbus_method_arg_add(DBusMethod *method, DBusParam
*param)
+{
+ return dbus_method_param_add(method, param, 1);
+}
+
+static inline char *dbus_method_return_add(DBusMethod *method,
DBusParam *param)
+{
+ return dbus_method_param_add(method, param, 0);
+}
+
+static inline char *dbus_signal_arg_add(DBusMethod *signal, DBusParam
*param)
+{
+ return dbus_method_param_add(signal, param, 0);
+}
+
+#endif
diff -Naur /tmp/dbus/dbus-service-test.c dbus/dbus-service-test.c
--- /tmp/dbus/dbus-service-test.c 1970-01-01 02:00:00.000000000
+0200
+++ dbus/dbus-service-test.c 2007-08-09 12:13:08.000000000 +0300
@@ -0,0 +1,278 @@
+/*
+ * Example/Unit-test D-Bus service code.
+ * Written by Shahar Frank <shaharf at qumranet.com>
+ *
+ * This code has been released into the Public Domain.
+ * You may do whatever you like with it.
+ */
+#include <dbus-service.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *test_method1(DBusMethod *method, DBusMessage *msg, void *user)
+{
+ char *s;
+ unsigned u, r;
+
+ DBUS_LOG(dbus_method_service(method), DBUS_SERVICE_LOG_VERBOSE,
+ "%s method called", method->name);
+
+ dbus_method_arg(method, "name", &s);
+ dbus_method_arg(method, "number", &u);
+ DBUS_LOG(dbus_method_service(method), DBUS_SERVICE_LOG_VERBOSE,
+ "args (%s %u)", s, u);
+
+ r = u * 2;
+ dbus_method_return(method, "outcome", &r);
+ DBUS_LOG(dbus_method_service(method), DBUS_SERVICE_LOG_VERBOSE,
"return %u", r);
+ return NULL;
+}
+
+struct {
+ char name[64];
+ unsigned number;
+ unsigned outcome;
+} m2;
+
+char *test_method2(DBusMethod *method, DBusMessage *msg, void *user)
+{
+ unsigned r;
+ DBUS_LOG(dbus_method_service(method), DBUS_SERVICE_LOG_VERBOSE,
+ "%s method called", method->name);
+
+ if (user != &m2)
+ DBUS_PANIC(dbus_method_service(method),
+ "method handler got bad user data pointer");
+
+ DBUS_LOG(dbus_method_service(method), DBUS_SERVICE_LOG_VERBOSE,
+ "args (%s %u)", m2.name, m2.number);
+
+ //dbus_method_set_param_uint32(method, 0, "outcome", r);
+ m2.outcome = m2.number * 2;
+ dbus_method_get_return(method, "outcome", &r);
+
+ DBUS_LOG(dbus_method_service(method), DBUS_SERVICE_LOG_VERBOSE,
"return %u", r);
+ return NULL;
+}
+
+struct {
+ int flag;
+ dbus_uint32_t base;
+ dbus_uint32_t div;
+ double outcome;
+ char msg[256];
+} m3;
+
+char *test_method3(DBusMethod *method, DBusMessage *msg, void *user)
+{
+ DBUS_LOG(dbus_method_service(method), DBUS_SERVICE_LOG_VERBOSE,
+ "%s method called", method->name);
+
+ if (user != &m3)
+ DBUS_PANIC(dbus_method_service(method),
+ "method handler got bad user data pointer");
+
+ DBUS_LOG(dbus_method_service(method), DBUS_SERVICE_LOG_VERBOSE,
+ "args (%s %d %hu)", m3.flag ? "True" : "False",
+ (int)m3.base, m3.div);
+
+ //dbus_method_set_param_uint32(method, 0, "outcome", r);
+ m3.outcome = (double)m3.base / m3.div;
+ snprintf(m3.msg, sizeof(m3.msg)-1, "args (%s %d %hu)",
+ m3.flag ? "True" : "False", (int)m3.base, m3.div);
+
+ DBUS_LOG(dbus_method_service(method), DBUS_SERVICE_LOG_VERBOSE,
+ "return %f %s", m3.outcome, m3.msg);
+ return NULL;
+}
+
+char *signal_handler(DBusMethod *method, DBusMessage *msg, void *user)
+{
+ char *s;
+
+ dbus_method_arg(method, "name", &s);
+ DBUS_LOG(dbus_method_service(method), DBUS_SERVICE_LOG_VERBOSE,
"signal %s: %s",
+ method->name, s);
+
+ return NULL;
+}
+
+char *emit_signal(DBusMethod *method, DBusMessage *msg, void *user)
+{
+ DBusMethod *emitter = user;
+ char *s, *err;
+
+ dbus_method_arg(method, "name", &s);
+ DBUS_LOG(dbus_method_service(method), DBUS_SERVICE_LOG_VERBOSE,
"emit signal %s: %s",
+ emitter->name, s);
+
+ dbus_signal_set_arg(emitter, "name", s);
+
+ if ((err = dbus_service_emit_signal(dbus_method_service(method),
emitter)))
+ DBUS_LOG(dbus_method_service(method),
DBUS_SERVICE_LOG_WARN,
+ "emit signal %s failed: %s", emitter->name,
err);
+
+ return NULL;
+}
+
+int main(int argc, char **argv)
+{
+ DBusService *service;
+ DBusObject *object;
+ DBusInterface *interface;
+ DBusMethod *method, *emitter;
+ char *err;
+
+ dbus_log_level = DBUS_SERVICE_LOG_VERBOSE;
+
+
+ // Initialize the service structure
+ if (!(service = dbus_service_new("com.exmaple.test")))
+ DBUS_PANIC(service, "can't setup a service");
+
+ // Initialize an object - this is optional, interafaces can use
rootobject
+ if (!(object = dbus_object_new(service, NULL, "/TestObject")))
+ DBUS_PANIC(service, "can't alloc an object");
+
+ if (!(interface = dbus_interface_new(object,
"com.example.text.TestInterface")))
+ DBUS_PANIC(service, "can't create interface");
+
+ // FirstMethod declaration and params
+ if (!(method = dbus_method_new(interface, "FirstMethod",
test_method1, NULL)))
+ DBUS_PANIC(service, "can't create method");
+
+ if ((err = dbus_method_arg_add(method, dbus_param_new("name",
"s", NULL, 64))))
+ DBUS_PANIC(service, "can't add method param");
+ if ((err = dbus_method_arg_add(method,
+ dbus_param_new("number", "u", NULL, 0))))
+ DBUS_PANIC(service, "can't add method param");
+ if ((err = dbus_method_return_add(method,
+ dbus_param_new("outcome", "u", NULL, 0))))
+ DBUS_PANIC(service, "can't add method param");
+
+ // TestMethod declaration and params
+ if (!(method = dbus_method_new(interface, "TestMethod",
test_method2, &m2)))
+ DBUS_PANIC(service, "can't create method");
+
+ if ((err = dbus_method_arg_add(method,
+ dbus_param_new("name", "s", m2.name,
+ sizeof(m2.name)))))
+ DBUS_PANIC(service, "can't add method param");
+ if ((err = dbus_method_arg_add(method,
+ dbus_param_new("number", "u", &m2.number, 0))))
+ DBUS_PANIC(service, "can't add method param");
+ if ((err = dbus_method_return_add(method,
+ dbus_param_new("outcome", "u", &m2.outcome,
0))))
+ DBUS_PANIC(service, "can't add method param");
+
+ // TestSignal declaration and params
+ if (!(emitter = dbus_signal_emitter_new(interface,
"TestSignal")))
+ DBUS_PANIC(service, "can't create method");
+
+ if ((err = dbus_signal_arg_add(emitter,
+ dbus_param_new("name", "s", NULL, 32))))
+ DBUS_PANIC(service, "can't add signal param");
+
+ // Another interface
+ if (!(interface = dbus_interface_new(object,
"com.example.text.AnotherInterface")))
+ DBUS_PANIC(service, "can't create interface");
+
+ // GoodMethod declaration and params
+ if (!(method = dbus_method_new(interface, "GoodMethod",
test_method1, NULL)))
+ DBUS_PANIC(service, "can't create method");
+
+ if ((err = dbus_method_arg_add(method, dbus_param_new("name",
"s", NULL, 64))))
+ DBUS_PANIC(service, "can't add method param");
+ if ((err = dbus_method_arg_add(method,
+ dbus_param_new("number", "u", NULL, 0))))
+ DBUS_PANIC(service, "can't add method param");
+ if ((err = dbus_method_return_add(method,
+ dbus_param_new("outcome", "u", NULL, 0))))
+ DBUS_PANIC(service, "can't add method param");
+
+ // EmitTestSignal declaration and params
+ if (!(method = dbus_method_new(interface, "EmitTestSignal",
emit_signal, emitter)))
+ DBUS_PANIC(service, "can't create method");
+
+ if ((err = dbus_method_arg_add(method, dbus_param_new("name",
"s", NULL, 64))))
+ DBUS_PANIC(service, "can't add method param");
+
+ if (!(object = dbus_object_new(service, object,
"/ChildObject")))
+ DBUS_PANIC(service, "can't alloc an object");
+
+ if (!(interface = dbus_interface_new(object,
"com.example.text.SubInterface")))
+ DBUS_PANIC(service, "can't create interface");
+
+ // YetAnotherMethod declaration and params
+ if (!(method = dbus_method_new(interface, "YetAnotherMethod",
test_method1, NULL)))
+ DBUS_PANIC(service, "can't create method");
+
+ if ((err = dbus_method_arg_add(method, dbus_param_new("name",
"s", NULL, 64))))
+ DBUS_PANIC(service, "can't add method param");
+ if ((err = dbus_method_arg_add(method,
+ dbus_param_new("number", "u", NULL, 0))))
+ DBUS_PANIC(service, "can't add method param");
+ if ((err = dbus_method_return_add(method,
+ dbus_param_new("outcome", "u", NULL, 0))))
+ DBUS_PANIC(service, "can't add method param");
+
+ // DifferentMethod declaration and params
+ if (!(method = dbus_method_new(interface, "DifferentMethod",
test_method3, &m3)))
+ DBUS_PANIC(service, "can't create method");
+
+ if ((err = dbus_method_arg_add(method,
+ dbus_param_new("flag", "b", &m3.flag, 0))))
+ DBUS_PANIC(service, "can't add method param");
+ if ((err = dbus_method_arg_add(method,
+ dbus_param_new("base", "u", &m3.base, 0))))
+ DBUS_PANIC(service, "can't add method param");
+ if ((err = dbus_method_arg_add(method,
+ dbus_param_new("div", "u", &m3.div, 0))))
+ DBUS_PANIC(service, "can't add method param");
+ if ((err = dbus_method_return_add(method,
+ dbus_param_new("outcome", "d", &m3.outcome,
0))))
+ DBUS_PANIC(service, "can't add method param");
+ if ((err = dbus_method_return_add(method,
+ dbus_param_new("msg", "s", &m3.msg,
sizeof(m3.msg)))))
+ DBUS_PANIC(service, "can't add method param");
+
+ /*
+ * Register the bus to receive two signals: the bus NameAcquired
and our own
+ * TestSignal. Note the the same signal(method) handler is used
for both
+ * signals. This is easy because they have identical argument
signature.
+ */
+
+ // create signal handler (method)
+ if (!(method = dbus_signal_handler_new(signal_handler, NULL)))
+ DBUS_PANIC(service, "can't create signal handler");
+
+ // add a single string argument to the handler
+ if ((err = dbus_method_arg_add(method, dbus_param_new("name",
"s", NULL, 128))))
+ DBUS_PANIC(service, "can't add method param");
+
+ // register to receive the signal defined by the signal_catcher
+ if ((err = dbus_service_signal_listen(service,
+ dbus_signal_catcher_new("NameAcquired",
"org.freedesktop.DBus",
+ "/org/freedesktop/DBus", method))))
+ DBUS_PANIC(service, "can't listen to signal");
+
+ // use the same handler to handle a our own emitter signal
+ if ((err = dbus_service_signal_listen(service,
+ dbus_signal_catcher_new("TestSignal",
"com.example.text.TestInterface",
+ "/TestObject", method))))
+ DBUS_PANIC(service, "can't listen to signal");
+
+ // Connect to bus daemon
+ if ((err = dbus_service_connect(service, 1)))
+ DBUS_PANIC(service, "connect failed: %s", err);
+
+ DBUS_LOG(service, DBUS_SERVICE_LOG_INFO, "service is
connected");
+
+ // start the main loop
+ dbus_service_serve(service);
+
+ return 0;
+}
diff -Naur /tmp/dbus/Makefile dbus/Makefile
--- /tmp/dbus/Makefile 1970-01-01 02:00:00.000000000 +0200
+++ dbus/Makefile 2007-08-09 11:56:37.000000000 +0300
@@ -0,0 +1,34 @@
+PKGCONF ?= pkg-config
+
+CFLAGS += -Wall
+CFLAGS += $(shell $(PKGCONF) --cflags dbus-1)
+CFLAGS += -I. -g
+
+LDFLAGS += $(shell $(PKGCONF) --libs dbus-1)
+
+LIB_DYNAMIC := dbus-service.so
+LIB_STATIC := dbus-service.a
+LIB_OBJS := dbus-service.o
+LIB_HDRS := dbus-service.h
+
+TESTSERVER := dbus-service-test
+TESTSERV_OBJS := dbus-service-test.o
+
+.PHONY: client server all clean
+all: $(LIB_STATIC) $(TESTSERVER)
+
+$(LIB_DYNAMIC): $(LIB_HDRS)
+
+$(LIB_STATIC): $(LIB_HDRS)
+
+$(LIB_STATIC): $(LIB_OBJS)
+ $(AR) $(ARFLAGS) $@ $?
+ ranlib $@
+
+$(TESTSERVER): $(LIB_HDRS) $(LIB_STATIC)
+
+$(TESTSERVER): $(TESTSERV_OBJS)
+ $(CC) $(LDFLAGS) $(TESTSERV_OBJS) ./$(LIB_STATIC) -o $@
+
+clean:
+ rm -f *.o *~ $(LIB_DYNAMIC) $(LIB_STATIC) $(TESTSERVER)
More information about the dbus
mailing list