title: D-Bus tutorial in C to communicate with wpa_supplicant
body: <p>I'm trying to write some code to communicate with wpa_supplicant using DBUS. As I'm working in an embedded system (ARM), I'd like to avoid the use of Python or the GLib. I'm wondering if I'm stupid because I really have the feeling that there is no nice and clear documentation about D-Bus. Even with the official one, I either find the documentation too high level, or the examples shown are using Glib! Documentation I've looked at: <a href="http://www.freedesktop.org/wiki/Software/dbus" rel="noreferrer">http://www.freedesktop.org/wiki/Software/dbus</a> </p>
  
  <p>I found a nice article about using D-Bus in C: <a href="http://www.matthew.ath.cx/articles/dbus" rel="noreferrer">http://www.matthew.ath.cx/articles/dbus</a></p>
  
  <p>However, this article is pretty old and not complete enough! I also found the c++-dbus API but also here, I don't find ANY documentation! I've been digging into wpa_supplicant and NetworkManager source code but it's quite a nightmare! I've  been looking into the "low-level D-Bus API" as well but this doesn't tell me how to extract a string parameter from a D-Bus message! <a href="http://dbus.freedesktop.org/doc/api/html/index.html" rel="noreferrer">http://dbus.freedesktop.org/doc/api/html/index.html</a></p>
  
  <p>Here is some code I wrote to test a little but I really have trouble to extract string values. Sorry for the long source code but if someone want to try it ... My D-Bus configuration seems fine because it "already" catches "StateChanged" signals from wpa_supplicant but cannot print the state:</p>
  
  <pre class="lang-c prettyprint-override"><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;signal.h&gt;
  #include &lt;string.h&gt;
  
  #include &lt;dbus/dbus.h&gt;
  
  //#include "wpa_supp_dbus.h"
  /* Content of wpa_supp_dbus.h */
  #define WPAS_DBUS_SERVICE   "fi.epitest.hostap.WPASupplicant"
  #define WPAS_DBUS_PATH      "/fi/epitest/hostap/WPASupplicant"
  #define WPAS_DBUS_INTERFACE "fi.epitest.hostap.WPASupplicant"
  
  #define WPAS_DBUS_PATH_INTERFACES   WPAS_DBUS_PATH "/Interfaces"
  #define WPAS_DBUS_IFACE_INTERFACE   WPAS_DBUS_INTERFACE ".Interface"
  
  #define WPAS_DBUS_NETWORKS_PART "Networks"
  #define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network"
  
  #define WPAS_DBUS_BSSIDS_PART   "BSSIDs"
  #define WPAS_DBUS_IFACE_BSSID   WPAS_DBUS_INTERFACE ".BSSID"
  
  int running = 1;
  
  void stopLoop(int sig)
  {
      running = 0;
  }
  
  void sendScan()
  {
    // TODO !
  }
  
  void loop(DBusConnection* conn)
  {
      DBusMessage* msg;
      DBusMessageIter args;
      DBusMessageIter subArgs;
      int argType;
      int i;
      int buffSize = 1024;
      char strValue[buffSize];
      const char* member = 0;
  
      sendScan();
  
      while (running)
      {
          // 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 (!msg)
          {
              printf("No message received, waiting a little ...\n");
              sleep(1);
              continue;
          }
          else printf("Got a message, will analyze it ...\n");
  
          // Print the message member
          printf("Got message for interface %s\n",
                  dbus_message_get_interface(msg));
          member = dbus_message_get_member(msg);
          if(member) printf("Got message member %s\n", member);
  
          // Check has argument
          if (!dbus_message_iter_init(msg, &amp;args))
          {
              printf("Message has no argument\n");
              continue;
          }
          else
          {
              // Go through arguments
              while(1)
              {
                  argType = dbus_message_iter_get_arg_type(&amp;args);
  
                  if (argType == DBUS_TYPE_STRING)
                  {
                      printf("Got string argument, extracting ...\n");
  
                      /* FIXME : got weird characters
                      dbus_message_iter_get_basic(&amp;args, &amp;strValue);
                      */
  
                      /* FIXME : segmentation fault !
                      dbus_message_iter_get_fixed_array(
                              &amp;args, &amp;strValue, buffSize);
                      */
  
                      /* FIXME : segmentation fault !
                      dbus_message_iter_recurse(&amp;args, &amp;subArgs);
                      */
  
                      /* FIXME : deprecated!
                      if(dbus_message_iter_get_array_len(&amp;args) &gt; buffSize)
                          printf("message content to big for local buffer!");
                      */
  
                      //printf("String value was %s\n", strValue);
                  }
                  else
                      printf("Arg type not implemented yet !\n");
  
                  if(dbus_message_iter_has_next(&amp;args))
                      dbus_message_iter_next(&amp;args);
                  else break;
              }
              printf("No more arguments!\n");
          }
  
          // free the message
          dbus_message_unref(msg);
      }
  }
  
  int main(int argc, char* argv[])
  {
      DBusError err;
      DBusConnection* conn;
      int ret;
      char signalDesc[1024];     // Signal description as string
  
      // Signal handling
      signal(SIGKILL, stopLoop);
      signal(SIGTERM, stopLoop);
  
      // Initialize err struct
      dbus_error_init(&amp;err);
  
      // connect to the bus
      conn = dbus_bus_get(DBUS_BUS_SYSTEM, &amp;err);
      if (dbus_error_is_set(&amp;err))
      {
          fprintf(stderr, "Connection Error (%s)\n", err.message);
          dbus_error_free(&amp;err);
      }
      if (!conn)
      {
          exit(1);
      }
  
      // request a name on the bus
      ret = dbus_bus_request_name(conn, WPAS_DBUS_SERVICE, 0, &amp;err);
      if (dbus_error_is_set(&amp;err))
      {
          fprintf(stderr, "Name Error (%s)\n", err.message);
          dbus_error_free(&amp;err);
      }
  
      /* Connect to signal */
      // Interface signal ..
      sprintf(signalDesc, "type='signal',interface='%s'",
              WPAS_DBUS_IFACE_INTERFACE);
      dbus_bus_add_match(conn, signalDesc, &amp;err);
      dbus_connection_flush(conn);
      if (dbus_error_is_set(&amp;err))
      {
          fprintf(stderr, "Match Error (%s)\n", err.message);
          exit(1);
      }
  
      // Network signal ..
      sprintf(signalDesc, "type='signal',interface='%s'",
              WPAS_DBUS_IFACE_NETWORK);
      dbus_bus_add_match(conn, signalDesc, &amp;err);
      dbus_connection_flush(conn);
      if (dbus_error_is_set(&amp;err))
      {
          fprintf(stderr, "Match Error (%s)\n", err.message);
          exit(1);
      }
  
      // Bssid signal ..
      sprintf(signalDesc, "type='signal',interface='%s'",
              WPAS_DBUS_IFACE_BSSID);
      dbus_bus_add_match(conn, signalDesc, &amp;err);
      dbus_connection_flush(conn);
      if (dbus_error_is_set(&amp;err))
      {
          fprintf(stderr, "Match Error (%s)\n", err.message);
          exit(1);
      }
  
      // Do main loop
      loop(conn);
  
      // Main loop exited
      printf("Main loop stopped, exiting ...\n");
  
      dbus_connection_close(conn);
  
      return 0;
  }
  </code></pre>
  
  <p>Any pointer to any nice, complete, low-level C tutorial is strongly appreciated! I'm also planning to do some remote method call, so if the tutorial covers this subject it would be great! Saying I'm not very smart because I don't get it with the official tutorial is also appreciated :-p!</p>
  
  <p>Or is there another way to communicate with wpa_supplicant (except using wpa_cli)?</p>
  
  <p><strong>EDIT 1:</strong></p>
  
  <p>Using 'qdbusviewer' and the introspection capabilty, this helped me a lot discovering what and how wpa_supplicant works using dbus. Hopping that this would help someone else!</p>
  
  <p><strong>Edit 2:</strong></p>
  
  <p>Will probably come when I'll find a way to read string values on D-Bus!</p>