Tutoriel D-Bus en C pour communiquer avec wpa_supplicant

J’essaie d’écrire du code pour communiquer avec wpa_supplicant en utilisant DBUS. Comme je travaille dans un système embarqué (ARM), je voudrais éviter l’utilisation de Python ou du GLib. Je me demande si je suis stupide parce que j’ai vraiment l’impression qu’il n’y a pas de documentation claire et claire sur D-Bus. Même avec la version officielle, je trouve que la documentation est trop volumineuse ou que les exemples présentés utilisent Glib! Documentation que j’ai consultée: http://www.freedesktop.org/wiki/Software/dbus

J’ai trouvé un article intéressant sur l’utilisation de D-Bus dans C: http://www.matthew.ath.cx/articles/dbus

Cependant, cet article est assez ancien et pas assez complet! J’ai aussi trouvé l ‘API c ++ – dbus mais aussi ici, je ne trouve AUCUNE documentation! Je me suis plongé dans le code source de wpa_supplicant et de NetworkManager, mais c’est un véritable cauchemar! J’ai également examiné l’API de bas niveau D-Bus, mais cela ne me dit pas comment extraire un paramètre de chaîne d’un message D-Bus! http://dbus.freedesktop.org/doc/api/html/index.html

Voici un code que j’ai écrit pour tester un peu mais j’ai vraiment du mal à extraire des valeurs de chaîne. Désolé pour le long code source mais si quelqu’un veut l’essayer … Ma configuration de D-Bus semble correcte car il “capte” déjà les signaux “StateChanged” de wpa_supplicant mais ne peut pas imprimer l’état:

#include  #include  #include  #include  #include  #include  //#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 ssortingng 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("Ssortingng 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 ssortingng // 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; } 

Tout pointeur vers un didacticiel de bas niveau complet et de qualité est fortement apprécié! Je compte aussi faire un appel de méthode à distance, donc si le tutoriel couvre ce sujet, ce serait génial! Dire que je ne suis pas très intelligent parce que je ne comprends pas avec le tutoriel officiel est également apprécié :-p!

Ou existe-t-il un autre moyen de communiquer avec wpa_supplicant (sauf avec wpa_cli)?

EDIT 1:

En utilisant ‘qdbusviewer’ et la capacité d’introspection, cela m’a beaucoup aidé à découvrir comment et comment wpa_supplicant fonctionne avec dbus. En espérant que cela aiderait quelqu’un d’autre!

Edit 2:

Je viendrai probablement quand je trouverai un moyen de lire les valeurs de chaîne sur D-Bus!

    Vous avez abandonné les outils qui vous aideraient à apprendre plus facilement D-Bus et vous utilisez l’implémentation libdbus de bas niveau, alors vous méritez peut-être de souffrir. BTW, parlez-vous d’ARM, comme un ARM de téléphone portable? Avec peut-être 500 Mhz et 256 Mo de RAM? Dans ce cas, le processeur est bien adapté à l’utilisation de Glib, Qt ou même Python. Et D-Bus est très utile lorsque vous écrivez un code piloté par un événement asynchrone, avec une boucle principale intégrée, par exemple à partir de glib, même lorsque vous utilisez le libdbus de bas niveau (il a des fonctions pour se connecter à la boucle principale glib, par exemple).

    Puisque vous utilisez la bibliothèque de bas niveau, la documentation est ce que vous avez déjà:

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

    Le code source de libdbus fait également partie de la documentation:

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

    Le point d’entrée principal de la documentation est la page Modules (en particulier la section API publique):

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

    Pour la gestion des messages, la section DBusMessage est pertinente: DBusMessage

    Vous y trouverez la documentation pour les fonctions qui parsingnt les valeurs des éléments. Dans votre cas, vous avez commencé avec un dbus_message_iter_get_basic. Comme décrit dans la documentation, la récupération de la chaîne nécessite une variable const char **, car la valeur renvoyée indiquera la chaîne pré-allouée dans le message reçu:

    Donc pour int32 ce devrait être un “dbus_int32_t *” et pour une chaîne un “const char **”. La valeur renvoyée est par référence et ne doit pas être libérée.

    Vous ne pouvez donc pas définir un tableau, car libdbus ne copiera pas le texte dans votre tableau. Si vous avez besoin de sauvegarder la chaîne, commencez par obtenir la référence de la chaîne constante, puis envoyez-la à votre propre groupe.

    Ensuite, vous avez essayé d’obtenir un tableau fixe sans déplacer l’iterator. Vous avez besoin d’un appel à l’iterator suivant (dbus_message_iter_next) entre la chaîne de base et le tableau fixe. Même chose avant de récurer dans le sous-iterator.

    Enfin, vous n’appelez pas get_array_len pour obtenir le nombre d’éléments sur le tableau. À partir des documents, il ne renvoie que le nombre d’octets. Au lieu de cela, vous parcourez le sous-iterator en utilisant iter_next de la même manière que vous auriez dû le faire avec l’iterator principal. Après avoir parcouru la fin du tableau, dbus_message_iter_get_arg_type retournera DBUS_TYPE_INVALID.

    Pour plus d’informations, lisez le manuel de référence, ne cherchez pas de tutoriel. Ou utilisez simplement une implémentation d-bus raisonnable:

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

    GDBus de GIO crée automatiquement des wrappers pour vos appels de bus D.

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

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

    etc.

    Vous n’avez pas besoin d’utiliser / de comprendre le fonctionnement de dbus Si vous avez juste besoin d’écrire un programme C pour communiquer avec wpa_supplicant. J’ai inversé le code source de wpa_cli. Nous sums passés à travers son implémentation et les fonctions utilisées dans wpa_ctrl.h / c. Cette mise en œuvre prend soin de tout. Vous pouvez utiliser / modifier ce que vous voulez, construire votre exécutable et vous avez terminé!

    Voici le lien officiel vers la ctrl_interface de wpa_supplicant: http://hostap.epitest.fi/wpa_supplicant/devel/ctrl_iface_page.html

    L’extrait ci-dessous fonctionne pour moi

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