1585 lines
52 KiB
C
1585 lines
52 KiB
C
// 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 "node.h"
|
|
|
|
// Static variables
|
|
static list *data_list;
|
|
static list *neighbour_list;
|
|
|
|
/* ---- Fonctions utilitaires ---- */
|
|
|
|
// Looks for more peers
|
|
int ask_for_peers(int socket_num) {
|
|
print_debug(">> Asking for more peers...");
|
|
// Print out the current peer list.
|
|
|
|
// Only ask for more peers if the neighbour list is small enough
|
|
int nbr_peers = len_list(neighbour_list);
|
|
if( nbr_peers >= 5){
|
|
print_debug(">> We have enough peers, skipping...");
|
|
return 0;
|
|
} else if (nbr_peers <= 0){
|
|
print_debug(">> No peers found in the peer list, something terrible happened.");
|
|
return -1;
|
|
} else {
|
|
|
|
// Get random peer
|
|
neighbour_peer *peer = get_random_neighbour();
|
|
struct in6_addr ip = peer->ip;
|
|
int16_t port = peer->port;
|
|
|
|
/*int ifindex = if_nametoindex("enp3s0");
|
|
if(ifindex == 0) {
|
|
int ifindex = if_nametoindex("eth0");
|
|
if(ifindex == 0) {
|
|
perror("if_nametoindex failed");
|
|
return -1;
|
|
}
|
|
}*/
|
|
|
|
int ifindex = 0;
|
|
|
|
// Initialize sockaddr
|
|
struct sockaddr_in6 dest;
|
|
memset(&dest, 0, sizeof(struct sockaddr_in6));
|
|
dest.sin6_family = AF_INET6;
|
|
memcpy(&dest.sin6_addr, &ip, 16);
|
|
dest.sin6_port = htobe16(port);
|
|
dest.sin6_scope_id = ifindex;
|
|
|
|
// Send neighbour request TLV
|
|
tlv neighbour_req;
|
|
neighbour_req.pad1 = NULL;
|
|
int rc = build_neighbour_req(&neighbour_req);
|
|
if (rc < 0) {
|
|
print_debug(">> Failed to build neighbour_req");
|
|
}
|
|
|
|
rc = send_single_tlv(&neighbour_req, &dest, socket_num);
|
|
if (rc < 0) {
|
|
print_debug(">> Error while sending a TLV.");
|
|
return -1;
|
|
} else {
|
|
print_debug(">> Send TLV.");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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() {
|
|
print_debug(">> Getting random peer...");
|
|
// Get a random number
|
|
srand((unsigned) time(NULL));
|
|
int n = (rand() % len_list(neighbour_list)) + 1;
|
|
// Get nth neighbour
|
|
list *tmp = neighbour_list;
|
|
|
|
for(int i=1; i < n; i++) {
|
|
tmp = tmp->next;
|
|
}
|
|
|
|
return (neighbour_peer*) tmp->data;
|
|
}
|
|
|
|
// Search for this peer in the neighbour table
|
|
neighbour_peer *get_neighbour(struct in6_addr *ip, int16_t port) {
|
|
print_debug(">> Getting neighbour.");
|
|
|
|
if (DEBUG_LEVEL > 1) {
|
|
char * buff_str_ip[1024];
|
|
char * ip_str = (char * ) inet_ntop(AF_INET6,ip,(char * restrict) buff_str_ip, 1024);
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> Looking up %s @ %i\n", ip_str, port );
|
|
}
|
|
|
|
// Look for neighbour
|
|
list *tmp = neighbour_list;
|
|
neighbour_peer *peer;
|
|
|
|
while(tmp != NULL) {
|
|
// check for same ip and same port
|
|
peer = (neighbour_peer*) tmp->data;
|
|
|
|
if(memcmp(&peer->ip, ip, sizeof(struct in6_addr)) == 0
|
|
&& memcmp(&peer->port, &port, sizeof(int16_t)) == 0) {
|
|
return peer;
|
|
}
|
|
|
|
// if they differ, get next peer
|
|
tmp = tmp->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Return -1 if we have enough peers,
|
|
// 1 if it was added
|
|
// Return 0 if peer was updated as last_seen
|
|
int add_n_update_neighbour(struct in6_addr *ip, int16_t port) {
|
|
|
|
|
|
// We try to find a peer with this address and port.
|
|
neighbour_peer *peer = get_neighbour(ip, port);
|
|
time_t curtime;
|
|
|
|
if (peer == NULL) {
|
|
print_debug(">> We don't know this peer yet");
|
|
// check if there are less than 15 neighbours
|
|
if(len_list(neighbour_list) >= 15){
|
|
return -1;
|
|
} else {
|
|
print_debug(">> Adding them to the peer table.\n");
|
|
// if there are less, initialize the new peer to add to the list
|
|
peer = (neighbour_peer*) malloc(sizeof(neighbour_peer));
|
|
memcpy(&peer->ip, ip, sizeof(struct in6_addr));
|
|
peer->port = LISTEN_PORT;
|
|
peer->is_temporary = 1;
|
|
|
|
// set last_seen time
|
|
time(&curtime);
|
|
peer->last_seen = curtime;
|
|
|
|
list * tmp = neighbour_list;
|
|
|
|
// set new peer as head of list
|
|
list *node = (list*) malloc(sizeof(list));
|
|
node->data = (void*) peer;
|
|
node->next = tmp;
|
|
neighbour_list = node;
|
|
return 1;
|
|
}
|
|
} else {
|
|
|
|
if (DEBUG_LEVEL > 0) {
|
|
char * buff_str_ip[1024];
|
|
char * ip_str = (char * ) inet_ntop(AF_INET6,ip,(char * restrict) buff_str_ip, 1024);
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> Found peer %s @ %i, updating the last seen time...\n", ip_str, port);
|
|
|
|
}
|
|
|
|
time_t curtime;
|
|
// if the peer was already in the list, update it
|
|
time(&curtime);
|
|
peer->last_seen = curtime;
|
|
return 0;
|
|
|
|
}
|
|
}
|
|
|
|
// get data associated with id, if it doesn't exist return NULL
|
|
pub_data *get_data(uint64_t id) {
|
|
list *tmp = data_list;
|
|
pub_data *data;
|
|
|
|
while(tmp != NULL) {
|
|
data = (pub_data*) tmp->data;
|
|
tmp = tmp->next;
|
|
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, uint64_t id, uint16_t seqno, char *data) {
|
|
pub_data *new_data = (pub_data*) malloc(sizeof(pub_data));
|
|
char *_data = (char*) malloc(len);
|
|
if (_data == NULL) {
|
|
print_error("Failed to allocate memory for copying the data !");
|
|
return NULL;
|
|
}
|
|
new_data->length = len;
|
|
new_data->id = id;
|
|
new_data->seqno = seqno;
|
|
new_data->data = _data;
|
|
if(memcpy(_data, data, len) == NULL){
|
|
print_error("Failed to copy data !");
|
|
return NULL;
|
|
}
|
|
|
|
|
|
return new_data;
|
|
}
|
|
|
|
// A node state TLV was received and either no data associated to it's id is in our data list or the data was updated, return -1 if an error occurend, 0 if nothing had to be done and 1 if something was updated/added
|
|
int add_data(unsigned char len, uint64_t id, uint16_t seqno, char *data, pub_data *found) {
|
|
// Check if it's our own id
|
|
if(id == NODE_ID) {
|
|
// wtf
|
|
if(found == NULL) {
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> Our own node is not in the data list, something went terribly wrong.\n");
|
|
return -1;
|
|
}
|
|
|
|
// If seqno is bigger or equals than our stored seqno then update seqno
|
|
if( ((seqno - found->seqno) & 32768) == 0 ) {
|
|
printf(">> Updating seqno of our own published data.\n");
|
|
found->seqno = (seqno + 1) % (65535);
|
|
return 1;
|
|
}
|
|
|
|
// Else, do nothing
|
|
printf(">> Our own seqno didn't need to be updated.\n");
|
|
return 0;
|
|
}
|
|
|
|
// If it's not our own id, update the data if it's already in our data list and seqno is bigger than our stored seqno
|
|
if(found != NULL) {
|
|
// Check if seqno is smaller or equals to our stored seqno
|
|
if( ((found->seqno - seqno) & 32768) == 0 ) {
|
|
printf(">> Data received has smaller seqno than stored seqno, nothing has to be done.\n");
|
|
return 0;
|
|
}
|
|
|
|
// Update data
|
|
found->length = len;
|
|
found->id = id;
|
|
found->seqno = seqno;
|
|
|
|
// Updata message
|
|
free(found->data);
|
|
found->data = (char*) malloc(len);
|
|
memcpy(found->data, data, len);
|
|
|
|
printf(">> Updated %li's published data.\n", id);
|
|
|
|
return 1;
|
|
}
|
|
|
|
// Else, add new data
|
|
pub_data *new_data = copy_data(len, id, seqno, data);
|
|
|
|
// Find correct position for new data
|
|
list *tmp = data_list;
|
|
list *last = NULL;
|
|
list *new_node;
|
|
uint64_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;
|
|
|
|
printf(">> Added new message to data list.\n");
|
|
|
|
return 1;
|
|
}
|
|
|
|
// 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;
|
|
|
|
printf(">> Added new message to data list.\n");
|
|
|
|
return 1;
|
|
}
|
|
|
|
// 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
|
|
new_node = (list*) malloc(sizeof(list));
|
|
new_node->data = (void*) new_data;
|
|
new_node->next = NULL;
|
|
last->next = new_node;
|
|
|
|
printf(">> Added new message to data list.\n");
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ---- Fin fonctions utilitaires ---- */
|
|
|
|
// Update the neighbour list
|
|
int update_neighbours() {
|
|
print_debug(">> Updating neighbours.");
|
|
list *tmp = neighbour_list, *last = NULL, *node_to_delete;
|
|
neighbour_peer *peer;
|
|
time_t curtime;
|
|
int deleted = 0;
|
|
|
|
// check every neighbour
|
|
while(tmp != NULL) {
|
|
peer = (neighbour_peer*) tmp->data;
|
|
if (DEBUG_LEVEL > 1) {
|
|
char * buff_str_ip[1024];
|
|
char * ip_str = (char * ) inet_ntop(AF_INET6,&peer->ip,(char * restrict) buff_str_ip, 1024);
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> Checking for neighbour %s\n", ip_str );
|
|
}
|
|
// Check if peer is temporary
|
|
if(peer->is_temporary) {
|
|
// If it's been 70 seconds or more since we last received a packet from this peer then remove it from the list
|
|
time(&curtime);
|
|
|
|
if(difftime(peer->last_seen, curtime) >= 70) {
|
|
// increase the count of deleted nodes
|
|
deleted++;
|
|
|
|
print_debug(">> They have not been seen for the past 70 seconds, deleting...");
|
|
|
|
// If head of the list
|
|
if(last == NULL) {
|
|
// Store node to delete
|
|
node_to_delete = tmp;
|
|
|
|
// Update list
|
|
tmp = tmp->next;
|
|
neighbour_list = tmp;
|
|
|
|
// Free allocated memory
|
|
free(node_to_delete->data);
|
|
free(node_to_delete);
|
|
|
|
continue;
|
|
}
|
|
|
|
// Store node to delete
|
|
node_to_delete = tmp;
|
|
|
|
// Update list
|
|
tmp = tmp->next;
|
|
last->next = tmp;
|
|
|
|
// Free allocated memory
|
|
free(node_to_delete->data);
|
|
free(node_to_delete);
|
|
|
|
continue;
|
|
} else {
|
|
print_debug(">> Peer has been seen in the last 70 seconds, keeping him in.");
|
|
}
|
|
} else {
|
|
print_debug(">> Peer is not temporary, keeping him in.");
|
|
}
|
|
|
|
last = tmp;
|
|
tmp = tmp->next;
|
|
}
|
|
|
|
// returns the amount of nodes that were deleted
|
|
return deleted;
|
|
}
|
|
|
|
// 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) {
|
|
print_debug(">> Adding tlv to packet");
|
|
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->magic = 95;
|
|
pack->version = 1;
|
|
pack->length = 0;
|
|
|
|
memset(pack->body, 0, 1020);
|
|
sent = 1;
|
|
}
|
|
} else {
|
|
// In case we need to add a padding packet, and the packet is full,
|
|
// we just ignore that padding, and send out the packet.
|
|
if(pack->length >= 1020) {
|
|
errval = send_packet((char*) pack, pack->length, dest, socket_num);
|
|
|
|
pack->magic = 95;
|
|
pack->version = 1;
|
|
pack->length = 0;
|
|
|
|
memset(pack->body, 0, 1020);
|
|
sent = 1;
|
|
}
|
|
}
|
|
|
|
// Copy data from tlv into body
|
|
switch(type) {
|
|
case 1:
|
|
memcpy(pack->body + pack->length, (char*) &tlv->pad1->type, 1);
|
|
pack->length += 1;
|
|
|
|
break;
|
|
case 2:
|
|
memcpy(pack->body + pack->length, (char*) &tlv->padn->type, 1);
|
|
memcpy(pack->body + pack->length + 1, (char*) &tlv->padn->length, 1);
|
|
memcpy(pack->body + pack->length + 2, (char*) &tlv->padn->mbz, tlv->padn->length);
|
|
|
|
pack->length += len;
|
|
|
|
break;
|
|
case 3:
|
|
memcpy(pack->body + pack->length, (char*) &tlv->neighbour->type, 1);
|
|
memcpy(pack->body + pack->length + 1, (char*) &tlv->neighbour->length, 1);
|
|
|
|
pack->length += len;
|
|
|
|
break;
|
|
case 4:
|
|
memcpy(pack->body + pack->length, (char*) &tlv->network_hash->type, 1);
|
|
memcpy(pack->body + pack->length + 1, (char*) &tlv->network_hash->length, 1);
|
|
memcpy(pack->body + pack->length + 2, (char*) &tlv->network_hash->network_hash, 16);
|
|
|
|
pack->length += len;
|
|
|
|
break;
|
|
case 5:
|
|
memcpy(pack->body + pack->length, (char*) &tlv->network_state_req->type, 1);
|
|
memcpy(pack->body + pack->length + 1, (char*) &tlv->network_state_req->length, 1);
|
|
|
|
pack->length += len;
|
|
|
|
break;
|
|
case 6:
|
|
memcpy(pack->body + pack->length, (char*) &tlv->node_hash->type, 1);
|
|
memcpy(pack->body + pack->length + 1, (char*) &tlv->node_hash->length, 1);
|
|
memcpy(pack->body + pack->length + 2, (char*) &tlv->node_hash->node_id, 8);
|
|
memcpy(pack->body + pack->length + 10, (char*) &tlv->node_hash->seqno, 2);
|
|
memcpy(pack->body + pack->length + 12, (char*) &tlv->node_hash->node_hash, 16);
|
|
|
|
pack->length += len;
|
|
|
|
break;
|
|
case 7:
|
|
memcpy(pack->body + pack->length, (char*) &tlv->node_state_req->type, 1);
|
|
memcpy(pack->body + pack->length + 1, (char*) &tlv->node_state_req->length, 1);
|
|
memcpy(pack->body + pack->length + 2, (char*) &tlv->node_state_req->node_id, 8);
|
|
|
|
pack->length += len;
|
|
|
|
break;
|
|
case 8:
|
|
memcpy(pack->body + pack->length, (char*) &tlv->node_state->type, 1);
|
|
memcpy(pack->body + pack->length + 1, (char*) &tlv->node_state->length, 1);
|
|
memcpy(pack->body + pack->length + 2, (char*) &tlv->node_state->node_id, 8);
|
|
memcpy(pack->body + pack->length + 10, (char*) &tlv->node_state->seqno, 2);
|
|
memcpy(pack->body + pack->length + 12, (char*) &tlv->node_state->node_hash, 16);
|
|
memcpy(pack->body + pack->length + 28, (char*) &tlv->node_state->data, tlv->node_state->length - 26);
|
|
|
|
pack->length += len;
|
|
|
|
break;
|
|
case 9:
|
|
memcpy(pack->body + pack->length, (char*) &tlv->warning->type, 1);
|
|
memcpy(pack->body + pack->length + 1, (char*) &tlv->warning->length, 1);
|
|
memcpy(pack->body + pack->length + 2, (char*) &tlv->warning->message, tlv->warning->length);
|
|
|
|
pack->length += len;
|
|
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
print_debug(">> Finished adding the TLVs to the packet");
|
|
|
|
// If the previous packet was sent 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, uint16_t length, struct sockaddr_in6 *dest, int socket_num) {
|
|
uint16_t be_len = htobe16(*(uint16_t*) (packet_buff + 2));
|
|
memcpy(packet_buff + 2, &be_len, 2);
|
|
|
|
// Vectorized buffer
|
|
struct iovec vec_buff[1];
|
|
vec_buff[0].iov_len = length + 4;
|
|
vec_buff[0].iov_base = packet_buff;
|
|
|
|
int error_while_sending = 0;
|
|
|
|
// Creating the struct to send out with sendmsg
|
|
struct msghdr packet_tlv_send_out;
|
|
memset(&packet_tlv_send_out, 0, sizeof(struct msghdr));
|
|
packet_tlv_send_out.msg_name = dest;
|
|
packet_tlv_send_out.msg_namelen = sizeof(struct sockaddr_in6);
|
|
packet_tlv_send_out.msg_iov = vec_buff;
|
|
packet_tlv_send_out.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) {
|
|
print_error("Unable to send out the packet to peer.");
|
|
error_while_sending = 1;
|
|
} else if (response_code < length) {
|
|
print_debug(">> Sent out only part of the packet.");
|
|
error_while_sending = 1;
|
|
} else {
|
|
print_debug(">> Send out packet to peer.");
|
|
}
|
|
|
|
if (error_while_sending == 1) {
|
|
return -1;
|
|
} else {
|
|
if (DEBUG_LEVEL > 0) {
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> Packet successfully sent to peer. %d bytes sent.\n", response_code);
|
|
}
|
|
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;
|
|
packet pack = (packet) {.magic = 95, .version = 1, .length = 0};
|
|
memset(pack.body, 0, 1020);
|
|
|
|
// Copy data from tlv into body
|
|
switch(type) {
|
|
case 1:
|
|
memcpy(pack.body + pack.length, (char*) &tlv->pad1->type, 1);
|
|
pack.length += 1;
|
|
|
|
break;
|
|
case 2:
|
|
memcpy(pack.body + pack.length, (char*) &tlv->padn->type, 1);
|
|
memcpy(pack.body + pack.length + 1, (char*) &tlv->padn->length, 1);
|
|
memcpy(pack.body + pack.length + 2, (char*) &tlv->padn->mbz, tlv->padn->length);
|
|
|
|
pack.length += tlv->padn->length + 2;
|
|
|
|
break;
|
|
case 3:
|
|
memcpy(pack.body + pack.length, (char*) &tlv->neighbour->type, 1);
|
|
memcpy(pack.body + pack.length + 1, (char*) &tlv->neighbour->length, 1);
|
|
|
|
pack.length += tlv->neighbour->length + 2;
|
|
|
|
break;
|
|
case 4:
|
|
memcpy(pack.body + pack.length, (char*) &tlv->network_hash->type, 1);
|
|
memcpy(pack.body + pack.length + 1, (char*) &tlv->network_hash->length, 1);
|
|
memcpy(pack.body + pack.length + 2, (char*) &tlv->network_hash->network_hash, 16);
|
|
|
|
pack.length += tlv->network_hash->length + 2;
|
|
|
|
break;
|
|
case 5:
|
|
memcpy(pack.body + pack.length, (char*) &tlv->network_state_req->type, 1);
|
|
memcpy(pack.body + pack.length + 1, (char*) &tlv->network_state_req->length, 1);
|
|
|
|
pack.length += tlv->network_state_req->length + 2;
|
|
|
|
break;
|
|
case 6:
|
|
memcpy(pack.body + pack.length, (char*) &tlv->node_hash->type, 1);
|
|
memcpy(pack.body + pack.length + 1, (char*) &tlv->node_hash->length, 1);
|
|
memcpy(pack.body + pack.length + 2, (char*) &tlv->node_hash->node_id, 8);
|
|
memcpy(pack.body + pack.length + 10, (char*) &tlv->node_hash->seqno, 2);
|
|
memcpy(pack.body + pack.length + 12, (char*) &tlv->node_hash->node_hash, 16);
|
|
|
|
pack.length += tlv->node_hash->length + 2;
|
|
|
|
break;
|
|
case 7:
|
|
memcpy(pack.body + pack.length, (char*) &tlv->node_state_req->type, 1);
|
|
memcpy(pack.body + pack.length + 1, (char*) &tlv->node_state_req->length, 1);
|
|
memcpy(pack.body + pack.length + 2, (char*) &tlv->node_state_req->node_id, 8);
|
|
|
|
pack.length += tlv->node_state_req->length + 2;
|
|
|
|
break;
|
|
case 8:
|
|
memcpy(pack.body + pack.length, (char*) &tlv->node_state->type, 1);
|
|
memcpy(pack.body + pack.length + 1, (char*) &tlv->node_state->length, 1);
|
|
memcpy(pack.body + pack.length + 2, (char*) &tlv->node_state->node_id, 8);
|
|
memcpy(pack.body + pack.length + 10, (char*) &tlv->node_state->seqno, 2);
|
|
memcpy(pack.body + pack.length + 12, (char*) &tlv->node_state->node_hash, 16);
|
|
memcpy(pack.body + pack.length + 28, (char*) &tlv->node_state->data, tlv->node_state->length - 26);
|
|
|
|
pack.length += tlv->node_state->length + 2;
|
|
|
|
break;
|
|
case 9:
|
|
memcpy(pack.body + pack.length, (char*) &tlv->warning->type, 1);
|
|
memcpy(pack.body + pack.length + 1, (char*) &tlv->warning->length, 1);
|
|
memcpy(pack.body + pack.length + 2, (char*) &tlv->warning->message, tlv->warning->length);
|
|
|
|
pack.length += tlv->warning->length + 2;
|
|
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
// Send the packet
|
|
return send_packet((char*) &pack, pack.length, dest, socket_num);
|
|
}
|
|
|
|
// TODO This function can be deleted.
|
|
// int send_tlv(tlv *tlv_to_send, uint16_t tlv_size, struct sockaddr_in6 * dest_list, int dest_list_size, int socket_num){
|
|
// print_debug(">> 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) {
|
|
// print_debug(">> Unable to send the tlv, it's size is 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.
|
|
// memcpy(&packet_buff,&pack,1024);
|
|
//
|
|
// if (DEBUG_LEVEL > 1) {
|
|
// print_debug(">> 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) {
|
|
// if (DEBUG_LEVEL > 0) {
|
|
// printf("\x1b[31m[DEBUG]\x1b[0m >> Unable to send out the packet to peer %li", i);
|
|
// }
|
|
// error_while_sending = 1;
|
|
// continue;
|
|
// } else if (response_code < sizeof(packet_tlv_send_out)) {
|
|
// print_debug(">> Sent out only part of the packet.");
|
|
// error_while_sending = 1;
|
|
// continue;
|
|
// } else {
|
|
// if (DEBUG_LEVEL > 0) {
|
|
// printf("\x1b[31m[DEBUG]\x1b[0m >> Sent out packet to peer %i", i);
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// if (error_while_sending == 1) {
|
|
// print_debug(">> 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, uint16_t packet_len){
|
|
|
|
char type = data[pos];
|
|
|
|
// Nothing to do in this case
|
|
if(type == 0){
|
|
print_debug(">> Found padding TLV type.");
|
|
return 0;
|
|
}
|
|
|
|
// Check that we can read a length
|
|
if(pos + 1 >= packet_len){
|
|
print_debug(">> Reading outside of packet's max length.");
|
|
return -1;
|
|
}
|
|
// 0 1 2 3 = Packet
|
|
// 4 = type 5 = tlv_len
|
|
unsigned char tlv_len = data[pos+1];
|
|
|
|
// Check that the tlv does not exceed the packet length
|
|
if(pos + tlv_len > packet_len){
|
|
print_debug(">> The TLV Length exceeds the packet length\n");
|
|
return -1;
|
|
}
|
|
|
|
if (DEBUG_LEVEL > 1) {
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> TLV has type %i\n", type );
|
|
}
|
|
|
|
// 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;
|
|
|
|
/*
|
|
// Check if it has the right hash
|
|
uint16_t *seqno = (uint16_t*) (data + pos + 10);
|
|
uint64_t *id = (uint64_t*) (data + pos + 2);
|
|
|
|
pub_data pdata = (pub_data) {
|
|
.length = tlv_len,
|
|
.id = *id,
|
|
.seqno = *seqno,
|
|
.data = (unsigned char*) malloc(tlv_len)
|
|
};
|
|
|
|
unsigned char *cur_hash = (unsigned char*) (data + pos + 12);
|
|
char *cur_message = data + pos + 28;
|
|
|
|
unsigned char hash[16];
|
|
|
|
memcpy(pdata.data, cur_message, tlv_len);
|
|
|
|
hash_data(&pdata, hash);
|
|
|
|
if(memcmp(hash, cur_hash, 16) != 0) {
|
|
print_debug(">> Malformed hash.");
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> Received : ");
|
|
|
|
for(int x = 0; x < 16; x++){
|
|
printf("%02x", hash[x]);
|
|
fflush(0);
|
|
}
|
|
|
|
printf("\n");
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> Received : ");
|
|
|
|
for(int x = 0; x < 16; x++){
|
|
printf("%02x", cur_hash[x]);
|
|
fflush(0);
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
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 * received_data_buffer, int received_data_len, struct packet * packet_to_return){
|
|
|
|
packet_to_return = (packet*) received_data_buffer;
|
|
|
|
// We need to check a few things ;
|
|
// The first byte must be worth 95,
|
|
if (packet_to_return->magic != 95) {
|
|
print_debug(">> The magic number of the packet is no good.");
|
|
return -1;
|
|
}
|
|
|
|
// The second byte must be worth 1,
|
|
if (packet_to_return->version != 1) {
|
|
print_debug(">> The version number of the packet is no good.");
|
|
return -1;
|
|
}
|
|
|
|
// Convert to hardware order.
|
|
((packet*) packet_to_return)->length = be16toh(((packet*) packet_to_return)->length);
|
|
if (packet_to_return->length + 4 < received_data_len ) {
|
|
print_debug(">> The packet length is bigger than the UDP datagram, which is not possible with the current laws of physics.");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int add_message(char * message, int message_len){
|
|
// Don't update the message if it's empty
|
|
if(message_len == 0){
|
|
return -1;
|
|
}
|
|
|
|
// If not, get our data in the list and update it
|
|
pub_data *our_data = get_data(NODE_ID);
|
|
|
|
if(our_data != NULL) {
|
|
our_data->seqno = (our_data->seqno + 1) % 65535;
|
|
our_data->length = message_len;
|
|
free(our_data->data);
|
|
our_data->data = (char*) malloc(message_len);
|
|
memcpy(our_data->data, message, message_len);
|
|
|
|
print_debug(">> Message added.");
|
|
|
|
return 0;
|
|
}
|
|
|
|
print_debug(">> Message could not be added because our own ID is not in the data_list, something went wrong.");
|
|
return -1;
|
|
}
|
|
|
|
// We then look at the differents TLVs in the packet.
|
|
int work_with_tlvs(char * data, uint16_t total_packet_len, struct sockaddr_in6 *sender, int socket_num){
|
|
uint16_t packet_len = ((packet*) data)->length;
|
|
|
|
if(packet_len != total_packet_len - 4) {
|
|
print_debug(">> Length indicated in packet differs from real length of packet received, disgarding packet.");
|
|
return -1;
|
|
}
|
|
int nbr_of_tlvs = 0;
|
|
|
|
int pos = 4;
|
|
unsigned char tlv_len, hash[16], hash2[16];
|
|
char warn[32];
|
|
|
|
// The TLV we are going to send back.
|
|
tlv new_tlv;
|
|
new_tlv.pad1 = NULL;
|
|
|
|
list * tmp_list;
|
|
pub_data * pdata;
|
|
|
|
// holds the random neighbour we send back in case of a neighbour_req.
|
|
struct neighbour_peer *random_neighbour;
|
|
// memset(random_neighbour, 0, sizeof(struct neighbour_peer));
|
|
|
|
// Holds the new neighbour send to us by a "neighbour tlv"
|
|
struct sockaddr_in6 new_neighbour;
|
|
|
|
// We create the packet in which we are going to send back our responses.
|
|
packet pack = (packet) {.magic = 95, .version = 1, .length = 0};
|
|
memset(pack.body, 0, 1020);
|
|
|
|
int ifindex = 0;
|
|
|
|
// Temporary values
|
|
uint16_t *port, *seqno;
|
|
uint64_t *id;
|
|
unsigned char *cur_hash, *ip;
|
|
char *cur_message;
|
|
|
|
while(pos < total_packet_len) {
|
|
// Making sure the current TLV we are looking at is valid.
|
|
// TODO : I think we should reset all the structs here.
|
|
// memset(random_neighbour, 0, sizeof(struct neighbour_peer));
|
|
// memset(pdata, 0, sizeof(struct pub_data));
|
|
// memset(tmp_list, 0, sizeof(struct list));
|
|
memset(hash, 0, 16);
|
|
memset(warn, 0, 32);
|
|
tlv_len = 0;
|
|
|
|
switch(validate_tlv(data, pos, total_packet_len)) {
|
|
case 0:
|
|
// We received a padding tlv so it is ignored
|
|
print_debug(">> Received padding tlv, ignoring...");
|
|
pos += 1;
|
|
nbr_of_tlvs++;
|
|
break;
|
|
case 1:
|
|
// We received a padding tlv so it is ignored
|
|
print_debug(">> Received padding(n) tlv, ignoring...");
|
|
tlv_len = data[pos+1];
|
|
pos += tlv_len + 2;
|
|
nbr_of_tlvs++;
|
|
|
|
break;
|
|
case 2:
|
|
|
|
// We received a neighbour request so a random neighbor tlv has to be sent
|
|
print_debug(">> Received neighbour request, sending out a neighbour address.");
|
|
// Send a neighbour tlv
|
|
random_neighbour = get_random_neighbour();
|
|
if (random_neighbour == NULL) {
|
|
print_debug(">> Failed to get a random neighbour, failing...");
|
|
return -1;
|
|
}
|
|
|
|
// TODO : Seems to be a bug here, as this frees the new_tlv
|
|
build_neighbour(&new_tlv, random_neighbour->ip, random_neighbour->port);
|
|
// TODO : I suppose that since new_tlv is freed above, add_tlv ads an empty
|
|
// value to the packet ?
|
|
add_tlv(&pack, &new_tlv, sender, socket_num);
|
|
|
|
// The position is updated
|
|
tlv_len = data[pos+1];
|
|
pos += tlv_len + 2;
|
|
nbr_of_tlvs++;
|
|
|
|
break;
|
|
case 3:
|
|
|
|
print_debug(">> Received neighbour tlv, sending back network hash.");
|
|
// We received a neighbour tlv so a tlv network hash is sent to that address
|
|
ip = (unsigned char*) (data + pos + 2);
|
|
port = (uint16_t*) (data + pos + 18);
|
|
|
|
// Init dest socket
|
|
memset(&new_neighbour, 0, sizeof(new_neighbour));
|
|
new_neighbour.sin6_family = AF_INET6;
|
|
memcpy(&new_neighbour.sin6_addr, ip, 16);
|
|
new_neighbour.sin6_port = be16toh(*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;
|
|
nbr_of_tlvs++;
|
|
|
|
break;
|
|
case 4:
|
|
|
|
print_debug(">> Received network_hash, comparing with our own..");
|
|
// 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_hash = (unsigned char*) (data + pos + 2);
|
|
|
|
hash_network(data_list, hash);
|
|
|
|
if (DEBUG_LEVEL > 1) {
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> Our hash : ");
|
|
for(int x = 0; x < 16; x++){
|
|
printf("%02x", hash[x]);
|
|
fflush(0);
|
|
}
|
|
printf("\n");
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> Received : ");
|
|
for(int x = 0; x < 16; x++){
|
|
printf("%02x", cur_hash[x]);
|
|
fflush(0);
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
if(memcmp(hash, cur_hash, 16) != 0) {
|
|
print_debug(">> Sending out our network hash.");
|
|
build_network_state_req(&new_tlv);
|
|
send_single_tlv(&new_tlv, sender, socket_num);
|
|
} else {
|
|
print_debug(">> We're up to date.");
|
|
}
|
|
|
|
// The position is updated
|
|
tlv_len = data[pos+1];
|
|
pos += tlv_len + 2;
|
|
nbr_of_tlvs++;
|
|
|
|
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
|
|
print_debug(">> Received network state request, sending back hashes for messages.");
|
|
// for each known data build a node hash and add to packet
|
|
tmp_list = data_list;
|
|
|
|
while(tmp_list != NULL) {
|
|
pdata = (pub_data*) tmp_list->data;
|
|
build_node_hash(&new_tlv, pdata->id, pdata->seqno, pdata->data, pdata->length);
|
|
add_tlv(&pack, &new_tlv, sender, socket_num);
|
|
tmp_list = tmp_list->next;
|
|
|
|
printf("%lu\n", *(uint64_t*) (pack.body + 2));
|
|
}
|
|
|
|
// The position is updated
|
|
tlv_len = data[pos+1];
|
|
pos += tlv_len + 2;
|
|
|
|
break;
|
|
case 6:
|
|
// 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
|
|
print_debug(">> Received node hash, updating message entry...");
|
|
|
|
id = (uint64_t*) (data + pos + 2);
|
|
cur_hash = (unsigned char*) (data + pos + 12);
|
|
|
|
pdata = get_data(be64toh(*id));
|
|
|
|
// If data is found for this id then we check that both hashes are the same
|
|
if(pdata != NULL) {
|
|
print_debug(">> Comparing hashes...");
|
|
// 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_hash, 16) == 0) {
|
|
// The position is updated
|
|
tlv_len = data[pos+1];
|
|
pos += tlv_len + 2;
|
|
print_debug(">> Both hashes are the same, nothing to do.");
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
print_debug(">> No hash found, or hashes are different, sending back node state request.");
|
|
// If no pub_data was found or the hashes differ then we send a node state request
|
|
build_node_state_req(&new_tlv, be64toh(*id));
|
|
add_tlv(&pack, &new_tlv, sender, socket_num);
|
|
|
|
printf(">> Sending node state request for node %lu...\n", be64toh(*id));
|
|
|
|
// The position is updated
|
|
tlv_len = data[pos+1];
|
|
pos += tlv_len + 2;
|
|
|
|
break;
|
|
case 7:
|
|
|
|
// 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
|
|
print_debug(">> Received node state request. Processing...");
|
|
|
|
id = (uint64_t*) (data + pos + 2);
|
|
|
|
pdata = get_data(be64toh(*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);
|
|
} else {
|
|
print_debug(">> Found no data for the requested node, skipping...");
|
|
}
|
|
|
|
// The position is updated
|
|
tlv_len = data[pos+1];
|
|
pos += tlv_len + 2;
|
|
|
|
break;
|
|
case 8:
|
|
// We received a node state tlv so
|
|
// we add it to the data list
|
|
// or update the data stored
|
|
print_debug(">> Received node state, updating...");
|
|
|
|
tlv_len = data[pos + 1];
|
|
id = (uint64_t*) (data + pos + 2);
|
|
seqno = (uint16_t*) (data + pos + 10);
|
|
cur_hash = (unsigned char*) (data + pos + 12);
|
|
cur_message = data + pos + 28;
|
|
|
|
print_debug(">> Received message ! ");
|
|
printf("Type : %d\n", data[pos] );
|
|
printf("Length : %d\n", tlv_len );
|
|
printf("Node ID : %lu\n", be64toh(*id) );
|
|
printf("Seqno : %hu\n", be16toh(*seqno) );
|
|
printf("Hash :");
|
|
for(int x = 0; x < 16; x++){
|
|
printf("%02x", cur_hash[x]);
|
|
fflush(0);
|
|
}
|
|
printf("\n");
|
|
for(int x = 0; x < tlv_len - 26; x++){
|
|
printf("%c", cur_message[x]);
|
|
fflush(0);
|
|
}
|
|
printf("\n");
|
|
|
|
// Check if it has the right hash
|
|
pub_data pdata_check = (pub_data) {
|
|
.length = tlv_len - 26,
|
|
.id = be64toh(*id),
|
|
.seqno = be16toh(*seqno),
|
|
.data = (char*) malloc(tlv_len)
|
|
};
|
|
|
|
memcpy(pdata_check.data, cur_message, tlv_len - 26);
|
|
|
|
hash_data(&pdata_check, hash2);
|
|
|
|
print_debug(">> Built message: ");
|
|
printf("Type : %d\n", data[pos] );
|
|
printf("Length : %d\n", pdata_check.length + 26);
|
|
printf("Node ID : %lu\n", pdata_check.id);
|
|
printf("Seqno : %hu\n", pdata_check.seqno);
|
|
printf("Hash :");
|
|
for(int x = 0; x < 16; x++){
|
|
printf("%02x", hash2[x]);
|
|
fflush(0);
|
|
}
|
|
printf("\n");
|
|
for(int x = 0; x < tlv_len - 26; x++){
|
|
printf("%c", pdata_check.data[x]);
|
|
fflush(0);
|
|
}
|
|
printf("\n");
|
|
|
|
if(memcmp(hash2, cur_hash, 16) != 0) {
|
|
print_debug(">> Malformed hash.");
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> Calculated : ");
|
|
|
|
for(int x = 0; x < 16; x++){
|
|
printf("%02x", hash2[x]);
|
|
fflush(0);
|
|
}
|
|
|
|
printf("\n");
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> Received : ");
|
|
|
|
for(int x = 0; x < 16; x++){
|
|
printf("%02x", cur_hash[x]);
|
|
fflush(0);
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
pos += tlv_len + 2;
|
|
break;
|
|
}
|
|
|
|
free(pdata_check.data);
|
|
|
|
/*
|
|
if (DEBUG_LEVEL > 0) {
|
|
if (cur_message == NULL) {
|
|
print_error("The data in the current node is NULL !");
|
|
return -1;
|
|
}
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> “%ls\0”\n", (const wchar_t*) cur_message);
|
|
sleep(1);
|
|
}
|
|
*/
|
|
|
|
// Compare hashes
|
|
pdata = get_data(be64toh(*id));
|
|
|
|
// If data is found for this id then we check that both hashes are the same
|
|
if(pdata != NULL) {
|
|
print_debug(">> Comparing hashes...");
|
|
// We hash the data stored in the data list
|
|
memset(hash, 0, 16);
|
|
hash_data(pdata, hash);
|
|
|
|
// If both hashes are the same then nothing has to be done
|
|
if(memcmp(hash, cur_hash, 16) == 0) {
|
|
// The position is updated
|
|
pos += tlv_len + 2;
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
// Else, we update the data
|
|
int rc = add_data(tlv_len - 26, be64toh(*id), be16toh(*seqno), cur_message, pdata);
|
|
if (rc < 0) {
|
|
print_error("Error while adding node state !");
|
|
}
|
|
// The position is updated
|
|
pos += tlv_len + 2;
|
|
|
|
break;
|
|
case 9:
|
|
print_debug(">> \aReceived warning !");
|
|
// We received a warning tlv so it's message is printed
|
|
tlv_len = data[pos+1];
|
|
cur_message = data + pos + 2;
|
|
|
|
// Print exactly new_tlv.length characters from new_tlv.message
|
|
sprintf(warn, ">> WARNING:\n%%.%ds\n", tlv_len + 1);
|
|
printf(warn, cur_message);
|
|
|
|
// The position is updated
|
|
pos += tlv_len + 2;
|
|
|
|
break;
|
|
default:
|
|
// A malformed packet was found so we stop looking for more packets and send a warning tlv
|
|
strcpy(warn, "Packet is malformed.");
|
|
print_debug(">> Malformed packet, we won't treat it.");
|
|
print_debug(">> Sending back a Warning to sender.");
|
|
build_warning(&new_tlv, warn, strlen(warn));
|
|
add_tlv(&pack, &new_tlv, sender, socket_num);
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// Free the previously allocated memory
|
|
free(new_tlv.pad1);
|
|
|
|
// If the packet still has data in it then send it
|
|
if(pack.length > 0){
|
|
send_packet((char*) &pack, pack.length, sender, socket_num);
|
|
}
|
|
print_data(data_list);
|
|
|
|
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){
|
|
print_debug(">> Error while checking the header, aborting this packet, by choice, and conviction.");
|
|
return -1;
|
|
}
|
|
|
|
// Neighbour check
|
|
struct in6_addr ip = sender->sin6_addr;
|
|
int16_t port = htobe16(sender->sin6_port);
|
|
|
|
|
|
int rc = add_n_update_neighbour(&ip, port);
|
|
if( rc == -1) {
|
|
print_debug(">> We have enough peers, we won't add him..");
|
|
return -1;
|
|
} else if (rc == 1){
|
|
print_debug(">> Peer was added to the table.\a");
|
|
} else {
|
|
print_debug(">> Updated the time it was last seen.");
|
|
}
|
|
|
|
int nbr_success_tlv = work_with_tlvs(received_data_buffer, received_data_len, sender, sock_fd);
|
|
if (nbr_success_tlv < 0){
|
|
print_debug(">> Error while treating the TLVs of the packet.");
|
|
if (DEBUG_LEVEL > 1) {
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> Managed to deal with %i TLVs\n", -nbr_success_tlv );
|
|
}
|
|
return -2;
|
|
} else {
|
|
print_debug(">> Done working with the TLVs of the packet, listening for new packets.");
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
int t_ask_for_more_peers(int sock_fd){
|
|
if (DEBUG_LEVEL > 1) {
|
|
print_peers(neighbour_list);
|
|
sleep(3);
|
|
}
|
|
return ask_for_peers(sock_fd);
|
|
}
|
|
|
|
/* For every peer we know about, we send out a TLV network hash
|
|
*/
|
|
int t_get_network_state(int sock_fd){
|
|
print_debug(">> Getting network state...");
|
|
print_debug(">> Sending out a TLV network hash to every peer we know of.");
|
|
if (neighbour_list == NULL) {
|
|
print_error("Our peer list is empty !");
|
|
print_error("Skipping..");
|
|
return -1;
|
|
} else {
|
|
// Build the network hash
|
|
// We use another variable so that we don't interfier with the current list
|
|
list * tmp_list = neighbour_list;
|
|
while (tmp_list != NULL) {
|
|
|
|
neighbour_peer * peer = (neighbour_peer *) tmp_list->data;
|
|
tlv new_tlv;
|
|
memset(&new_tlv, 0, sizeof(union tlv));
|
|
|
|
// Create the structure for the receiver.
|
|
struct sockaddr_in6 receiver;
|
|
memset(&receiver, 0, sizeof(struct sockaddr_in6));
|
|
|
|
receiver.sin6_family = AF_INET6;
|
|
receiver.sin6_addr = peer->ip;
|
|
receiver.sin6_port = htobe16(peer->port);
|
|
receiver.sin6_scope_id = 0;
|
|
|
|
// Send out a TLV network state.
|
|
if (build_network_hash(&new_tlv, data_list) < 0) {
|
|
print_error("Error while building a network hash.");
|
|
return -1;
|
|
} else {
|
|
if (send_single_tlv(&new_tlv, &receiver, sock_fd) < 0) {
|
|
print_error("Error while sending a network hash to a peer.");
|
|
return -1;
|
|
} else {
|
|
print_debug(">> Sent network hash to a peer.");
|
|
}
|
|
}
|
|
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int t_update_neighbours(){
|
|
return update_neighbours();
|
|
}
|
|
|
|
int run_node(int sock_fd){
|
|
print_debug(">> Running node...");
|
|
|
|
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));
|
|
time_t delay = time(NULL) + 5;
|
|
|
|
/* 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) {
|
|
t_ask_for_more_peers(sock_fd);
|
|
t_update_neighbours();
|
|
t_get_network_state(sock_fd);
|
|
print_data(data_list);
|
|
sleep(3);
|
|
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, 10);
|
|
|
|
if (ret < 0) {
|
|
print_error("Poll returned error");
|
|
break;
|
|
|
|
} else if (ret > 0) {
|
|
/* Regardless of requested events, poll() can always return these */
|
|
if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
|
|
print_error("Poll indicated stdin error\n");
|
|
break;
|
|
}
|
|
if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) {
|
|
print_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) {
|
|
print_error("stdin error");
|
|
break;
|
|
}
|
|
// Remove trailing \n
|
|
input_buffer[strcspn(input_buffer, "\n")] = 0;
|
|
if (DEBUG_LEVEL > 0) {
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> Adding following message to the table : “%s”\n", input_buffer );
|
|
}
|
|
// Add message to the message table.
|
|
if (add_message(input_buffer, bytes-1) < 0) {
|
|
print_debug(">> Error while trying to add the message to the list of messages, please try again..");
|
|
// Reset buffer
|
|
memset(input_buffer, 0, sizeof(input_buffer));
|
|
}
|
|
}
|
|
|
|
// 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) {
|
|
if (DEBUG_LEVEL > 0) {
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> Error - recvfrom error: %s\n", strerror(errno));
|
|
}
|
|
break;
|
|
}
|
|
if (bytes > 0) {
|
|
if (DEBUG_LEVEL > 0) {
|
|
printf("\x1b[31m[DEBUG]\x1b[0m >> Received %i bytes as : %s\n", (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) {
|
|
print_error("Error while treating the incoming packet.");
|
|
}
|
|
// Reset buffer
|
|
memset(output_buffer, 0, sizeof(output_buffer));
|
|
}
|
|
}
|
|
} else {
|
|
// TODO : Here, we can write all of the current messages we have in stack
|
|
// to a file, or to stdout.
|
|
// TODO : Same as above, but for the peers have know about.
|
|
continue;
|
|
}
|
|
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// This function runs once, and sets the sock_fd as well as the neighbourhood
|
|
int bootstrap_node(int * sock_fd, char * root_peer_ip, uint16_t root_peer_port){
|
|
print_debug(">> Boostraping node...");
|
|
|
|
struct sockaddr_in6 server_addr;
|
|
|
|
/* Create UDP socket */
|
|
* sock_fd = socket(AF_INET6, SOCK_DGRAM, 0);
|
|
if ( * sock_fd < 0) {
|
|
print_error("Failed to open socket");
|
|
perror("");
|
|
exit(-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 = LISTEN_PORT;
|
|
if (bind( * sock_fd, (struct sockaddr *)(&server_addr), sizeof(server_addr)) < 0) {
|
|
print_error("Failed to bind socket");
|
|
perror("");
|
|
exit(-1);
|
|
}
|
|
|
|
/* Make the first peer*/
|
|
struct neighbour_peer * root_peer = (struct neighbour_peer *) malloc(sizeof(struct neighbour_peer));
|
|
time_t root_peer_seen = time(NULL);
|
|
|
|
int inet_p = inet_pton(AF_INET6, root_peer_ip, &root_peer->ip);
|
|
if(inet_p < 1){
|
|
perror(">> Failed to create the root peer.");
|
|
return -3;
|
|
}
|
|
|
|
root_peer->port = (int16_t) root_peer_port;
|
|
root_peer->is_temporary = 0;
|
|
root_peer->last_seen = root_peer_seen;
|
|
|
|
// TODO: Add the first peer to the neighbourhood
|
|
print_debug(">> Adding the first root peer to the list...");
|
|
neighbour_list = malloc(sizeof(struct list));
|
|
memset(neighbour_list, 0, sizeof(struct list));
|
|
neighbour_list->data = (void *) root_peer;
|
|
neighbour_list->next = NULL;
|
|
|
|
print_debug(">> Initializing data list...");
|
|
data_list = (list*) malloc(sizeof(list));
|
|
memset(data_list, 0, sizeof(struct list));
|
|
data_list->data = malloc(sizeof(pub_data));
|
|
data_list->next = NULL;
|
|
|
|
pub_data *our_data = (pub_data*) data_list->data;
|
|
our_data->length = 0;
|
|
our_data->id = NODE_ID;
|
|
our_data->seqno = 1337;
|
|
our_data->data = NULL;
|
|
|
|
print_debug(">> Boostraping done.");
|
|
return 0;
|
|
}
|
|
|
|
|
|
int main(int argc, const char *argv[]) {
|
|
|
|
if (argc != 3) {
|
|
print_error("Usage : ./dazibao <root peer IPv6> <port number>");
|
|
exit(-1);
|
|
}
|
|
|
|
char *end;
|
|
intmax_t val = strtoimax(argv[2], &end, 10);
|
|
if (errno == ERANGE || val < 0 || val > UINT16_MAX || end == argv[2] || *end != '\0'){
|
|
print_error("Conversion of port number failed, please choose a smaller number.");
|
|
}
|
|
|
|
uint16_t root_peer_port = (uint16_t) val;
|
|
|
|
char * root_peer_ip = (char *) argv[1];
|
|
|
|
setlocale(LC_ALL, "");
|
|
print_debug(">> Starting node");
|
|
|
|
int sock_fd;
|
|
bootstrap_node(&sock_fd, root_peer_ip, root_peer_port);
|
|
run_node(sock_fd);
|
|
close(sock_fd);
|
|
|
|
return 0;
|
|
}
|