Faire un don ! | | style | statistiques | contactez-nous | plan | lettre d'information

Programmation.c : Galère de pointeurs avec les GArrays

Posté par Julien Vehent (Jabber id, page perso, ) le 10 juillet 2007
Bonjour à tous,



J'ai besoin de stocker les paquets que composent une communications dans un programme C.

Comme j'ai beaucoup de communications, j'ai commencé par faire un B-Tree dans lequel chaque valeur (associée à une clé) est un GArray qui contient les paquets de la communication.



Le soucis, c'est que ça bug... les 2 premiers paquets de chaque com. sont bien enregistrés et repris, mais pour les suivants j'ai des résultats bizarres...



voilà mon code :



/*!******************************

* *

* search the entry *

* *

* ******************************/

if (

TRUE != g_tree_lookup_extended(Storing_B_Tree, key_one->str, NULL, NULL)

&&

TRUE != g_tree_lookup_extended(Storing_B_Tree, key_two->str, NULL, NULL)

)

{

/*! if doesn't exist, create it and init the GArray

* as a value for this entry

*/

GArray *value;



/*! Creates a new GArray as a B-Tree value to store the packets of this connection

*/

value = g_array_new(FALSE, FALSE, 1500);



g_array_append_val(value, m->payload);



/*! add it to the tree, value contain the address of the pointer to the array in the memory

*/

g_tree_insert(Storing_B_Tree, key_one->str, value);



g_print("STORING FUNCTION : entry created and packet %s stored in memory\n",key_one->str);



}

else {

/*! the tuple exist in the B-Tree, so add the packet at the end of the

* existing GArray table

*/

GString *key;

key = key_one;



GArray *P_to_Array;

/*! get @ of the array in memory */

if (TRUE != g_tree_lookup_extended(Storing_B_Tree, key_one->str, NULL, (gpointer *) &P_to_Array))

{

/*! if key_one is not the good key, try with key_two */

g_tree_lookup_extended(Storing_B_Tree, key_two->str, NULL,(gpointer *) &P_to_Array);

key = key_two;

}



/*! store the value at the end of the GArray table

*/

g_array_append_val(P_to_Array, m->payload);



g_print("STORING FUNCTION : %dst packet of %s stored in memory\n",P_to_Array->len, key->str);



/*! TEST PURPOSE

*

* print all the entries from the corresponding array

*/

int i;



for (i=0; i < P_to_Array->len; i++)

{

struct iphdr *iph2;



iph2 = & g_array_index(P_to_Array, struct iphdr *, i);



g_print("IP table: %s; length : %u\n",(char *) inet_ntoa(iph2->saddr), ntohs(iph2->tot_len));

}





}







et voila ce que donne une exécution, les 2 premières IP sont bien reprises mais les suivantes ne sont pas bonnes

dans le second paquet, la "length" est également fausse...



STORING FUNCTION : 4st packet of 128.8.37.122:56107:130.92.6.40:80 stored in memory

IP table: 128.8.37.122; length : 52

IP table: 130.92.6.40; length : 16384

IP table: 219.43.0.80; length : 52160

IP table: 15.53.67.83; length : 9594





Alors j'essaie de comprendre pourquoi je ne récupère pas bien mes paquets.... Il me semble que GArray attribue un nouvel index pour chaque entrée, je ne devrais donc pas dépasser sur les autres index lorsque je récupère mon entrée...

> Lire le message (17 commentaires, moyenne: 1,6).  

Vous avez demandé le commentaire #850046.

Question:

Posté par liberforce (Jabber id, page perso, ) le 11/07/2007 à 08:34. (lien). Évalué à 2.

Pourquoi utilises tu un GArray si c'est pour y mettre un seul élément ? Fais juste un g_new/g_new0, ou mieux, un g_slice_alloc/g_slice_alloc0.

  • [^]Re: Question:

    Posté par liberforce (Jabber id, page perso, ) le 11/07/2007 à 12:40. (lien). Évalué à 2.

    Ah, en plus pour copier tes 52 octets, tu en lis 1500 (donc que tu lis n'importe qui dans la mémoire).

    • [^]Re: Question:

      Posté par Julien Vehent (Jabber id, page perso, ) le 11/07/2007 à 12:50. (lien). Évalué à 1.

      Voila, on y arrive, GArray m'impose de spécifier une taille pour chaque élément mais la taille de mes éléments est variable....

      un paquet va être un TCP/SYN, donc tout petit, le suivant va être un PUSH/ACK de 1200 octets.... bref, pas de taille fixe

      De fait, j'espérais que GArray s'occuperait de l'indexation proprement, mais on dirait que ce n'est pas le cas. De fait, je vois pas trop de solutions pour stocker mon bazard... si vous avez une idée ...

      --
      www.linuxwall.info
      • [^]Re: C'est simple:

        Posté par liberforce (Jabber id, page perso, ) le 11/07/2007 à 14:48. (lien). Évalué à 2.

        GArray est fait pour stocker plein d'objets de taille fixe, pour ne pas avoir besoin d'allocation dynamique. Pour toi ce n'est pas possible, car tes objets ne font pas tous la même taille. Tu pourrais dans ce cas utiliser GPtrArray qui est fait pour stocker un pointeur vers des données (que tu allouerais dynamiquement), mais dans ce cas aussi, tu perds la taille de tes données.

        Conclusion: si tu veux pouvoir accéder à tes données sans risquer d'aller lire en dehors des limites du buffer où elles se trouvent, tu dois utiliser une structure qui contient:
        - la taille de ton buffer
        - un pointeur vers ton buffer de données

        Tu peux le faire à la main, c'est simple, mais si tu n'as pas envie de te prendre la tête, tu utilise une GString, qui le fait à ta place . Si tu la crées avec g_string_new_len, tu peux spécifier la taille de tes données, et dans ce cas là, la chaine à copier est autorisée à contenir des caractères '\0'. Ton code ressemblera alors à :
        value = g_string_new_len(m->payload, m->data_len);
        g_tree_insert(Storing_B_Tree, key_one->str, value);


        Tu accèdes ensuite à ton buffer avec value->str et tu en connais la taille grâce à value->len. Avec ça tu ne consommes juste ce qu'il faut de mémoire, pas plus, et connais toujours la longueur de tes données.

        • [^]Re: C'est simple:

          Posté par Julien Vehent (Jabber id, page perso, ) le 11/07/2007 à 15:03. (lien). Évalué à 1.

          Ok merci pour l'explication, ça confirme ce que je pensais....

          le soucis, c'est que je n'ai pas qu'un seul élément à stocker dans la valeur de mon B-Tree, mais bien une liste d'élément

          je vais me faire une structure du type :
          - taille du buffer
          - pointeur vers le buffer
          - pointeur vers le buffer suivant

          à moins que GLib ais un type pour créer des listes chaînées directement ?

          --
          www.linuxwall.info
          • [^]Re: C'est simple:

            Posté par liberforce (Jabber id, page perso, ) le 11/07/2007 à 16:09. (lien). Évalué à 2.

            Hum... Tu es sûr que c'est bien une liste que tu dois utiliser ? Tu es sûr que ce n'est pas juste un nouveau noeud dans le btree ? Sinon, pour les listes, oui la GLib en a: GSList pour les listes simplement chainées, et GList pour les listes doublement chainées. Pour connaitre tous les types d'éléments fournis par la GLib, regarde la doc: http://developer.gnome.org/doc/API/2.0/glib/glib-data-types.(...)

            Mais qu'est ce que tu essaie de faire au juste ?

            • [^]Re: C'est simple:

              Posté par Julien Vehent (Jabber id, page perso, ) le 11/07/2007 à 16:53. (lien). Évalué à 1.

              Je vois passer TOUTES les connections réseaux d'une machine

              donc pour chaque connexion réseau, je crée une entrée dans le B-Tree. La clé de cette entrée est le tuple Source IP + Source Port + Dest IP + Dest Port.

              maintenant, il faut également que je conserve TOUS les paquets de chaque connection, et je veux pouvoir retrouver facilement les paquets d'une connections spécifique

              donc, je pensais lier un tableau, ou une liste chaînées, a la valeur de mon entrée dans le B-Tree

              ca donne un truc comme ca :
              http://jvehent.free.fr/ressources/connerie/Store-connections(...)

              De fait, j'ai modifié mon code pour utiliser une GSList mais ca marche pas encore... j'insére et je récupère bien mon pointeur mais j'ai l'impression que les données ne sont plus en mémoire....

              --
              www.linuxwall.info
              • [^]Re: C'est simple:

                Posté par liberforce (Jabber id, page perso, ) le 11/07/2007 à 21:36. (lien). Évalué à 2.

                Hum... Quel est l'intérêt d'un B-tree par rapport à une table de hachage dans ce cas ? Tu peux faire une table de hachage contenant tes listes de paquets correspondant à ta connnexion.
                http://developer.gnome.org/doc/API/2.0/glib/glib-Hash-Tables(...)

                Si l'ordre d'arrivée des paquets est important, tu peux même utiliser les files.
                http://developer.gnome.org/doc/API/2.0/glib/glib-Double-ende(...)
                L'avantage est que tu peux rajouter un élément à la fin en temps constant. Tu n'as pas besoin de parcourir la liste entière pour rajouter cet élément à la fin. En tout cas vu ce que tu veux faire, c'est la solution que j'adopterais, à moins qu'il n'y ait une bonne raison (que je ne vois pas) pour utiliser un B-tree...

                [^]Re: C'est simple:

                Posté par liberforce (Jabber id, page perso, ) le 11/07/2007 à 21:42. (lien). Évalué à 2.

                Ah, et je te recommande refaire un peu le point sur le fonctionnement de l'allocation mémoire et les pointeurs. Là j'ai l'impression que tu vas un peu trop vite en besogne. C'est pas méchant hein, mais c'est bien de bien maitriser le langage avant l'API.

                Reposte ton code quand tu auras quelque chose, je te filerai un coup de main.

                • [^]Re: C'est simple:

                  Posté par Julien Vehent (Jabber id, page perso, ) le 11/07/2007 à 22:13. (lien). Évalué à 1.

                  je repose tant que possible, mais n'étant pas développeur et codant en C une fois par an, les histoires de pointeurs ça repart aussi vite que ça revient

                  et c'était bien la que se trouvais le problème, car je stockais mal l'adresse de mon payload dans ma liste...
                  maintenant je fait ca :

                  New_List = g_slist_append(New_List, & m->payload);

                  et je récup avec ca

                  struct iphdr *iptest = (struct iphdr *) g_slist_nth_data(P_to_List, index);

                  et, forcément, ca marche !!!!

                  Pour ce qui est du design, j'ai choisi les B-Tree car je lit plus que je n'écris, de fait je gagne un peu en rapidité... menfin, B-Tree ou Hash Table, le résultat est le meme : c'est juste un point d'accès pour ma liste chaînée

                  Merci pour le coup de main, ca m'a bien aidé ! De toute façon, vous risquez de me revoir poster pendant l'été ;)

                  --
                  www.linuxwall.info

    [^]Re: Question:

    Posté par liberforce (Jabber id, page perso, ) le 11/07/2007 à 14:52. (lien). Évalué à 2.

    Ah, pour les g_slice_*, ce n'est intéressant que si tous les objets ont la même taille. Donc si tu veux allouer/désallouer plein d'objets de 15000 octets, c'est ce qu'il faut utiliser. Mais là dans ton cas, vu que la taille des données est variable, ce n'est pas indiqué: autant ne stocker que ce dont tu as besoin.