/* Chrysalide - Outil d'analyse de fichiers binaires * packed.c - regroupement de bribes de paquets réseau * * Copyright (C) 2017 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Chrysalide. If not, see . */ #include "packed.h" #include #include #include #include /* Taille d'allocation en cas de besoin */ #define PACKET_BLOCK_SIZE 1000 /****************************************************************************** * * * Paramètres : pbuf = paquet de données à initialiser. [OUT] * * * * Description : Initialise un paquet réseau pour une constitution. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void init_packed_buffer(packed_buffer *pbuf) { pbuf->allocated = PACKET_BLOCK_SIZE; pbuf->data = malloc(pbuf->allocated * sizeof(uint8_t)); reset_packed_buffer(pbuf); } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à réinitialiser. [OUT] * * * * Description : Réinitialise un paquet réseau pour une constitution. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void reset_packed_buffer(packed_buffer *pbuf) { pbuf->used = 0; pbuf->pos = sizeof(uint32_t); assert(pbuf->pos <= pbuf->allocated); } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à libérer. * * * * Description : Efface les données contenues par un paquet réseau. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void exit_packed_buffer(packed_buffer *pbuf) { free(pbuf->data); } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à consulter. * * * * Description : Indique le nombre d'octets de la charge utile d'un paquet. * * * * Retour : Quantité de données utiles. * * * * Remarques : - * * * ******************************************************************************/ size_t get_packed_buffer_payload_length(const packed_buffer *pbuf) { size_t result; /* Quantité à renvoyer */ result = pbuf->used; return result; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à compléter. * * buf = nouvelles données à ajouter. * * len = quantité de ces données. * * hton = indique si une conversion est à réaliser. * * * * Description : Ajoute des données à un paquet en amont à un envoi. * * * * Retour : true. * * * * Remarques : - * * * ******************************************************************************/ bool extend_packed_buffer(packed_buffer *pbuf, const void *buf, size_t len, bool hton) { uint16_t tmp16; /* Valeur intermédiaire 16b */ uint32_t tmp32; /* Valeur intermédiaire 32b */ uint64_t tmp64; /* Valeur intermédiaire 64b */ /* Réallocation nécessaire ? */ while ((pbuf->pos + len) > pbuf->allocated) { pbuf->allocated += PACKET_BLOCK_SIZE; pbuf->data = realloc(pbuf->data, pbuf->allocated * sizeof(uint8_t)); } /* Conversion au formalisme du réseau */ if (!hton) goto skip_conversion; switch (len) { case 1: *((uint8_t *)(pbuf->data + pbuf->pos)) = *((uint8_t *)buf); break; case 2: tmp16 = htobe16(*(uint16_t *)buf); *((uint16_t *)(pbuf->data + pbuf->pos)) = tmp16; break; case 4: tmp32 = htobe32(*(uint32_t *)buf); *((uint32_t *)(pbuf->data + pbuf->pos)) = tmp32; break; case 8: tmp64 = htobe64(*(uint64_t *)buf); *((uint64_t *)(pbuf->data + pbuf->pos)) = tmp64; break; default: skip_conversion: /** * Dans ce cas de figure, c'est à l'appelant de s'assurer que la * conversion a bien été réalisée. */ assert(!hton); memcpy(pbuf->data + pbuf->pos, buf, len); break; } pbuf->used += len; pbuf->pos += len; return true; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à consulter. * * buf = nouvelles données à définir. * * len = quantité de ces données. * * ntoh = indique si une conversion est à réaliser. * * * * Description : Récupère des données depuis un paquet après une réception. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool extract_packed_buffer(packed_buffer *pbuf, void *buf, size_t len, bool ntoh) { bool result; /* Bilan à retourner */ uint16_t tmp16; /* Valeur intermédiaire 16b */ uint32_t tmp32; /* Valeur intermédiaire 32b */ uint64_t tmp64; /* Valeur intermédiaire 64b */ result = ((pbuf->pos + len - sizeof(uint32_t)) <= pbuf->used); /* Conversion au formalisme du réseau */ if (!ntoh) goto skip_conversion; if (result) { switch (len) { case 1: *((uint8_t *)buf) = *((uint8_t *)(pbuf->data + pbuf->pos)); break; case 2: tmp16 = be16toh(*(uint16_t *)(pbuf->data + pbuf->pos)); *((uint16_t *)buf) = tmp16; break; case 4: tmp32 = be32toh(*(uint32_t *)(pbuf->data + pbuf->pos)); *((uint32_t *)buf) = tmp32; break; case 8: tmp64 = be64toh(*(uint64_t *)(pbuf->data + pbuf->pos)); *((uint64_t *)buf) = tmp64; break; default: skip_conversion: /** * Dans ce cas de figure, c'est à l'appelant de s'assurer que la * conversion a bien été réalisée. */ assert(!ntoh); memcpy(buf, pbuf->data + pbuf->pos, len); break; } pbuf->pos += len; } return result; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à constituer. [OUT] * * fd = flux ouvert en lecture. * * * * Description : Lit des données depuis un flux local. * * * * Retour : true si toutes les données ont été reçues, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool read_packed_buffer(packed_buffer *pbuf, int fd) { bool result; /* Bilan à retourner */ uint32_t used; /* Taille de charge utile */ result = safe_read(fd, &used, sizeof(uint32_t)); if (result) { assert(pbuf->pos == sizeof(uint32_t)); if ((pbuf->pos + used) > pbuf->allocated) { pbuf->allocated = pbuf->pos + used; pbuf->data = realloc(pbuf->data, pbuf->allocated * sizeof(uint8_t)); } pbuf->used = used; result = safe_read(fd, pbuf->data + pbuf->pos, used); } return result; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à émettre. * * fd = flux ouvert en écriture. * * * * Description : Ecrit des données dans un flux local. * * * * Retour : true si toutes les données ont été émises, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool write_packed_buffer(packed_buffer *pbuf, int fd) { bool result; /* Bilan à retourner */ *((uint32_t *)pbuf->data) = pbuf->used; result = safe_write(fd, pbuf->data, sizeof(uint32_t) + pbuf->used); return result; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à constituer. [OUT] * * fd = flux ouvert en lecture. * * * * Description : Réceptionne des données depuis un flux réseau. * * * * Retour : true si toutes les données ont été reçues, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool recv_packed_buffer(packed_buffer *pbuf, int fd) { bool result; /* Bilan à retourner */ uint32_t used; /* Taille de charge utile */ result = safe_recv(fd, &used, sizeof(uint32_t), 0); if (result) { assert(pbuf->pos == sizeof(uint32_t)); if ((pbuf->pos + used) > pbuf->allocated) { pbuf->allocated = pbuf->pos + used; pbuf->data = realloc(pbuf->data, pbuf->allocated * sizeof(uint8_t)); } pbuf->used = used; result = safe_recv(fd, pbuf->data + pbuf->pos, used, 0); } return result; } /****************************************************************************** * * * Paramètres : pbuf = paquet de données à émettre. * * fd = flux ouvert en écriture. * * * * Description : Envoie des données au travers un flux réseau. * * * * Retour : true si toutes les données ont été émises, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool send_packed_buffer(packed_buffer *pbuf, int fd) { bool result; /* Bilan à retourner */ *((uint32_t *)pbuf->data) = pbuf->used; result = safe_send(fd, pbuf->data, sizeof(uint32_t) + pbuf->used, 0); return result; }