// 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" /* ---- 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; } // 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; } /* ---- Fin fonctions utilitaires ---- */ 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; } 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; }