Using the DBUS C API

Using the DBUS C API

              
THE CANONICAL ADDRESS OF THIS DOCUMENT IS NOW http://dbus.freedesktop.org/doc/dbus/libdbus-tutorial.html

              

D-BUS is a message
   bus system, a simple way for applications to talk to one another The
   low-level API for DBUS is written in C but most of the documentation and
   code is written for a higher level binding, such as Python or GLib.
   Here I provide tutorial/howto for a basic server and client using the C API
   directly, including example code. The DBUS website has Doxygen documentation
   for the C API.

              


   NOTE: you should not use this API unless you absolutely have to. Application
   developers should use one of the bindings if at all possible. If you are
   writing in C then the GLib bindings are recommended.

              
Common Code

              


   A lot of the code is common no matter what you want to do on the Bus. First
   you need to connect to the bus. There is normally a system and a session
   bus. The DBUS config may restrict who can connect to the system bus.
   Secondly, you need to request a name on the bus. For simplicity I don't cope
   with the situation where someone already owns that name.

              


   DBusError err;
   DBusConnection* conn;
   int ret;
   // initialise the errors
   dbus_error_init(&err);


              

// connect to the bus
   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 a name on the bus
   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) {
      exit(1);
   }


              


   After you have finished with the bus you should close the connection. Note
   that this is a shared connection to the bus so you probably only want to do
   this just before the application terminates.

              


   dbus_connection_close(conn);


              
Sending a Signal

              


   The simplest operation is sending a broadcast signal to the bus. To do this
   you need to create a DBusMessage object representing the signal, and
   specifying what object and interface the signal represents. You then need to
   add any parameters to it as appropriate, and send it to the bus.  Finally
   you need to free the message. Several methods return false on out of memory,
   this should be checked for and handled.

              


   dbus_uint32_t serial = 0; // unique number to associate replies with requests
   DBusMessage* msg;
   DBusMessageIter args;
      
   // create a signal and 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);
   
   // free the message
   dbus_message_unref(msg);


              
Calling a Method

              


   Calling a remote method is very similar to sending a signal. You need to
   create the message and specify the name on the bus it is being send to, and
   what object, interface and method is being called. You then add parameters
   to the message as above. If you need a reply to the message you need to use
   a different method to send the message. This gives you a pending reply
   object which you can block on to wait for the reply and get another
   DBusMessage* as the reply. From this you can read the parameters
   returned by the remote method.

              


   DBusMessage* msg;
   DBusMessageIter args;
   DBusPendingCall* pending;

   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, &param)) {
      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);

   // free message
   dbus_message_unref(msg);


              


   bool stat;
   dbus_uint32_t level;
        
   // block until we receive 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 close connection
   dbus_message_unref(msg);   


              
Receiving a Signal

              


   These next two operations require reading messages from the bus and handling
   them. There is not a simple way in the C API as of 0.50 to do this.  Because
   DBUS is designed to use OO bindings and an event based model all the methods
   that handle the messages on the wire use callbacks. I have submitted a patch
   which should make it into the next release which allows messages to be read
   and marshalled from the wire in a non-blocking operation. This is the
   dbus_connection_read_write() method, which is required to use the
   code on this page.

              


   To receive a signal you have to tell the bus what signals you are interested
   in so they are sent to your application, then you read messages off the bus
   and can check what type they are and what interfaces and signal names each
   signal represents.

              

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


              

// 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 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, &sigvalue);
            printf("Got Signal with value %s\n", sigvalue);
         }
      }

      // free the message
      dbus_message_unref(msg);
   }


              


   Note that the use of sleep in this example is to simulate some other thing we are blocking on,
   such as select. If the only thing happening in this thread is the DBus communication then the
   dbus_connection_read_write call can take a timeout parameter, which is how many ms to block for.
   -1 blocks forever.

              
Exposing a Method to be called

              


   To expose a method which may be called by other DBUS applications you have
   to listen for messages as above, then when you get a method call
   corresponding to the method you exposed you parse out the parameters,
   construct a reply message from the original and populate its parameters with
   the return value.  Finally you have to send and free the reply.

              

// 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 and 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);
   }


              


void reply_to_method_call(DBusMessage* msg, DBusConnection* conn)
{
   DBusMessage* reply;
   DBusMessageIter args;
   DBusConnection* conn;
   bool stat = true;
   dbus_uint32_t level = 21614;
   dbus_uint32_t serial = 0;
   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, &param);
   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);
}


              
Code Examples

              


   That should be all you need to write a simple server and client for DBUS
   using the C API. The code snippets above come from dbus-example.c which you can download
   and test. It contains code for all four operations above.

              


    *                 To receive signals: dbus-example receive

    *                 To send a signal: dbus-example send param

    *                 To listen for method calls: dbus-example listen

    *                 To call the method: dbus-example query param
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是一个简单的DBus C语言示例,它创建了一个DBus连接,发送一个DBus消息,等待并接收回复消息: ```c #include <stdio.h> #include <stdlib.h> #include <dbus/dbus.h> int main(int argc,char **argv){ DBusError err; DBusConnection *conn; DBusMessage *msg,*reply; int ret; // 初始化错误变量 dbus_error_init(&err); // 连接到DBus session bus 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); return EXIT_FAILURE; } // 创建DBus消息 msg = dbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames"); if(!msg){ fprintf(stderr,"Message Null"); return EXIT_FAILURE; } // 发送DBus消息并等待回复 reply = dbus_connection_send_with_reply_and_block(conn,msg,-1,&err); dbus_message_unref(msg); if(!reply){ fprintf(stderr,"Reply Null (%s)\n",err.message); dbus_error_free(&err); return EXIT_FAILURE; } // 打印回复消息中的字符串 if(dbus_message_get_args(reply,&err,DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,&ret,DBUS_TYPE_INVALID)){ printf("List of services:\n"); for(int i=0;i<ret;i++){ char *s; dbus_message_iter_get_basic(&ret,&s); printf("%s\n",s); dbus_message_iter_next(&ret); } } // 释放DBus连接和消息 dbus_message_unref(reply); dbus_connection_close(conn); return EXIT_SUCCESS; } ``` 这个例子连接到DBus的会话总线,发送一个`ListNames`请求,等待回复并打印回复中包含的服务列表。需要注意的是,如果没有连接到总线或发送消息出错,代码会返回EXIT_FAILURE,否则返回EXIT_SUCCESS。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值