2011-12-15 10 views
17

Sto provando a scrivere del codice per comunicare con wpa_supplicant usando DBUS. Dato che sto lavorando su un sistema embedded (ARM), vorrei evitare l'uso di Python o GLib. Mi chiedo se sono stupido perché ho davvero la sensazione che non ci sia una documentazione chiara e chiara su D-Bus. Anche con quello ufficiale, o trovo la documentazione di livello troppo alto, o gli esempi mostrati stanno usando Glib! Documentazione Ho guardato: http://www.freedesktop.org/wiki/Software/dbusTutorial D-Bus in C per comunicare con wpa_supplicant

ho trovato un bel articolo sull'utilizzo di D-Bus in C: http://www.matthew.ath.cx/articles/dbus

Tuttavia, questo articolo è piuttosto vecchio e non abbastanza completo! Ho anche trovato l'API C++ - dbus ma anche qui, non trovo NESSUNA documentazione! Sto scavando nel codice sorgente di wpa_supplicant e NetworkManager ma è un vero incubo! Ho esaminato anche le "API D-Bus di basso livello" ma questo non mi dice come estrarre un parametro stringa da un messaggio D-Bus! http://dbus.freedesktop.org/doc/api/html/index.html

Ecco un codice che ho scritto per testare un po 'ma ho davvero problemi ad estrarre i valori stringa. Ci scusiamo per il codice sorgente a lungo, ma se qualcuno vuole provare ... La mia configurazione D-Bus sembra che vada bene perché "già" catture "StateChanged" i segnali provenienti da wpa_supplicant, ma non è possibile stampare lo stato:

#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; 
} 

Qualsiasi puntatore un tutorial C carino, completo e di basso livello è molto apprezzato! Sto anche pensando di fare qualche chiamata a metodo remota, quindi se il tutorial copre questo argomento sarebbe fantastico! Dire che non sono molto intelligente perché non lo capisco con il tutorial ufficiale è anche apprezzato :-p!

Oppure c'è un altro modo per comunicare con wpa_supplicant (tranne che usando wpa_cli)?

EDIT 1:

Usando 'qdbusviewer' e la capabilty introspezione, questo mi ha aiutato molto scoprire cosa e come funziona wpa_supplicant utilizzando dbus. Saltellando che questo aiuterebbe qualcun altro!

Edit 2:

probabilmente verrà quando troverò un modo per leggere i valori di stringa su D-Bus!

+0

Hai trovato un modo per leggere i valori di stringa su D-Bus? –

risposta

1
+0

dead link ....... –

+2

Sebbene questo collegamento possa rispondere alla domanda, è meglio includere qui le parti essenziali della risposta e fornire il link per riferimento. Le risposte di solo collegamento possono diventare non valide se la pagina collegata cambia. - [Dalla recensione] (/ recensione/post di bassa qualità/18892083) – Boiethios

2

Non è necessario utilizzare/comprensione di lavoro di dbus Se avete solo bisogno di scrivere un programma C per comunicare con wpa_supplicant. Ho decodificato il codice sorgente di wpa_cli. Sono passati attraverso la sua implementazione e le funzioni utilizzate fornite in wpa_ctrl.h/c. Questa implementazione si prende cura di tutto. Puoi usare/modificare ciò che vuoi, costruire il tuo eseguibile e il gioco è fatto!

Ecco il link ufficiale per ctrl_interface di wpa_supplicant: http://hostap.epitest.fi/wpa_supplicant/devel/ctrl_iface_page.html

+0

Giusto. Ho usato lo stesso approccio. Tutto è in wpa_cli.c e wpa_ctrl.h per una copia/incolla.L'interfaccia di controllo è il modo consigliato per comunicare con wpa_supplicant, come per il link sopra. Non c'è bisogno di lottare con il d-bus. – FractalSpace

4

Hai rinunciato gli strumenti che vi aiutano a imparare D-Bus più facilmente e si utilizza l'implementazione a basso livello libdbus, così forse si meritano di essere dolorante. A proposito, stai parlando di ARM, come un telefono cellulare ARM? Con forse 500 Mhz e 256 MB di RAM? In questo caso il processore è adatto all'uso di glib, Qt o anche python. E D-Bus è molto utile quando si scrive codice asincrono basato su eventi, con un loop principale integrato, ad esempio da glib, anche quando si utilizza il libdbus di basso livello (ha funzioni per connettersi al ciclo principale di glib, per esempio).

Dal momento che si sta utilizzando la libreria di basso livello, quindi la documentazione è quello che hai già:

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

Inoltre, il codice sorgente libdbus è anche parte della documentazione:

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

Il punto di accesso principale per la documentazione è la pagina Moduli (in particolare, la sezione API pubblica):

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

Per la gestione dei messaggi, il DBusMessage sezione è quella corrispondente: DBusMessage

Ci avete la documentazione per le funzioni che analizzano i valori delle voci. Nel tuo caso, hai iniziato con un dbus_message_iter_get_basic. Come descritto nella documentazione, il recupero della stringa richiede una variabile const char **, poiché il valore restituito punterà alla stringa preassegnata nel messaggio ricevuto:

Quindi per int32 dovrebbe essere un "dbus_int32_t *" e per string un "const char **". Il valore restituito è di riferimento e non dovrebbe essere liberato.

Quindi non è possibile definire un array, poiché libdbus non copierà il testo nell'array. Se è necessario salvare la stringa, prima ottenere il riferimento di stringa costante, quindi eseguire il comando strcpy sul proprio array.

Quindi si è tentato di ottenere un array fisso senza spostare l'iteratore. È necessaria una chiamata al successivo iteratore (dbus_message_iter_next) tra la stringa di base e l'array fisso. Stesso diritto prima di ricorrere al sub iteratore.

Infine, non chiamare get_array_len per ottenere il numero di elementi nell'array. Dai documenti, restituisce solo i conteggi dei byte. Invece si esegue il looping sull'iteratore secondario usando iter_next nello stesso modo in cui si sarebbe dovuto fare con l'iteratore principale. Dopo aver iterato oltre la fine dell'array, dbus_message_iter_get_arg_type restituirà DBUS_TYPE_INVALID.

Per maggiori informazioni, leggere il manuale di riferimento, non cercare un tutorial. O semplicemente usare un'implementazione D-Bus ragionevole:

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

GDBus di GIO crea automaticamente wrapper per le chiamate D-BUS.

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

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

ecc

0

Il frammento di seguito funziona per me

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

}