Ted's Blog

Happy coding

dbus基础

这是以前学习dbus时候写的使用dbus API来接收消息的一个比较全的例子,目的是熟悉dbus的c api的功能。今天又温习了一下,贴出来永久保留:), 有时间把原理写下,kde4都用它了,应该很重要。
/**
* the demo is to demonstrate the whole process of setting up
* a dbus message loop manually. for simplicity, we connect to
* session bus instead of coding a server from the grand up.
* the best of dbus is that we can register our own callbacks in
* all most every step of message process. by using notify functions
* the main loop of application awares of the changes, including coming
* of raw message data from the transport, new outgoing message, incoming
* message queue is empty and so on.
*/
#include dbus/dbus.h>
#include stdbool.h>
#include unistd.h>
#include stdio.h>
#include stdlib.h>
#include stdarg.h>
#include string.h>
#include sys/select.h>
/**
* for every connection, there is a transport mechanism ( here
* maybe is unix domain socket ). data come and go from the connection,
* a watch is used to monitor incoming or outgoing data flow or exception.
* a watch bind with a fd (i know here fd is owned by the socket),
* when fd is ready to read data or write from transport, a notify
* event occurs.
*/
struct watchlist_t {
    DBusWatch *watch;
    struct watchlist_t *next;
};
static struct watchlist_t *watchlist = NULL;
/**
* when you send a message typed method_call with a reply, you
* may need to set up a timeout handler. when a reply available,
* a timeout event ocurrs.
*/
static struct timeoutlist_t {
    DBusTimeout *timeout;
    struct timeoutlist_t *next;
} *timeoutlist = NULL;
/**
* you can register any path you like, just follow the dbus specification,
* such as "/org", "/org/redflag", "/com" etc. i think dbus internally
* splits all path into components ("org", "redflag", "com") and arranges
* them into a tree, every node bind a handler. if one node has no
* handler registered, it processed by dbus( use
* DBUS_HANDLER_RESULT_NOT_YET_HANDLED to notify dbus).
*/
char *objectPaths[] = {
    "/org/freedesktop",
    "/com",
    "/com/redflag",
    "/org/freedesktop/DBus",
    "/org/freedesktop/csy",
    "/com/redflag/csy"
};
/** object handlers and object path handlers */
DBusHandlerResult object_dbus_handler(DBusConnection*, DBusMessage*, void*);
DBusHandlerResult object_csy_handler(DBusConnection*, DBusMessage*, void*);
DBusHandlerResult subsection_com_redflag_handler(DBusConnection*,
        DBusMessage*, void*);
DBusHandlerResult subsection_com_handler(DBusConnection*,
        DBusMessage*, void*);
DBusHandlerResult subsection_org_freedesktop_handler(DBusConnection*,
        DBusMessage*, void*);
void object_unregister_handler(DBusConnection*, void*);
DBusObjectPathVTable objectPathVTable[] = {
    {
        .unregister_function = NULL,
        .message_function = subsection_org_freedesktop_handler
    },
    {   
        .unregister_function = NULL,
        .message_function = subsection_com_handler
    },
    {
        .unregister_function = NULL,
        .message_function = subsection_com_redflag_handler
    },
    {
        .unregister_function = NULL,
        .message_function = object_dbus_handler
    },
    {
        .unregister_function = object_unregister_handler,
        .message_function = object_csy_handler
    },
    {
        .unregister_function = object_unregister_handler,
        .message_function = object_csy_handler
    }
};
static struct seriallist_t {
    dbus_uint32_t serial;
    struct seriallist_t *next;
} *seriallist = NULL;
/**------------- debug facilities --------------------------------*/
void err_quit(const char *fmt, ...) {
    va_list args;
    va_start(args, fmt);
    fprintf(stderr, fmt, args);
    va_end(args);
    exit(1);   
}
/**
* for debug purpose
*/
char* _verbose_watch(DBusWatch *watch) {
    char *s_flags[] = {
        "readable",
        "writable"
    };
    char p[1024] = "", ret[1024] = "";
    if (dbus_watch_get_flags(watch) & DBUS_WATCH_READABLE )
        strncpy(p, s_flags[0], strlen(s_flags[0]));
    else if (dbus_watch_get_flags(watch) & DBUS_WATCH_WRITABLE ) {
        if ( p[0] )
            strncat(p, "&", strlen("&"));
        strncat(p, s_flags[1], strlen(s_flags[1]));
    }
    sprintf(ret, ":%s", dbus_watch_get_fd(watch), p);
    return ret;
}
char* _verbose_message(DBusMessage *msg) {
    char s_msg[1024] = "", ret[1024] = "";
    int bc = sprintf(s_msg, "\ttype: %s\n\tpath: %s\n"
            "\tmember: %s\n\t",
            dbus_message_type_to_string(dbus_message_get_type(msg)),
            dbus_message_get_path(msg),
            dbus_message_get_member(msg));
    strncpy(ret, s_msg, bc+1);
   
    if (dbus_message_get_serial(msg)) {
        bc = sprintf(s_msg, "serial: %ud\n\t",
                dbus_message_get_serial(msg));
        strncat(ret, s_msg, bc+1);
    }
    if (dbus_message_get_reply_serial(msg)) {
        bc = sprintf(s_msg, "reply_serial: %ud\n\t",
                dbus_message_get_reply_serial(msg));
        strncat(ret, s_msg, bc+1);
    }
    DBusMessageIter args, subargs;
    char *s;
    int i;
    dbus_message_iter_init(msg, &args);
    bc = sprintf(s_msg, "args: ");
    strncat(ret, s_msg, bc+1);
    /** here is not the best way to parse the params, i just want to test some of
     * nested situations and different types of params. */
    while (DBUS_TYPE_INVALID != dbus_message_iter_get_arg_type(&args)) {
        // demo here: only care about int and string, igore other types
        switch (dbus_message_iter_get_arg_type(&args)) {
        case DBUS_TYPE_STRING:
            dbus_message_iter_get_basic(&args, &s);
            bc = sprintf(s_msg, " %s", s);
            strncat(ret, s_msg, bc+1);
            break;
        case DBUS_TYPE_INT32:
            dbus_message_iter_get_basic(&args, &i);
            bc = sprintf(s_msg, " %d", i);
            strncat(ret, s_msg, bc+1);
            break;
        case DBUS_TYPE_ARRAY:
            dbus_message_iter_recurse(&args, &subargs);
            strcat(ret, " [ ");
            while (dbus_message_iter_get_arg_type(&subargs)
                    != DBUS_TYPE_INVALID) {
                switch (dbus_message_iter_get_arg_type(&subargs)) {
                case DBUS_TYPE_STRING:
                    dbus_message_iter_get_basic(&subargs, &s);
                    bc = sprintf(s_msg, " %s", s);
                    strncat(ret, s_msg, bc+1);
                    break;
                case DBUS_TYPE_INT32:
                    dbus_message_iter_get_basic(&subargs, &i);
                    bc = sprintf(s_msg, " %d", i);
                    strncat(ret, s_msg, bc+1);
                    break;
                }
                dbus_message_iter_next(&subargs);
            }
            strcat(ret, " ] ");
        }
        dbus_message_iter_next(&args);
    }
    return ret;
}
char* _verbose_timeout(DBusTimeout *timeout) {
    char ret[1024] = "";
    sprintf(ret, "timeout: \n",
            (unsigned int)timeout, dbus_timeout_get_interval(timeout));
    return ret;        
}
/** -------------------------------------------------------*/
DBusHandlerResult handle_method_return(DBusConnection *conn,
        DBusMessage *reply) {
    struct seriallist_t *l = seriallist;
    while (l != NULL) {
        if (l->serial == dbus_message_get_reply_serial(reply)) {        
            printf("reply_msg:\t%s\n", _verbose_message(reply));
            return DBUS_HANDLER_RESULT_HANDLED;
        }
        l = l->next;
    }
    return DBUS_HANDLER_RESULT_HANDLED;
}
int reply_to_method_call(DBusMessage *msg, DBusConnection *conn) {
    DBusMessage *reply;
    DBusMessageIter args;
    DBusError err;
    // suppose we expect two argument, one is id, and second is
    // a string.
    if (!dbus_message_iter_init(msg, &args))
        err_quit("arg init error.\n");
    dbus_int32_t id;
    char *content;
    dbus_error_init( &err );
    dbus_message_get_args( msg, &err,
            DBUS_TYPE_INT32, &id,
            DBUS_TYPE_STRING, &content,
            DBUS_TYPE_INVALID );
    if (dbus_error_is_set(&err))
        err_quit("get arg error.\n");
    reply = dbus_message_new_method_return(msg);
    if (NULL == reply)
        err_quit("Memory is not enough.\n");
    printf("received call args: %d: %s\n", id, content);
    const char *comment = "reply to method call from com.redflag.csy.";
    dbus_message_iter_init_append( reply, &args );
    dbus_message_append_args ( reply,
            DBUS_TYPE_STRING, &comment,
            DBUS_TYPE_INVALID );
    dbus_uint32_t serial;
    dbus_connection_send( conn, reply, &serial );
    dbus_connection_flush( conn );
   
    printf( "build reply msg and send: \n\t%s\n", _verbose_message(reply) );
    dbus_message_unref( reply );
}
dbus_bool_t watchAddNotify(DBusWatch *watch, void *data) {
    struct watchlist_t *l;
    for (l = watchlist; l != NULL; l = l->next) {
        if (l->watch == watch)
            return TRUE;
    }
    printf("watchAdd: %s\n", _verbose_watch(watch));   
    l = dbus_new(struct watchlist_t, 1);
    if ( NULL == l )
        return FALSE;
    l->watch = watch;
    l->next = watchlist;
    watchlist = l;
    return TRUE;
}
void watchRemoveNotify(DBusWatch *watch, void *data) {
    struct watchlist_t *l, *pre;
    for ( pre = l = watchlist; l != NULL; pre = l, l = l->next ) {
        if (l->watch == watch) {
            printf("watchRemove: \n", dbus_watch_get_fd(watch));
            if ( l == watchlist ) {
                watchlist = l->next;
                dbus_free(l);
            } else {
                pre->next = l->next;
                dbus_free(l);
            }
            break;
        }
    }        
}
void watchToggleNotify(DBusWatch *watch, void *data) {
    if (watch == NULL)
        err_quit("line %d: watch should not be null.", __LINE__);
    printf( "toggleNotify: watch %d toogled %s",
            dbus_watch_get_fd(watch),
            dbus_watch_get_enabled(watch)?"enable":"disabled" );
}
/**
* process any watches added to connection
*/
dbus_bool_t watchHandler() {
    struct watchlist_t *l;
    fd_set rfds, wfds, efds;
    int maxid = -1, fd;
    FD_ZERO(&rfds);
    FD_ZERO(&wfds);
    FD_ZERO(&efds);
    // prepare all readble and writable fds
    for (l = watchlist; l != NULL; l = l->next) {
        if (!dbus_watch_get_enabled(l->watch))
            continue;
        fd = dbus_watch_get_fd(l->watch);
        if ( fd & DBUS_WATCH_READABLE ) {
            FD_SET(fd, &rfds);
            maxid = (maxid  fd? fd: maxid);
        }
        if ( fd & DBUS_WATCH_WRITABLE ) {
            FD_SET(fd, &wfds);
            maxid = (maxid  fd? fd: maxid);
        }
        if ( fd & DBUS_WATCH_ERROR ) {
            FD_SET(fd, &efds);
            maxid = (maxid  fd? fd: maxid);
        }
    }
    int ret = select(maxid+1, &rfds, &wfds, &efds, NULL);
    if (ret = 0)
        return;
   
    // call dbus_watch_handle is a must, it uses internal predefined
    // watch handler to do some thing, but i am not  quite sure what
    // it is right now.
    for (l = watchlist; l != NULL; l = l->next) {
        fd = dbus_watch_get_fd(l->watch);
   
        if (FD_ISSET(fd, &rfds))
            dbus_watch_handle(l->watch, DBUS_WATCH_READABLE);
         
        if (FD_ISSET(fd, &wfds))
            dbus_watch_handle(l->watch, DBUS_WATCH_WRITABLE);
        
        if (FD_ISSET(fd, &efds))
            dbus_watch_handle(l->watch, DBUS_WATCH_ERROR);   
    }
}
/**---- timeout process functions ------------------------------*/
dbus_bool_t timeoutAddNotify(DBusTimeout *timeout, void *data) {
    struct timeoutlist_t *l;
    for (l = timeoutlist; l != NULL; l = l->next) {
        if (l->timeout == timeout)
            return TRUE;
    }
    l = dbus_new(struct timeoutlist_t, 1);
    if (NULL == l)
        return FALSE;
    l->timeout = timeout;
    fprintf(stdout, "timeoutAdd:%s\n", _verbose_timeout(timeout));
    l->next = timeoutlist;
    timeoutlist = l;
    return TRUE;
}
void timeoutRemoveNotify(DBusTimeout *timeout, void *data) {
    struct timeoutlist_t *pre = NULL, *l = timeoutlist;
    while( l != NULL ) {
        if (l->timeout == timeout) {
            if (pre == NULL)
                timeoutlist = l->next;
            else
                pre->next = l->next;
            fprintf(stdout, "timeoutRemove:%s\n",
                    _verbose_timeout(timeout));
            break;
        }
        pre = l;
        l = l->next;
    }
}
void timeoutToggleNotify(DBusTimeout *timeout, void *data) {
    fprintf(stdout, "timeoutToggle: %s\n", _verbose_timeout(timeout));
}
/**
* in this function, we call dbus_timeout_handle to handle all timeout
* events, it will call internal predefined handler to process.
*/
void timeoutHandle() {
    struct timeoutlist_t *l = timeoutlist;
    for (; l != NULL; l = l->next) {
        if (dbus_timeout_get_enabled(l->timeout)) {
            printf("timeoutHandle: %s\n", _verbose_timeout(l->timeout));
            dbus_timeout_handle(l->timeout);
        }
    }
}
/**----------- all handlers -------------------------------------*/
/**
* filter messages that already stayed in the incoming queue,
* decide whether a further process is needed.
*/
DBusHandlerResult msgFilter(DBusConnection *conn,
        DBusMessage *msg, void *data) {
    printf("incoming msg: %s\n", _verbose_message(msg));
    switch (dbus_message_get_type(msg)) {
    case DBUS_MESSAGE_TYPE_METHOD_CALL:
        if (!strcmp(dbus_message_get_member(msg), "ignore")) {
            DBusMessage *errMsg;
            errMsg = dbus_message_new_error(msg,
                    "com.redflag.csy.IgnoreService",
                    "this demonstrate the filter.");
            dbus_connection_send(conn, errMsg, NULL);
            return DBUS_HANDLER_RESULT_HANDLED;
        } else
            break;
    case DBUS_MESSAGE_TYPE_METHOD_RETURN:
        // never reach here.
        break;
    case DBUS_MESSAGE_TYPE_SIGNAL:
        break;
    case DBUS_MESSAGE_TYPE_ERROR:
        break;
    }
    // set this flag is very important, if not, dbus may not
    // process messages for you. it pass the control to dbus
    // default filter.
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
DBusHandlerResult subsection_com_handler(DBusConnection* conn,
        DBusMessage* msg, void* data) {
    if ( strncmp(dbus_message_get_path(msg), objectPaths[1],
                strlen(objectPaths[1])) != 0 ) {
        printf("subsection_com_handler: something wrong.\n");
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    }
    if ( strncmp(dbus_message_get_member(msg), "pseudo", 6) == 0 ) {
        reply_to_method_call(msg, conn);
        printf("subsection_com_handler: handled.\n");
        return DBUS_HANDLER_RESULT_HANDLED;
    } else
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
DBusHandlerResult subsection_org_freedesktop_handler(
        DBusConnection* conn, DBusMessage* msg, void* data) {
    if ( strncmp(dbus_message_get_path(msg), objectPaths[0],
                strlen(objectPaths[0])) != 0 ) {
        printf("subsection_org_freedesktop__handler: something wrong.\n");
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    }
   
    if ( strncmp(dbus_message_get_member(msg), "error", 5) == 0 ) {
        printf("subsection_org_freedesktop_handler(error): handled.\n");
        return DBUS_HANDLER_RESULT_HANDLED;
    } else
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
DBusHandlerResult subsection_com_redflag_handler(DBusConnection* conn,
        DBusMessage* msg, void* data) {
    if ( strncmp(dbus_message_get_path(msg), objectPaths[2],
                strlen(objectPaths[2])) != 0 ) {
        printf("subsection_com_redflag_handler: something wrong.\n");
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    }
   
    if ( strncmp(dbus_message_get_member(msg), "pseudo", 6) == 0 ) {
        reply_to_method_call(msg, conn);
        printf("subsection_com_redflag_handler: handled.\n");
        return DBUS_HANDLER_RESULT_HANDLED;
    } else
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
DBusHandlerResult object_dbus_handler(DBusConnection* conn,
        DBusMessage* msg, void* data) {
    if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_RETURN) {
        printf("object_dbus_handler: method_return.\n");
        int ret = handle_method_return( conn, msg );
        printf("object_dbus_handler: handled.\n");
        return ret;
    }
    fprintf(stdout, "object_dbus_handler: cannot handle.\n");
    fprintf(stdout, "\t%s\n", _verbose_message(msg));
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
DBusHandlerResult object_csy_handler(DBusConnection* conn,
        DBusMessage* msg, void* data) {
    switch (dbus_message_get_type(msg)) {
    case DBUS_MESSAGE_TYPE_SIGNAL:
    case DBUS_MESSAGE_TYPE_ERROR:
        fprintf(stdout, "object_csy_handler(error/signal):\n\t%s\n",
                _verbose_message(msg));
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    case DBUS_MESSAGE_TYPE_METHOD_RETURN:
            return handle_method_return(conn, msg);
    case DBUS_MESSAGE_TYPE_METHOD_CALL:
        if ( strstr(dbus_message_get_path(msg), "sycao") != NULL ) {
            printf("object_csy_handler(call): "
                    "cannot handle, through to tree.");
            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
        }
        if ( !strcmp(dbus_message_get_member(msg), "pseudo") ) {
            reply_to_method_call(msg, conn);
            printf("object_csy_handler(call): handled.\n");
            return DBUS_HANDLER_RESULT_HANDLED;
        } else {
            fprintf(stdout, "object_csy_handler(call): cannot handle.\n");
            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
        }
    }
}
void object_unregister_handler(DBusConnection* conn, void* data) {
    printf("object_unregister_handler:\n");
}
/**----------------testing routines ----------------------------------*/
/**
* test send signal method call, send certain signal randomly
*/
void send_random_signal(DBusConnection *conn) {
    DBusMessage *msg;
    char *msg_args[] = {
        "/org/freedesktop/DBus\0org.freedesktop.DBus\0NotExist",
        "/org/freedesktop/HAL\0org.freedesktop.HAL\0Device",
        "/com/redflag/csy\0com.redflag.csy\0NewSignal",
        "\0", "\0"
    };
    char *pargs = msg_args[rand()%(sizeof(msg_args)/sizeof(msg_args[0]))];
    if (!*pargs)
        return;
   
    long chance = 0x0fffffff;
    if ((rand() % chance) > 100)
        return;
    char *path = pargs;
    char *intf, *member;
    while( *pargs++ );
        intf = pargs;
    while( *pargs++ );
        member = pargs;
//    printf("%s,%s,%s\n", path, intf, member);
    dbus_uint32_t serial;
    msg = dbus_message_new_signal(path, intf, member);
    if (NULL == msg)
        err_quit("no enough memory.\n");
    if ( !dbus_connection_send(conn, msg, &serial) )
        fprintf( stderr, "no enough memory to send signal.\n" );
    fprintf(stdout, "SendSignal(%d): %s\n", serial, _verbose_message(msg));
}
void pendingCallNotify(DBusPendingCall *pending, void *data) {
    // one can process the pending and then read the reply message
    // alternatively, one can leave it to message handlers
    DBusMessage *msg = dbus_pending_call_steal_reply(pending);   
    printf( "pendingCallNotify: %s\n", _verbose_message(msg) );
}
void send_random_method_expecting_reply(DBusConnection *conn) {
    DBusMessage *msg;
    char *msg_args[] = {
        "org.freedesktop.DBus\0/org/freedesktop/DBus\0org.freedesktop.DBus\0ListNames",
        "org.freedesktop.DBus\0/org/freedesktop/DBus\0org.freedesktop.DBus.Peer\0Ping",
        "org.freedesktop.DBus\0/org/freedesktop/DBus\0org.freedesktop.DBus.Peer\0GetMachineId",
        "\0" // add possibility of not sending any msg this turn
    };
    long chance = 0x0fffffff;
    if ((rand() % chance) > 100)
        return;
    char *pargs = msg_args[rand()%(sizeof(msg_args)/sizeof(msg_args[0]))];
    if (!*pargs)
        return;   
    char *dest, *path, *intf, *member;
    dest = pargs;
    while( *pargs++ );
        path = pargs;
    while( *pargs++ );
        intf = pargs;
    while( *pargs++ );
        member = pargs;
   
    msg = dbus_message_new_method_call(dest, path, intf, member);
    if (NULL == msg)
        err_quit("no enough memory.\n");
    DBusPendingCall *pendingCall;
    if (!dbus_connection_send_with_reply(conn, msg, &pendingCall, 10000))
        fprintf( stderr, "no memory to send method_call.\n" );
    dbus_pending_call_set_notify(pendingCall, pendingCallNotify, NULL, NULL);
    struct seriallist_t *l;
    l = dbus_new(struct seriallist_t, 1);
    l->serial = dbus_message_get_serial(msg);
    l->next = seriallist;
    seriallist = l;
    fprintf(stdout, "SendMethod: %s\n", _verbose_message(msg));
}
int dbus_process_msg_loop() {
    DBusConnection *conn;
    DBusError *perr;
    // 1. connection to bus
    perr = dbus_new(DBusError, 1);
    dbus_error_init(perr);
    conn = dbus_bus_get(DBUS_BUS_SESSION, perr);
    if ( dbus_error_is_set(perr) )
        err_quit("connection failed.\n");
    // 2. request well-known name
    int ret = dbus_bus_request_name( conn, "com.redflag.csy",
            DBUS_NAME_FLAG_REPLACE_EXISTING, perr );
    if ( DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret )
        err_quit("not primary owner.\n");
    // 3. register any handler
    dbus_bus_add_match( conn,
            "type='method_call',path='/org/freedesktop/csy'"
            ",interface='com.redflag.sycao',member='faked'"
            , perr);
    if (dbus_error_is_set(perr))
        err_quit("add match failed.\n");
    dbus_connection_add_filter( conn, msgFilter, NULL, NULL);
    dbus_connection_set_watch_functions( conn,
            watchAddNotify, watchRemoveNotify, watchToggleNotify,
            NULL, NULL );
    dbus_connection_set_timeout_functions( conn,
            timeoutAddNotify, timeoutRemoveNotify, timeoutToggleNotify,
            NULL, NULL );
    int i;
    for (i = 0; i  sizeof(objectPaths)/sizeof(objectPaths[0]); i++) {
        if (i  3)
            dbus_connection_register_fallback( conn,
                    objectPaths, &objectPathVTable, NULL );
        else
            dbus_connection_register_object_path( conn,
                    objectPaths, &objectPathVTable, NULL);
    }
    printf("main: registered %d objectHandlers.\n", i);
    // 4. main loop: wait and process incoming msgs
    // there are several steps :
    //    a. check if any watch is ready for read (incoming data prepared)
    //    or write (outgoing data prepared), and process it.
    //    b. check if any timeout occurred ( i know now method_call that
    //    needs a reply will set a timeout ), and process it.
    //    c. call dispatch will do:
    //        i. parse incoming raw data if has.
    //        ii. process any pending call ( bind with a reply message );
    //        ii. call any filter registered.
    //        iv. call any object path handler registered.
    //        ps: a single dispatch call processes at most one message.
    //            
    while( 1 ) {
        DBusDispatchStatus status;
        
        while( 1 ) {
            watchHandler();
            timeoutHandle();
            status = dbus_connection_dispatch( conn );
            
            switch( status ) {
            case DBUS_DISPATCH_DATA_REMAINS:
                // there may be more msgs remain, go on
                printf("DBUS_DISPATCH_DATA_REMAINS\n");
                continue;
            case DBUS_DISPATCH_COMPLETE:
                break;
            case DBUS_DISPATCH_NEED_MEMORY:
                fprintf( stderr, "more memory is needed.\n" );
            }
            break;
        }
        send_random_signal( conn );
        send_random_method_expecting_reply( conn );
}
    dbus_free(perr);
    return 0;
}
int main(int argc, char **argv) {
    return dbus_process_msg_loop();
}
编译的时候带上:
CFLAGS=-Wall `pkg-config dbus-1 --cflags`
LDFLAGS=`pkg-config dbus-1 --libs`
可以用下面的脚本测试下不同的对象路径、接口和方法的影响:
#!/bin/bash
if [ $# == 0 ]; then
        loop=10
else
        loop=$1
fi
loop2=$loop
loop3=$loop
loop4=$loop
while (( loop > 0 ))
do
        dbus-send --session --type="method_call" --print-reply  --dest="com.redflag.csy" "/com/redflag/csy" "com.redflag.csy.pseudo" int32:$loop string:"hello,dbus1"
        let "loop = loop - 1"
done
while (( loop2 > 0 ))
do
        dbus-send --session --type="method_call" --print-reply  --dest="com.redflag.csy" "/org/freedesktop/csy" "com.redflag.csy.pseudo" int32:$loop2 string:"hello,dbus2"
        let "loop2 = loop2 - 1"
done
while (( loop3 > 0 ))
do
        dbus-send --session --type="method_call" --print-reply  --dest="com.redflag.csy" "/com/redflag/sycao" "com.redflag.sycao.pseudo" int32:$loop3 string:"hello,dbus3"
        let "loop3 = loop3 - 1"
done
while (( loop4 > 0 ))
do
        dbus-send --session --type="method_call" --print-reply  --dest="com.redflag.csy" "/org/freedesktop/csy" "com.redflag.csy.ignore" int32:$loop4 string:"hello,dbus4"
        let "loop4 = loop4 - 1"
done