2011-12-15 24 views
17

Estoy tratando de escribir algún código para comunicarme con wpa_supplicant usando DBUS. Como estoy trabajando en un sistema integrado (ARM), me gustaría evitar el uso de Python o el GLib. Me pregunto si soy estúpido porque realmente tengo la sensación de que no hay documentación buena y clara sobre D-Bus. Incluso con el oficial, o encuentro la documentación de un nivel demasiado alto, o los ejemplos que se muestran están usando Glib! Documentación que he mirado: http://www.freedesktop.org/wiki/Software/dbusTutorial de D-Bus en C para comunicarse con wpa_supplicant

He encontrado un buen artículo sobre el uso de D-Bus en C: http://www.matthew.ath.cx/articles/dbus

Sin embargo, este artículo es bastante viejo y no es lo suficientemente completa! También encontré la API de C++ - dbus, pero también aquí, ¡no encuentro CUALQUIER documentación! ¡He estado investigando el código fuente de wpa_supplicant y NetworkManager, pero es una verdadera pesadilla! También he estado investigando la "API de D-Bus de bajo nivel", pero esto no me dice cómo extraer un parámetro de cadena de un mensaje de D-Bus. http://dbus.freedesktop.org/doc/api/html/index.html

Aquí hay un código que escribí para probar un poco, pero realmente tengo problemas para extraer valores de cadena. Lo siento por el código fuente de largo, pero si alguien quiere probarlo ... Mi configuración de D-Bus parece muy bien porque "ya" capturas "StateChanged" señales de wpa_supplicant, pero no puede imprimir el estado:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <signal.h> 
#include <string.h> 

#include <dbus/dbus.h> 

//#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, &args)) 
     { 
      printf("Message has no argument\n"); 
      continue; 
     } 
     else 
     { 
      // Go through arguments 
      while(1) 
      { 
       argType = dbus_message_iter_get_arg_type(&args); 

       if (argType == DBUS_TYPE_STRING) 
       { 
        printf("Got string argument, extracting ...\n"); 

        /* FIXME : got weird characters 
        dbus_message_iter_get_basic(&args, &strValue); 
        */ 

        /* FIXME : segmentation fault ! 
        dbus_message_iter_get_fixed_array(
          &args, &strValue, buffSize); 
        */ 

        /* FIXME : segmentation fault ! 
        dbus_message_iter_recurse(&args, &subArgs); 
        */ 

        /* FIXME : deprecated! 
        if(dbus_message_iter_get_array_len(&args) > 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(&args)) 
        dbus_message_iter_next(&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(&err); 

    // connect to the bus 
    conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); 
    if (dbus_error_is_set(&err)) 
    { 
     fprintf(stderr, "Connection Error (%s)\n", err.message); 
     dbus_error_free(&err); 
    } 
    if (!conn) 
    { 
     exit(1); 
    } 

    // request a name on the bus 
    ret = dbus_bus_request_name(conn, WPAS_DBUS_SERVICE, 0, &err); 
    if (dbus_error_is_set(&err)) 
    { 
     fprintf(stderr, "Name Error (%s)\n", err.message); 
     dbus_error_free(&err); 
    } 

    /* Connect to signal */ 
    // Interface signal .. 
    sprintf(signalDesc, "type='signal',interface='%s'", 
      WPAS_DBUS_IFACE_INTERFACE); 
    dbus_bus_add_match(conn, signalDesc, &err); 
    dbus_connection_flush(conn); 
    if (dbus_error_is_set(&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, &err); 
    dbus_connection_flush(conn); 
    if (dbus_error_is_set(&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, &err); 
    dbus_connection_flush(conn); 
    if (dbus_error_is_set(&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; 
} 

Cualquier puntero a cualquier tutorial agradable, completo y de bajo nivel de C es muy apreciada! También estoy planeando hacer una llamada a método remoto, así que si el tutorial cubre este tema sería genial. Decir que no soy muy inteligente porque no lo entiendo con el tutorial oficial también es apreciado: ¡p!

¿O existe otra forma de comunicarse con wpa_supplicant (excepto con wpa_cli)?

EDIT 1:

El uso de 'qdbusviewer' y la capabilty introspección, esto me ayudó mucho descubrir qué y cómo funciona wpa_supplicant usando dbus. ¡Saltando que esto ayudaría a alguien más!

Edición 2:

probablemente vendrá cuando voy a encontrar una manera de leer los valores de cadena de D-Bus!

+0

¿Ha encontrado una manera de leer los valores de cadena de D-Bus? –

Respuesta

1
+0

enlace muerto ....... –

+2

Si bien este enlace puede responder a la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionar el enlace de referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página vinculada cambia. - [De la crítica] (/ reseña/mensajes de baja calidad/18892083) – Boiethios

2

No es necesario usar/entender trabajo de dbus Si sólo necesita escribir un programa en C para comunicarse con wpa_supplicant. Invertí la ingeniería del código fuente de wpa_cli. Realicé su implementación y usé funciones provistas en wpa_ctrl.h/c. Esta implementación se ocupa de todo. Puedes usar/modificar lo que quieras, construir tu ejecutable y ¡listo!

Aquí está el enlace oficial a ctrl_interface de wpa_supplicant: http://hostap.epitest.fi/wpa_supplicant/devel/ctrl_iface_page.html

+0

Derecha. Usé el mismo enfoque. Todo está en wpa_cli.c y wpa_ctrl.h para copiar/pegar.La interfaz de control es la forma recomendada de comunicarse con wpa_supplicant, según el enlace anterior. No hay necesidad de luchar con d-bus. – FractalSpace

4

Usted ha renunciado a las herramientas que le ayudarán a aprender D-Bus con mayor facilidad y usan la aplicación bajo nivel libdbus, así que tal vez merece ser En dolor. Por cierto, ¿estás hablando de ARM, como un ARM de celular? ¿Con quizás 500 Mhz y 256 MB de RAM? En este caso, el procesador es muy adecuado para usar glib, Qt o incluso python. Y D-Bus es más útil cuando estás escribiendo código impulsado por eventos asíncronos, con un bucle principal integrado, por ejemplo desde glib, incluso cuando estás usando el libdbus de bajo nivel (tiene funciones para conectarse al bucle principal glib, por ejemplo).

Dado que está utilizando la biblioteca de bajo nivel, a continuación, la documentación es lo que ya tiene:

http://dbus.freedesktop.org/doc/api/html/index.html

Además, el código fuente libdbus es también parte de la documentación:

http://dbus.freedesktop.org/doc/api/html/files.html

El punto de entrada principal para la documentación es la página Módulos (en particular, la sección API pública):

http://dbus.freedesktop.org/doc/api/html/modules.html

Para el manejo de mensajes, la sección DBusMessage es el correspondiente uno: DBusMessage

No tener la documentación para las funciones que analizan valores de los elementos. En su caso, comenzó con un dbus_message_iter_get_basic. Como se describe en los documentos, la recuperación de la cadena requiere una variable const char **, ya que el valor devuelto apuntará a la cadena preasignada en el mensaje recibido:

Entonces para int32 debería ser un "dbus_int32_t *" y para la cadena a "const char **". El valor devuelto es por referencia y no debe liberarse.

Así que no puede definir una matriz, porque libdbus no copiará el texto en la matriz. Si necesita guardar la cadena, primero obtenga la referencia de cadena constante, luego strcpy a su propia matriz.

Luego tratas de obtener una matriz fija sin mover el iterador. Necesita una llamada al siguiente iterador (dbus_message_iter_next) entre la cadena básica y la matriz fija. Mismo derecho antes de recurrir al sub iterador.

Finalmente, no llama a get_array_len para obtener la cantidad de elementos en la matriz. De los documentos, solo devuelve recuentos de bytes. En su lugar, recorre el sub iterador usando iter_next de la misma manera que debería haber hecho con el iterador principal. Después de iterar más allá del final de la matriz, dbus_message_iter_get_arg_type devolverá DBUS_TYPE_INVALID.

Para obtener más información, lea el manual de referencia, no busque un tutorial. O simplemente utilizar una aplicación D-Bus razonable:

https://developer.gnome.org/gio/2.36/gdbus-codegen.html

GDBus de GIO crea automáticamente contenedores para sus llamadas de D-Bus.

http://qt-project.org/doc/qt-4.8/intro-to-dbus.html

http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html

etc.

0

El siguiente fragmento de código funciona para mí

if (argType == DBUS_TYPE_STRING) 
{ 
printf("Got string argument, extracting ...\n"); 
char* strBuffer = NULL; 
dbus_message_iter_get_basic(&args, &strBuffer); 
printf("Received string: \n %s \n",strBuffer); 

} 
Cuestiones relacionadas