diff --git a/Notes.md b/Notes.md index c4d7d4b..f0fd541 100644 --- a/Notes.md +++ b/Notes.md @@ -7,3 +7,9 @@ s ⊕ n = (s + n) and 65535 s ≼ s ′ lorsque ((s ′ − s) mod 2 16 ) < 32768 s ≼ s ′ lorsque ((s ′ − s) and 32768) = 0 + +------- + +jch.irif.fr port UDP 1212 + +http://jch.irif.fr:8082/ diff --git a/src/Notes.md b/src/Notes.md new file mode 100644 index 0000000..5137b8a --- /dev/null +++ b/src/Notes.md @@ -0,0 +1,4 @@ +# Notes et recherches sur le projet + +Telecharger la librarie OpenSSl avec 'sudo apt-get install libssl-dev' +Utiliser 'gcc -o {exec} {fichier.c} -lssl -lcrypto' pour utiliser la librarie OpenSSL \ No newline at end of file diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..084ce3a --- /dev/null +++ b/src/README.md @@ -0,0 +1,5 @@ +# dazibao + +Le but de ce projet est d’implémenter un dazibao (« journal à grandes lettres »), semblable à +un « mur » de réseau social, mais de façon complètement distribuée. Le protocole est basé sur un +algorithme non-fiable d’inondation. \ No newline at end of file diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..287e2c4 --- /dev/null +++ b/src/hash.c @@ -0,0 +1,60 @@ +#include "hash.h" + +// Hash a single data +void hash_data(pub_data *data, unsigned char *buf) { + // All three fields are concatenated into a single buffer + int totlen = data->length + 10; + unsigned char concat[totlen]; + concat_data(data, concat); + + // The resulting buf is hashed and put into a buffer + unsigned char hash[SHA256_DIGEST_LENGTH]; + SHA256(concat, totlen, hash); + + // Put truncated hash into buf + hash_trunc(hash, buf); +} + +// Hash every data contained in data_list then return a network hash +void hash_network(list *data_list, unsigned char *buf) { + unsigned char *concat = (unsigned char*) malloc(0); + unsigned char hash[SHA256_DIGEST_LENGTH]; + int totlen = 0; + list *tmp = data_list; + + // Hash every known data and concatenate it to buffer concat + while(tmp != NULL) { + hash_data((pub_data*) tmp->data, hash); + concat_hash(concat, hash, totlen); + totlen += 16; + tmp = tmp->next; + } + + // Hash all of concat to obtain the network hash + SHA256(concat, totlen, hash); + + // Put truncated hash into buf + hash_trunc(hash, buf); + + // Get rid of concat + free(concat); +} + +// Truncate 32 octet hash to 16 octets +void hash_trunc(unsigned char *hash32oct, unsigned char *buf) { + // Copy the first 16 octets from hash32oct + memcpy(buf, hash32oct, 16); +} + +// Concat all fields of data and put them in buf +void concat_data(pub_data *data, unsigned char *buf) { + memcpy(buf, &(data->id), 8); + memcpy(buf+8, &(data->seqno), 2); + memcpy(buf+10, data->data, data->length); +} + +// Concat hash2 to hash1 (hash1 is modified) +void concat_hash(unsigned char *hash1, unsigned char *hash2, size_t size) { + hash1 = (unsigned char*) realloc(hash1, size + 16); + memcpy(hash1+size, hash2, 16); +} \ No newline at end of file diff --git a/src/hash.h b/src/hash.h new file mode 100644 index 0000000..358c7b5 --- /dev/null +++ b/src/hash.h @@ -0,0 +1,23 @@ +#ifndef HASH_H +#define HASH_H + +#include +#include "node.h" +#include "tlv.h" + +// Hash a single data +void hash_data(pub_data *data, unsigned char *buf); + +// Hash every data contained in data_list then return a network hash +void hash_network(list *data_list, unsigned char *buf); + +// Truncate 32 octet hash to 16 octets +void hash_trunc(unsigned char *hash256bit, unsigned char *buf); + +// Concat all fields of data and put them in buf +void concat_data(pub_data *data, unsigned char *buf); + +// Concat hash2 to hash1 (hash1 is modified) +void concat_hash(unsigned char *hash1, unsigned char *hash2, size_t size); + +#endif \ No newline at end of file diff --git a/src/install.sh b/src/install.sh new file mode 100755 index 0000000..bf11d28 --- /dev/null +++ b/src/install.sh @@ -0,0 +1 @@ +sudo apt-get install libssl-dev \ No newline at end of file diff --git a/src/node.c b/src/node.c index fdfb6fe..fbe2830 100644 --- a/src/node.c +++ b/src/node.c @@ -1,79 +1,371 @@ // This is the main file of the Dazibao project. It represents the node, and // handles all of the main logic, including the network connexions. +#include +#include +#include +#include +#include +#include +#include +#include "tlv.h" +#include "node.h" -// Will return a packet when we receive one that's valid. -packet listen_for_packets(){ +/* ---- Fonctions utilitaires ---- */ +// Get list length +int len_list(list *l) { + int len = 0; + list *tmp = l; + + while(tmp != NULL) { + tmp = tmp->next; + len++; + } + + return len; } -int validate_tlvs(union tlv tlv_to_validate){ - // We need to make sure the TLV announces a length that will no go onto - // another tlv, as we might end up reading bullshit. +// Get a random neighbour +neighbour_peer *get_random_neighbour() { + // Get a random number + time_t t; + srand((unsigned) time(&t)); + int n = rand() % len_list(neighbour_list); + + // Get nth neighbour + list *tmp = neighbour_list; + + for(int i=0; inext; + } + + return (neighbour_peer*) tmp->data; } -void work_with_tlvs(struct tlvs_list receivied_tlvs){ +/* ---- Fin fonctions utilitaires ---- */ - // For every TLV, - // We make sure the TLV is legal. - if(!validate_tlvs(tlv)){ - perror(">> Invalid TLV receivied, is will be ignored."); +int send_tlv(struct tlv tlv_to_send, int tlv_type, struct sockaddr_in6 * dest_list[], int dest_list_size, int sock_num){ + debug_print("Building packet to send a TLV."); + + // We first need to build the packet, + char packet_buff[1024]; + struct packet pack; + + pack.magic = 95; + pack.version = 1; + if(sizeof(tlv_to_send) > 1020){ + debug_print("Unable to send TLV, the size is bigger than 1020 bits."); + return -1; + } else { + pack.length = sizeof(tlv_to_send); + strcpy(pack.body, (char) tlv_to_send); + } + + // Casting the struct to a buffer. + packet_buff = (char *) pack; + + debug_print("Packet has been built."); + + // Vectorized buffer + struct iovec vec_buff = { .iov_len = sizeof(packet_buff), .iov_base = packet_buff }; + + int error_while_sending = 0; + + // For every dest + for (size_t i = 0; i < dest_list_size; i++) { + // Creating the struct to send out with sendmsg + struct msghdr packet_tlv_send_out = { + .msg_name = &dest_list[i], + .msg_namelen = sizeof(dest_list[i]), + .msg_iov = &vec_buff, + .msg_iovlen = 1 // We have only one iovec buffer. But if we had 2, we would write 2. + }; + + response_code = sendmsg((int) sock_num, &packet_tlv_send_out, 0); + if (response_code < 0) { + debug_print("Unable to send out the packet to peer %i", i); + error_while_sending = 1; + continue; + } else if (response_code < sizeof(packet_tlv_send_out)) { + debug_print("Sent out only part of the packet."); + error_while_sending = 1; + continue; + } else { + debug_print("Send out packet to peer %i", i); + } + } + + if (error_while_sending == 1) { + debug_print("Error occured while sending out a packet."); + return -1; + } else { + return 0; + } +} + +// We need to make sure the TLV announces a length that will no go onto +// another tlv, as we might end up reading bullshit. +int validate_tlv(char *data, int pos, short packet_len){ + char type = data[pos]; + + // Nothing to do in this case + if(type == 0) + return 0; + + // Check that we can read a length + if(pos + 1 >= packet_len) + return -1; + + unsigned char tlv_len = data[pos+1]; + + // Check that the tlv does not exceed the packet length + if(pos + length >= packet_len) + return -1; + + // Returns the type of the tlv or -1 if something went wrong + switch(type) { + case 1: + return 1; + case 2: + if(tlv_len != LEN_NEIGHBOUR_REQ) return -1; + return 2; + case 3: + if(tlv_len != LEN_NEIGHBOUR) return -1; + return 3; + case 4: + if(tlv_len != LEN_NETWORK_HASH) return -1; + return 4; + case 5: + if(tlv_len != LEN_NETWORK_STATE_REQ) return -1; + return 5; + case 6: + if(tlv_len != LEN_NODE_HASH) return -1; + return 6; + case 7: + if(tlv_len != LEN_NODE_STATE_REQ) return -1; + return 7; + case 8: + if(tlv_len < MIN_LEN_NODE_STATE || tlv_len > MAX_LEN_NODE_STATE) return -1; + return 8; + case 9: + return 9; + default: + return -1; + } +} + +// For every packet recivied, +// then we make sure it's conform +// We then extract the data from it to make it easy to work with +int check_header(char * req[], int buffer_size, struct packet * packet_to_return){ + + packet * packet_to_return = (packet*) req; + + // We need to check a few things ; + // The first byte must be worth 95, + if (packet_to_return->magic != 95) { + perror(">> The magic number of the packet is no good."); + return -1; + } + + // The second byte must be worth 1, + if (packet_to_return->version != 1) { + perror(">> The version number of the packet is no good."); + return -1; + } + + if (packet_to_return.length + 4 > buffer_size ) { + perror(">> The packet length is bigger than the UDP datagram, which is not possible with the current laws of physics."); + return -1; + } + + return 0; +} + +// If the sender is not in the neighbourhood, and we have 15 neighbours, we +// ignore the packet. Otherwise, we add him to the neighbourhood, marked as +// temporary. +int update_neighbours(){ + return 0; +}; + +// We then look at the differents TLVs in the packet. +void work_with_tlvs(char *data, short packet_len, struct sockaddr_in6 sender){ + int pos = 0; + unsigned char tlv_len; + tlv tmp_tlv; + + while(pos < packet_len) { + switch(validate_tlv(data, pos, packet_len)) { + case 0: + // We received a padding tlv so it is ignored + pos += 1; + break; + case 1: + // We received a padding tlv so it is ignored + tlv_len = data[pos+1]; + pos += tlv_len + 2; + break; + case 2: + // We received a neighbour request so a random neighbor tlv has to be sent + tlv_len = data[pos+1]; + pos += tlv_len + 2; + + // Send a neighbour tlv + neighbour_peer *random = get_random_neighbour(); + build_neighbour(&tmp_tlv, random->ip, random->port); + + // NOT FINISHED - What packet is it added to? + add_tlv(packet, &tmp_tlv, 3); + break; + case 3: + // We received a neighbour tlv so a tlv network hash is sent to that address + neighbour* cur_tlv = ((neighbour*) data) + pos; + struct in6_addr ip = cur_tlv->ip; + short port = cur_tlv->port; + + tlv_len = data[pos+1]; + pos += tlv_len + 2; + + // Build network hash + unsigned char hash[16]; + hash_network(neighbour_list, hash); + build_network_hash(&tmp_tlv, hash); + + // NOT FINISHED - What packet is it added to? + add_tlv(packet, &tmp_tlv, 4); + break; + case 4: + // We reveived a network hash tlv so + tlv_len = data[pos+1]; + pos += tlv_len +2; + + // NOT FINISHED - Where is network_hash? + build_neighbour(&tmp_tlv, network_hash); + // NOT FINISHED - What packet is it added to? + add_tlv(packet, &tmp_tlv, 4); + break; + case 5: + // We received a network state request tlv so a series of tlv node hash have to be sent for each data known + pos += 2; + + // NOT FINISHED - for each known data + list *tmp_list = data_list; + pub_data *tmp_data; + + while(tmp_list != NULL) { + tmp_data = (pub_data*) tmp_list->data; + build_node_hash(&tmp_tlv, tmp_data->id, tmp_data->seqno); + } + + break; + case 6: + // We received a node hash tlv + break; + case 7: + // We received a node state request tlv + break; + case 8: + // We received a node state tlv + break; + case 9: + // We received a warning tlv so it's message is printed + break; + default: + return ; + } + } +} + +// We listen forever for new paquets; +void listen_for_packets(){ + + // Create new socket for UDP + int s = socket(AF_INET6, SOCK_DGRAM, 0); + + if(s < 0) { + perror(">> Error, cannot create socket."); + perror(">> Exiting..."); + exit(1); + } + + struct sockaddr_in6 server; + memset(&server, 0, sizeof(server)); + + server.sin6_family = AF_INET6; + server.sin6_port = htons(LISTEN_PORT); + int rc = bind(s, (struct sockaddr*)&server, sizeof(server)); + if(rc < 0) { + perror(">> Error, cannot bind socket to choosen port."); + perror(">> Exiting..."); + exit(1); + } + + // A paquet has at most a length of 1024 bytes + char req[1024]; + struct sockaddr_in6 sender; + struct iovec io = { .iov_len = 1024, .iov_base = req }; + struct msghdr msg_to_receive = { + .msg_name = &sender, + .msg_namelen = sizeof(sender), + .msg_iov = &io, + .msg_iovlen = 1 + }; + while(1){ + memset(req, '\0', 1024); + + rc = recvmsg(s, &msg_to_receive, 0); + if(rc < 0) { + perror(">> Error while receiving a new datagram."); + perror(">> Ignoring, continuing..."); + continue; } - // Switch + printf(">> New paquet received :\n"); + printf("%s\n", req); - // TLV Network Hash - // We calculate a network hash, + // TODO : Here, we need to fork. - // We compare both, + // We verify the received packet is well formated, + // and we return it in the struct designed to work with it. + struct packet * formated_rec_datagram; + if(check_header(&req, 1024, formated_rec_datagram) < 0){ + perror(">> Error while checking the header, aborting this packet, by choice, and conviction."); + continue; + } - // If they differ, we send a TLV Network State Request - // back to the sender. + // TODO : Add the neighbour check here. - // TLV Network State Request - // We check our neighbourhood, and for each peer, we send back - // to the sender a TLV Node Hash - - // TLV Node hash - // We get a hash _h_ for the node _l_ - // If we don't have an entry for _l_, or if we have the same one as the - // on we just receivied, we send out a TLV Node State Request back. - - // TLV Node State - // We get a hash _h_, sequence number _s_, data _d_ for node _l_. - // We compute a network hash, - // We compare the hash, if they differ, then with l',s',d' our data and - // h' the corresponding hash, - // if _l_ is our own node id, then - // if s >> s' then we update our sequence number to s ⊕ 1 mod 2^16 - // If it's another's node id, then - // If there is no entry for the sender, - // we store the entry in our data table. + // struct tlv_list received_tlvs; + // if (validate_tlvs(formated_rec_datagram) < 0) + int nbr_success_tlv = work_with_tlvs(formated_rec_datagram, &req, sender); + if (nbr_success_tlv < 0){ + perror(">> Error while treating the TLVs of the packet."); + printf(">> Managed to deal with %i TLVs\n", -nbr_success_tlv ); + } else { + printf(">> Done working with the TLVs of the packet, listenin for new packets.\n"); + } + } } -int main(int argc, char const *argv[]) { +int main(int argc, const char *argv[]) { + int cont = 1; - while(CONTINUE){ + while(cont){ // We create the neighbourhood table + neighbour_peer neighbour_list[NEIGHBOUR_MAX]; // We create the message table + // We create our own message. // Listen for incoming packets listen_for_packets(); - // For every packet recivied, we fork, - // then we make sure it's conform - // We then extract the data from it to make it easy to work with - check_header(); - // If the sender is not in the neighbourhood, and we have 15 neighbours, we - // ignore the packet. Otherwise, we add him to the neighbourhood, marked as - // temporary. - update_neighbours(); - // We then look at the differents TLVs in the packet. - work_with_tlvs(); + // This is in it's own fork. time_t delay = time(NULL) + 20; - while(! (delay < time(NULL)){ + while(! (delay < time(NULL))) { // Theses functions are there for general book-keeping,and run in there own // thread, being run every 20 seconds. // Every 20 sec, if we have less than 5 neighbours, we ask for more peers diff --git a/src/node.h b/src/node.h index 21329be..0f7e2c6 100644 --- a/src/node.h +++ b/src/node.h @@ -1,19 +1,93 @@ // Define constants +#ifndef NODE_H +#define NODE_H + +#include +#include +#include +#include +#include +#include +#include + +#include "tlv.h" +#include "hash.h" + +// On which port do we listen to +#define LISTEN_PORT 1212 + +// The node ID +#define NODE_ID 42675882021843277 + +// The number of neighbours +// The neighbour table has 15 entries +#define NEIGHBOUR_MAX 15 + +/* la table de voisins, qui est indexée par adresses de socket (des paires (IP, Port)), + * et dont chaque entrée contient un booléen indiquant si le pair est permanent + * (configuré au lancement) ou transitoire, et la date de dernière réception d’un + * paquet de la part de ce pair ; +*/ +typedef struct neighbour_peer { + struct in6_addr ip; + short port; + char is_temporary; + struct timeval last_seen; +} neighbour_peer; + +// The strucuture to hold the messages +/* It's a list of triplets, (Li,Si,Di) + * Li : The Node ID of the publisher 64 bits + * Si : the sequence number 16 bits + * Di : the data of the message 192 bytes +*/ + +typedef struct pub_data { + unsigned char length; + long id; + short seqno; + char *data; +} pub_data; + +// General list +typedef struct list { + void *data; + void *next; +} list; + +// Static variables +static list *data_list; +static list *neighbour_list; + +// TODO // fonctions signatures void listen_for_packets(); -void check_header(); +int check_header(char * received_datagram[], int len, struct packet pack); -void update_neighbours(); +int validate_tlvs(struct packet * pack, struct tlv_list * tlv_l); -void work_with_tlvs(); +int update_neighbours(); -int validate_tlvs(); +int work_with_tlvs(struct packet received_packet, char * data_from_packet[], struct sockaddr_in6 sender); + +void add_tlv(packet *packet, tlv *tlv, char type); + +int send_packet(); + +/* Takes a TLV and sends it over to everyone in the list of addresses. + * Returns -1 in case of error, 0 otherwise. + */ +int send_tlv(struct tlv tlv_to_send, int tlv_type, struct sockaddr_in6 * dest_list[], int dest_list_size, int socket_num); + +/* Takes a list of TLV and sends them over to everyone in the list of addresses. + * Returns -1 in case of error, 0 otherwise. + */ +int send_tlvs(struct list * tlv_list, int tlv_type, struct sockaddr_in6 * dest_list[], int dest_list_size, int socket_num); // threaded functions - void t_ask_for_more_peers(); void t_update_neighbours(); @@ -21,6 +95,8 @@ void t_update_neighbours(); void t_get_network_state(); // Helper functions -char * hash(); +int len_list(list *l); -short * get_seq_no(short s, int n); +neighbour_peer *get_random_neighbour(); + +#endif diff --git a/src/parser.c b/src/parser.c new file mode 100644 index 0000000..e4acb03 --- /dev/null +++ b/src/parser.c @@ -0,0 +1,32 @@ +#include "parser.h" + +// retourne le type de commande à exécuter +cmd_token parse_cmd() { + char buf[198], cmd[5], arg[193]; + cmd_token token; + token.type = ERROR; + memset(token.arg, 0, 193); + + if(fgets(buf, 198, stdin) == NULL) + return token; + + // cmd sera le premier mot rencontré et arg la suite de mots après celui ci, + // si les deux variables ne sont pas remplies alors il y a une erreur + if(sscanf(buf, "%s %[^\t\n]", cmd, arg) != 2) + return token; + + if(strcmp("req", cmd) == 0) { + if(strcmp("neighbour", arg) == 0) + token.type = NEIGHBOUR_REQ; + else if(strcmp("network state", arg) == 0) + token.type = NETWORK_STATE_REQ; + else if(strcmp("node state", arg) == 0) + token.type = NODE_STATE_REQ; + } else if(strcmp("post", cmd) == 0) { + token.type = POST; + //arg[192] = 0; + strcpy(token.arg, arg); + } + + return token; +} diff --git a/src/parser.h b/src/parser.h new file mode 100644 index 0000000..b373a0d --- /dev/null +++ b/src/parser.h @@ -0,0 +1,19 @@ +#include +#include + +#ifndef PARSER_H +#define PARSER_H + +typedef enum cmd_type { + NEIGHBOUR_REQ, NETWORK_STATE_REQ, NODE_STATE_REQ, POST, ERROR +} cmd_type; + +typedef struct cmd_token { + cmd_type type; + char arg[193]; +} cmd_token; + +// retourne le type de commande à exécuter +cmd_token parse_cmd(); + +#endif \ No newline at end of file diff --git a/src/tlv.c b/src/tlv.c new file mode 100644 index 0000000..e19cfd9 --- /dev/null +++ b/src/tlv.c @@ -0,0 +1,188 @@ +#include "tlv.h" + +// creer un tlv +int build_tlv(tlv *tlv, cmd_token token) { + switch(token.type) { + case NEIGHBOUR_REQ: + // a remplir + break; + case NETWORK_STATE_REQ: + // a remplir + break; + case NODE_STATE_REQ: + // a remplir + break; + case POST: + // a remplir + break; + case ERROR: + printf("Wrong format, use 'req {neighbour | network state | node state}' or 'post {message}'"); + break; + } +} + +int build_pad1(tlv *tlv) { + pad1 *new = (pad1*) malloc(sizeof(pad1)); + + if(new == NULL) + return -1; + + new->type = 0; + + tlv->pad1 = new; + + return 0; +} + +int build_padn(tlv *tlv, size_t len) { + padn *new = (padn*) malloc(sizeof(padn)); + + if(new == NULL) + return -1; + + new->type = 1; + new->length = len; + new->mbz = (char*) calloc(sizeof(char), len); + + tlv->padn = new; + + return 0; +} + +int build_neighbour_req(tlv *tlv) { + neighbour_req *new = (neighbour_req*) malloc(sizeof(neighbour_req)); + + if(new == NULL) + return -1; + + new->type = 2; + new->length = 0; + + tlv->neighbour_req = new; + + return 0; +} + +int build_neighbour(tlv *tlv, struct in6_addr ip, short port) { + neighbour *new = (neighbour*) malloc(sizeof(neighbour)); + + if(new == NULL) + return -1; + + new->type = 3; + new->length = 18; + new->ip = ip; + new->port = port; + + tlv->neighbour = new; + + return 0; +} + +int build_network_hash(tlv *tlv, char *hash) { + network_hash *new = (network_hash*) malloc(sizeof(network_hash)); + + if(new == NULL) + return -1; + + new->type = 4; + new->length = 16; + memcpy(new->network_hash, hash, 16); + + tlv->network_hash = new; + + return 0; +} + +int build_network_state_req(tlv *tlv) { + network_state_req *new = (network_state_req*) malloc(sizeof(network_state_req)); + + if(new == NULL) + return -1; + + new->type = 5; + new->length = 0; + + tlv->network_state_req = new; + + return 0; +} + +int build_node_hash(tlv *tlv, long node_id, short seqno, char *hash) { + node_hash *new = (node_hash*) malloc(sizeof(node_hash)); + + if(new == NULL) + return -1; + + new->type = 6; + new->length = 26; + new->node_id = node_id; + new->seqno = seqno; + memcpy(new->node_hash, hash, 16); + + tlv->node_hash = new; + + return 0; +} + +int build_node_state_req(tlv *tlv, long node_id) { + node_state_req *new = (node_state_req*) malloc(sizeof(node_state_req)); + + if(new == NULL) + return -1; + + new->type = 7; + new->length = 8; + new->node_id = node_id; + + tlv->node_state_req = new; + + return 0; +} + +int build_node_state(tlv *tlv, long node_id, short seqno, char *node_hash, char *data) { + node_state *new = (node_state*) malloc(sizeof(node_state)); + int len = strlen(data); + + if(new == NULL) + return -1; + + // en mettant cet octet à 0 on est surs de traiter un champ data de taille 192 max + if(len > 192) { + data[192] = 0; + len = 192; + } + + new->type = 8; + new->length = 26 + len; + new->node_id = node_id; + new->seqno = seqno; + memcpy(new->node_hash, node_hash, 16); + memcpy(new->data, data, len); + + tlv->node_state = new; + + return 0; +} + +int build_warning(tlv *tlv, char *message) { + warning *new = (warning*) malloc(sizeof(warning)); + int len = strlen(message); + + if(new == NULL) + return -1; + + // en mettant cet octet à 0 on est surs de traiter un champ message de taille 256 max + if(len > 256) { + message[256] = 0; + len = 256; + } + + new->type = 9; + new->length = len; + memcpy(new->message, message, len); + + tlv->warning = new; + + return 0; +} diff --git a/src/tlv.h b/src/tlv.h new file mode 100644 index 0000000..c9a3d00 --- /dev/null +++ b/src/tlv.h @@ -0,0 +1,127 @@ +#ifndef TLV_H +#define TLV_H + +#include +#include +#include +#include "parser.h" +#include "hash.h" + +#define LEN_NEIGHBOUR_REQ 0 +#define LEN_NEIGHBOUR 18 +#define LEN_NETWORK_HASH 16 +#define LEN_NETWORK_STATE_REQ 0 +#define LEN_NODE_HASH 26 +#define LEN_NODE_STATE_REQ 8 +#define MIN_LEN_NODE_STATE 26 +#define MAX_LEN_NODE_STATE 218 + +// 8 octets min (struct pointer 4 octets), 1024 octets max +typedef struct packet { + unsigned char magic; // 95 (si autre, ignorer) + unsigned char version; // 1 (si autre, ignorer) + short length; // 1020 max + char *body; +} packet; + +// 1 octet +typedef struct pad1 { + unsigned char type; +} pad1; + +// 2 octets min, 258 octets max (unsigned char 0 -> 255) +typedef struct padn { + unsigned char type; + unsigned char length; + char mbz[256]; +} padn; + +// 2 octets +typedef struct neighbour_req { + unsigned char type; + unsigned char length; +} neighbour_req; + +// 20 octets +typedef struct neighbour { + unsigned char type; + unsigned char length; + struct in6_addr ip; + short port; +} neighbour; + +// 18 octets +typedef struct network_hash { + unsigned char type; + unsigned char length; + char network_hash[16]; +} network_hash; + +// 2 octets +typedef struct network_state_req { + unsigned char type; + unsigned char length; +} network_state_req; + +// 28 octets +typedef struct node_hash { + unsigned char type; + unsigned char length; + long node_id; + short seqno; + char node_hash[16]; +} node_hash; + +// 10 octets +typedef struct node_state_req { + unsigned char type; + unsigned char length; + long node_id; +} node_state_req; + +// 28 octets min, 220 octets max (data 0 -> 192) +typedef struct node_state { + unsigned char type; + unsigned char length; + long node_id; + short seqno; + char node_hash[16]; + char data[192]; +} node_state; + +// 2 octets min, 258 ocets max (unsigned char 0 -> 255) +typedef struct warning { + unsigned char type; + unsigned char length; + char message[256]; +} warning; + +typedef union tlv { + pad1 *pad1; + padn *padn; + neighbour_req *neighbour_req; + neighbour *neighbour; + network_hash *network_hash; + network_state_req *network_state_req; + node_hash *node_hash; + node_state_req *node_state_req; + node_state *node_state; + warning *warning; +} tlv; + +// build tlv from token +int build_tlv(tlv *tlv, cmd_token token); + +// build specific tlv +int build_pad1(tlv *tlv); +int build_padn(tlv *tlv, size_t len); +int build_neighbour_req(tlv *tlv); +int build_neighbour(tlv *tlv, struct in6_addr ip, short port); +int build_network_hash(tlv *tlv, char *network_hash); +int build_network_state_req(tlv *tlv); +int build_node_hash(tlv *tlv, long node_id, short seqno, char *node_hash); +int build_node_state_req(tlv *tlv, long node_id); +int build_node_state(tlv *tlv, long node_id, short seqno, char *node_hash, char *data); +int build_warning(tlv *tlv, char *message); + +#endif diff --git a/src/énoncé.pdf b/src/énoncé.pdf new file mode 100644 index 0000000..0d725fe Binary files /dev/null and b/src/énoncé.pdf differ