Commit 2e3b123e authored by xpetrak2's avatar xpetrak2
Browse files

Merge request problems resolved

parent 2c541eb3
......@@ -56,13 +56,15 @@ int main(void)
global_state_t global_state;
struct evconnlistener *listener;
struct event *sigint_event;
time_t t;
struct event *sigterm_event;
srand((unsigned) time(&t));
/* TODO: use randombytes (from libsodium?) for the seed of randomness */
srand((unsigned) time(NULL));
/* initialize all global_state variables */
global_state.event_loop = NULL;
if (setup_paths(&global_state.filepaths)) {
log_error("Initializing paths to needed files/dirs");
return 1;
}
......@@ -70,13 +72,12 @@ int main(void)
linkedlist_init(&global_state.neighbours);
linkedlist_init(&global_state.peers);
if (fetch_peers(global_state.filepaths.peers, &global_state.peers)) {
return 2;
}
fetch_peers(global_state.filepaths.peers, &global_state.peers);
/* setup everything needed for TCP listening */
if (listen_init(&listener, &global_state) != 0) {
return 3;
log_error("Initialization of TCP listening");
return 2;
}
/* register SIGINT event to its callback */
......@@ -85,8 +86,18 @@ int main(void)
signal_cb,
&global_state);
if (!sigint_event || event_add(sigint_event, NULL) < 0) {
log_error("main - couldn't create or add SIGINT event");
return 4;
log_error("Creating or adding SIGINT event");
return 3;
}
/* register SIGTERM event too */
sigterm_event = evsignal_new(global_state.event_loop,
SIGTERM,
signal_cb,
&global_state);
if (!sigterm_event || event_add(sigterm_event, NULL) < 0) {
log_error("Creating or adding SIGTERM event");
return 3;
}
/* setup a function that actively checks the number of neighbours */
......@@ -99,8 +110,8 @@ int main(void)
conns_cb,
&global_state);
if (!conns_event || event_add(conns_event, &conns_interval) < 0) {
log_error("main - couldn't create or add conns_event");
return 4;
log_error("Creating or adding Connections event");
return 3;
}
/* initiate joining the coincer network */
......@@ -119,6 +130,7 @@ int main(void)
evconnlistener_free(listener);
event_free(sigint_event);
event_free(sigterm_event);
event_free(conns_event);
event_base_free(global_state.event_loop);
......
......@@ -38,7 +38,7 @@ static int set_homedir(char **homedir)
{
*homedir = getenv("HOME");
if (*homedir == NULL || *homedir[0] == '\0') {
log_error("set_homedir - cannot find home directory");
log_error("Can not find home directory");
return 1;
}
return 0;
......@@ -70,7 +70,7 @@ static int set_directories(char **config_dir, char **data_dir)
sizeof("/.config/" PACKAGE_NAME
"/"));
if (*config_dir == NULL) {
log_error("set_directories - setting config_dir");
log_error("Setting configdir");
return 1;
}
strcpy(*config_dir, homedir);
......@@ -80,7 +80,7 @@ static int set_directories(char **config_dir, char **data_dir)
*config_dir = (char *) malloc(tmpsize +
sizeof("/" PACKAGE_NAME "/"));
if (*config_dir == NULL) {
log_error("set_directories - setting config_dir");
log_error("Setting configdir");
return 1;
}
strcpy(*config_dir, tmpchar);
......@@ -99,7 +99,7 @@ static int set_directories(char **config_dir, char **data_dir)
sizeof("/.local/share/" PACKAGE_NAME
"/"));
if (*data_dir == NULL) {
log_error("set_directories - setting data_dir");
log_error("Setting datadir");
free(config_dir);
return 1;
}
......@@ -110,7 +110,7 @@ static int set_directories(char **config_dir, char **data_dir)
*data_dir = (char *) malloc(tmpsize +
sizeof("/" PACKAGE_NAME "/"));
if (*data_dir == NULL) {
log_error("set_directories - setting data_dir");
log_error("Setting datadir");
free(config_dir);
return 1;
}
......@@ -139,16 +139,15 @@ static int create_dirs(const char *config_dir, const char *data_dir)
if (errno == ENOENT) {
/* create */
if (mkdir(config_dir, S_IRWXU)) {
log_error("create_dirs - could not create "
"configuration directory %s",
config_dir);
log_error("Could not create configuration "
"directory %s", config_dir);
return 1;
} else {
log_debug("create_dirs - created configuration "
"directory %s", config_dir);
}
} else {
log_error("create_dirs - could not open configuration "
log_error("Could not open configuration "
"directory %s", config_dir);
return 1;
}
......@@ -159,17 +158,15 @@ static int create_dirs(const char *config_dir, const char *data_dir)
if (errno == ENOENT) {
/* create */
if (mkdir(data_dir, S_IRWXU)) {
log_error("create_dirs - could not create "
"data directory %s",
data_dir);
log_error("Could not create "
"data directory %s", data_dir);
return 1;
} else {
log_debug("create_dirs - created data "
"directory %s", data_dir);
}
} else {
log_error("create_dirs - could not open data "
"directory %s", data_dir);
log_error("Could not open data directory %s", data_dir);
return 1;
}
}
......
......@@ -216,7 +216,7 @@ linkedlist_node_t *linkedlist_insert_after(linkedlist_t *root,
new_node = (linkedlist_node_t *) malloc(sizeof(linkedlist_node_t));
if (new_node == NULL) {
log_error("linkedlist_insert_after - malloc");
log_error("Inserting a new node");
return NULL;
}
......
......@@ -127,6 +127,54 @@ void delete_neighbour(linkedlist_t *neighbours, struct bufferevent *bev)
linkedlist_delete(neighbour_node);
}
/**
* Fetch pointers to neighbours with specific flags set, into an array
* that is being allocated in here.
*
* @param neighbours Our neighbours.
* @param output Output array of pointers to satisfying
* neighbours. If set to NULL, function just
* returns the number of them.
* @param flags Choose neighbours based on these flags.
* Fetches output with all neighbours if set to 0.
*
* @return >=0 The number of satisfying neighbours.
* @return -1 Allocation failure.
*/
int fetch_specific_neighbours(const linkedlist_t *neighbours,
neighbour_t ***output,
int flags)
{
linkedlist_node_t *current_node;
neighbour_t *current_neighbour;
size_t n = 0;
if (output != NULL) {
*output = (neighbour_t **) malloc(linkedlist_size(neighbours) *
sizeof(neighbour_t *));
if (*output == NULL) {
log_error("Fetching specific neighbours");
return -1;
}
}
current_node = linkedlist_get_first(neighbours);
while (current_node != NULL) {
current_neighbour = (neighbour_t *) current_node->data;
/* if all specified flags are being set on this neighbour */
if ((current_neighbour->flags & flags) == flags) {
if (output != NULL) {
(*output)[n++] = current_neighbour;
} else {
n++;
}
}
current_node = linkedlist_get_next(neighbours, current_node);
}
return n;
}
/**
* Find neighbour in neighbours based on their bufferevent.
*
......@@ -148,7 +196,6 @@ neighbour_t *find_neighbour(const linkedlist_t *neighbours,
/* bufferevents equal => neighbour found */
if (current_data->buffer_event == bev) {
/* return node's data; struct s_neighbour */
return current_data;
}
......@@ -189,3 +236,25 @@ neighbour_t *find_neighbour_by_addr(const linkedlist_t *neighbours,
/* neighbour not found */
return NULL;
}
/**
* Set flags on given neighbour.
*
* @param neighbour Set flags on this neighbour.
* @param flags Set these flags on the neighbour.
*/
void set_neighbour_flags(neighbour_t *neighbour, int flags)
{
neighbour->flags |= flags;
}
/**
* Unset flags on given neighbour.
*
* @param neighbour Unset flags on this neighbour.
* @param flags Unset these flags on the neighbour.
*/
void unset_neighbour_flags(neighbour_t *neighbour, int flags)
{
neighbour->flags &= ~flags;
}
......@@ -28,6 +28,9 @@
/* minimum number of peers we need to be connected to */
#define MIN_NEIGHBOURS 3
/* request for addresses */
#define NEIGHBOUR_ADDRS_REQ 0x01
/** Data type for the linkedlist of neighbours. */
typedef struct s_neighbour {
/** Neighbour's IPv6 address.
......@@ -37,6 +40,8 @@ typedef struct s_neighbour {
struct bufferevent *buffer_event;
/** Number of failed ping attempts -- max 3, then disconnect. */
size_t failed_pings;
/** A set of flags for this neighbour. */
int flags;
} neighbour_t;
neighbour_t *add_new_neighbour(linkedlist_t *neighbours,
......@@ -47,6 +52,9 @@ void clear_neighbours(linkedlist_t *neighbours);
void delete_neighbour(linkedlist_t *neighbours, struct bufferevent *bev);
int fetch_specific_neighbours(const linkedlist_t *neighbours,
neighbour_t ***output,
int flags);
neighbour_t *find_neighbour(const linkedlist_t *neighbours,
const struct bufferevent *bev);
......@@ -54,4 +62,7 @@ neighbour_t *find_neighbour(const linkedlist_t *neighbours,
neighbour_t *find_neighbour_by_addr(const linkedlist_t *neighbours,
const struct in6_addr *ip_addr);
void set_neighbour_flags(neighbour_t *neighbour, int flags);
void unset_neighbour_flags(neighbour_t *neighbour, int flags);
#endif /* NEIGHBOURS_H */
......@@ -48,12 +48,12 @@ static void ip_to_string(const struct in6_addr *binary_ip, char *ip)
}
/**
* Ask the neighbour for a list of peers.
* Ask the neighbour for a list of addresses.
*
* @param global_state Data for the event loop to work with.
* @param neighbour The neighbour to be asked.
*/
void ask_for_peers(neighbour_t *neighbour)
static void ask_for_addresses(neighbour_t *neighbour)
{
struct bufferevent *bev;
......@@ -64,6 +64,8 @@ void ask_for_peers(neighbour_t *neighbour)
/* send message "peers" to the neighbour, as a request
* for the list of peers; 6 is the number of bytes to be transmitted */
evbuffer_add(bufferevent_get_output(bev), "peers", 6);
/* accept addresses only from those neighbours that we've asked */
set_neighbour_flags(neighbour, NEIGHBOUR_ADDRS_REQ);
}
/**
......@@ -125,6 +127,10 @@ static void p2p_process(struct bufferevent *bev, void *ctx)
/* allocate memory for the input message including '\0' */
message = (char *) malloc((len + 1) * sizeof(char));
if (message == NULL) {
log_error("Received message allocation");
return;
}
/* drain input buffer into data; -1 if evbuffer_remove failed */
if (evbuffer_remove(input, message, len) == -1) {
......@@ -147,9 +153,12 @@ static void p2p_process(struct bufferevent *bev, void *ctx)
/* "peers" is a request for list of addresses */
} else if (strcmp(message, "peers") == 0) {
peers_to_str(&global_state->peers, response);
/* list of peers */
/* list of addresses */
} else {
process_peers(global_state, message);
if (neighbour->flags & NEIGHBOUR_ADDRS_REQ) {
process_peers(global_state, message);
unset_neighbour_flags(neighbour, NEIGHBOUR_ADDRS_REQ);
}
}
if (response[0] != '\0') {
......@@ -192,9 +201,7 @@ static void timeout_process(linkedlist_t *neighbours,
neighbour->failed_pings++;
} else {
log_info("timeout_process - 3 failed pings."
" Removing %s from neighbours",
text_ip);
log_info("%s timed out", text_ip);
delete_neighbour(neighbours, neighbour->buffer_event);
}
}
......@@ -239,20 +246,22 @@ static void process_pending_neighbour(global_state_t *global_state,
neighbour_t *neighbour,
short events)
{
size_t available_peers_size;
int available_peers_size;
int needed_conns;
neighbour_t *new_neighbour;
char text_ip[INET6_ADDRSTRLEN];
available_peers_size = fetch_available_peers(&global_state->peers,
NULL);
/* fetch peers with PEER_AVAILABLE flag set;
* no allocation with NULL parameter -> result always >=0 */
available_peers_size = fetch_specific_peers(&global_state->peers,
NULL,
PEER_AVAILABLE);
/* initialize text_ip */
ip_to_string(&neighbour->addr, text_ip);
/* we've successfully connected to the neighbour */
if (events & BEV_EVENT_CONNECTED) {
log_info("process_pending_neighbour - connecting to "
"%s was SUCCESSFUL", text_ip);
log_info("%s successfully connected", text_ip);
/* we've got a new neighbour;
* we can't just delete the neighbour from pending
* and add it into 'neighbours' as the delete would
......@@ -268,14 +277,14 @@ static void process_pending_neighbour(global_state_t *global_state,
/* if we need more neighbours */
if (needed_conns > 0) {
/* and we don't have enough available */
if ((int) available_peers_size < needed_conns) {
if (available_peers_size < needed_conns) {
ask_for_addresses(new_neighbour);
}
}
/* connecting to the neighbour was unsuccessful */
} else {
log_info("process_pending_neighbour - connecting to "
"%s was NOT SUCCESSFUL", text_ip);
log_debug("process_pending_neighbour - connecting to "
"%s was unsuccessful", text_ip);
/* the peer is no longer a pending neighbour */
delete_neighbour(&global_state->pending_neighbours,
neighbour->buffer_event);
......@@ -299,12 +308,11 @@ static void process_neighbour(global_state_t *global_state,
ip_to_string(&neighbour->addr, text_ip);
if (events & BEV_EVENT_ERROR) {
log_info("process_neighbour - error on bev: removing %s",
text_ip);
log_info("Connection error, removing %s", text_ip);
delete_neighbour(&global_state->neighbours,
neighbour->buffer_event);
} else if (events & BEV_EVENT_EOF) {
log_info("process_neighbour - %s disconnected", text_ip);
log_info("%s disconnected", text_ip);
delete_neighbour(&global_state->neighbours,
neighbour->buffer_event);
/* timeout flag on 'bev' */
......@@ -357,6 +365,7 @@ static void accept_connection(struct evconnlistener *listener,
struct event_base *base;
struct bufferevent *bev;
struct in6_addr *new_addr;
peer_t *new_peer;
char text_ip[INET6_ADDRSTRLEN];
struct timeval timeout;
......@@ -402,9 +411,12 @@ static void accept_connection(struct evconnlistener *listener,
return;
}
log_info("accept_connection - new connection from [%s]:%d", text_ip,
log_info("New connection from [%s]:%d", text_ip,
ntohs(addr_in6->sin6_port));
save_peer(&global_state->peers, new_addr);
if ((new_peer = save_peer(&global_state->peers, new_addr))) {
/* we are now connected to this peer, hence unavailable */
unset_peer_flags(new_peer, PEER_AVAILABLE);
}
}
/**
......@@ -420,8 +432,10 @@ static void accept_error_cb(struct evconnlistener *listener,
global_state_t *global_state = (struct s_global_state *) ctx;
int err = EVUTIL_SOCKET_ERROR();
log_error("accept_error_cb - got an error %d (%s) on the listener. "
"Shutting down.", err, evutil_socket_error_to_string(err));
/* TODO: If we have enough connections, don't stop the event loop */
log_error("Error %d (%s) on the listener, shutting down",
err, evutil_socket_error_to_string(err));
/* stop the event loop */
event_base_loopexit(base, NULL);
......@@ -449,7 +463,7 @@ int listen_init(struct evconnlistener **listener,
*base = event_base_new();
if (!*base) {
log_error("listen_init - event_base creation failure");
log_error("Creating eventbase");
return 1;
}
......@@ -467,7 +481,7 @@ int listen_init(struct evconnlistener **listener,
sizeof(sock_addr));
if (!*listener) {
log_error("listen_init - evconnlistener_new_bind");
log_error("Creating listener");
return 1;
}
......@@ -558,7 +572,7 @@ int connect_to_addr(global_state_t *global_state,
peer = find_peer_by_addr(&global_state->peers, addr);
if (peer != NULL) {
peer->is_available = 0;
unset_peer_flags(peer, PEER_AVAILABLE);
}
/* connect to the peer; socket_connect also assigns fd */
......@@ -576,16 +590,22 @@ int connect_to_addr(global_state_t *global_state,
void add_more_connections(global_state_t *global_state, size_t conns_amount)
{
struct in6_addr addr;
size_t available_peers_size;
peer_t *available_peers[MAX_PEERS_SIZE];
int available_peers_size;
peer_t **available_peers;
size_t cur_conn_attempts = 0;
size_t idx;
neighbour_t *neigh;
size_t result;
peer_t *selected_peer;
available_peers_size = fetch_available_peers(&global_state->peers,
available_peers);
available_peers_size = fetch_specific_peers(&global_state->peers,
&available_peers,
PEER_AVAILABLE);
/* if fetch_specific_peers had allocation failure */
if (available_peers_size == -1) {
log_error("Adding more connections");
return;
}
/* only if we don't have any non-default peers available */
if (available_peers_size == 0) {
......@@ -613,7 +633,7 @@ void add_more_connections(global_state_t *global_state, size_t conns_amount)
neighbours,
&addr);
assert(neigh != NULL);
ask_for_peers(neigh);
ask_for_addresses(neigh);
log_debug("add_more_connections - "
"asking for peers");
/* the peer is a pending connection */
......@@ -630,7 +650,7 @@ void add_more_connections(global_state_t *global_state, size_t conns_amount)
/* we need to choose 'conns_amount' of random connections */
shuffle_peers_arr(available_peers, available_peers_size);
/* clamp to 'available_peers_size' */
if (conns_amount > available_peers_size) {
if (conns_amount > (size_t) available_peers_size) {
conns_amount = available_peers_size;
}
......@@ -643,5 +663,6 @@ void add_more_connections(global_state_t *global_state, size_t conns_amount)
cur_conn_attempts++;
}
}
}
free(available_peers);
}
......@@ -49,8 +49,6 @@ typedef struct s_global_state {
void add_more_connections(global_state_t *global_state, size_t conns_amount);
void ask_for_peers(neighbour_t *neighbour);
int connect_to_addr(global_state_t *global_state,
const struct in6_addr *addr);
......
......@@ -37,49 +37,14 @@ void clear_peers(linkedlist_t *peers)
linkedlist_destroy(peers);
}
/**
* Fetch available peers from linkedlist into an array.
*
* @param peers All peers known to us.
* @param available_peers The peers marked as available.
*
* @return >=0 The number of available peers.
*/
size_t fetch_available_peers(const linkedlist_t *peers,
peer_t *available_peers[MAX_PEERS_SIZE])
{
linkedlist_node_t *current_node;
peer_t *current_peer;
size_t n = 0;
current_node = linkedlist_get_first(peers);
while (current_node != NULL) {
current_peer = (peer_t *) current_node->data;
if (current_peer->is_available) {
/* we can use this function with 'available_peers'
* set to NULL just to get the number of available
* peers as return value
*/
if (available_peers != NULL) {
available_peers[n++] = current_peer;
} else {
n++;
}
}
current_node = linkedlist_get_next(peers, current_node);
}
return n;
}
/**
* Fetch peers from file into linkedlist.
*
* @param peers_path Path to 'peers' file.
* @param peers_path Path to peers file.
* @param peers Fetch loaded peers in here.
*
* @return 0 Successfully fetched.
* @return 1 Failure.
* @return 1 Peers file could not be opened.
*/
int fetch_peers(const char *peers_path, linkedlist_t *peers)
{
......@@ -88,18 +53,66 @@ int fetch_peers(const char *peers_path, linkedlist_t *peers)
peers_file = fopen(peers_path, "rb");
if (peers_file == NULL) {
log_error("fetch_peers - peers_file not found");
log_warning("Peers file not found at %", peers_path);
return 1;
}
while (fread(&addr, sizeof(struct in6_addr), 1, peers_file) == 1) {
add_peer(peers, &addr);
save_peer(peers, &addr);
}
fclose(peers_file);
return 0;
}
/**
* Fetch pointers to peers with specific flags set, into array that is being
* allocated in here.
*
* @param peers All peers known to us.
* @param output Output array of pointers to satisfying peers.
* If set to NULL, function just returns
* the number of them.
* @param flags Choose peers based on these flags.
* Fetches output with all known peers if set to 0.
*
* @return >=0 The number of satisfying peers.
* @return -1 Allocation failure.
*/
int fetch_specific_peers(const linkedlist_t *peers,
peer_t ***output,
int flags)
{
linkedlist_node_t *current_node;
peer_t *current_peer;
size_t n = 0;
if (output != NULL) {
*output = (peer_t **) malloc(linkedlist_size(peers) *
sizeof(peer_t *));
if (*output == NULL) {
log_error("Fetching specific peers");
return -1;
}
}
current_node = linkedlist_get_first(peers);
while (current_node != NULL) {
current_peer = (peer_t *) current_node->data;
/* if all specified flags are being set on this peer */
if ((current_peer->flags & flags) == flags) {
if (output != NULL) {
(*output)[n++] = current_peer;
} else {
n++;
}
}
current_node = linkedlist_get_next(peers, current_node);