diff --git a/headers/packet_interface.h b/headers/packet_interface.h index 86063f39ec44849cd76b1ca88802da9b5eae4608..e7fa21cb2f48a07e63bd1428885faff504ecbe42 100644 --- a/headers/packet_interface.h +++ b/headers/packet_interface.h @@ -1,58 +1,71 @@ -/** - * @file packet_interface.h - * @brief This header contains structs and definitions needed in order to encode and decode TRTP packets - */ - #ifndef __PACKET_INTERFACE_H_ #define __PACKET_INTERFACE_H_ #include <stddef.h> /* size_t */ #include <stdint.h> /* uintx_t */ +#include <unistd.h> #include <stdio.h> /* ssize_t */ +/* Taille maximale permise pour le payload */ +#define MAX_PAYLOAD_SIZE 512 +/* Taille maximale de Window */ +#define MAX_WINDOW_SIZE 31 + +#define member_size(type, member) sizeof((((type *) NULL)->member)) + +#define PKT_MAX_HEADERLEN offsetof(pkt_t, payload) +#define PKT_MIN_HEADERLEN PKT_MAX_HEADERLEN - 2 +#define PKT_CRC1LEN member_size(pkt_t, crc1) +#define PKT_FOOTERLEN (sizeof(pkt_t) - offsetof(pkt_t, crc2)) +#define PKT_MIN_LEN PKT_MIN_HEADERLEN +#define PKT_MAX_LEN (PKT_MAX_HEADERLEN + MAX_PAYLOAD_SIZE + PKT_FOOTERLEN) +#define PKT_TR_BIT_OFFSET 2 + +#define PKT_TIMESTAMP 0xdeadbeef + /* Raccourci pour struct pkt */ typedef struct pkt pkt_t; /* Types de paquets */ typedef enum { - PTYPE_FEC = 0, // added line (Samuel) - PTYPE_DATA = 1, - PTYPE_ACK = 2, - PTYPE_NACK = 3, + PTYPE_FEC = 0, + PTYPE_DATA = 1, + PTYPE_ACK = 2, + PTYPE_NACK = 3, } ptypes_t; -/* Taille maximale permise pour le payload */ -#define MAX_PAYLOAD_SIZE 512 -/* Taille maximale de Window */ -#define MAX_WINDOW_SIZE 31 /* Valeur de retours des fonctions */ typedef enum { - PKT_OK = 0, /* Le paquet a ete traite avec succes */ - E_TYPE, /* Erreur liee au champs Type */ - E_TR, /* Erreur liee au champ TR */ - E_LENGTH, /* Erreur liee au champs Length */ - E_CRC, /* CRC invalide */ - E_WINDOW, /* Erreur liee au champs Window */ - E_SEQNUM, /* Numero de sequence invalide */ - E_NOMEM, /* Pas assez de memoire */ - E_NOHEADER, /* Le paquet n'a pas de header (trop court) */ - E_UNCONSISTENT, /* Le paquet est incoherent */ + PKT_OK = 0, /* Le paquet a ÊtÊ traitÊ avec succès */ + E_TYPE, /* Erreur liÊe au champs Type */ + E_TR, /* Erreur liee au champ TR */ + E_LENGTH, /* Erreur liÊe au champs Length */ + E_CRC, /* CRC invalide */ + E_WINDOW, /* Erreur liÊe au champs Window */ + E_SEQNUM, /* NumÊro de sÊquence invalide */ + E_NOMEM, /* Pas assez de mÊmoire */ + E_NOHEADER, /* Le paquet n'a pas de header (trop court) */ + E_UNCONSISTENT, /* Le paquet est incohÊrent */ } pkt_status_code; /* Alloue et initialise une struct pkt * @return: NULL en cas d'erreur */ pkt_t* pkt_new(); -/* Libere le pointeur vers la struct pkt, ainsi que toutes les - * ressources associees - */ +/* Libère le pointeur vers la struct pkt, ainsi que toutes les + * ressources associÊes */ void pkt_del(pkt_t*); /* - * Decode des donnees recues et cree une nouvelle structure pkt. - * Le paquet recu est en network byte-order. - * La fonction verifie que: - * - Le CRC32 du header recu est le mÃÂĒme que celui decode a la fin + * Retourne la longueur du header en bytes. + */ +ssize_t predict_header_length(const pkt_t *pkt); + +/* + * DÊcode des donnÊes reçues et crÊe une nouvelle structure pkt. + * Le paquet reçu est en network byte-order. + * La fonction vÊrifie que: + * - Le CRC32 du header recu est le mÃĒme que celui decode a la fin * du header (en considerant le champ TR a 0) * - S'il est present, le CRC32 du payload recu est le meme que celui * decode a la fin du payload @@ -60,32 +73,34 @@ void pkt_del(pkt_t*); * - La longueur du paquet et le champ TR sont valides et coherents * avec le nombre d'octets recus. * - * @data: L'ensemble d'octets constituant le paquet recu - * @len: Le nombre de bytes recus + * @data: L'ensemble d'octets constituant le paquet reçu + * @len: Le nombre de bytes reçus * @pkt: Une struct pkt valide - * @post: pkt est la representation du paquet recu + * @post: pkt est la reprÊsentation du paquet reçu * - * @return: Un code indiquant si l'operation a reussi ou representant - * l'erreur rencontree. + * @return: Un code indiquant si l'opÊration a rÊussi ou reprÊsentant + * l'erreur rencontrÊe. */ pkt_status_code pkt_decode(const char *data, const size_t len, pkt_t *pkt); /* - * Encode une struct pkt dans un buffer, prÃÂĒt a ÃÂĒtre envoye sur le reseau - * (c-a-d en network byte-order), incluant le CRC32 du header et + * Encode une struct pkt dans un buffer, prÃĒt à ÃĒtre envoyÊ sur le rÊseau + * (c-à -d en network byte-order), incluant le CRC32 du header et * eventuellement le CRC32 du payload si celui-ci est non nul. + * La fonction pkt doit calculer les champs CRC elle-mÃĒme, car + * ils ne sont pas nÊcessairements prÊsents dans pkt. * - * @pkt: La structure a encoder - * @buf: Le buffer dans lequel la structure sera encodee + * @pkt: La structure à encoder + * @buf: Le buffer dans lequel la structure sera encodÊe * @len: La taille disponible dans le buffer - * @len-POST: Le nombre de d'octets ecrit dans le buffer - * @return: Un code indiquant si l'operation a reussi ou E_NOMEM si + * @len-POST: Le nombre de d'octets Êcrit dans le buffer + * @return: Un code indiquant si l'opÊration a rÊussi ou E_NOMEM si * le buffer est trop petit. */ -pkt_status_code pkt_encode(const pkt_t*, char *buf, size_t *len); +pkt_status_code pkt_encode(const pkt_t *pkt, char *buf, size_t *len); -/* Accesseurs pour les champs toujours presents du paquet. - * Les valeurs renvoyees sont toutes dans l'endianness native +/* Accesseurs pour les champs toujours prÊsents du paquet. + * Les valeurs renvoyÊes sont toutes dans l'endianness native * de la machine! */ ptypes_t pkt_get_type (const pkt_t*); @@ -106,7 +121,7 @@ uint32_t pkt_get_crc2(const pkt_t*); /* Setters pour les champs obligatoires du paquet. Si les valeurs * fournies ne sont pas dans les limites acceptables, les fonctions - * doivent renvoyer un code d'erreur adapte. + * doivent renvoyer un code d'erreur adaptÊ. * Les valeurs fournies sont dans l'endianness native de la machine! */ pkt_status_code pkt_set_type (pkt_t*, const ptypes_t type); @@ -115,9 +130,9 @@ pkt_status_code pkt_set_window (pkt_t*, const uint8_t window); pkt_status_code pkt_set_seqnum (pkt_t*, const uint8_t seqnum); pkt_status_code pkt_set_length (pkt_t*, const uint16_t length); pkt_status_code pkt_set_timestamp(pkt_t*, const uint32_t timestamp); -pkt_status_code pkt_set_crc1 (pkt_t*, const uint32_t crc1); -/* Defini la valeur du champs payload du paquet. - * @data: Une succession d'octets representants le payload +pkt_status_code pkt_set_crc1 (pkt_t*, const uint32_t crc1); +/* DÊfini la valeur du champs payload du paquet. + * @data: Une succession d'octets reprÊsentants le payload * @length: Le nombre d'octets composant le payload * @POST: pkt_get_length(pkt) == length */ pkt_status_code pkt_set_payload(pkt_t*, @@ -129,55 +144,4 @@ pkt_status_code pkt_set_payload(pkt_t*, pkt_status_code pkt_set_crc2(pkt_t*, const uint32_t crc2); -/* - * Decode un varuint (entier non signe de taille variable dont le premier bit indique la longueur) - * encode en network byte-order dans le buffer data disposant d'une taille maximale len. - * @post: place à l'adresse retval la valeur en host byte-order de l'entier de taille variable stocke - * dans data si aucune erreur ne s'est produite - * @return: - * - * -1 si data ne contient pas un varuint valide (la taille du varint - * est trop grande par rapport à la place disponible dans data) - * - * le nombre de bytes utilises si aucune erreur ne s'est produite - */ -ssize_t varuint_decode(const uint8_t *data, const size_t len, uint16_t *retval); - - -/* - * Encode un varuint en network byte-order dans le buffer data disposant d'une - * taille maximale len. - * @pre: val < 0x8000 (val peut ÃĒtre encode en varuint) - * @return: - * -1 si data ne contient pas une taille suffisante pour encoder le varuint - * - * la taille necessaire pour encoder le varuint (1 ou 2 bytes) si aucune erreur ne s'est produite - */ -ssize_t varuint_encode(uint16_t val, uint8_t *data, const size_t len); - - -/* - * @pre: data pointe vers un buffer d'au moins 1 byte - * @return: la taille en bytes du varuint stocke dans data, soit 1 ou 2 bytes. - */ -size_t varuint_len(const uint8_t *data); - - -/* - * @return: la taille en bytes que prendra la valeur val - * une fois encodee en varuint si val contient une valeur varuint valide (val < 0x8000). - -1 si val ne contient pas une valeur varuint valide - */ -ssize_t varuint_predict_len(uint16_t val); - - -/* - * Retourne la longueur du header en bytes si le champs pkt->length - * a une valeur valide pour un champs de type varuint (i.e. pkt->length < 0x8000). - * Retourne -1 sinon - * @pre: pkt contient une adresse valide (!= NULL) - */ -ssize_t predict_header_length(const pkt_t *pkt); - - #endif /* __PACKET_INTERFACE_H_ */ \ No newline at end of file diff --git a/src/packet_interface.c b/src/packet_interface.c index 81a60be5f41d86a9b2d2ed84844d1e7b898635a3..e23f9e60e4a61663e730287fd71211f0d82fe0b3 100644 --- a/src/packet_interface.c +++ b/src/packet_interface.c @@ -7,9 +7,10 @@ #include <string.h> #include <stdlib.h> -#define ACK_OR_NACK_PACKET_SIZE 12 // Bytes +#define ACK_OR_NACK_PACKET_SIZE 10 // Bytes #define FEC_PACKET_SIZE 528 // Bytes -#define DATA_ +#define CRC_SIZE 4 // Bytes +#define TIMESTAMP_SIZE 4 #define TYPE_MASK 0xC0 #define TR_MASK 0x20 @@ -38,7 +39,7 @@ struct __attribute__((__packed__)) pkt { /************* Functions definition *************/ pkt_t* pkt_new() { - pkt_t * toReturn = (pkt_t *) calloc(1, sizeof(pkt_t)); + pkt_t * toReturn = (pkt_t *) malloc(sizeof(pkt_t)); return toReturn; } @@ -126,24 +127,21 @@ pkt_status_code pkt_decode_ack_nack(const char *data, const size_t len, pkt_t *p return E_UNCONSISTENT; // REMINDER : *data will read the first byte - ptypes_t type = ((*data) & 0xC0) >> 6; - if ( type != PTYPE_ACK && type != PTYPE_NACK ) - return E_TYPE; - - if ( ((*data) & 0x20) != 0) + ptypes_t type = ((*data) & TYPE_MASK) >> TYPE_SHIFT; + if ( ((*data) & TR_MASK) != 0) return E_TR; uint8_t seqnum, window; memcpy((char *) &seqnum, data+1, 1); memcpy((char *) &window, data, 1); - window = window & 0x1F; + window = window & WINDOW_MASK; if ( seqnum > window ) return E_SEQNUM; // CheckSum no need to set TR at 0 as it should be at 0 uint32_t crc1; - memcpy((void *) &crc1, data+8, 4); - crc1 = ntohl((uint32_t) crc1); + memcpy((void *) &crc1, data+6, 4); + crc1 = ntohl(crc1); if ( calculate_crc(data, 4) != crc1 ) return E_CRC; @@ -166,14 +164,55 @@ pkt_status_code pkt_decode(const char *data, const size_t len, pkt_t *pkt) return pkt_decode_data_fec(data, len, pkt); } -pkt_status_code pkt_encode(const pkt_t *pkt, char *buf, size_t *len) +pkt_status_code pkt_encode_ACK_NACK(const pkt_t *pkt, char *buf, size_t *len) +{ + size_t required = ACK_OR_NACK_PACKET_SIZE; + if (*len < required) + return E_NOMEM; + memcpy((void *) buf, (void *) &(pkt->header.front), 1); + memcpy((void *) buf+1, (void *) &(pkt->header.seqnum), 1); + uint32_t n_timestamp = htons(pkt_get_timestamp(pkt)); + memcpy((void *) buf+2, (void *) &n_timestamp, 4); + uint32_t crc1 = htonl(calculate_crc(buf, 4)); + memcpy((void *) buf+6, (void *) &crc1, CRC_SIZE); + *len = ACK_OR_NACK_PACKET_SIZE; + return PKT_OK; +} + +pkt_status_code pkt_encode_DATA_FEC(const pkt_t *pkt, char *buf, size_t *len) { - if (pkt->header.front == 0 && buf[0] == 'c' && len == 0) - return PKT_OK; + size_t required = sizeof(header_t) + TIMESTAMP_SIZE + CRC_SIZE + pkt_get_length(pkt) + CRC_SIZE; + if ( *len < required ) + return E_NOMEM; + memcpy((void *) buf, (void *) &(pkt->header.front), 1); + uint16_t n_length = htons(pkt_get_length(pkt)); + memcpy((void *) buf+1, (void *) &n_length, 2); + memcpy((void *) buf+3, (void *) &(pkt->header.seqnum), 1); + uint32_t n_timestamp = htons(pkt_get_timestamp(pkt)); + memcpy((void *) buf+4, (void *) &n_timestamp, 4); + uint32_t crc1 = htonl(calculate_crc(buf, 4)); + memcpy((void *) buf+8, (void *) &crc1, CRC_SIZE); + memcpy((void *) buf+12,(void *) pkt->payload, pkt_get_length(pkt)); + uint32_t crc2 = htonl(calculate_crc(buf+12, pkt_get_length(pkt))); + memcpy((void *) buf+12+pkt_get_length(pkt), (void *) &crc2, CRC_SIZE); + *len = sizeof(header_t) + TIMESTAMP_SIZE + CRC_SIZE + pkt_get_length(pkt) + CRC_SIZE; return PKT_OK; } + +pkt_status_code pkt_encode(const pkt_t *pkt, char *buf, size_t *len) +{ + ptypes_t type = pkt_get_type(pkt); + if ( type == PTYPE_ACK || type == PTYPE_NACK ) + return pkt_encode_ACK_NACK(pkt, buf, len); + else if ( type == PTYPE_DATA || type == PTYPE_FEC) + return pkt_encode_DATA_FEC(pkt, buf, len); + else + return E_UNCONSISTENT; +} + + /** GETTER */ ptypes_t pkt_get_type (const pkt_t* pkt) { diff --git a/src/test.c b/src/test.c new file mode 100644 index 0000000000000000000000000000000000000000..5997b46238e484550f69bc6ca833e1247082b975 --- /dev/null +++ b/src/test.c @@ -0,0 +1,18 @@ +#include "packet_interface.h" + +#include <arpa/inet.h> +#include <zlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +int main(int argc, char const *argv[]) +{ + if (argc < 2) + return 1; + pkt_t * pkt = pkt_new(); + int err = pkt_decode(argv[1], 10, pkt); + printf("Returned %d\n", err); + return 0; +} diff --git a/test b/test deleted file mode 100755 index 6a4d932ce38e508374b215828ab9d9780ddde912..0000000000000000000000000000000000000000 Binary files a/test and /dev/null differ diff --git a/test.c b/test.c deleted file mode 100644 index 5a5644f804aa58e9c9e69ee54797622c6f64bc16..0000000000000000000000000000000000000000 --- a/test.c +++ /dev/null @@ -1,9 +0,0 @@ -#include <stdio.h> -#include <zlib.h> - -int main() { - char * arr = "123456789"; - printf("%ld\n", crc32(0, (const void *) arr, 9)); - return 0; -} - \ No newline at end of file