Merge branch 'master' into '5-ajouter-un-flag-de-debut'

# Conflicts:
#   src/node.c
This commit is contained in:
PERDRIAU nelson 2020-04-29 14:03:23 +02:00
commit abb55957bc
9 changed files with 904 additions and 214 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
dazibao
*.o
debug.*

View File

@ -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)

View File

@ -2,8 +2,11 @@
#define HASH_H
#include <openssl/sha.h>
#include "node.h"
#include <stdint.h>
#include "tlv.h"
#include "parser.h"
#include "node.h"
// Hash a single data
void hash_data(pub_data *data, unsigned char *buf);

View File

@ -7,10 +7,18 @@
#include <netinet/in.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>
#include "tlv.h"
#include "node.h"
// Static variables
static list *data_list;
static list *neighbour_list;
/* ---- Fonctions utilitaires ---- */
void debug_print(char message_debug){
@ -49,11 +57,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
@ -67,7 +436,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
@ -105,9 +474,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,
@ -122,7 +491,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;
}
@ -137,195 +506,408 @@ 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(list * neighbourhood, int sock_fd){
return 0;
}
int t_get_network_state(list * neighbourhood, int sock_fd){
return 0;
}
int t_update_neighbours(list * neighbourhood){
return 0;
}
int run_node(int sock_fd, list * neighbourhood){
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(neighbourhood, sock_fd);
printf(">> Updating neighbours...\n");
t_update_neighbours(neighbourhood);
printf(">> Getting network state...\n");
t_get_network_state(neighbourhood, sock_fd);
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;
}
// This function runs once, and sets the sock_fd as well as the neighbourhood
int bootstrap_node(int * sock_fd, list * neighbourhood){
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;
}
/* Make the first peer*/
struct neighbour_peer root_peer;
struct timeval root_peer_seen;
int inet_p = inet_pton(AF_INET6, ROOT_PEER_ADDR, &root_peer.ip);
if(inet_p < 1){
perror(">> Failed to create the root peer.");
return -3;
}
root_peer.port = 1212;
root_peer.is_temporary = 0;
root_peer.last_seen = root_peer_seen;
// TODO: Add the first peer to the neighbourhood
printf(">> Boostraping done.\n");
return 0;
}
int main(int argc, const char *argv[]) {
printf(">> Starting node\n");
list neighbourhood;
int sock_fd;
bootstrap_node(&sock_fd, &neighbourhood);
run_node(sock_fd, &neighbourhood);
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;
int debug_flag = 0;
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;
}

View File

@ -4,25 +4,14 @@
#define NODE_H
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#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 <time.h>
#include <stdint.h>
#include <net/if.h>
/* 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,46 +33,88 @@ 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
// The adress of the main peer
#define ROOT_PEER_ADDR "2001:660:3301:9200::51c2:1b9b"
// 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);
// threaded functions
int send_single_tlv(tlv *tlv, struct sockaddr_in6 *dest, int socket_num);
void t_ask_for_more_peers();
// This function is in charge of saying how and what goes where.
int run_node(int sock_fd, list * neighbourhood);
void t_update_neighbours();
/* 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);
void t_get_network_state();
/* 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);
/* Check our peer list. If we have less than 5 peers, send out a
TLV NEIGHBOUR_REQUEST to a random peer
*/
int t_ask_for_more_peers(list * neighbourhood, int sock_fd);
/* We look at every peer, if he is marked as is_temporary, AND we didn't get a
packet from him in the last 70 sec, we remove him from the list.
*/
int t_update_neighbours(list * neighbourhood);
/* We send out a TLV Network Hash to every peer, and we expect getting a TLV
Network state from each of them.
*/
int t_get_network_state(list * neighbourhoodn, int sock_fd);
// 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, list * neighbourhood);
// Helper functions
int len_list(list *l);
@ -92,4 +123,13 @@ void debug_print(char message_debug);
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

View File

@ -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;

View File

@ -4,8 +4,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include "parser.h"
#include "hash.h"
#include <stdint.h>
#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