diff --git a/Makefile b/Makefile index e69de29..3d676e4 100644 --- a/Makefile +++ b/Makefile @@ -0,0 +1,20 @@ +TARGET ?= dazibao +SRC_DIRS ?= ./src/* +CC := gcc +CFLAGS= -O2 -Wall +SRCS := $(shell find $(SRC_DIRS) -name *.c -or -name *.s) +OBJS := $(addsuffix .o,$(basename $(SRCS))) +DEPS := $(OBJS:.o=.d) +SSLFLAGS = -lssl -lcrypto + +INC_DIRS := $(shell find $(SRC_DIRS) -type d) +INC_FLAGS := $(addprefix -I,$(INC_DIRS)) + +$(TARGET): $(OBJS) + $(CC) $(CFLAGS) $(OBJS) -o $@ $(LOADLIBES) $(LDLIBS) $(SSLFLAGS) + +.PHONY: clean +clean: + $(RM) $(TARGET) $(OBJS) $(DEPS) + +-include $(DEPS) 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..5258a7e 100644 --- a/src/hash.h +++ b/src/hash.h @@ -2,8 +2,11 @@ #define HASH_H #include -#include "node.h" +#include + #include "tlv.h" +#include "parser.h" +#include "node.h" // Hash a single data void hash_data(pub_data *data, unsigned char *buf); @@ -20,4 +23,4 @@ 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 +#endif diff --git a/src/hash.o b/src/hash.o new file mode 100644 index 0000000..920c6ac Binary files /dev/null and b/src/hash.o differ diff --git a/src/node.c b/src/node.c index 499651d..a5d39e7 100644 --- a/src/node.c +++ b/src/node.c @@ -7,10 +7,18 @@ #include #include #include +#include +#include +#include +#include +#include -#include "tlv.h" #include "node.h" +// Static variables +static list *data_list; +static list *neighbour_list; + /* ---- Fonctions utilitaires ---- */ // Get list length @@ -43,11 +51,372 @@ 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(int64_t 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, int64_t id, int16_t 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, int64_t id, int16_t 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; + int64_t 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 ---- */ +// Add TLV to packet, if it does not fit then send the packet and reset the packet buff to be able to add more TLVs that will be sent afterwards +int add_tlv(packet *pack, tlv *tlv, struct sockaddr_in6 *dest, int socket_num) { + char type = tlv->pad1->type, sent = 0, errval = 0; + unsigned char len; + + // Check if TLV fits in the packet, if not then send the packet and reset it + if(type != 1) { + len = tlv->padn->length + 2; + + if(pack->length + len > 1020) { + errval = send_packet((char*) pack, pack->length, dest, socket_num); + *pack = (packet) {.magic = 95, .version = 1, .length = 0}; + memset(pack->body, 0, 1020); + sent = 1; + } + } else { + if(pack->length >= 1020) { + errval = send_packet((char*) pack, pack->length, dest, socket_num); + *pack = (packet) {.magic = 95, .version = 1, .length = 0}; + memset(pack->body, 0, 1020); + sent = 1; + } + } + + // Copy data from tlv into body + switch(type) { + case 1: + memcpy(pack->body + pack->length, tlv->pad1, 1); + pack->length += 1; + + break; + case 2: + memcpy(pack->body + pack->length, tlv->padn, len); + pack->length += len; + + break; + case 3: + memcpy(pack->body + pack->length, tlv->neighbour, len); + pack->length += len; + + break; + case 4: + memcpy(pack->body + pack->length, tlv->network_hash, len); + pack->length += len; + + break; + case 5: + memcpy(pack->body + pack->length, tlv->network_state_req, len); + pack->length += len; + + break; + case 6: + memcpy(pack->body + pack->length, tlv->node_hash, len); + pack->length += len; + + break; + case 7: + memcpy(pack->body + pack->length, tlv->node_state_req, len); + pack->length += len; + + break; + case 8: + memcpy(pack->body + pack->length, tlv->node_state, len); + pack->length += len; + + break; + case 9: + memcpy(pack->body + pack->length, tlv->warning, len); + pack->length += len; + + break; + default: + return -1; + } + + // If the previous packet was went return 1 or -1 if there was an error sending it + if(sent) + return errval? -1:1; + + // Return 0 if the TLV was added to the packet + return 0; +} + +// Send length bytes from packet +int send_packet(char *packet_buff, int16_t length, struct sockaddr_in6 *dest, int socket_num) { + // Vectorized buffer + struct iovec vec_buff = {.iov_len = length, .iov_base = packet_buff}; + + int error_while_sending = 0; + + // Creating the struct to send out with sendmsg + struct msghdr packet_tlv_send_out = { + .msg_name = dest, + .msg_namelen = sizeof(struct sockaddr_in6), + .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(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; + } else if (response_code < length) { + // debug_print("Sent out only part of the packet."); + error_while_sending = 1; + } 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; + } +} + +// Send a single TLV to the specified addresses, return -1 if an error was encountered, 0 otherwise +int send_single_tlv(tlv *tlv, struct sockaddr_in6 *dest, int socket_num) { + char type = tlv->pad1->type; + unsigned char len; + packet pack = (packet) {.magic = 95, .version = 1, .length = 4}; + memset(pack.body, 0, 1020); + + // Copy data from tlv into body + switch(type) { + case 1: + memcpy(pack.body, tlv->pad1, 1); + pack.length += 1; + + break; + case 2: + len = tlv->padn->length + 2; + memcpy(pack.body, tlv->padn, len); + pack.length += len; + + break; + case 3: + len = tlv->neighbour->length + 2; + memcpy(pack.body, tlv->neighbour, len); + pack.length += len; + + break; + case 4: + len = tlv->network_hash->length + 2; + memcpy(pack.body, tlv->network_hash, len); + pack.length += len; + + break; + case 5: + len = tlv->network_state_req->length + 2; + memcpy(pack.body, tlv->network_state_req, len); + pack.length += len; + + break; + case 6: + len = tlv->node_hash->length + 2; + memcpy(pack.body, tlv->node_hash, len); + pack.length += len; + + break; + case 7: + len = tlv->node_state_req->length + 2; + memcpy(pack.body, tlv->node_state_req, len); + pack.length += len; + + break; + case 8: + len = tlv->node_state->length + 2; + memcpy(pack.body, tlv->node_state, len); + pack.length += len; + + break; + case 9: + len = tlv->warning->length + 2; + memcpy(pack.body, tlv->warning, len); + pack.length += len; + + break; + default: + return -1; + } + + // Send the packet + return send_packet((char*) &pack, pack.length, dest, socket_num); +} + +int send_tlv(tlv *tlv_to_send, int16_t 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){ +int validate_tlv(char *data, int pos, int16_t packet_len){ char type = data[pos]; // Nothing to do in this case @@ -61,7 +430,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 +468,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_data_buffer[], int received_data_len, struct packet * packet_to_return){ - packet * packet_to_return = (packet*) req; + packet_to_return = (packet*) received_data_buffer; // We need to check a few things ; // The first byte must be worth 95, @@ -116,7 +485,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 > received_data_len ) { perror(">> The packet length is bigger than the UDP datagram, which is not possible with the current laws of physics."); return -1; } @@ -131,193 +500,388 @@ int update_neighbours(){ return 0; }; +int add_message(char * message, int message_len){ + 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 work_with_tlvs(char * data, int16_t packet_len, struct sockaddr_in6 *sender, int socket_num){ int pos = 0; - unsigned char tlv_len; - tlv tmp_tlv; + unsigned char tlv_len, hash[16]; + char warn[32]; + tlv new_tlv, cur_tlv; + new_tlv.pad1 = NULL; + cur_tlv.pad1 = NULL; + list *tmp_list; + pub_data *pdata; + struct neighbour_peer *random_neighbour; + struct sockaddr_in6 new_neighbour; + + packet pack = (packet) {.magic = 95, .version = 1, .length = 0}; + memset(pack.body, 0, 1020); + + int ifindex = if_nametoindex("eth0"); + + if(ifindex == 0) { + perror("if_nametoindex failed"); + return -1; + } 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); + add_tlv(&pack, &new_tlv, sender, socket_num); + + // 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); + // Init dest socket + memset(&new_neighbour, 0, sizeof(new_neighbour)); + new_neighbour.sin6_family = AF_INET6; + memcpy(&new_neighbour.sin6_addr, &cur_tlv.neighbour->ip, 16); + new_neighbour.sin6_port = htons(LISTEN_PORT); + new_neighbour.sin6_scope_id = ifindex; + + // Build network hash + build_network_hash(&new_tlv, data_list); + send_single_tlv(&new_tlv, &new_neighbour, socket_num); + + // 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); + add_tlv(&pack, &new_tlv, sender, socket_num); + } + + // 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); + add_tlv(&pack, &new_tlv, sender, socket_num); } + // 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); + add_tlv(&pack, &new_tlv, sender, socket_num); + + // 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); + add_tlv(&pack, &new_tlv, sender, socket_num); + } + + // 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)); + add_tlv(&pack, &new_tlv, sender, socket_num); + + return -1; } } -} -// We listen forever for new paquets; -void listen_for_packets(){ + // Free the previously allocated memory + free(new_tlv.pad1); - // Create new socket for UDP - int s = socket(AF_INET6, SOCK_DGRAM, 0); + // If the packet still has data in it then send it + if(pack.length > 0) + send_packet((char*) &pack, pack.length, sender, socket_num); + + return 0; +} + +int listen_for_packets(char * received_data_buffer[], int received_data_len, struct sockaddr_in6 * sender, int sock_fd){ + + // 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(received_data_buffer, received_data_len, &formated_rec_datagram) < 0){ + perror(">> Error while checking the header, aborting this packet, by choice, and conviction."); + return -1; + } + + // TODO : Add the neighbour check here. + + // struct tlv_list received_tlvs; + // if (validate_tlvs(formated_rec_datagram) < 0) + int nbr_success_tlv = work_with_tlvs(received_data_buffer, received_data_len, sender, sock_fd); + 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 ); + return -2; + } else { + printf(">> Done working with the TLVs of the packet, listening for new packets.\n"); + return 0; + } + +} + +int t_ask_for_more_peers(){ + return 0; +} + +int t_get_network_state(){ + return 0; +} + +int t_update_neighbours(){ + return 0; +} + +int run_node(int sock_fd){ + printf(">> Running node...\n"); + + int ret; + ssize_t bytes; + char input_buffer[1024]; + char output_buffer[1024]; + struct pollfd fds[2]; + + // Init the ~20s delay for node update. + srand(time(NULL)); + int delay = time(NULL) + 20; + + /* Descriptor zero is stdin */ + fds[0].fd = 0; + fds[1].fd = sock_fd; + fds[0].events = POLLIN | POLLPRI; + fds[1].events = POLLIN | POLLPRI; + + /* Normally we'd check an exit condition, but for this example + * we loop endlessly. + */ + while (1) { + + if (time(NULL) >= delay) { + printf(">> Asking for more peers...\n"); + t_ask_for_more_peers(); + printf(">> Updating neighbours...\n"); + t_update_neighbours(); + printf(">> Getting network state...\n"); + t_get_network_state(); + delay = time(NULL) + 20 + (rand() % 10); + } + + // This might be cool to add, but we need to find a way to write to stdin + // while it's running. + // if (time(NULL) < delay) { + // // Thanks to : + // // https://gist.github.com/amullins83/24b5ef48657c08c4005a8fab837b7499 + // printf("\b\x1b[2K\r>> Next request in %li seconds..", delay - time(NULL)); + // fflush(stdout); + // } + // printf("\n"); + + + /* Call poll() */ + ret = poll(fds, 2, 5); + + if (ret < 0) { + printf(">> Error - poll returned error: %s\n", strerror(errno)); + break; + + } else if (ret > 0) { + /* Regardless of requested events, poll() can always return these */ + if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { + printf("Error - poll indicated stdin error\n"); + break; + } + if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) { + printf("Error - poll indicated socket error\n"); + break; + } + + // Read data from stdin (new message to post ) + if (fds[0].revents & (POLLIN | POLLPRI)) { + bytes = read(0, input_buffer, sizeof(input_buffer)); + if (bytes < 0) { + printf("Error - stdin error: %s\n", strerror(errno)); + break; + } + input_buffer[strcspn(input_buffer, "\n")] = 0; + printf(">> Adding following message to the table : “%s”\n", input_buffer ); + // Add message to the message table. + if (add_message(&input_buffer, bytes) < 0) { + perror(">> Error while trying to add the message to the list of messages, please try again.."); + } + } + + // Read data from the socket ( incoming packet ) + if (fds[1].revents & (POLLIN | POLLPRI)) { + + + // Vectorized buffer + struct iovec vec_buff_rec = { .iov_len = sizeof(output_buffer), .iov_base = output_buffer }; + + struct sockaddr_in6 sender; + // Creating the struct receive the server reponse. + // Is empty, will be filled by recvmsg() + struct msghdr msg_from_peer = { + .msg_name = &sender, + .msg_namelen = sizeof(sender), + .msg_iov = &vec_buff_rec, + .msg_iovlen = 1 // We have only one iovec buffer. But if we had 2, we would write 2. + }; + + bytes = recvmsg(sock_fd, &msg_from_peer, 0); + if (bytes < 0) { + printf("Error - recvfrom error: %s\n", strerror(errno)); + break; + } + if (bytes > 0) { + printf("Received: %.*s\r", (int)bytes, output_buffer); + // Treat incoming packets. + int work_tlv_status = listen_for_packets(&output_buffer, bytes, &sender, sock_fd); + if (work_tlv_status < 0) { + perror(">> Error while treating the incoming packet."); + } + } + } + } else { + continue; + } + + + } + return 0; +} + +int bootstrap_node(int * sock_fd){ + printf(">> Boostraping node...\n"); + + struct sockaddr_in6 server_addr; + + /* Create UDP socket */ + * sock_fd = socket(AF_INET6, SOCK_DGRAM, 0); + if ( * sock_fd < 0) { + printf("Error - failed to open socket: %s\n", strerror(errno)); + return -1; + } + + /* Bind socket */ + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin6_family = AF_INET6; + // server_addr.sin6_addr.in6_addr = htonl(INADDR_ANY); + server_addr.sin6_port = htons(LISTEN_PORT); + if (bind( * sock_fd, (struct sockaddr *)(&server_addr), sizeof(server_addr)) < 0) { + printf("Error - failed to bind socket: %s\n", strerror(errno)); + return -2; + } + + printf(">> Boostraping done.\n"); + return 0; +} + + +int main(int argc, const char *argv[]) { + printf(">> Starting node\n"); + + int sock_fd; + bootstrap_node(&sock_fd); + run_node(sock_fd); + close(sock_fd); - 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; - } - - printf(">> New paquet received :\n"); - printf("%s\n", req); - - // TODO : Here, we need to fork. - - // 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; - } - - // TODO : Add the neighbour check here. - - // 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, const char *argv[]) { - int cont = 1; - - 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(); - - // This is in it's own fork. - time_t delay = time(NULL) + 20; - 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 - // by sending out a TLV neighbour Request at a random peer. - t_ask_for_more_peers(); - // Every 20 sec, we also check for a peer that didn't emit a new message for - // the past 70 sec, if he's temporary, we delete him from the neighbourhood. - t_update_neighbours(); - // We send out a TLV Network hash to get an ideal of the network state. - t_get_network_state(); - } - } return 0; } diff --git a/src/node.h b/src/node.h index d4ba94b..ba28d61 100644 --- a/src/node.h +++ b/src/node.h @@ -4,25 +4,14 @@ #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 +#include +#include +#include /* 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 @@ -31,7 +20,7 @@ */ typedef struct neighbour_peer { struct in6_addr ip; - short port; + int16_t port; char is_temporary; struct timeval last_seen; } neighbour_peer; @@ -44,50 +33,90 @@ typedef struct neighbour_peer { */ typedef struct pub_data { - unsigned char length; - long id; - short seqno; + unsigned char length; + int64_t id; + int16_t seqno; char *data; } pub_data; // General list typedef struct list { - void *data; - void *next; + void *data; + void *next; } list; -// Static variables -static list *data_list; -static list *neighbour_list; +#include "tlv.h" +#include "hash.h" +#include "parser.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 // TODO // fonctions signatures -void listen_for_packets(); +int listen_for_packets(char * received_data_buffer[], int received_data_len, struct sockaddr_in6 * sender, int sock_fd); -int check_header(char * received_datagram[], int len, struct packet pack); +int check_header(char * received_data_buffer[], int received_data_len, packet * packet_to_return); -int validate_tlvs(struct packet * pack, struct tlv_list * tlv_l); +int validate_tlv(char *data, int pos, int16_t packet_len); 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, int16_t packet_len, struct sockaddr_in6 *sender, int socket_num); -void add_tlv(packet *packet, tlv *tlv, char type); +int add_tlv(packet *pack, tlv *tlv, struct sockaddr_in6 *dest, int socket_num); -int send_packet(struct tlv_list tlvs_to_send, ); +int send_packet(char *packet_buff, int16_t length, struct sockaddr_in6 *dest, int socket_num); + +int send_single_tlv(tlv *tlv, struct sockaddr_in6 *dest, int socket_num); + +// This function is in charge of saying how and what goes where. +int run_node(int sock_fd); + +/* 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(tlv *tlv_to_send, int16_t length, 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, int16_t length, struct sockaddr_in6 * dest_list, int dest_list_size, int socket_num); // threaded functions +int t_ask_for_more_peers(); -void t_ask_for_more_peers(); +int t_update_neighbours(); -void t_update_neighbours(); +int t_get_network_state(); -void t_get_network_state(); +// This function adds a message to the message table. +int add_message(char * message, int message_len); + +// This functions creates the structures needed for the rest of the project, +// creates the socket, and returns all of it. +int bootstrap_node(int * sock_fd); // Helper functions 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(int64_t id); + +// Take data as args and create a pub_data structure in the heap +pub_data *copy_data(unsigned char len, int64_t id, int16_t seqno, char *data); + +// add new data to data list +void add_data(unsigned char len, int64_t id, int16_t seqno, char *data); + #endif diff --git a/src/node.o b/src/node.o new file mode 100644 index 0000000..21df733 Binary files /dev/null and b/src/node.o differ 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/parser.o b/src/parser.o new file mode 100644 index 0000000..0cdd296 Binary files /dev/null and b/src/parser.o differ diff --git a/src/tlv.c b/src/tlv.c index 2284815..1f5b4e8 100644 --- a/src/tlv.c +++ b/src/tlv.c @@ -18,10 +18,18 @@ 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) { + // Free the previously allocated memory + free(tlv->pad1); + pad1 *new = (pad1*) malloc(sizeof(pad1)); if(new == NULL) @@ -35,6 +43,9 @@ int build_pad1(tlv *tlv) { } int build_padn(tlv *tlv, size_t len) { + // Free the previously allocated memory + free(tlv->pad1); + padn *new = (padn*) malloc(sizeof(padn)); if(new == NULL) @@ -42,7 +53,7 @@ int build_padn(tlv *tlv, size_t len) { new->type = 1; new->length = len; - new->mbz = (char*) calloc(sizeof(char), len); + memset(new->mbz, 0, 256); tlv->padn = new; @@ -50,6 +61,9 @@ int build_padn(tlv *tlv, size_t len) { } int build_neighbour_req(tlv *tlv) { + // Free the previously allocated memory + free(tlv->pad1); + neighbour_req *new = (neighbour_req*) malloc(sizeof(neighbour_req)); if(new == NULL) @@ -63,7 +77,10 @@ int build_neighbour_req(tlv *tlv) { return 0; } -int build_neighbour(tlv *tlv, struct in6_addr ip, short port) { +int build_neighbour(tlv *tlv, struct in6_addr ip, int16_t port) { + // Free the previously allocated memory + free(tlv->pad1); + neighbour *new = (neighbour*) malloc(sizeof(neighbour)); if(new == NULL) @@ -79,7 +96,10 @@ 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) { + // Free the previously allocated memory + free(tlv->pad1); + network_hash *new = (network_hash*) malloc(sizeof(network_hash)); if(new == NULL) @@ -87,7 +107,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, (unsigned char*) new->network_hash); tlv->network_hash = new; @@ -95,6 +115,9 @@ int build_network_hash(tlv *tlv, char *hash) { } int build_network_state_req(tlv *tlv) { + // Free the previously allocated memory + free(tlv->pad1); + network_state_req *new = (network_state_req*) malloc(sizeof(network_state_req)); if(new == NULL) @@ -108,7 +131,10 @@ 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, int64_t node_id, int16_t seqno, char *data) { + // Free the previously allocated memory + free(tlv->pad1); + node_hash *new = (node_hash*) malloc(sizeof(node_hash)); if(new == NULL) @@ -118,14 +144,19 @@ 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, (unsigned char*) new->node_hash); tlv->node_hash = new; return 0; } -int build_node_state_req(tlv *tlv, long node_id) { +int build_node_state_req(tlv *tlv, int64_t node_id) { + // Free the previously allocated memory + free(tlv->pad1); + node_state_req *new = (node_state_req*) malloc(sizeof(node_state_req)); if(new == NULL) @@ -140,9 +171,12 @@ 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, int64_t node_id, int16_t seqno, char *data, size_t data_len) { + // Free the previously allocated memory + free(tlv->pad1); + 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 +191,22 @@ 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, (unsigned char*) 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) { + // Free the previously allocated memory + free(tlv->pad1); + warning *new = (warning*) malloc(sizeof(warning)); - int len = strlen(message); + int len = message_len; if(new == NULL) return -1; @@ -180,9 +219,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..d10d3c9 100644 --- a/src/tlv.h +++ b/src/tlv.h @@ -4,8 +4,7 @@ #include #include #include -#include "parser.h" -#include "hash.h" +#include #define LEN_NEIGHBOUR_REQ 0 #define LEN_NEIGHBOUR 18 @@ -20,8 +19,8 @@ typedef struct packet { unsigned char magic; // 95 (si autre, ignorer) unsigned char version; // 1 (si autre, ignorer) - short length; // 1020 max - char *body; + int16_t length; // 1020 max + char body[1020]; } packet; // 1 octet @@ -47,7 +46,7 @@ typedef struct neighbour { unsigned char type; unsigned char length; struct in6_addr ip; - short port; + int16_t port; } neighbour; // 18 octets @@ -67,8 +66,8 @@ typedef struct network_state_req { typedef struct node_hash { unsigned char type; unsigned char length; - long node_id; - short seqno; + int64_t node_id; + int16_t seqno; char node_hash[16]; } node_hash; @@ -76,15 +75,15 @@ typedef struct node_hash { typedef struct node_state_req { unsigned char type; unsigned char length; - long node_id; + int64_t 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; + int64_t node_id; + int16_t seqno; char node_hash[16]; char data[192]; } node_state; @@ -109,19 +108,23 @@ typedef union tlv { warning *warning; } tlv; +#include "node.h" +#include "hash.h" +#include "parser.h" + // 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(tlv *tlv, struct in6_addr ip, short port); -int build_network_hash(tlv *tlv, char *network_hash); +int build_neighbour_req(union tlv *tlv); +int build_neighbour(tlv *tlv, struct in6_addr ip, int16_t port); +int build_network_hash(tlv *tlv, 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_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_hash(tlv *tlv, int64_t node_id, int16_t seqno, char *data); +int build_node_state_req(tlv *tlv, int64_t node_id); +int build_node_state(tlv *tlv, int64_t node_id, int16_t seqno, char *data, size_t data_len); +int build_warning(tlv *tlv, char *message, size_t message_len); #endif diff --git a/src/tlv.o b/src/tlv.o new file mode 100644 index 0000000..1e8ab96 Binary files /dev/null and b/src/tlv.o differ