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

Posté par  (site web personnel) .
Étiquettes : aucune
0
10
juil.
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...
  • # g_array_index

    Posté par  . Évalué à 2.

    regarde bien, ton utilisation de g_array_index est fausse...

    si c'est un tableau de iphdr tu dois faire ça :

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

    si c'est un tableau de iphdr* tu dois faire ça :

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

    voilà...
    • [^] # Re: g_array_index

      Posté par  (site web personnel) . Évalué à 1.

      hélas non, ca me renvoi un segfault
      • [^] # Re: g_array_index

        Posté par  . Évalué à 2.

        Dans quel cas, les deux? tu mets quoi dans ton GArray?
        Peux tu donner plus d'infos sur la structure de ta variable m?
        • [^] # Re: g_array_index

          Posté par  (site web personnel) . Évalué à 1.

          j'obtiens un segfault dans le cas :

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

          quand j'utilise :

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

          j'obtiens les résultats erratiques dont je parlais dans mon premier post


          la structure "m" est de type ipq_packet_msg_t, elle contient un paquet ramené dans un hook IPQ par netfilter
          de fait, "m->payload" contient le paquet raw, le reste de la structure c'est des metadonnées IPQ qui ne m'interesse pas

          le GArray semble être fonctionnel car lorsque j'accède à "P_to_Array->len" il me retourne bien le nombre de cases que contient le tableau, et ce dans tous les cas

          de fait, je pense que mon problème vient soit de l'ajout dans le tableau, soit dans la définition du tableau avec

          value = g_array_new(FALSE, FALSE, 1500);

          ou 1500 est censé être la taille en bytes de chaque case
          • [^] # Re: g_array_index

            Posté par  . Évalué à 2.

            on avance, j'ai l'impression que à mal lu mon premier commentaire, qu'est-ce que t'obtiens dans le cas :
            struct iphdr *iph2;
            iph2 = & g_array_index(P_to_Array, struct iphdr, i);

            je pense que c'est ce cas là qui devrait marcher... et je vais t'expliquer pourquoi...

            g_array_index est défini par :
            #define g_array_index(a,t,i) (((t*) (a)->data) [(i)])

            remarque ce qu'il fait... il cast a->data en t* !!!!

            Or, toi tu lui dis de faire un cast en struct iphdr **, ce qui est faux je pense. Si j'ai raison, ça ne devrait marcher que pour le premier index, pour les autres ça devrait induire un décalage des données.
            Or chez toi tu obtiens le bon résultat pour le premier index, pas pour les autres. Ce qui semble comfirmer mon hypothèse.
            Essaie donc et dis moi si ça corrige quelquechose...
            • [^] # Re: g_array_index

              Posté par  (site web personnel) . Évalué à 1.

              je l'avais déjà essayé celle là, et ça ne résoud pas le problème


              REDIRECTION CHECK : Conn ID 128.8.37.122:13666:128.8.37.121:22 or 128.8.37.121:22:128.8.37.122:13666 is not redirected
              NETFILTER_CONNTRACK : Connection check called for 128.8.37.122:13666:128.8.37.121:22 state = activ
              PCAP_TOOL : Current packet writed to output pcap file
              STORING FUNCTION : 163st packet of 128.8.37.122:13666:128.8.37.121:22 stored in memory
              IP table: 128.8.37.122; length : 60
              IP table: 160.2.22.208; length : 22
              IP table: 0.0.0.0; length : 1460
              IP table: 1.0.0.0; length : 0
              IP table: 184.22.220.191; length : 61879
              IP table: 3.0.0.0; length : 0
              IP table: 12.0.0.0; length : 56511
              IP table: 232.114.218.183; length : 56511
              IP table: 1.0.0.0; length : 65463
              IP table: 0.0.0.0; length : 0


              Dans la doc de GLib, ils disent de ne pas mettre struct devant :

              EDayViewEvent *event;

              /* This gets a pointer to the 3rd element in the array of EDayViewEvent
              structs. */
              event = &g_array_index (events, EDayViewEvent, 3);


              mais quand je fais ca

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


              il me dit que iphdr est une variable non déclarée....
  • # Question:

    Posté par  (site web personnel) . É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  (site web personnel) . É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  (site web personnel) . É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 ...
        • [^] # Re: C'est simple:

          Posté par  (site web personnel) . É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  (site web personnel) . É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 ?
            • [^] # Re: C'est simple:

              Posté par  (site web personnel) . É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  (site web personnel) . É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....
                • [^] # Re: C'est simple:

                  Posté par  (site web personnel) . É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  (site web personnel) . É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  (site web personnel) . É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é ;)
    • [^] # Re: Question:

      Posté par  (site web personnel) . É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.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.