diff --git a/src/hash.c b/src/hash.c index 287e2c4..44e3827 100644 --- a/src/hash.c +++ b/src/hash.c @@ -11,7 +11,7 @@ void hash_data(pub_data *data, unsigned char *buf) { unsigned char hash[SHA256_DIGEST_LENGTH]; SHA256(concat, totlen, hash); - // Put truncated hash into buf + // Put truncated hash into buf hash_trunc(hash, buf); } @@ -33,7 +33,7 @@ void hash_network(list *data_list, unsigned char *buf) { // Hash all of concat to obtain the network hash SHA256(concat, totlen, hash); - // Put truncated hash into buf + // Put truncated hash into buf hash_trunc(hash, buf); // Get rid of concat @@ -57,4 +57,4 @@ void concat_data(pub_data *data, unsigned char *buf) { 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 index 358c7b5..4f16809 100644 --- a/src/hash.h +++ b/src/hash.h @@ -2,22 +2,24 @@ #define HASH_H #include -#include "node.h" + #include "tlv.h" +#include "parser.h" +#include "node.h" // Hash a single data -void hash_data(pub_data *data, unsigned char *buf); +void hash_data(struct 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); +void hash_network(struct 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); +void concat_data(struct 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 +#endif diff --git a/src/node.c b/src/node.c index 499651d..0c33abb 100644 --- a/src/node.c +++ b/src/node.c @@ -8,8 +8,11 @@ #include #include -#include "tlv.h" #include "node.h" +#include "tlv.h" +#include "hash.h" +#include "parser.h" + /* ---- Fonctions utilitaires ---- */ @@ -43,8 +46,182 @@ neighbour_peer *get_random_neighbour() { return (neighbour_peer*) tmp->data; } +// get data associated with id, if it doesn't exist return NULL +pub_data *get_data(long id) { + list *tmp = data_list; + pub_data *data; + + while(tmp != NULL) { + data = (pub_data*) tmp->data; + + if(data->id == id) + return data; + } + + return NULL; +} + +// Take data as args and create a pub_data structure in the heap +pub_data *copy_data(unsigned char len, long id, short seqno, char *data) { + pub_data *new_data = (pub_data*) malloc(sizeof(pub_data)); + char *_data = (char*) malloc(len); + new_data->length = len; + new_data->id = id; + new_data->seqno = seqno; + new_data->data = _data; + memcpy(_data, data, len); + + return new_data; +} + +// Add new data to data list +void add_data(unsigned char len, long id, short seqno, char *data) { + // If id is the same as this node's id then we only update seqno + if(id == NODE_ID) { + pub_data *node_data = get_data(NODE_ID); + + if(seqno >= node_data->seqno) { + node_data->seqno = seqno ^ 1; + } + + return; + } + + // Copy data + pub_data *new_data = copy_data(len, id, seqno, data); + + if(data_list == NULL) { + // Update list + data_list = (list*) malloc(sizeof(list)); + data_list->data = (void*) new_data; + data_list->next = NULL; + + return; + } + + // Find correct position for new data + list *tmp = data_list; + list *last = NULL; + list *new_node; + long cur_id; + + while(tmp != NULL) { + cur_id = ((pub_data*) tmp->data)->id; + + // If id is smaller than cur_id then the new data has to be added at this position + if(id < cur_id) { + // If last hasn't been set then the new data becomes the head of the list + if(last == NULL) { + // Update list + data_list = (list*) malloc(sizeof(list)); + data_list->data = (void*) new_data; + data_list->next = tmp; + + return; + } + + // Else, we update the last node + new_node = (list*) malloc(sizeof(list)); + new_node->data = (void*) new_data; + new_node->next = tmp; + last->next = new_node; + + return; + } else if(id == cur_id) { + // If data already exists for this id then we update it if it's seqno is greater than the one stored + pub_data *cur_data = (pub_data*) tmp->data; + + if(seqno > cur_data->seqno) { + // Updata data + tmp->data = (void*) new_data; + + // Free old data + free(cur_data); + + return; + } + + // seqno is smaller so the new data allocated is freed and nothing else is done + free(new_data); + + return; + } + + // Get next node in list + last = tmp; + tmp = tmp->next; + } + + // If no correct position was found then the new data has to be added at the end of the list + + // Update list + new_node = (list*) malloc(sizeof(list)); + new_node->data = (void*) new_data; + new_node->next = NULL; + last->next = new_node; +} + /* ---- Fin fonctions utilitaires ---- */ +int send_tlv(union tlv * tlv_to_send, int tlv_size, struct sockaddr_in6 * dest_list[], int dest_list_size, int socket_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 (tlv_size > 1020) { + perror(">> Unable to send the tlv, it's size if above 1020 bytes."); + return -1; + } else { + memcpy((void *) pack.body, tlv_to_send, tlv_size); + } + + // Move the content of the paquet struct to a buffer + // That will be send out in a vectorized buffer. + // packet_buff = (char *) pack; + memcpy(&packet_buff,&pack,1024); + + // 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. + }; + + int response_code = sendmsg((int) socket_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){ @@ -61,7 +238,7 @@ int validate_tlv(char *data, int pos, short packet_len){ unsigned char tlv_len = data[pos+1]; // Check that the tlv does not exceed the packet length - if(pos + length >= packet_len) + if(pos + tlv_len >= packet_len) return -1; // Returns the type of the tlv or -1 if something went wrong @@ -99,9 +276,9 @@ int validate_tlv(char *data, int pos, short packet_len){ // 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){ +int check_header(char * received_datagram[], int buffer_len, struct packet * packet_to_return){ - packet * packet_to_return = (packet*) req; + packet_to_return = (packet*) received_datagram; // We need to check a few things ; // The first byte must be worth 95, @@ -116,7 +293,7 @@ int check_header(char * req[], int buffer_size, struct packet * packet_to_return return -1; } - if (packet_to_return.length + 4 > buffer_size ) { + if (packet_to_return->length + 4 > buffer_len ) { perror(">> The packet length is bigger than the UDP datagram, which is not possible with the current laws of physics."); return -1; } @@ -132,91 +309,175 @@ int update_neighbours(){ }; // We then look at the differents TLVs in the packet. -void work_with_tlvs(char *data, short packet_len, struct sockaddr_in6 sender){ +int work_with_tlvs(char * data[], short packet_len, struct sockaddr_in6 sender){ int pos = 0; - unsigned char tlv_len; - tlv tmp_tlv; + unsigned char tlv_len, hash[16], warn[32]; + tlv new_tlv, cur_tlv; + list *tmp_list; + pub_data *pdata; + + struct neighbour_peer * random_neighbour; + 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 + + // Send a neighbour tlv + random_neighbour = get_random_neighbour(); + build_neighbour(&new_tlv, random_neighbour->ip, random_neighbour->port); + + // NOT FINISHED - What packet is it added to? + // add_tlv(packet, &new_tlv, 3); + + // The position is updated 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; + cur_tlv.neighbour = (neighbour*) (data + pos); + // Build network hash + build_network_hash(&new_tlv, data_list); + + // NOT FINISHED - What packet is it added to? + // add_tlv(packet, &new_tlv, 4); + + // The position is updated 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; + // We reveived a network hash tlv so we compare the hash with our own, if they differ we send a network state request tlv + cur_tlv.network_hash = (network_hash*) (data + pos); + hash_network(data_list, hash); + + if(memcmp(hash, cur_tlv.network_hash->network_hash, 16) == 0) { + build_network_state_req(&new_tlv); + // NOT FINISHED - What packet is it added to? + // add_tlv(packet, &new_tlv, 5); + } + + // The position is updated + 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; + // for each known data build a node hash and add to packet + tmp_list = data_list; while(tmp_list != NULL) { - tmp_data = (pub_data*) tmp_list->data; - build_node_hash(&tmp_tlv, tmp_data->id, tmp_data->seqno); + pdata = (pub_data*) tmp_list->data; + build_node_hash(&new_tlv, pdata->id, pdata->seqno, pdata->data); + // NOT FINISHED - What packet is it added to? + // add_tlv(packet, &new_tlv, 4); } + // The position is updated + pos += 2; + break; case 6: - // We received a node hash tlv + // We received a node hash tlv so if there is no entry for node_id in the data list or the hashes differ we send a node state request, if the hashes are identical nothing has to be done + cur_tlv.node_hash = (node_hash*) (data + pos); + pdata = get_data(cur_tlv.node_hash->node_id); + + // If data is found for this id then we check that both hashes are the same + if(pdata != NULL) { + // We hash the data stored in the data list + hash_data(pdata, hash); + + // If both hashes are the same then nothing has to be done + if(memcmp(hash, cur_tlv.node_hash->node_hash, 16) != 0) { + // The position is updated + tlv_len = data[pos+1]; + pos += 2; + + break; + } + + } + + // If no pub_data was found or the hashes differ then we send a node state request + build_node_state_req(&new_tlv, cur_tlv.node_hash->node_id); + // NOT FINISHED - What packet is it added to? + // add_tlv(packet, &new_tlv, 7); + + // The position is updated + tlv_len = data[pos+1]; + pos += tlv_len + 2; + break; case 7: - // We received a node state request tlv + // We received a node state request tlv so a node state tlv for this node id has to be sent, if no pub_data exists for this id nothing is sent + cur_tlv.node_state_req = (node_state_req*) (data + pos); + pdata = get_data(cur_tlv.node_state_req->node_id); + + if(pdata != NULL) { + build_node_state(&new_tlv, pdata->id, pdata->seqno, pdata->data, pdata->length); + // NOT FINISHED - What packet is it added to? + // add_tlv(packet, &new_tlv, 8); + } + + // The position is updated + tlv_len = data[pos+1]; + pos += tlv_len + 2; + break; case 8: - // We received a node state tlv + // We received a node state tlv so we add it to the data list or update the data stored + cur_tlv.node_state = (node_state*) (data + pos); + + add_data(cur_tlv.node_state->length - 26, cur_tlv.node_state->node_id, cur_tlv.node_state->seqno, cur_tlv.node_state->data); + + // The position is updated + tlv_len = data[pos+1]; + pos += tlv_len + 2; + break; case 9: // We received a warning tlv so it's message is printed + cur_tlv.warning = (warning*) (data + pos); + + // Print exactly new_tlv.length characters from new_tlv.message + sprintf(warn, ">> WARNING:\n%%.%ds", cur_tlv.warning->length + 1); + printf(warn, cur_tlv.warning->message); + + // The position is updated + tlv_len = data[pos+1]; + pos += tlv_len + 2; + break; default: - return ; + // A malformed packet was found so we stop looking for more packets and send a warning tlv + strcpy(warn, "Packet is malformed."); + build_warning(&new_tlv, warn, strlen(warn)); + // NOT FINISHED - What packet is it added to? + // add_tlv(packet, &new_tlv, 9); + + return -1; } } + + return 0; } // We listen forever for new paquets; @@ -280,7 +541,7 @@ void listen_for_packets(){ // struct tlv_list received_tlvs; // if (validate_tlvs(formated_rec_datagram) < 0) - int nbr_success_tlv = work_with_tlvs(formated_rec_datagram, &req, sender); + int nbr_success_tlv = work_with_tlvs(&req, 1024, 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 ); @@ -291,12 +552,13 @@ void listen_for_packets(){ } int main(int argc, const char *argv[]) { + printf(">> Starting node\n"); int cont = 1; while(cont){ // We create the neighbourhood table - neighbour_peer neighbour_list[NEIGHBOUR_MAX]; + // neighbour_peer neighbour_list[NEIGHBOUR_MAX]; // We create the message table // We create our own message. diff --git a/src/node.h b/src/node.h index d4ba94b..7daef54 100644 --- a/src/node.h +++ b/src/node.h @@ -13,6 +13,7 @@ #include "tlv.h" #include "hash.h" +#include "parser.h" // On which port do we listen to #define LISTEN_PORT 1212 @@ -65,20 +66,29 @@ static list *neighbour_list; // fonctions signatures void listen_for_packets(); -int check_header(char * received_datagram[], int len, struct packet pack); +int check_header(char * received_datagram[], int buffer_len, struct packet * packet_to_return); int validate_tlvs(struct packet * pack, struct tlv_list * tlv_l); int update_neighbours(); -int work_with_tlvs(struct packet received_packet, char * data_from_packet[], struct sockaddr_in6 sender); +int work_with_tlvs(char * data[], short packet_len, struct sockaddr_in6 sender); -void add_tlv(packet *packet, tlv *tlv, char type); +void add_tlv(struct packet *packet, union tlv *tlv, char type); -int send_packet(struct tlv_list tlvs_to_send, ); +// 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(union tlv * tlv_to_send, int tlv_size, 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_size, struct sockaddr_in6 * dest_list[], int dest_list_size, int socket_num); // threaded functions - void t_ask_for_more_peers(); void t_update_neighbours(); @@ -90,4 +100,13 @@ int len_list(list *l); neighbour_peer *get_random_neighbour(); +// get data associated with id, if it doesn't exist return NULL +pub_data *get_data(long id); + +// Take data as args and create a pub_data structure in the heap +pub_data *copy_data(unsigned char len, long id, short seqno, char *data); + +// add new data to data list +void add_data(unsigned char len, long id, short seqno, char *data); + #endif diff --git a/src/parser.h b/src/parser.h index b373a0d..15b5fcb 100644 --- a/src/parser.h +++ b/src/parser.h @@ -16,4 +16,4 @@ typedef struct cmd_token { // retourne le type de commande à exécuter cmd_token parse_cmd(); -#endif \ No newline at end of file +#endif diff --git a/src/tlv.c b/src/tlv.c index 2284815..5fe7dbf 100644 --- a/src/tlv.c +++ b/src/tlv.c @@ -18,7 +18,12 @@ int build_tlv(tlv *tlv, cmd_token token) { case ERROR: printf("Wrong format, use 'req {neighbour | network state | node state}' or 'post {message}'"); break; + default: + perror("Unrecognized tlv type."); + return -1; } + + return -1; } int build_pad1(tlv *tlv) { @@ -79,7 +84,7 @@ int build_neighbour(tlv *tlv, struct in6_addr ip, short port) { return 0; } -int build_network_hash(tlv *tlv, char *hash) { +int build_network_hash(tlv *tlv, list *data_list) { network_hash *new = (network_hash*) malloc(sizeof(network_hash)); if(new == NULL) @@ -87,7 +92,7 @@ int build_network_hash(tlv *tlv, char *hash) { new->type = 4; new->length = 16; - memcpy(new->network_hash, hash, 16); + hash_network(data_list, new->network_hash); tlv->network_hash = new; @@ -108,7 +113,7 @@ int build_network_state_req(tlv *tlv) { return 0; } -int build_node_hash(tlv *tlv, long node_id, short seqno, char *hash) { +int build_node_hash(tlv *tlv, long node_id, short seqno, char *data) { node_hash *new = (node_hash*) malloc(sizeof(node_hash)); if(new == NULL) @@ -118,7 +123,9 @@ int build_node_hash(tlv *tlv, long node_id, short seqno, char *hash) { new->length = 26; new->node_id = node_id; new->seqno = seqno; - memcpy(new->node_hash, hash, 16); + + pub_data pdata = (pub_data) {.id = node_id, .seqno = seqno, .data = data}; + hash_data(&pdata, new->node_hash); tlv->node_hash = new; @@ -140,9 +147,9 @@ int build_node_state_req(tlv *tlv, long node_id) { return 0; } -int build_node_state(tlv *tlv, long node_id, short seqno, char *node_hash, char *data) { +int build_node_state(tlv *tlv, long node_id, short seqno, char *data, size_t data_len) { node_state *new = (node_state*) malloc(sizeof(node_state)); - int len = strlen(data); + int len = data_len + 26; if(new == NULL) return -1; @@ -157,17 +164,19 @@ int build_node_state(tlv *tlv, long node_id, short seqno, char *node_hash, char new->length = 26 + len; new->node_id = node_id; new->seqno = seqno; - memcpy(new->node_hash, node_hash, 16); memcpy(new->data, data, len); + pub_data pdata = (pub_data) {.id = node_id, .seqno = seqno, .data = data}; + hash_data(&pdata, new->node_hash); + tlv->node_state = new; return 0; } -int build_warning(tlv *tlv, char *message) { +int build_warning(tlv *tlv, char *message, size_t message_len) { warning *new = (warning*) malloc(sizeof(warning)); - int len = strlen(message); + int len = message_len; if(new == NULL) return -1; @@ -180,9 +189,9 @@ int build_warning(tlv *tlv, char *message) { new->type = 9; new->length = len; - memcpy(new->message, message, len); + memcpy(new->message, message, len); tlv->warning = new; return 0; -} \ No newline at end of file +} diff --git a/src/tlv.h b/src/tlv.h index c9a3d00..b548ca0 100644 --- a/src/tlv.h +++ b/src/tlv.h @@ -4,8 +4,10 @@ #include #include #include -#include "parser.h" + +#include "node.h" #include "hash.h" +#include "parser.h" #define LEN_NEIGHBOUR_REQ 0 #define LEN_NEIGHBOUR 18 @@ -33,7 +35,7 @@ typedef struct pad1 { typedef struct padn { unsigned char type; unsigned char length; - char mbz[256]; + char *mbz; } padn; // 2 octets @@ -110,18 +112,18 @@ typedef union tlv { } tlv; // build tlv from token -int build_tlv(tlv *tlv, cmd_token token); +int build_tlv(tlv *tlv, struct 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_req(union 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_hash(tlv *tlv, struct list *data_list); int build_network_state_req(tlv *tlv); -int build_node_hash(tlv *tlv, long node_id, short seqno, char *node_hash); +int build_node_hash(tlv *tlv, long node_id, short seqno, char *data); 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); +int build_node_state(tlv *tlv, long node_id, short seqno, char *data, size_t data_len); +int build_warning(tlv *tlv, char *message, size_t message_len); #endif