D-Bus tutoriel en C pour communiquer avec wpa_supplicant
Je suis en train d'écrire un peu de 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 de la GLib. Je me demande si je suis stupide parce que j'ai vraiment le sentiment qu'il n'est pas agréable et claire de la documentation à propos de D-Bus. Même avec l'officiel, je trouve la documentation de trop haut niveau, ou les exemples présentés sont à l'aide de Glib! La Documentation que j'ai regardé: 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
Toutefois, cet article est assez vieux et pas assez complet! J'ai aussi trouvé le c++API dbus, mais aussi ici, je n'ai pas trouvé de documentation! J'ai fouiné dans wpa_supplicant et NetworkManager code source, mais il est tout à fait un cauchemar! J'ai été regarder dans le "bas-niveau D-Bus API" ainsi, mais cela ne me dites pas comment extraire un paramètre de chaîne de D-Bus de message! 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 les valeurs de chaîne. Désolé pour le long code source, mais si quelqu'un veut l'essayer ... Mon D-Bus configuration semble très bien, parce que "déjà" captures "StateChanged" signaux de wpa_supplicant, mais ne peut pas imprimer de l'état:
#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;
}
Un pointeur vers un joli, complet, de bas-niveau C tutoriel est fortement apprécié! Je prévois aussi de faire une certaine distance l'appel de méthode, de sorte que si le tutoriel couvre ce sujet, il serait grand! Dire que je ne suis pas très intelligent parce que je n'ai pas l'obtenir avec le tutoriel officiel est également apprécié :-p!
Ou est-il une autre façon de communiquer avec wpa_supplicant (à l'exception de l'aide wpa_cli)?
EDIT 1:
À l'aide de 'qdbusviewer' et l'introspection capabilty, cela m'a beaucoup aidé à découvrir ce que et comment wpa_supplicant fonctionne en utilisant dbus. Saut que cela aide quelqu'un d'autre!
Edit 2:
Viendra sans doute quand je vais trouver un moyen de lire les valeurs de chaîne sur D-Bus!
- Avez-vous trouver un moyen pour lire les valeurs de chaîne sur D-Bus?
Vous devez vous connecter pour publier un commentaire.
Vous avez donné les outils qui pourraient vous aider à apprendre D-Bus plus facilement et utiliser le faible niveau libdbus mise en œuvre, peut-être que vous méritez d'être dans la douleur. BTW, tu parles de BRAS, comme un téléphone cellulaire BRAS ? Avec peut-être 500 Mhz et de 256 MO de RAM ? Dans ce cas, le processeur est bien adapté à un à l'aide de glib, Qt ou encore python. Et D-Bus est le plus utile lors de l'écriture d'événements asynchrones pilotés par le code, avec un système intégré à la boucle principale, par exemple à partir de glib, même lorsque vous utilisez le faible niveau libdbus (il a des fonctions pour se connecter à la glib boucle principale, par exemple).
Depuis que vous utilisez le faible niveau de la bibliothèque, de la documentation est-ce que vous avez déjà:
http://dbus.freedesktop.org/doc/api/html/index.html
Aussi, libdbus code source est également partie de la documentation:
http://dbus.freedesktop.org/doc/api/html/files.html
Le principal point d'entrée de la documentation est la page Modules (en particulier, l'API publique de la section):
http://dbus.freedesktop.org/doc/api/html/modules.html
Pour le traitement des messages, la section DBusMessage est le:
DBusMessage
Là, vous avez de la documentation pour les fonctions d'analyser les valeurs des éléments. Dans votre cas, vous avez commencé avec un dbus_message_iter_get_basic. Comme décrit dans la documentation, de la récupération de la chaîne nécessite un const char ** variable, puisque la valeur retournée sera point à la pré-alloués chaîne dans le message reçu:
De sorte que vous ne pouvez pas définir un tableau, parce que libdbus de ne pas copier le texte dans le tableau. Si vous avez besoin pour économiser de la chaîne, de la première à obtenir la constante de chaîne de référence, alors la fonction strcpy à votre propre tableau.
Alors vous avez essayé d'obtenir un tableau fixe sans bouger l'itérateur. Vous avez besoin d'un appel à l'itérateur suivant (dbus_message_iter_next) entre la chaîne de base et le tableau fixe. Même juste avant recursing dans le sous itérateur.
Enfin, vous n'appelez pas get_array_len pour obtenir le nombre d'éléments du tableau. De la documentation, il ne renvoie le nombre d'octets. Au lieu de cela vous en boucle sur les sous itérateur à l'aide de iter_next de la même façon que vous devriez avoir fait avec le principal de l'itérateur. Après avoir réitéré au-delà de la fin du tableau, dbus_message_iter_get_arg_type sera de retour DBUS_TYPE_INVALID.
Pour plus d'infos, lisez le manuel de référence, ne cherchez pas un tutoriel. Ou tout simplement utiliser un raisonnable d-bus mise en œuvre:
https://developer.gnome.org/gio/2.36/gdbus-codegen.html
GIO de GDBus crée automatiquement des wrappers pour vos appels 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.
Vous n'avez pas besoin d'utiliser/de comprendre le travail de dbus Si vous avez juste besoin d'écrire un programme en C pour communiquer avec wpa_supplicant. Je l'ingénierie inverse de la wpa_cli du code source. Est passé par sa mise en œuvre et utilisés à des fonctions prévues dans le wpa_ctrl.h/c. Cette mise en œuvre s'occupe de tout. Vous pouvez utiliser/modifier ce que vous voulez, construire l'exécutable et vous avez terminé!
Voici le lien officiel pour wpa_supplicant est ctrl_interface:
http://hostap.epitest.fi/wpa_supplicant/devel/ctrl_iface_page.html
L'extrait de code ci-dessous fonctionne pour moi
Je doute que cette réponse sera toujours pertinents pour l'auteur de cette question,
mais pour quelqu'un qui tombe sur ce comme je l'ai fait:
La situation est maintenant mieux que toutes ces années, si vous ne voulez pas inclure GTK/QT dans votre projet pour accéder à dbus.
Il y a de l'API dbus dans Linux embarqué Bibliothèque par Intel (bizarre j'en ai un souvenir de l'ouvrir, peut-être que c'est seulement pour les utilisateurs enregistrés aujourd'hui?)
et systemd sd-bus de la bibliothèque offre maintenant de l'API publique. Vous avez probablement courir à systemd de toute façon, sauf si vous avez vraiment une contrainte du système embarqué.
J'ai travaillé avec GDbus, dbus-rpc et sd-bus et même si je voulais une bibliothèque C++,
J'ai trouvé sd-bus pour être le plus simple et le moins problématique de l'expérience.
Je n'ai pas essayer sa C++ liaisons, mais ils ont aussi agréable à regarder
Je m'excuse si l'exemple ci-dessus ne fonctionne pas parfaitement. C'est un extrait d'un vieux projet que j'ai réécrit à C de C++ (je pense que c'est C(-ish), le compilateur ne proteste pas et que vous avez demandé C) mais je ne peux pas le tester car tous mes dongles refuser de travailler avec mon ordinateur de bureau maintenant. Il devrait vous donner une idée générale cependant.
Notez que vous aurez probablement la chance de rencontrer plusieurs magiques ou semi-magiques questions.
Pour assurer le bon développement/essais suivants:
ip link
Aussi, parce que c'est pas bien documentée dès maintenant:
Vous pouvez accéder à des tableaux et à l'intérieur des valeurs de type variant par
sd_bus_message_enter_container
et _exit homologue.
sd_bus_message_peek_type
pourrait être utile tout en faisant cela.Ou
sd_bus_message_read_array
pour un ensemble homogène de matrice.