// 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 "tlv.h" #include "node.h" // 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, 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; } // 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 client; struct iovec io = { .iov_len = 1024, .iov_base = req }; struct msghdr msg_to_receive = { .msg_name = &client, .msg_namelen = sizeof(client), .msg_iov = &io, .msg_iovlen = 1 }; while(1){ memset(req, '\0', 1024); struct sockaddr_in6 client; unsigned int client_len = sizeof(client); 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); // 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; } struct tlv_list received_tlvs; if (validate_tlvs(formated_rec_datagram) < 0) { /* code */ } } } // 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(){ }; // 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; } } // We then look at the differents TLVs in the packet. void work_with_tlvs(char *data, short packet_len){ 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 neighbor tlv has to be sent tlv_len = data[pos+1]; pos += tlv_len + 2; // NOT FINISHED - Where are ip and seqno stored? build_neighbour(&tmp_tlv, ip, seqno); // 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 tlv_len = data[pos+1]; pos += tlv_len + 2; tlv.neighbour = (neighbour*) (data + pos); 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 ; } } } void work_with_tlvs(struct tlvs_list receivied_tlvs){ // For every TLV, // We make sure the TLV is legal. if(!validate_tlvs(tlv)){ perror(">> Invalid TLV receivied, it will be ignored."); } // Switch // TLV Network Hash // We calculate a network hash, // We compare both, // If they differ, we send a TLV Network State Request // back to the sender. // 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. } 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; }