/* 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)
init_packed_buffer(pbuf);
else
{
pbuf->allocated = sizeof(uint32_t) + used;
pbuf->data = malloc(pbuf->allocated * sizeof(uint8_t));
pbuf->used = used;
pbuf->pos = sizeof(uint32_t);
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)
init_packed_buffer(pbuf);
else
{
pbuf->allocated = sizeof(uint32_t) + used;
pbuf->data = malloc(pbuf->allocated * sizeof(uint8_t));
pbuf->used = used;
pbuf->pos = sizeof(uint32_t);
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;
}