From 1f9e5d672f228d7c98207dfe9ebf58996c3c5b61 Mon Sep 17 00:00:00 2001 From: xpetrak2 <456484@mail.muni.cz> Date: Fri, 20 Apr 2018 19:16:10 +0200 Subject: [PATCH 1/6] Connect to default peers --- src/coincerd.c | 2 + src/p2p.c | 172 ++++++++++++++++++++++++++++++++++++++----------- src/p2p.h | 45 +++++++++++-- 3 files changed, 176 insertions(+), 43 deletions(-) diff --git a/src/coincerd.c b/src/coincerd.c index 141d749..2d786ed 100644 --- a/src/coincerd.c +++ b/src/coincerd.c @@ -50,6 +50,8 @@ int main(void) if (listen_init(&listener, &global_state) != 0) { return 1; + } else if (joining_init(&global_state) != 0) { + return 2; } event_base_dispatch(global_state.event_loop); diff --git a/src/p2p.c b/src/p2p.c index 9032457..258bcd3 100644 --- a/src/p2p.c +++ b/src/p2p.c @@ -36,7 +36,7 @@ * @param binary_ip Binary represented IP address. * @param ip Readable IP address. */ -static void ip_to_string(unsigned char *binary_ip, char *ip) +static void ip_to_string(const unsigned char *binary_ip, char *ip) { inet_ntop(AF_INET6, binary_ip, ip, INET6_ADDRSTRLEN); } @@ -49,16 +49,18 @@ static void ip_to_string(unsigned char *binary_ip, char *ip) */ static void p2p_process(struct bufferevent *bev, void *ctx) { - char *data; global_state_t *global_state; struct evbuffer *input; size_t len; + char *message; neighbour_t *neighbour; struct evbuffer *output; + char response[256]; /* TODO: adjust size */ + char text_ip[INET6_ADDRSTRLEN]; global_state = (global_state_t *) ctx; - /* find the neighbour based on their buffer event */ + /* find the neighbour based on their bufferevent */ neighbour = find_neighbour(&global_state->neighbours, bev); /* message from unknown neighbour; quit p2p_process */ @@ -73,29 +75,38 @@ static void p2p_process(struct bufferevent *bev, void *ctx) input = bufferevent_get_input(bev); output = bufferevent_get_output(bev); - /* get length of the input messaage */ + /* get length of the input message */ len = evbuffer_get_length(input); /* allocate memory for the input message including '\0' */ - data = (char *) malloc((len + 1) * sizeof(char)); - - /* FOR TESTING PURPOSES */ + message = (char *) malloc((len + 1) * sizeof(char)); /* drain input buffer into data; -1 if evbuffer_remove failed */ - if (evbuffer_remove(input, data, len) == -1) { - free(data); + if (evbuffer_remove(input, message, len) == -1) { + free(message); return; } else { - data[len] = '\0'; - } + message[len] = '\0'; + } - printf("Sending back: %s", data); + ip_to_string(neighbour->ip_addr, text_ip); + printf("Received: %s from %s\n", message, text_ip); - /* copy string data to the output buffer */ - evbuffer_add_printf(output, "%s", data); + /* TODO: Replace with JSON messages */ + if (strcmp(message, "ping") == 0) { + strcpy(response, "pong"); + } else { + strcpy(response, ""); + } + + if (strcmp(response, "") != 0) { + printf("Responding with: %s\n", response); + /* copy response to the output buffer */ + evbuffer_add_printf(output, "%s", response); + } /* deallocate input message */ - free(data); + free(message); } /** @@ -163,17 +174,18 @@ static void event_cb(struct bufferevent *bev, short events, void *ctx) ip_to_string(neighbour->ip_addr, text_ip); if (events & BEV_EVENT_ERROR) { - perror("Error from bufferevent"); - printf("%s was removed\n", text_ip); + printf("Connection error: removing %s\n", text_ip); delete_neighbour(&global_state->neighbours, bev); return; } + if (events & (BEV_EVENT_CONNECTED)) { + printf("Successfully connected to %s\n", text_ip); + } if (events & (BEV_EVENT_EOF)) { printf("%s disconnected\n", text_ip); delete_neighbour(&global_state->neighbours, bev); return; } - /* timeout flag on 'bev' */ if (events & BEV_EVENT_TIMEOUT) { timeout_process(&global_state->neighbours, neighbour); @@ -197,10 +209,9 @@ static void accept_connection(struct evconnlistener *listener, struct event_base *base; struct bufferevent *bev; - unsigned char inet6_ip[sizeof(struct in6_addr)]; - struct timeval read_timeout; + unsigned char ip_addr[16]; char text_ip[INET6_ADDRSTRLEN]; - struct timeval write_timeout; + struct timeval timeout; global_state_t *global_state = (struct s_global_state *) ctx; struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *) addr; @@ -211,26 +222,25 @@ static void accept_connection(struct evconnlistener *listener, /* setup a bufferevent for the new connection */ bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); - /* subscribe every received P2P message to be processed */ + /* subscribe every received P2P message to be processed; + * p2p_process for read callback, NULL for write callback + */ bufferevent_setcb(bev, p2p_process, NULL, event_cb, ctx); bufferevent_enable(bev, EV_READ | EV_WRITE | EV_TIMEOUT); - /* after READ_TIMEOUT or WRITE_TIMEOUT seconds invoke event_cb */ - write_timeout.tv_sec = WRITE_TIMEOUT; - write_timeout.tv_usec = 0; - - read_timeout.tv_sec = READ_TIMEOUT; - read_timeout.tv_usec = 0; + timeout.tv_sec = TIMEOUT_TIME; + timeout.tv_usec = 0; - bufferevent_set_timeouts(bev, &read_timeout, &write_timeout); + /* after TIMEOUT_TIME seconds invoke event_cb */ + bufferevent_set_timeouts(bev, &timeout, NULL); /* put binary representation of IP to inet6_ip */ - memcpy(inet6_ip, addr_in6->sin6_addr.s6_addr, sizeof(struct in6_addr)); + memcpy(ip_addr, addr_in6->sin6_addr.s6_addr, 16); /* add the new connection to the list of our neighbours */ if (!add_new_neighbour(&global_state->neighbours, - inet6_ip, + ip_addr, bev)) { /* free the bufferevent if adding failed */ @@ -238,7 +248,7 @@ static void accept_connection(struct evconnlistener *listener, return; } - ip_to_string(inet6_ip, text_ip); + ip_to_string(ip_addr, text_ip); printf("New connection from [%s]:%d\n", text_ip, ntohs(addr_in6->sin6_port)); @@ -268,6 +278,7 @@ static void accept_error_cb(struct evconnlistener *listener, /* delete neighbours */ clear_neighbours(&global_state->neighbours); } + /** * Initialize listening and set up callbacks. * @@ -298,11 +309,11 @@ int listen_init(struct evconnlistener **listener, sock_addr.sin6_port = htons(port); *listener = evconnlistener_new_bind(*base, accept_connection, - global_state, - LEV_OPT_CLOSE_ON_FREE | - LEV_OPT_REUSEABLE, -1, - (struct sockaddr *) &sock_addr, - sizeof(sock_addr)); + global_state, + LEV_OPT_CLOSE_ON_FREE | + LEV_OPT_REUSEABLE, -1, + (struct sockaddr *) &sock_addr, + sizeof(sock_addr)); if (!*listener) { perror("Couldn't create listener: evconnlistener_new_bind"); @@ -313,3 +324,90 @@ int listen_init(struct evconnlistener **listener, return 0; } + +/** + * Attempt to connect to the particular peer. + * + * @param global_state Data for the event loop to work with. + * @param ip_addr Binary IP of a peer that we want to connect to. + * + * @return neighbour_t * Pointer to newly connected neighbour. + * @return NULL Connecting was unsuccessful. + */ +neighbour_t *connect_to_peer(global_state_t *global_state, + const unsigned char *ip_addr) +{ + struct bufferevent *bev; + struct sockaddr *sock_addr; + struct sockaddr_in6 sock_addr6; + int sock_len; + char text_ip[INET6_ADDRSTRLEN]; + struct timeval timeout; + + /* get textual representation of the input ip address */ + ip_to_string(ip_addr, text_ip); + + /* don't connect to already connected peer */ + if (find_neighbour_by_ip(&global_state->neighbours, ip_addr) != NULL) { + printf("connect_to_peer: skipping already connected peer\n"); + return NULL; + } + + memset(&sock_addr6, 0x0, sizeof(sock_addr6)); + sock_addr6.sin6_family = AF_INET6; + sock_addr6.sin6_port = htons(DEFAULT_PORT); + memcpy(&sock_addr6.sin6_addr, ip_addr, 16); + + sock_addr = (struct sockaddr *) &sock_addr6; + sock_len = sizeof(sock_addr6); + + /* it is safe to set file descriptor to -1 if we define it later */ + bev = bufferevent_socket_new(global_state->event_loop, + -1, + BEV_OPT_CLOSE_ON_FREE); + + /* subscribe every received P2P message to be processed; + * p2p_process as read callback, NULL as write callback + */ + bufferevent_setcb(bev, + p2p_process, + NULL, + event_cb, + global_state); + + /* enable bufferevent for read, write and timeout */ + bufferevent_enable(bev, EV_READ | EV_WRITE | EV_TIMEOUT); + + /* set the timeout value */ + timeout.tv_sec = TIMEOUT_TIME; + timeout.tv_usec = 0; + + /* after TIMEOUT_TIME seconds invoke event_cb */ + bufferevent_set_timeouts(bev, &timeout, &timeout); + + /* connect to the peer; socket_connect also assigns fd */ + if (bufferevent_socket_connect(bev, sock_addr, sock_len) < 0) { + printf("Connecting to %s failed\n", text_ip); + bufferevent_free(bev); + return NULL; + } + + /* connecting succeeded; add peer to the list of our neighbours */ + return add_new_neighbour(&global_state->neighbours, ip_addr, bev); +} + +/** + * Initiate joining the coincer network. + * + * @param global_state Data for the event loop to work with. + */ +int joining_init(global_state_t *global_state) +{ + int i; + + for (i = 0; i < DEFAULT_PEERS_SIZE; i++) { + connect_to_peer(global_state, DEFAULT_PEERS[i]); + } + + return 0; +} diff --git a/src/p2p.h b/src/p2p.h index 7ead353..2393177 100644 --- a/src/p2p.h +++ b/src/p2p.h @@ -22,11 +22,40 @@ #include #include "linkedlist.h" +#include "neighbours.h" -#define DEFAULT_PORT 31070 -/* after (READ/WRITE)_TIMEOUT seconds invoke timeout callback */ -#define READ_TIMEOUT 30 -#define WRITE_TIMEOUT 30 +/* number of peers guaranteed to be in the network */ +#define DEFAULT_PEERS_SIZE 3 +/* default port for TCP listening */ +#define DEFAULT_PORT 31070 +/* minimum number of peers we need to be connected to */ +#define MINIMUM_NEIGHBOURS 2 +/* after TIMEOUT_TIME seconds invoke timeout callback */ +#define TIMEOUT_TIME 30 + +/* IPv6 addresses of peers guaranteed to be in the network */ +static const unsigned char DEFAULT_PEERS[DEFAULT_PEERS_SIZE][16] = { + /* TODO: Replace with the actual default peer IPs */ + { + (int)0, (int)0, (int)0, (int)0, + (int)0, (int)0, (int)0, (int)0, + (int)0, (int)0, (int)0, (int)0, + (int)0, (int)0, (int)0, (int)1 + }, + { + (int)0, (int)0, (int)0, (int)0, + (int)0, (int)0, (int)0, (int)0, + (int)0, (int)0, (int)255, (int)255, + (int)192, (int)168, (int)0, (int)125 + }, + { + (int)0, (int)0, (int)0, (int)0, + (int)0, (int)0, (int)0, (int)0, + (int)0, (int)0, (int)255, (int)255, + (int)192, (int)168, (int)0, (int)130 + } + +}; /** * Event loop works with the data stored in an instance of this struct. @@ -36,7 +65,11 @@ typedef struct s_global_state { linkedlist_t neighbours; /**< Linked list of our neighbours. */ } global_state_t; -int listen_init(struct evconnlistener **listener, - struct s_global_state *global_state); +int listen_init(struct evconnlistener **listener, + global_state_t *global_state); + +int joining_init(global_state_t *global_state); +neighbour_t *connect_to_peer(global_state_t *global_state, + const unsigned char *ip_addr); #endif /* P2P_H */ -- GitLab From 07d01c79fb8fa095a087d2eadb1d76dfc9d0cadd Mon Sep 17 00:00:00 2001 From: xpetrak2 <456484@mail.muni.cz> Date: Sun, 24 Jun 2018 11:33:52 +0200 Subject: [PATCH 2/6] Simple logger and configuration of files and dirs --- Makefile.am | 3 + src/configuration.c | 198 ++++++++++++++++++++++++++++++++++++++++++++ src/configuration.h | 25 ++++++ src/filing.c | 97 ++++++++++++++++++++++ src/filing.h | 40 +++++++++ src/log.c | 102 +++++++++++++++++++++++ src/log.h | 28 +++++++ 7 files changed, 493 insertions(+) create mode 100644 src/configuration.c create mode 100644 src/configuration.h create mode 100644 src/filing.c create mode 100644 src/filing.h create mode 100644 src/log.c create mode 100644 src/log.h diff --git a/Makefile.am b/Makefile.am index 5daab0d..b605437 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,7 +4,10 @@ bin_PROGRAMS = src/coincerd src/coincer src_coincerd_SOURCES = \ src/coincerd.c \ + src/configuration.c src/configuration.h \ + src/filing.c src/filing.h \ src/linkedlist.c src/linkedlist.h \ + src/log.c src/log.h \ src/neighbours.c src/neighbours.h \ src/p2p.c src/p2p.h diff --git a/src/configuration.c b/src/configuration.c new file mode 100644 index 0000000..7481472 --- /dev/null +++ b/src/configuration.c @@ -0,0 +1,198 @@ +/* + * Coincer + * Copyright (C) 2017 Coincer Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "autoconfig.h" +#include "configuration.h" +#include "log.h" + +/** + * Set home directory. + * + * @param homedir Path to homedir. + * + * @return 0 Path successfully set. + * @return 1 Home directory retrieval failure. + */ +static int set_homedir(char **homedir) +{ + *homedir = getenv("HOME"); + if (*homedir == NULL || *homedir[0] == '\0') { + log_error("set_homedir - cannot find home directory"); + return 1; + } + return 0; +} + +/** + * Set paths to config and data directories. + * + * @param config_dir Config directory. + * @param data_dir Data directory. + * + * @return 0 Paths successfully set. + * @return 1 Allocation failure. + */ +static int set_directories(char **config_dir, char **data_dir) +{ + char *homedir = NULL, + *tmpchar = NULL; + size_t tmpsize; + + /* configuration directory */ + tmpchar = getenv("XDG_CONFIG_HOME"); + if (tmpchar == NULL || tmpchar[0] == '\0') { + if (set_homedir(&homedir)) { + return 1; + } + tmpsize = strlen(homedir); + *config_dir = (char *) malloc(tmpsize + + sizeof("/.config/" PACKAGE_NAME + "/")); + if (*config_dir == NULL) { + log_error("set_directories - setting config_dir"); + return 1; + } + strcpy(*config_dir, homedir); + strcpy(*config_dir + tmpsize, "/.config/" PACKAGE_NAME "/"); + } else { + tmpsize = strlen(tmpchar); + *config_dir = (char *) malloc(tmpsize + + sizeof("/" PACKAGE_NAME "/")); + if (*config_dir == NULL) { + log_error("set_directories - setting config_dir"); + return 1; + } + strcpy(*config_dir, tmpchar); + strcpy(*config_dir + tmpsize, "/" PACKAGE_NAME "/"); + } + + /* data directory */ + tmpchar = getenv("XDG_DATA_HOME"); + if (tmpchar == NULL || tmpchar[0] == '\0') { + if (homedir == NULL && set_homedir(&homedir)) { + free(config_dir); + return 1; + } + tmpsize = strlen(homedir); + *data_dir = (char *) malloc(tmpsize + + sizeof("/.local/share/" PACKAGE_NAME + "/")); + if (*data_dir == NULL) { + log_error("set_directories - setting data_dir"); + free(config_dir); + return 1; + } + strcpy(*data_dir, homedir); + strcpy(*data_dir + tmpsize, "/.local/share/" PACKAGE_NAME "/"); + } else { + tmpsize = strlen(tmpchar); + *data_dir = (char *) malloc(tmpsize + + sizeof("/" PACKAGE_NAME "/")); + if (*data_dir == NULL) { + log_error("set_directories - setting data_dir"); + free(config_dir); + return 1; + } + strcpy(*data_dir, tmpchar); + strcpy(*data_dir + tmpsize, "/" PACKAGE_NAME "/"); + } + + return 0; +} + +/** + * Creates directories if they don't exist yet. + * + * @param config_dir Config directory. + * @param data_dir Data directory. + * + * @return 0 Directories created. + * @return 1 Creating directories failed. + */ +static int create_dirs(const char *config_dir, const char *data_dir) +{ + struct stat buffer; + + /* configuration directory */ + if (stat(config_dir, &buffer)) { + if (errno == ENOENT) { + /* create */ + if (mkdir(config_dir, S_IRWXU)) { + log_error("create_dirs - 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 " + "directory %s", config_dir); + return 1; + } + } + + /* data directory */ + if (stat(data_dir, &buffer)) { + if (errno == ENOENT) { + /* create */ + if (mkdir(data_dir, S_IRWXU)) { + log_error("create_dirs - 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); + return 1; + } + } + + return 0; +} + +/** + * Create needed directories and fetch their paths into params. + * + * @param config_dir Config directory. + * @param data_dir Data directory. + * + * @return 0 Directories created. + * @return 1 Directories setup failure. + */ +int setup_directories(char **config_dir, char **data_dir) +{ + if (set_directories(config_dir, data_dir) || + create_dirs(*config_dir, *data_dir)) { + return 1; + } + + return 0; +} + diff --git a/src/configuration.h b/src/configuration.h new file mode 100644 index 0000000..7cc528b --- /dev/null +++ b/src/configuration.h @@ -0,0 +1,25 @@ +/* + * Coincer + * Copyright (C) 2017 Coincer Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CONFIGURATION_H +#define CONFIGURATION_H + +int setup_directories(char **config_dir, char **data_dir); + +#endif /* CONFIGURATION_H */ + diff --git a/src/filing.c b/src/filing.c new file mode 100644 index 0000000..a1ffe9b --- /dev/null +++ b/src/filing.c @@ -0,0 +1,97 @@ +/* + * Coincer + * Copyright (C) 2017 Coincer Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include /* chmod */ + +#include "configuration.h" +#include "filing.h" +#include "log.h" + +static const char *PEERS_FILE_NAME = "peers"; + +/** + * Sets path to peers file. + * + * @param data_dir Path to data dir. + * @param peers The file path of peers. + * + * @return 0 Path successfully set. + * @return 1 Allocation failure. + */ +static int set_peers_path(char *data_dir, char **peers) +{ + FILE *peers_file; + + /* size of data_dir + PEERS_FILE_NAME + '\0' */ + *peers = (char *) malloc(strlen(data_dir) + + strlen(PEERS_FILE_NAME) + 1); + if (*peers == NULL) { + log_error("set_peers_path - peers file malloc"); + return 1; + } + + strcpy(*peers, data_dir); + strcat(*peers, PEERS_FILE_NAME); + + /* create file if doesn't exist */ + peers_file = fopen(*peers, "a"); + fclose(peers_file); + + /* change permissions */ + chmod(*peers, strtol("0600", 0, 8)); + + return 0; +} + +/** + * Initializes a filepaths_t instance. + * + * @param filepaths filepaths_t to be initialized. + * + * @return 0 Successfully initialized. + * @return 1 Setup failure. + */ +int setup_paths(filepaths_t *filepaths) +{ + if (setup_directories(&filepaths->config_dir, + &filepaths->data_dir)) { + return 1; + } + + set_peers_path(filepaths->data_dir, &filepaths->peers); + + return 0; +} + +/** + * Clear allocated path strings. + * + * @param filepaths filepaths_t to be cleared. + */ +void clear_paths(filepaths_t *filepaths) +{ + free(filepaths->config_dir); + free(filepaths->data_dir); + + free(filepaths->peers); +} + diff --git a/src/filing.h b/src/filing.h new file mode 100644 index 0000000..20de277 --- /dev/null +++ b/src/filing.h @@ -0,0 +1,40 @@ +/* + * Coincer + * Copyright (C) 2017 Coincer Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FILING_H +#define FILING_H + +#include +#include + +/** Paths to needed files and directories. */ +typedef struct s_filepaths { + /**< Path to config directory. */ + char *config_dir; + /**< Path to data directory. */ + char *data_dir; + + /**< Path to file with addresses of peers. */ + char *peers; +} filepaths_t; + +void clear_paths(filepaths_t *filepaths); +int setup_paths(filepaths_t *filepaths); + +#endif /* FILING_H */ + diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..17dc516 --- /dev/null +++ b/src/log.c @@ -0,0 +1,102 @@ +/* + * Coincer + * Copyright (C) 2017 Coincer Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "autoconfig.h" +#include "log.h" + +/** + * Logs debugging stuff to stdout, but only when compiled with debug enabled. + * + * @param msg Formatted message. + * @param ... Parameters to be included in the message. + */ +void log_debug(const char *msg, ...) +{ +#ifdef DEBUG + va_list args; + + fprintf(stdout, "[Debug] "); + + va_start(args, msg); + vfprintf(stdout, msg, args); + va_end(args); + + fprintf(stdout, "\n"); +#endif /* DEBUG */ +} + +/** + * Logs information to stdout. + * + * @param msg Formatted message. + * @param ... Parameters to be included in the message. + */ +void log_info(const char *msg, ...) +{ + va_list args; + + fprintf(stdout, "[Info] "); + + va_start(args, msg); + vfprintf(stdout, msg, args); + va_end(args); + + fprintf(stdout, "\n"); +} + +/** + * Logs warnings to stderr. + * + * @param msg Formatted message. + * @param ... Parameters to be included in the message. + */ +void log_warn(const char *msg, ...) +{ + va_list args; + + fprintf(stderr, "[Warning] "); + + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + + fprintf(stderr, "\n"); +} + +/** + * Logs errors to stderr. + * + * @param msg Formatted message. + * @param ... Parameters to be included in the message. + */ +void log_error(const char *msg, ...) +{ + va_list args; + + fprintf(stderr, "[Error] "); + + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + + fprintf(stderr, "\n"); +} + diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..b5e6192 --- /dev/null +++ b/src/log.h @@ -0,0 +1,28 @@ +/* + * Coincer + * Copyright (C) 2017 Coincer Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LOG_H +#define LOG_H + +void log_debug(const char *msg, ...); +void log_info(const char *msg, ...); +void log_warn(const char *msg, ...); +void log_error(const char *msg, ...); + +#endif /* LOG_H */ + -- GitLab From 978d3a36ce2763c6b4afba5ebd9bcc15ccd384a5 Mon Sep 17 00:00:00 2001 From: xpetrak2 <456484@mail.muni.cz> Date: Sun, 24 Jun 2018 17:21:42 +0200 Subject: [PATCH 3/6] Peers representation, extended linkedlist * neighbours, peers and linked list functions in alphabetical order * more functions in the linked list * the peers are being represented by their own structure * linkedlist of pending_neighbours and peers for the next commit --- Makefile.am | 3 +- src/linkedlist.c | 258 ++++++++++++++++++++++++-------------- src/linkedlist.h | 26 +++- src/neighbours.c | 102 ++++++--------- src/neighbours.h | 25 ++-- src/p2p.h | 52 +++----- src/peers.c | 320 +++++++++++++++++++++++++++++++++++++++++++++++ src/peers.h | 81 ++++++++++++ 8 files changed, 660 insertions(+), 207 deletions(-) create mode 100644 src/peers.c create mode 100644 src/peers.h diff --git a/Makefile.am b/Makefile.am index b605437..3d63773 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,8 @@ src_coincerd_SOURCES = \ src/linkedlist.c src/linkedlist.h \ src/log.c src/log.h \ src/neighbours.c src/neighbours.h \ - src/p2p.c src/p2p.h + src/p2p.c src/p2p.h \ + src/peers.c src/peers.h src_coincerd_CFLAGS = $(AM_CFLAGS) $(JANSSON_CFLAGS) $(LIBEVENT_CFLAGS) $(LIBSODIUM_CFLAGS) src_coincerd_LDADD = $(AM_LDADD) $(JANSSON_LIBS) $(LIBEVENT_LIBS) $(LIBSODIUM_LIBS) diff --git a/src/linkedlist.c b/src/linkedlist.c index aff6aef..6aa8a79 100644 --- a/src/linkedlist.c +++ b/src/linkedlist.c @@ -20,30 +20,96 @@ #include #include "linkedlist.h" +#include "log.h" /** - * Initializes linked list to default values. + * Append new node at the end of the linked list. * - * @param root Linked list to initialize. + * @param root Root of the linked list. + * @param data Data of the new node. + * + * @return linkedlist_node_t Pointer to created node if succeeded. + * @return NULL If failure. */ -void linkedlist_init(linkedlist_t *root) +linkedlist_node_t *linkedlist_append(linkedlist_t *root, void *data) { - root->first.prev = NULL; - root->first.next = &root->last; - root->last.prev = &root->first; - root->last.next = NULL; + return linkedlist_insert_after(root, + root->last.prev, + data); +} - root->first.data = NULL; - root->last.data = NULL; +/** + * Delete node from the linked list. + * + * @param node Node to be deleted from the linked list. + */ +void linkedlist_delete(linkedlist_node_t *node) +{ + /* fix the links of neighbour nodes */ + node->prev->next = node->next; + node->next->prev = node->prev; + + /* node's data deletion part */ + if (node->data != NULL) { + free(node->data); + } + + /* node deletion part */ + free(node); } /** - * Get first node of the linked list. + * Destroys a linked list. * - * @param root Root of the linked list. + * @param root Root of the linked list to destroy. + */ +void linkedlist_destroy(linkedlist_t *root) +{ + linkedlist_node_t *tmp; + + tmp = root->first.next; + while (tmp->next != NULL) { + tmp = tmp->next; + if (tmp->prev->data != NULL) { + free(tmp->prev->data); + } + free(tmp->prev); + } +} + +/** + * Find node in the linked list by data. * - * @return First node of the linked list. - * @return NULL if linkedlist is empty. + * @param root Root of the linked list. + * @param data Data of the requested node. + * + * @return linkedlist_node_t Node containing 'data'. + * @return NULL If the node doesn't exist. + */ +linkedlist_node_t *linkedlist_find(const linkedlist_t *root, const void *data) +{ + /* start the search from the first node of the linked list */ + linkedlist_node_t *current = linkedlist_get_first(root); + while (current != NULL) { + /* node found */ + if (current->data == data) { + /* return the node containing 'data' */ + return current; + } + /* move to the next node and continue with the search */ + current = linkedlist_get_next(root, current); + } + /* node not found */ + return NULL; +} + +/** + * Get the first node of the linked list. + * + * @param root Root of the linked list. + * + * @return linkedlist_node_t First node of the linked list. + * @return NULL If the linkedlist is empty. */ linkedlist_node_t *linkedlist_get_first(const linkedlist_t *root) { @@ -55,12 +121,12 @@ linkedlist_node_t *linkedlist_get_first(const linkedlist_t *root) } /** - * Get last node of the linkedlist. + * Get the last node of the linkedlist. * - * @param root Root of the linked list. + * @param root Root of the linked list. * - * @return Last node of the linked list. - * @return NULL if linkedlist is empty. + * @return linkedlist_node_t Last node of the linked list. + * @return NULL If linkedlist is empty. */ linkedlist_node_t *linkedlist_get_last(const linkedlist_t *root) { @@ -72,13 +138,14 @@ linkedlist_node_t *linkedlist_get_last(const linkedlist_t *root) } /** - * Get node that is right after 'node' in the linked list. + * Get a node that is right after 'node' in the linked list. * - * @param root Root of the linked list. - * @param node We want node that is right after this node. + * @param root Root of the linked list. + * @param node A node right after this node. * - * @return The node we requested. - * @return NULL if 'node' was last in the linked list or NULL. + * @return linkedlist_node_t The node we requested. + * @return NULL If 'node' was the last or 'root' + * is empty. */ linkedlist_node_t *linkedlist_get_next(const linkedlist_t *root, const linkedlist_node_t *node) @@ -91,110 +158,115 @@ linkedlist_node_t *linkedlist_get_next(const linkedlist_t *root, } /** - * Destroys a linked list. + * Get a node that is right before 'node' in the linked list. * - * @param root Root of the linked list to destroy. + * @param root Root of the linked list. + * @param node A node right before this node. + * + * @return linkedlist_node The node we requested. + * @return NULL If 'node' was the first or 'root' + * is empty. */ -void linkedlist_destroy(linkedlist_t *root) +linkedlist_node_t *linkedlist_get_prev(const linkedlist_t *root, + const linkedlist_node_t *node) { - linkedlist_node_t *tmp; - - tmp = root->first.next; - while (tmp->next != NULL) { - tmp = tmp->next; - free(tmp->prev); + if (node == NULL || node->prev == &root->first) { + return NULL; } + + return node->prev; } /** - * Append new node at the end of the linked list. - * - * @param root Root of the linked list. - * @param data Data to append to the list. + * Initializes linked list to default values. * - * @return Pointer to created node if succeeded. - * @return NULL if failed. + * @param root Linked list to initialize. */ -linkedlist_node_t *linkedlist_append(linkedlist_t *root, void *data) +void linkedlist_init(linkedlist_t *root) { - linkedlist_node_t *node; - - if ((node = (linkedlist_node_t *) malloc(sizeof(linkedlist_node_t))) == - NULL) { - perror("linkedlist_append malloc"); - return NULL; - } - - node->data = data; - - node->prev = root->last.prev; - node->next = &root->last; - root->last.prev->next = node; - root->last.prev = node; + root->first.prev = NULL; + root->first.next = &root->last; + root->last.prev = &root->first; + root->last.next = NULL; - return node; + root->first.data = NULL; + root->last.data = NULL; } /** - * Delete node from the linked list. + * Insert new node into linked list after 'node'. * - * @param root Root of the linked list. - * @param node Node to be deleted from the linked list. + * @param root Root of the linked list. + * @param node Insert new node right after this node. + * @param data Data of the new node. + * + * @return linkedlist_node_t Pointer to the new node. + * @return NULL If failure. */ -void linkedlist_delete(linkedlist_t *root, linkedlist_node_t *node) +linkedlist_node_t *linkedlist_insert_after(linkedlist_t *root, + linkedlist_node_t *node, + void *data) { - /* start the search from the first node of the linked list */ - linkedlist_node_t *current = linkedlist_get_first(root); + linkedlist_node_t *new_node; - while (current != NULL) { + if (node == &root->last) { + node = root->last.prev; + } - /* node found */ - if (current == node) { + new_node = (linkedlist_node_t *) malloc(sizeof(linkedlist_node_t)); + if (new_node == NULL) { + log_error("linkedlist_insert_after - malloc"); + return NULL; + } - /* fix the links of neighbour nodes */ - node->prev->next = node->next; - node->next->prev = node->prev; + new_node->data = data; - /* node deletion part */ - free(node); - node = NULL; + new_node->prev = node; + new_node->next = node->next; + node->next->prev = new_node; + node->next = new_node; - /* no need to continue */ - return; - } + return new_node; +} - /* go to next node and continue the search */ - current = linkedlist_get_next(root, current); +/** + * Insert new node into linkedlist before 'node'. + * + * @param root Root of the linked list. + * @param node Insert new node right before this node. + * @param data Data of the new node. + * + * @return linkedlist_node_t Pointer to the new node. + * @return NULL If failure. + */ +linkedlist_node_t *linkedlist_insert_before(linkedlist_t *root, + linkedlist_node_t *node, + void *data) +{ + if (node == &root->first) { + node = root->first.next; } + return linkedlist_insert_after(root, node->prev, data); } /** - * Find node in the linked list by data. + * Get the number of elements in the linked list. * * @param root Root of the linked list. - * @param data Data of the requested node. * - * @return Node containing 'data'. - * @return NULL if the node doesn't exist. + * @return n Number of linked list elements. */ -linkedlist_node_t *linkedlist_find(const linkedlist_t *root, const void *data) +size_t linkedlist_size(const linkedlist_t *root) { - /* start the search from the first node of the linked list */ - linkedlist_node_t *current = linkedlist_get_first(root); - - while (current != NULL) { - - /* node found */ - if (current->data == data) { - - /* return the node containing 'data' */ - return current; - } + linkedlist_node_t *tmp; + size_t n = 0; - /* move to the next node and continue with the search */ - current = linkedlist_get_next(root, current); + tmp = root->first.next; + while (tmp->next != NULL) { + n++; + tmp = tmp->next; } - /* node not found */ - return NULL; + return n; } + diff --git a/src/linkedlist.h b/src/linkedlist.h index c013bf5..ada9554 100644 --- a/src/linkedlist.h +++ b/src/linkedlist.h @@ -19,6 +19,8 @@ #ifndef LINKEDLIST_H #define LINKEDLIST_H +#include + /** * Node of the linked list structure. */ @@ -36,7 +38,13 @@ typedef struct s_linkedlist { struct s_linkedlist_node last; /**< Auxiliary last node. */ } linkedlist_t; -void linkedlist_init(linkedlist_t *root); +linkedlist_node_t *linkedlist_append(linkedlist_t *root, void *data); + +void linkedlist_delete(linkedlist_node_t *node); + +void linkedlist_destroy(linkedlist_t *root); + +linkedlist_node_t *linkedlist_find(const linkedlist_t *root, const void *data); linkedlist_node_t *linkedlist_get_first(const linkedlist_t *root); @@ -45,12 +53,20 @@ linkedlist_node_t *linkedlist_get_last(const linkedlist_t *root); linkedlist_node_t *linkedlist_get_next(const linkedlist_t *root, const linkedlist_node_t *node); -void linkedlist_destroy(linkedlist_t *root); +linkedlist_node_t *linkedlist_get_prev(const linkedlist_t *root, + const linkedlist_node_t *node); -linkedlist_node_t *linkedlist_append(linkedlist_t *root, void *data); +void linkedlist_init(linkedlist_t *root); -void linkedlist_delete(linkedlist_t *root, linkedlist_node_t *node); +linkedlist_node_t *linkedlist_insert_after(linkedlist_t *root, + linkedlist_node_t *node, + void *data); -linkedlist_node_t *linkedlist_find(const linkedlist_t *root, const void *data); +linkedlist_node_t *linkedlist_insert_before(linkedlist_t *root, + linkedlist_node_t *node, + void *data); + +size_t linkedlist_size(const linkedlist_t *root); #endif /* LINKEDLIST_H */ + diff --git a/src/neighbours.c b/src/neighbours.c index aae77e8..0f7fd4c 100644 --- a/src/neighbours.c +++ b/src/neighbours.c @@ -16,32 +16,24 @@ * along with this program. If not, see . */ +#include #include #include #include #include #include "linkedlist.h" +#include "log.h" #include "neighbours.h" /** - * Initialize the linked list of neighbours to default values. - * - * @param neighbours Linked list to be initialized. - */ -void neighbours_init(linkedlist_t *neighbours) -{ - linkedlist_init(neighbours); -} - -/** * Find neighbour in neighbours based on their bufferevent. * - * @param neighbours Linked list of our neighbours. + * @param neighbours Our neighbours. * @param bev Neighbour's bufferevent. * - * @return Desired neighbour. - * @return NULL if not found. + * @return neighbour_t Requested neighbour. + * @return NULL If not found. */ neighbour_t *find_neighbour(const linkedlist_t *neighbours, const struct bufferevent *bev) @@ -60,25 +52,24 @@ neighbour_t *find_neighbour(const linkedlist_t *neighbours, /* return node's data; struct s_neighbour */ return current_data; } - /* get next node in the linked list */ current = linkedlist_get_next(neighbours, current); } - + /* neighbour not found */ return NULL; } -/** - * Find neighbour in neighbours based on their ip_addr. +/** + * Find neighbour in neighbours based on their addr. * - * @param neighbours Linked list of our neighbours. - * @param ip_addr Binary ip address stored in 16 bytes. + * @param neighbours Our neighbours. + * @param addr Binary ip address stored in 16 bytes. * - * @return Desired neighbour. - * @return NULL if not found. + * @return neighbour_t Requested neighbour. + * @return NULL If not found. */ -neighbour_t *find_neighbour_by_ip(const linkedlist_t *neighbours, - const unsigned char *ip_addr) +neighbour_t *find_neighbour_by_addr(const linkedlist_t *neighbours, + const struct in6_addr *addr) { /* start the search from the first linked list node */ const linkedlist_node_t *current = linkedlist_get_first(neighbours); @@ -89,58 +80,57 @@ neighbour_t *find_neighbour_by_ip(const linkedlist_t *neighbours, neighbour_t *current_data = (neighbour_t *) current->data; /* ip addresses match => neighbour found */ - if (memcmp(current_data->ip_addr, ip_addr, 16) == 0) { - + if (memcmp(¤t_data->addr, addr, 16) == 0) { /* return node's data; struct s_neighbour */ return current_data; } - /* get next node in the linked list */ current = linkedlist_get_next(neighbours, current); } - + /* neighbour not found */ return NULL; } -/** +/** * Add new neighbour into neighbours. * - * @param neighbours Linked list of our neighbours. - * @param ip_addr Binary ip address stored in 16 bytes. + * @param neighbours Linked list of our neighbours. + * @param addr Binary ip address stored in 16 bytes. * @param bev Neighbour's bufferevent. * - * @return Newly added neighbour. - * @return NULL if neighbour already exists or allocation failure occured. + * @return neighbour_t Newly added neighbour. + * @return NULL If the neighbour already exists or allocation + * failure occured. */ neighbour_t *add_new_neighbour(linkedlist_t *neighbours, - const unsigned char *ip_addr, + const struct in6_addr *addr, struct bufferevent *bev) { - /* create new neighbour */ neighbour_t *new_neighbour; - new_neighbour = (neighbour_t *) malloc(sizeof(neighbour_t)); + /* create new neighbour */ + new_neighbour = (neighbour_t *) malloc(sizeof(neighbour_t)); /* allocation failure */ if (new_neighbour == NULL) { - /* WIP */ - perror("malloc for a new neighbour"); + log_error("add_new_neighbour - new_neighbour malloc"); return NULL; } /* don't add duplicates */ - if (find_neighbour_by_ip(neighbours, ip_addr)) { + if (find_neighbour_by_addr(neighbours, addr) || + find_neighbour(neighbours, bev)) { + free(new_neighbour); return NULL; } /* initialize new neighbour */ - memcpy(new_neighbour->ip_addr, ip_addr, 16); + memcpy(&new_neighbour->addr, addr, 16); new_neighbour->failed_pings = 0; new_neighbour->buffer_event = bev; - /* add new neighbour into linked list; NULL if allocation failed */ + /* add new neighbour into linked list; NULL if the allocation failed */ if (linkedlist_append(neighbours, new_neighbour) == NULL) { - /* WIP */ - perror("malloc for a new neighbour of linkedlist node"); + free(new_neighbour); return NULL; } @@ -159,29 +149,19 @@ void delete_neighbour(linkedlist_t *neighbours, struct bufferevent *bev) linkedlist_node_t *neighbour_node; neighbour = find_neighbour(neighbours, bev); - /* no neighbour with bufferevent 'bev' => nothing to delete */ if (neighbour == NULL) { return; } neighbour_node = linkedlist_find(neighbours, neighbour); - /* since neighbour was found, neighbour_node should never be NULL */ - if (neighbour_node == NULL) { - /* WIP */ - perror("delete_neighbour"); - return; - } + assert(neighbour_node != NULL); /* free neighbour's bufferevent */ bufferevent_free(bev); - - /* free the linked list node's data; neighbour_t * */ - free(neighbour_node->data); - /* delete the neighbour from the linked list */ - linkedlist_delete(neighbours, neighbour_node); + linkedlist_delete(neighbour_node); } /** @@ -191,27 +171,23 @@ void delete_neighbour(linkedlist_t *neighbours, struct bufferevent *bev) */ void clear_neighbours(linkedlist_t *neighbours) { - linkedlist_node_t *current_node = linkedlist_get_first(neighbours); + neighbour_t *current; + linkedlist_node_t *current_node; + current_node = linkedlist_get_first(neighbours); /* safely delete data from the linked list nodes */ while (current_node != NULL) { - - neighbour_t *current; - /* load current node's data into 'current' */ current = (neighbour_t *) current_node->data; /* deallocate neighbour's bufferevent */ bufferevent_free(current->buffer_event); - /* deallocate data */ - free(current_node->data); - current_node->data = NULL; - /* get next node in the linked list */ current_node = linkedlist_get_next(neighbours, current_node); } - /* safely delete all nodes in the linked list */ + /* safely delete all nodes and their data in the linked list */ linkedlist_destroy(neighbours); } + diff --git a/src/neighbours.h b/src/neighbours.h index 5ee9114..dabfb03 100644 --- a/src/neighbours.h +++ b/src/neighbours.h @@ -20,33 +20,33 @@ #define NEIGHBOURS_H #include +#include #include #include "linkedlist.h" -/** Data type for the linked list of neighbours. */ +/* minimum number of peers we need to be connected to */ +#define MIN_NEIGHBOURS 3 + +/** Data type for the linkedlist of neighbours. */ typedef struct s_neighbour { /**< Neighbours's IPv6 address; - * also allows storing IPv4-mapped IPv6 addresses. */ - unsigned char ip_addr[16]; - + * also allows storing IPv4-mapped IPv6 addresses. */ + struct in6_addr addr; /**< Bufferevent belonging to this neighbour. */ struct bufferevent *buffer_event; - /**< Number of failed ping attempts -- max 3, then disconnect. */ size_t failed_pings; } neighbour_t; -void neighbours_init(linkedlist_t *neighbours); +neighbour_t *find_neighbour(const linkedlist_t *neighbours, + const struct bufferevent *bev); -neighbour_t *find_neighbour(const linkedlist_t *neighbours, - const struct bufferevent *bev); - -neighbour_t *find_neighbour_by_ip(const linkedlist_t *neighbours, - const unsigned char *ip_addr); +neighbour_t *find_neighbour_by_addr(const linkedlist_t *neighbours, + const struct in6_addr *ip_addr); neighbour_t *add_new_neighbour(linkedlist_t *neighbours, - const unsigned char *ip_addr, + const struct in6_addr *ip_addr, struct bufferevent *bev); void delete_neighbour(linkedlist_t *neighbours, struct bufferevent *bev); @@ -54,3 +54,4 @@ void delete_neighbour(linkedlist_t *neighbours, struct bufferevent *bev); void clear_neighbours(linkedlist_t *neighbours); #endif /* NEIGHBOURS_H */ + diff --git a/src/p2p.h b/src/p2p.h index 2393177..549ba42 100644 --- a/src/p2p.h +++ b/src/p2p.h @@ -20,56 +20,42 @@ #define P2P_H #include +#include +#include "filing.h" #include "linkedlist.h" #include "neighbours.h" -/* number of peers guaranteed to be in the network */ -#define DEFAULT_PEERS_SIZE 3 /* default port for TCP listening */ #define DEFAULT_PORT 31070 -/* minimum number of peers we need to be connected to */ -#define MINIMUM_NEIGHBOURS 2 /* after TIMEOUT_TIME seconds invoke timeout callback */ #define TIMEOUT_TIME 30 -/* IPv6 addresses of peers guaranteed to be in the network */ -static const unsigned char DEFAULT_PEERS[DEFAULT_PEERS_SIZE][16] = { - /* TODO: Replace with the actual default peer IPs */ - { - (int)0, (int)0, (int)0, (int)0, - (int)0, (int)0, (int)0, (int)0, - (int)0, (int)0, (int)0, (int)0, - (int)0, (int)0, (int)0, (int)1 - }, - { - (int)0, (int)0, (int)0, (int)0, - (int)0, (int)0, (int)0, (int)0, - (int)0, (int)0, (int)255, (int)255, - (int)192, (int)168, (int)0, (int)125 - }, - { - (int)0, (int)0, (int)0, (int)0, - (int)0, (int)0, (int)0, (int)0, - (int)0, (int)0, (int)255, (int)255, - (int)192, (int)168, (int)0, (int)130 - } - -}; - /** * Event loop works with the data stored in an instance of this struct. */ typedef struct s_global_state { - struct event_base *event_loop; /**< For holding and polling events. */ - linkedlist_t neighbours; /**< Linked list of our neighbours. */ + /**< For holding and polling events. */ + struct event_base *event_loop; + /**< Holder of paths to needed files/dirs. */ + filepaths_t filepaths; + /**< Linked list of our neighbours. */ + linkedlist_t neighbours; + /**< Linked list of some peers in the network. */ + linkedlist_t peers; + /**< Peers that didn't accept/reject us yet. */ + linkedlist_t pending_neighbours; } global_state_t; int listen_init(struct evconnlistener **listener, global_state_t *global_state); -int joining_init(global_state_t *global_state); +void add_more_connections(global_state_t *global_state, size_t conns_amount); + +int connect_to_addr(global_state_t *global_state, + const struct in6_addr *addr); + +void ask_for_peers(neighbour_t *neighbour); -neighbour_t *connect_to_peer(global_state_t *global_state, - const unsigned char *ip_addr); #endif /* P2P_H */ + diff --git a/src/peers.c b/src/peers.c new file mode 100644 index 0000000..6158c07 --- /dev/null +++ b/src/peers.c @@ -0,0 +1,320 @@ +/* + * Coincer + * Copyright (C) 2017 Coincer Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "linkedlist.h" +#include "log.h" +#include "peers.h" + +/** + * Add new peer into sorted linkedlist of peers. + * + * @param peers The linkedlist of peers. + * @param addr Address of the new peer. + * + * @return linkedlist_node_t Newly added node in the linkedlist. + * @return NULL Peer is already added, default or + * allocation failure. + */ +linkedlist_node_t *add_peer(linkedlist_t *peers, const struct in6_addr *addr) +{ + int cmp_value; + struct in6_addr curr_addr; + linkedlist_node_t *current_node; + peer_t *current_peer; + int i; + linkedlist_node_t *new_node; + peer_t *new_peer; + char text_ip[INET6_ADDRSTRLEN]; + + /* add peer to the list of known peers, unless it's a default peer */ + for (i = 0; i < DEFAULT_PEERS_SIZE; i++) { + memcpy(&curr_addr, DEFAULT_PEERS[i], 16); + /* it's a default peer, don't add it into 'peers' */ + if (memcmp(&curr_addr, addr, 16) == 0) { + return NULL; + } + } + + /* allocate memory for a new peer */ + new_peer = (peer_t *) malloc(sizeof(peer_t)); + if (new_peer == NULL) { + log_error("add_peer - malloc"); + return NULL; + } + + /* initialize all attributes of the new peer */ + memcpy(&new_peer->addr, addr, 16); + new_peer->is_available = 1; + + /* get textual representation of 'addr' */ + inet_ntop(AF_INET6, addr, text_ip, INET6_ADDRSTRLEN); + + /* insert 'new_peer' to its proper position in the sorted linkedlist; + * start from the last node of 'peers', as 'fetch_peers' (using this + * function) is likely to add in ascending order => better performance + */ + current_node = linkedlist_get_last(peers); + while (current_node != NULL) { + current_peer = (peer_t *) current_node->data; + + cmp_value = memcmp(&new_peer->addr, ¤t_peer->addr, 16); + /* the linkedlist already contains this peer */ + if (cmp_value == 0) { + free(new_peer); + return NULL; + } else if (cmp_value > 0) { + /* the proper position found */ + new_node = linkedlist_insert_after(peers, + current_node, + new_peer); + if (new_node != NULL) { + log_debug("add_peer - %s successfully added", + text_ip); + } + return new_node; + } + current_node = linkedlist_get_prev(peers, current_node); + } + /* the new peer's addr is lexicographically the lowest */ + new_node = linkedlist_insert_after(peers, &peers->first, new_peer); + if (new_node != NULL) { + log_debug("add_peer - %s successfully added", text_ip); + } + return new_node; +} + +/** + * Delete all peers and their data. + * + * @param peers Linkedlist of peers. + */ +void clear_peers(linkedlist_t *peers) +{ + /* peer_t has no dynamically allocated variables */ + linkedlist_destroy(peers); +} + +/** + * Fetch available peers from 'peers' into 'available_peers'. + * + * @param peers All peers known to us. + * @param available_peers The peers marked as available. + * + * @return n 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 'peers_path' file into 'peers' linkedlist. + * + * @param peers_path Path to 'peers' file. + * @param peers Fetch loaded peers in here. + * + * @return 0 Successfully fetched. + * @return 1 Failure. + */ +int fetch_peers(const char *peers_path, linkedlist_t *peers) +{ + struct in6_addr addr; + FILE *peers_file; + + peers_file = fopen(peers_path, "rb"); + if (peers_file == NULL) { + log_error("fetch_peers - peers_file not found"); + return 1; + } + + while (fread(&addr, sizeof(struct in6_addr), 1, peers_file) == 1) { + add_peer(peers, &addr); + } + + fclose(peers_file); + return 0; +} + +/** + * Find peer in the linkedlist by their address. + * + * @param peers Linkedlist of peers. + * @param addr Address of the peer we want. + * + * @return peer_t Requested peer. + * @return NULL Peer not found. + */ +peer_t *find_peer_by_addr(const linkedlist_t *peers, + const struct in6_addr *addr) +{ + const linkedlist_node_t *current = linkedlist_get_first(peers); + + while (current != NULL) { + peer_t *current_data = (peer_t *) current->data; + + /* ip addresses match => requested peer found */ + if (memcmp(¤t_data->addr, addr, 16) == 0) { + /* return node's data; struct s_peer */ + return current_data; + } + current = linkedlist_get_next(peers, current); + } + /* requested peer not found */ + return NULL; +} + +/* TODO: allocate memory for the 'output', don't assume any buffer size */ +/** + * '\n' separated 'output' of peer addresses in readable form from 'peers'. + * + * @param peers List of peers. + * @param output Output string. + */ +void peers_to_str(const linkedlist_t *peers, char *output) +{ + linkedlist_node_t *current_node; + peer_t *current_peer; + size_t output_size = 0; + char text_ip[INET6_ADDRSTRLEN]; + + output[0] = '\0'; + current_node = linkedlist_get_first(peers); + while (current_node != NULL) { + current_peer = (peer_t *) current_node->data; + + /* binary ip to text ip conversion */ + inet_ntop(AF_INET6, + ¤t_peer->addr, + text_ip, + INET6_ADDRSTRLEN); + output_size += strlen(text_ip); + strcat(output, text_ip); + + current_node = linkedlist_get_next(peers, current_node); + /* if it's not the last peer, append '\n' */ + if (current_node != NULL) { + output[output_size++] = '\n'; + } + output[output_size] = '\0'; + } +} + +/** + * Set all peers available. + * + * @param peers The peers to be set as available. + */ +void reset_peers_availability(linkedlist_t *peers) +{ + linkedlist_node_t *current_node; + peer_t *current_peer; + + current_node = linkedlist_get_first(peers); + while (current_node != NULL) { + current_peer = (peer_t *) current_node->data; + + current_peer->is_available = 1; + current_node = linkedlist_get_next(peers, current_node); + } +} + +/** + * Shuffle the input array 'peers'. + * + * @param peers The peers to be shuffled. + * @param peers_size Number of peers to be shuffled. + */ +void shuffle_peers_arr(peer_t *peers[MAX_PEERS_SIZE], size_t peers_size) +{ + size_t i; + size_t idx; + peer_t *tmp; + + for (i = 0; i < peers_size; i++) { + /* don't swap with already swapped */ + idx = i + rand() % (peers_size - i); + + tmp = peers[i]; + peers[i] = peers[idx]; + peers[idx] = tmp; + } +} + +/** + * Store peers from the linkedlist 'peers' into file at 'peers_path'. + * + * @param peers_path Path to 'peers' file. + * @param peers Linkedlist of the peers to be stored. + * + * @return 0 Successfully stored. + * @return 1 Failure. + */ +int store_peers(const char *peers_path, const linkedlist_t *peers) +{ + const linkedlist_node_t *current; + const peer_t *current_peer; + FILE *peers_file; + + peers_file = fopen(peers_path, "wb"); + if (peers_file == NULL) { + log_error("store_peers - unable to create %s", peers_path); + return 1; + } + + current = linkedlist_get_first(peers); + while (current != NULL) { + current_peer = (peer_t *) current->data; + fwrite(¤t_peer->addr, + sizeof(struct in6_addr), + 1, + peers_file); + current = linkedlist_get_next(peers, current); + } + + fclose(peers_file); + return 0; +} + diff --git a/src/peers.h b/src/peers.h new file mode 100644 index 0000000..8b0864b --- /dev/null +++ b/src/peers.h @@ -0,0 +1,81 @@ +/* + * Coincer + * Copyright (C) 2017 Coincer Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef PEERS_H +#define PEERS_H + +#include +#include + +#include "linkedlist.h" + +/* number of peers guaranteed to be in the network */ +#define DEFAULT_PEERS_SIZE 2 +/* maximum number of peers we store */ +#define MAX_PEERS_SIZE 50 + +/* IPv6 addresses of peers guaranteed to be in the network */ +static const unsigned char DEFAULT_PEERS[DEFAULT_PEERS_SIZE][16] = { + { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 255, 255, + 147, 251, 210, 17 + }, + { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 255, 255, + 147, 251, 210, 23 + } +}; + +/** Peer info holder. */ +typedef struct s_peer { + /**< Binary IPv6 address. */ + struct in6_addr addr; + /**< A peer is not available if they is already our neighbour, + * pending to become one, or if we are unnable to connect to them. + * 1 if available, 0 if not. + */ + short is_available; + /* TODO: add uptime */ +} peer_t; + +linkedlist_node_t *add_peer(linkedlist_t *peers, const struct in6_addr *addr); + +void clear_peers(linkedlist_t *peers); + +size_t fetch_available_peers(const linkedlist_t *peers, + peer_t *available_peers[MAX_PEERS_SIZE]); + +int fetch_peers(const char *peers_path, linkedlist_t *peers); + +peer_t *find_peer_by_addr(const linkedlist_t *peers, + const struct in6_addr *addr); + +void peers_to_str(const linkedlist_t *peers, char *output); + +void reset_peers_availability(linkedlist_t *peers); + +void shuffle_peers_arr(peer_t *peers[MAX_PEERS_SIZE], size_t peers_size); + +int store_peers(const char *peers_path, const linkedlist_t *peers); + +#endif /* PEERS_H */ + -- GitLab From 0b811dce73863e36b1370c8a33e50521af8c028c Mon Sep 17 00:00:00 2001 From: xpetrak2 <456484@mail.muni.cz> Date: Sun, 24 Jun 2018 17:32:35 +0200 Subject: [PATCH 4/6] The peers interconnecting and signal callback * SIGINT is now being handled * the peers can connect to each other now --- src/coincerd.c | 122 +++++++++++++- src/p2p.c | 424 ++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 449 insertions(+), 97 deletions(-) diff --git a/src/coincerd.c b/src/coincerd.c index 2d786ed..5a860a5 100644 --- a/src/coincerd.c +++ b/src/coincerd.c @@ -18,9 +18,18 @@ #include #include +#include +#include +#include +#include "filing.h" +#include "log.h" #include "neighbours.h" #include "p2p.h" +#include "peers.h" + +static void signal_cb(evutil_socket_t fd, short events, void *ctx); +static void conns_cb(evutil_socket_t fd, short events, void *ctx); int main(void) { @@ -42,23 +51,120 @@ int main(void) * - terminate on SIGTERM */ - struct evconnlistener *listener; - struct s_global_state global_state; + struct event *conns_event; + struct timeval conns_interval; + global_state_t global_state; + struct evconnlistener *listener; + struct event *sigint_event; + time_t t; - global_state.event_loop = NULL; - neighbours_init(&global_state.neighbours); + srand((unsigned) time(&t)); - if (listen_init(&listener, &global_state) != 0) { + /* initialize all global_state variables */ + global_state.event_loop = NULL; + if (setup_paths(&global_state.filepaths)) { return 1; - } else if (joining_init(&global_state) != 0) { + } + + linkedlist_init(&global_state.pending_neighbours); + linkedlist_init(&global_state.neighbours); + linkedlist_init(&global_state.peers); + + if (fetch_peers(global_state.filepaths.peers, &global_state.peers)) { return 2; } + /* setup everything needed for TCP listening */ + if (listen_init(&listener, &global_state) != 0) { + return 3; + } + + /* register SIGINT event to its callback */ + sigint_event = evsignal_new(global_state.event_loop, + SIGINT, + 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; + } + + /* setup a function that actively checks the number of neighbours */ + conns_interval.tv_sec = 10; + conns_interval.tv_usec = 0; + + conns_event = event_new(global_state.event_loop, + -1, + EV_PERSIST, + 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; + } + + /* initiate joining the coincer network */ + add_more_connections(&global_state, MIN_NEIGHBOURS); + + /* start the event loop */ event_base_dispatch(global_state.event_loop); - event_base_free(global_state.event_loop); - evconnlistener_free(listener); + /* SIGINT received, loop terminated; the clean-up part */ + clear_neighbours(&global_state.pending_neighbours); clear_neighbours(&global_state.neighbours); + /* store peers into 'peers' file before cleaning them */ + store_peers(global_state.filepaths.peers, &global_state.peers); + clear_peers(&global_state.peers); + clear_paths(&global_state.filepaths); + + evconnlistener_free(listener); + event_free(sigint_event); + event_free(conns_event); + event_base_free(global_state.event_loop); + + printf("\nCoincer says: Bye!\n"); return 0; } + +/** + * Callback function for a received signal. + * + * @param signal What signal was invoked. + * @param events Flags of the event occured. + * @param ctx Global state. + */ +static void signal_cb(evutil_socket_t signal __attribute__((unused)), + short events __attribute__((unused)), + void *ctx) +{ + global_state_t *global_state = (global_state_t *) ctx; + + event_base_loopexit(global_state->event_loop, NULL); +} + +/** + * Actively check the number of neighbours and add more if needed. + * + * @param fd File descriptor. + * @param events Event flags. + * @param ctx Global state. + */ +static void conns_cb(int fd __attribute__((unused)), + short events __attribute__((unused)), + void *ctx) +{ + int needed_conns; + + global_state_t *global_state = (global_state_t *) ctx; + needed_conns = MIN_NEIGHBOURS - + linkedlist_size(&global_state->neighbours); + if (needed_conns > 0) { + /* ask twice more peers than we need; it's preferable + * to have more neighbours than minimum + */ + log_debug("conns_cb - we need %d more neighbours"); + add_more_connections(global_state, 2 * needed_conns); + } +} + diff --git a/src/p2p.c b/src/p2p.c index 258bcd3..849baf2 100644 --- a/src/p2p.c +++ b/src/p2p.c @@ -16,7 +16,11 @@ * along with this program. If not, see . */ + +#define _POSIX_SOURCE /* strtok_r */ + #include /* inet_ntop */ +#include #include #include #include @@ -25,10 +29,13 @@ #include #include #include +#include /* sleep */ #include "linkedlist.h" +#include "log.h" #include "neighbours.h" #include "p2p.h" +#include "peers.h" /** * Simple helper for conversion of binary IP to readable IP address. @@ -36,11 +43,54 @@ * @param binary_ip Binary represented IP address. * @param ip Readable IP address. */ -static void ip_to_string(const unsigned char *binary_ip, char *ip) +static void ip_to_string(const struct in6_addr *binary_ip, char *ip) { inet_ntop(AF_INET6, binary_ip, ip, INET6_ADDRSTRLEN); } +/** + * Ask the neighbour for a list of peers. + * + * @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) +{ + struct bufferevent *bev; + + if (neighbour == NULL || (bev = neighbour->buffer_event) == NULL) { + return; + } + + /* 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); +} + +/** + * Process received list of peer addresses. + * + * @param global_state Data for the event loop to work with. + * @param peers '\n'-separated list of peer addresses. + */ +static void process_peers(global_state_t *global_state, char *peers) +{ + struct in6_addr addr; + const char delim[2] = "\n"; + char *line; + char *save_ptr; + + line = strtok_r(peers, delim, &save_ptr); + + while (line != NULL) { + if (inet_pton(AF_INET6, line, &addr) == 1) { + add_peer(&global_state->peers, &addr); + } + line = strtok_r(NULL, delim, &save_ptr); + } +} + /** * Processing a P2P message. * @@ -55,7 +105,7 @@ static void p2p_process(struct bufferevent *bev, void *ctx) char *message; neighbour_t *neighbour; struct evbuffer *output; - char response[256]; /* TODO: adjust size */ + char response[2048]; /* TODO: adjust size */ char text_ip[INET6_ADDRSTRLEN]; global_state = (global_state_t *) ctx; @@ -63,12 +113,9 @@ static void p2p_process(struct bufferevent *bev, void *ctx) /* find the neighbour based on their bufferevent */ neighbour = find_neighbour(&global_state->neighbours, bev); - /* message from unknown neighbour; quit p2p_process */ - if (neighbour == NULL) { - return; - } + assert(neighbour != NULL); - /* refresh neighbour's failed pings */ + /* reset neighbour's failed pings */ neighbour->failed_pings = 0; /* read from the input buffer, write to output buffer */ @@ -89,18 +136,26 @@ static void p2p_process(struct bufferevent *bev, void *ctx) message[len] = '\0'; } - ip_to_string(neighbour->ip_addr, text_ip); - printf("Received: %s from %s\n", message, text_ip); + ip_to_string(&neighbour->addr, text_ip); + log_debug("p2p_process - received: %s from %s", message, text_ip); + + response[0] = '\0'; /* TODO: Replace with JSON messages */ if (strcmp(message, "ping") == 0) { strcpy(response, "pong"); + /* ignore "pong" */ + } else if (strcmp(message, "pong") == 0) { + /* "peers" is a request for list of addresses */ + } else if (strcmp(message, "peers") == 0) { + peers_to_str(&global_state->peers, response); + /* list of peers */ } else { - strcpy(response, ""); + process_peers(global_state, message); } - if (strcmp(response, "") != 0) { - printf("Responding with: %s\n", response); + if (response[0] != '\0') { + log_debug("p2p_process - responding with: %s", response); /* copy response to the output buffer */ evbuffer_add_printf(output, "%s", response); } @@ -121,7 +176,7 @@ static void timeout_process(linkedlist_t *neighbours, char text_ip[INET6_ADDRSTRLEN]; /* initialize text_ip */ - ip_to_string(neighbour->ip_addr, text_ip); + ip_to_string(&neighbour->addr, text_ip); /* the neighbour hasn't failed enough pings to be deleted */ if (neighbour->failed_pings < 3) { @@ -130,9 +185,9 @@ static void timeout_process(linkedlist_t *neighbours, bufferevent_enable(neighbour->buffer_event, EV_READ | EV_WRITE | EV_TIMEOUT); - printf("Sending ping to %s. Failed pings: %lu\n", - text_ip, neighbour->failed_pings); - + log_debug("timeout_process - sending ping to %s." + " Failed pings: %lu", text_ip, + neighbour->failed_pings); /* send ping to the inactive neighbour; * 5 is the length of bytes to be transmitted */ @@ -141,57 +196,155 @@ static void timeout_process(linkedlist_t *neighbours, neighbour->failed_pings++; } else { - printf("3 failed pings. Removing %s from neighbours\n", - text_ip); + log_info("timeout_process - 3 failed pings." + " Removing %s from neighbours", + text_ip); delete_neighbour(neighbours, neighbour->buffer_event); } } /** - * Callback for bufferevent event detection. + * Delete 'neighbour' from 'pending_neighbours' and add it into 'neighbours'. * - * @param bev bufferevent on which the event occured. - * @param events Flags of the events occured. - * @param ctx Pointer to global_state_t to determine the neighbour. + * @param global_state Global state. + * @param neighbour Neighbour to be moved. + * + * @param neighbour_t The new neighbour in the 'neighbours'. + * @param NULL If adding failed. */ -static void event_cb(struct bufferevent *bev, short events, void *ctx) +static neighbour_t *move_neighbour_from_pending(global_state_t *global_state, + neighbour_t *neighbour) { - neighbour_t *neighbour; - char text_ip[INET6_ADDRSTRLEN]; + linkedlist_node_t *neighbour_node; + neighbour_t *new_neighbour; + + new_neighbour = add_new_neighbour(&global_state->neighbours, + &neighbour->addr, + neighbour->buffer_event); + /* if the add was unsuccessful, perform just the full delete */ + if (new_neighbour == NULL) { + bufferevent_free(neighbour->buffer_event); + } + neighbour_node = linkedlist_find(&global_state->pending_neighbours, + neighbour); + linkedlist_delete(neighbour_node); - global_state_t *global_state = (global_state_t *) ctx; + return new_neighbour; +} - /* find neighbour with 'bev' */ - neighbour = find_neighbour(&global_state->neighbours, bev); +/** + * Process the event that occured on our pending neighbour 'neighbour'. + * + * @param global_state Global state. + * @param neighbour The event occured on this pending neighbour. + * @param events What event occured. + */ +static void process_pending_neighbour(global_state_t *global_state, + neighbour_t *neighbour, + short events) +{ + size_t available_peers_size; + int needed_conns; + neighbour_t *new_neighbour; + char text_ip[INET6_ADDRSTRLEN]; - /* unknown neighbour; release 'bev' and stop processing the event */ - if (neighbour == NULL) { - bufferevent_free(bev); - return; + available_peers_size = fetch_available_peers(&global_state->peers, + NULL); + /* 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); + /* we've got a new neighbour; + * we can't just delete the neighbour from pending + * and add it into 'neighbours' as the delete would + * free'd the bufferevent + */ + new_neighbour = move_neighbour_from_pending(global_state, + neighbour); + if (new_neighbour == NULL) { + return; + } + needed_conns = MIN_NEIGHBOURS - + linkedlist_size(&global_state->neighbours); + /* if we need more neighbours */ + if (needed_conns > 0) { + /* and we don't have enough available */ + if ((int)available_peers_size < needed_conns) { + ask_for_peers(new_neighbour); + } + } + /* connecting to the neighbour was unsuccessful */ + } else { + log_info("process_pending_neighbour - connecting to " + "%s was NOT SUCCESSFUL", text_ip); + /* the peer is no longer a pending neighbour */ + delete_neighbour(&global_state->pending_neighbours, + neighbour->buffer_event); } +} + +/** + * Process the event that occured on our neighbour 'neighbour'. + * + * @param global_state Global state. + * @param neighbour The event occured on this neighbour. + * @param events What event occured. + */ +static void process_neighbour(global_state_t *global_state, + neighbour_t *neighbour, + short events) +{ + char text_ip[INET6_ADDRSTRLEN]; /* initialize text_ip */ - ip_to_string(neighbour->ip_addr, text_ip); + ip_to_string(&neighbour->addr, text_ip); if (events & BEV_EVENT_ERROR) { - printf("Connection error: removing %s\n", text_ip); - delete_neighbour(&global_state->neighbours, bev); - return; - } - if (events & (BEV_EVENT_CONNECTED)) { - printf("Successfully connected to %s\n", text_ip); - } - if (events & (BEV_EVENT_EOF)) { - printf("%s disconnected\n", text_ip); - delete_neighbour(&global_state->neighbours, bev); - return; - } + log_info("process_neighbour - error on bev: 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); + delete_neighbour(&global_state->neighbours, + neighbour->buffer_event); /* timeout flag on 'bev' */ - if (events & BEV_EVENT_TIMEOUT) { + } else if (events & BEV_EVENT_TIMEOUT) { timeout_process(&global_state->neighbours, neighbour); } } +/** + * Callback for bufferevent event detection. + * + * @param bev bufferevent on which the event occured. + * @param events Flags of the events occured. + * @param ctx Pointer to global_state_t to determine the neighbour. + */ +static void event_cb(struct bufferevent *bev, short events, void *ctx) +{ + neighbour_t *neighbour; + global_state_t *global_state = (global_state_t *) ctx; + + /* find neighbour with 'bev' */ + neighbour = find_neighbour(&global_state->neighbours, bev); + if (neighbour != NULL) { + process_neighbour(global_state, neighbour, events); + /* no such neighbour found; try finding it at pending_neighbours */ + } else { + neighbour = find_neighbour(&global_state->pending_neighbours, + bev); + /* 'bev' must belong either to 'neighbours' or + * 'pending_neighbours' + */ + assert(neighbour != NULL); + process_pending_neighbour(global_state, neighbour, events); + } +} + /** * Callback function for accepting new connections. * @@ -206,16 +359,27 @@ static void accept_connection(struct evconnlistener *listener, int socklen __attribute__((unused)), void *ctx) { - struct event_base *base; struct bufferevent *bev; - unsigned char ip_addr[16]; + struct in6_addr *new_addr; char text_ip[INET6_ADDRSTRLEN]; struct timeval timeout; global_state_t *global_state = (struct s_global_state *) ctx; struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *) addr; + /* put binary representation of IP to 'new_addr' */ + new_addr = &addr_in6->sin6_addr; + + ip_to_string(new_addr, text_ip); + + if (find_neighbour_by_addr(&global_state->pending_neighbours, + new_addr)) { + log_debug("accept_connection - peer %s already at " + "pending neighbours", text_ip); + return; + } + /* get the event_base */ base = evconnlistener_get_base(listener); @@ -235,23 +399,20 @@ static void accept_connection(struct evconnlistener *listener, /* after TIMEOUT_TIME seconds invoke event_cb */ bufferevent_set_timeouts(bev, &timeout, NULL); - /* put binary representation of IP to inet6_ip */ - memcpy(ip_addr, addr_in6->sin6_addr.s6_addr, 16); - /* add the new connection to the list of our neighbours */ if (!add_new_neighbour(&global_state->neighbours, - ip_addr, + new_addr, bev)) { /* free the bufferevent if adding failed */ + log_debug("accept_connection - adding failed"); bufferevent_free(bev); return; } - ip_to_string(ip_addr, text_ip); - - printf("New connection from [%s]:%d\n", text_ip, + log_info("accept_connection - new connection from [%s]:%d", text_ip, ntohs(addr_in6->sin6_port)); + add_peer(&global_state->peers, new_addr); } /** @@ -267,10 +428,8 @@ static void accept_error_cb(struct evconnlistener *listener, global_state_t *global_state = (struct s_global_state *) ctx; int err = EVUTIL_SOCKET_ERROR(); - fprintf(stderr, "Got an error %d (%s) on the listener. " - "Shutting down.\n", err, evutil_socket_error_to_string(err)); - - /* WIP */ + log_error("accept_error_cb - got an error %d (%s) on the listener. " + "Shutting down.", err, evutil_socket_error_to_string(err)); /* stop the event loop */ event_base_loopexit(base, NULL); @@ -282,7 +441,7 @@ static void accept_error_cb(struct evconnlistener *listener, /** * Initialize listening and set up callbacks. * - * @param listener The even loop listener. + * @param listener The event loop listener. * @param global_state Data for the event loop to work with. * * @return 0 if successfully initialized. @@ -298,7 +457,7 @@ int listen_init(struct evconnlistener **listener, *base = event_base_new(); if (!*base) { - puts("Couldn't open event base"); + log_error("listen_init - event_base creation failure"); return 1; } @@ -316,7 +475,7 @@ int listen_init(struct evconnlistener **listener, sizeof(sock_addr)); if (!*listener) { - perror("Couldn't create listener: evconnlistener_new_bind"); + log_error("listen_init - evconnlistener_new_bind"); return 1; } @@ -326,18 +485,21 @@ int listen_init(struct evconnlistener **listener, } /** - * Attempt to connect to the particular peer. + * Attempt to connect to the particular addr. * * @param global_state Data for the event loop to work with. - * @param ip_addr Binary IP of a peer that we want to connect to. + * @param addr Binary IP of a peer that we want to connect to. * - * @return neighbour_t * Pointer to newly connected neighbour. - * @return NULL Connecting was unsuccessful. + * @return 0 The connection attempt was succesful. + * @return 1 The peer is already our neighbour. + * @return 2 The peer is pending to become our neighbour. + * @return 3 Adding new pending neighbour unsuccessful. */ -neighbour_t *connect_to_peer(global_state_t *global_state, - const unsigned char *ip_addr) +int connect_to_addr(global_state_t *global_state, + const struct in6_addr *addr) { struct bufferevent *bev; + peer_t *peer; struct sockaddr *sock_addr; struct sockaddr_in6 sock_addr6; int sock_len; @@ -345,21 +507,27 @@ neighbour_t *connect_to_peer(global_state_t *global_state, struct timeval timeout; /* get textual representation of the input ip address */ - ip_to_string(ip_addr, text_ip); + ip_to_string(addr, text_ip); /* don't connect to already connected peer */ - if (find_neighbour_by_ip(&global_state->neighbours, ip_addr) != NULL) { - printf("connect_to_peer: skipping already connected peer\n"); - return NULL; + if (find_neighbour_by_addr(&global_state->neighbours, addr) != NULL) { + log_debug("connect_to_addr - peer already connected"); + return 1; + } + + /* don't attempt to connect to already pending connection */ + if (linkedlist_find(&global_state->pending_neighbours, addr) != NULL) { + log_debug("connect_to_addr - peer is in the pending conns"); + return 2; } memset(&sock_addr6, 0x0, sizeof(sock_addr6)); sock_addr6.sin6_family = AF_INET6; - sock_addr6.sin6_port = htons(DEFAULT_PORT); - memcpy(&sock_addr6.sin6_addr, ip_addr, 16); + sock_addr6.sin6_port = htons(DEFAULT_PORT); + memcpy(&sock_addr6.sin6_addr, addr, 16); sock_addr = (struct sockaddr *) &sock_addr6; - sock_len = sizeof(sock_addr6); + sock_len = sizeof(sock_addr6); /* it is safe to set file descriptor to -1 if we define it later */ bev = bufferevent_socket_new(global_state->event_loop, @@ -385,29 +553,107 @@ neighbour_t *connect_to_peer(global_state_t *global_state, /* after TIMEOUT_TIME seconds invoke event_cb */ bufferevent_set_timeouts(bev, &timeout, &timeout); - /* connect to the peer; socket_connect also assigns fd */ - if (bufferevent_socket_connect(bev, sock_addr, sock_len) < 0) { - printf("Connecting to %s failed\n", text_ip); + /* add peer to the list of pending neighbours and let event_cb + * determine whether the peer is our neighbour now + */ + if (!add_new_neighbour(&global_state->pending_neighbours, addr, bev)) { + log_debug("connect_to_addr - neighbour %s NOT ADDED into " + "pending neighbours", text_ip); bufferevent_free(bev); - return NULL; + return 3; + } else { + log_debug("connect_to_addr - neighbour %s ADDED into " + "pending neighbours", text_ip); + } + + peer = find_peer_by_addr(&global_state->peers, addr); + if (peer != NULL) { + peer->is_available = 0; } - /* connecting succeeded; add peer to the list of our neighbours */ - return add_new_neighbour(&global_state->neighbours, ip_addr, bev); + /* connect to the peer; socket_connect also assigns fd */ + bufferevent_socket_connect(bev, sock_addr, sock_len); + + return 0; } /** - * Initiate joining the coincer network. + * Attempt to connect to more peers. * * @param global_state Data for the event loop to work with. + * @param conns_amount Prefered number of new connections. */ -int joining_init(global_state_t *global_state) +void add_more_connections(global_state_t *global_state, size_t conns_amount) { - int i; - - for (i = 0; i < DEFAULT_PEERS_SIZE; i++) { - connect_to_peer(global_state, DEFAULT_PEERS[i]); + struct in6_addr addr; + size_t available_peers_size; + peer_t *available_peers[MAX_PEERS_SIZE]; + 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); + + /* only if we don't have any non-default peers available */ + if (available_peers_size == 0) { + log_debug("add_more_connections - " + "choosing random default peer"); + /* choose random default peer */ + idx = rand()%DEFAULT_PEERS_SIZE; + memcpy(&addr, DEFAULT_PEERS[idx], 16); + + result = connect_to_addr(global_state, &addr); + /* the connecting attempt was successful */ + if (result == 0) { + /* if the peer becomes our neighbour, + * and we need more connections, + * get a list of peers from them and + * attempt to connect to them; + * it's our goal to use as few + * default peers as possible + */ + log_debug("add_more_connections - " + "connect attempt succeeded"); + /* the peer is our neighbour; + * ask them for more peers + */ + } else if (result == 1) { + neigh = find_neighbour_by_addr(&global_state-> + neighbours, + &addr); + assert(neigh != NULL); + ask_for_peers(neigh); + log_debug("add_more_connections - " + "asking for peers"); + /* the peer is a pending connection */ + } else if (result == 2) { + /* wait for them to reject/accept us */ + log_debug("add_more_connections - " + "pending, do nothing"); + } else { + log_debug("add_more_connections - " + "connect attempt didn't succeed"); + } + /* we've got some available peers */ + } else { + /* 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) { + conns_amount = available_peers_size; + } + + while (cur_conn_attempts < conns_amount) { + idx = cur_conn_attempts; + selected_peer = available_peers[idx]; + /* perform a connection attempt */ + connect_to_addr(global_state, + &selected_peer->addr); + cur_conn_attempts++; + } } - - return 0; } + -- GitLab From 2c541eb363fb671644692f6aa180393d3b36560c Mon Sep 17 00:00:00 2001 From: xpetrak2 <456484@mail.muni.cz> Date: Fri, 6 Jul 2018 18:48:04 +0200 Subject: [PATCH 5/6] A few adjustments --- Makefile.am | 2 +- src/coincerd.c | 14 ++-- src/configuration.c | 3 +- src/configuration.h | 3 +- src/linkedlist.c | 9 +- src/linkedlist.h | 3 +- src/log.c | 3 +- src/log.h | 3 +- src/neighbours.c | 160 +++++++++++++++++------------------ src/neighbours.h | 32 +++---- src/p2p.c | 82 ++++++++---------- src/p2p.h | 27 +++--- src/{filing.c => paths.c} | 20 ++--- src/{filing.h => paths.h} | 12 +-- src/peers.c | 172 +++++++++++++++++++------------------- src/peers.h | 11 ++- 16 files changed, 259 insertions(+), 297 deletions(-) rename src/{filing.c => paths.c} (82%) rename src/{filing.h => paths.h} (87%) diff --git a/Makefile.am b/Makefile.am index 3d63773..dcf5574 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,11 +5,11 @@ bin_PROGRAMS = src/coincerd src/coincer src_coincerd_SOURCES = \ src/coincerd.c \ src/configuration.c src/configuration.h \ - src/filing.c src/filing.h \ src/linkedlist.c src/linkedlist.h \ src/log.c src/log.h \ src/neighbours.c src/neighbours.h \ src/p2p.c src/p2p.h \ + src/paths.c src/paths.h \ src/peers.c src/peers.h src_coincerd_CFLAGS = $(AM_CFLAGS) $(JANSSON_CFLAGS) $(LIBEVENT_CFLAGS) $(LIBSODIUM_CFLAGS) diff --git a/src/coincerd.c b/src/coincerd.c index 5a860a5..bf90241 100644 --- a/src/coincerd.c +++ b/src/coincerd.c @@ -1,6 +1,6 @@ /* * Coincer - * Copyright (C) 2017 Coincer Developers + * Copyright (C) 2017-2018 Coincer Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,10 +22,10 @@ #include #include -#include "filing.h" #include "log.h" #include "neighbours.h" #include "p2p.h" +#include "paths.h" #include "peers.h" static void signal_cb(evutil_socket_t fd, short events, void *ctx); @@ -122,8 +122,6 @@ int main(void) event_free(conns_event); event_base_free(global_state.event_loop); - printf("\nCoincer says: Bye!\n"); - return 0; } @@ -131,7 +129,7 @@ int main(void) * Callback function for a received signal. * * @param signal What signal was invoked. - * @param events Flags of the event occured. + * @param events Flags of the event occurred. * @param ctx Global state. */ static void signal_cb(evutil_socket_t signal __attribute__((unused)), @@ -160,11 +158,9 @@ static void conns_cb(int fd __attribute__((unused)), needed_conns = MIN_NEIGHBOURS - linkedlist_size(&global_state->neighbours); if (needed_conns > 0) { - /* ask twice more peers than we need; it's preferable - * to have more neighbours than minimum - */ log_debug("conns_cb - we need %d more neighbours"); + /* ask twice more peers than we need; it's preferable + * to have more neighbours than minimum */ add_more_connections(global_state, 2 * needed_conns); } } - diff --git a/src/configuration.c b/src/configuration.c index 7481472..523916b 100644 --- a/src/configuration.c +++ b/src/configuration.c @@ -1,6 +1,6 @@ /* * Coincer - * Copyright (C) 2017 Coincer Developers + * Copyright (C) 2017-2018 Coincer Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -195,4 +195,3 @@ int setup_directories(char **config_dir, char **data_dir) return 0; } - diff --git a/src/configuration.h b/src/configuration.h index 7cc528b..34d6b7c 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -1,6 +1,6 @@ /* * Coincer - * Copyright (C) 2017 Coincer Developers + * Copyright (C) 2017-2018 Coincer Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,4 +22,3 @@ int setup_directories(char **config_dir, char **data_dir); #endif /* CONFIGURATION_H */ - diff --git a/src/linkedlist.c b/src/linkedlist.c index 6aa8a79..cb80e35 100644 --- a/src/linkedlist.c +++ b/src/linkedlist.c @@ -1,6 +1,6 @@ /* * Coincer - * Copyright (C) 2017 Coincer Developers + * Copyright (C) 2017-2018 Coincer Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -194,7 +194,8 @@ void linkedlist_init(linkedlist_t *root) } /** - * Insert new node into linked list after 'node'. + * Insert new node into linkedlist after 'node'. In case of 'node' being the + * last (stub) node, insert before it. * * @param root Root of the linked list. * @param node Insert new node right after this node. @@ -230,7 +231,8 @@ linkedlist_node_t *linkedlist_insert_after(linkedlist_t *root, } /** - * Insert new node into linkedlist before 'node'. + * Insert new node into linkedlist before 'node'. In case of 'node' being + * the first (stub) node, insert after it. * * @param root Root of the linked list. * @param node Insert new node right before this node. @@ -269,4 +271,3 @@ size_t linkedlist_size(const linkedlist_t *root) return n; } - diff --git a/src/linkedlist.h b/src/linkedlist.h index ada9554..82f2ac5 100644 --- a/src/linkedlist.h +++ b/src/linkedlist.h @@ -1,6 +1,6 @@ /* * Coincer - * Copyright (C) 2017 Coincer Developers + * Copyright (C) 2017-2018 Coincer Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -69,4 +69,3 @@ linkedlist_node_t *linkedlist_insert_before(linkedlist_t *root, size_t linkedlist_size(const linkedlist_t *root); #endif /* LINKEDLIST_H */ - diff --git a/src/log.c b/src/log.c index 17dc516..56acae4 100644 --- a/src/log.c +++ b/src/log.c @@ -1,6 +1,6 @@ /* * Coincer - * Copyright (C) 2017 Coincer Developers + * Copyright (C) 2017-2018 Coincer Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -99,4 +99,3 @@ void log_error(const char *msg, ...) fprintf(stderr, "\n"); } - diff --git a/src/log.h b/src/log.h index b5e6192..1415977 100644 --- a/src/log.h +++ b/src/log.h @@ -1,6 +1,6 @@ /* * Coincer - * Copyright (C) 2017 Coincer Developers + * Copyright (C) 2017-2018 Coincer Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,4 +25,3 @@ void log_warn(const char *msg, ...); void log_error(const char *msg, ...); #endif /* LOG_H */ - diff --git a/src/neighbours.c b/src/neighbours.c index 0f7fd4c..f2f35f5 100644 --- a/src/neighbours.c +++ b/src/neighbours.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -26,71 +27,6 @@ #include "log.h" #include "neighbours.h" -/** - * Find neighbour in neighbours based on their bufferevent. - * - * @param neighbours Our neighbours. - * @param bev Neighbour's bufferevent. - * - * @return neighbour_t Requested neighbour. - * @return NULL If not found. - */ -neighbour_t *find_neighbour(const linkedlist_t *neighbours, - const struct bufferevent *bev) -{ - /* start the search from the first linked list node */ - const linkedlist_node_t *current = linkedlist_get_first(neighbours); - - while (current != NULL) { - - /* data of the 'current' node; struct s_neighbour */ - neighbour_t *current_data = (neighbour_t *) current->data; - - /* bufferevents equal => neighbour found */ - if (current_data->buffer_event == bev) { - - /* return node's data; struct s_neighbour */ - return current_data; - } - /* get next node in the linked list */ - current = linkedlist_get_next(neighbours, current); - } - /* neighbour not found */ - return NULL; -} - -/** - * Find neighbour in neighbours based on their addr. - * - * @param neighbours Our neighbours. - * @param addr Binary ip address stored in 16 bytes. - * - * @return neighbour_t Requested neighbour. - * @return NULL If not found. - */ -neighbour_t *find_neighbour_by_addr(const linkedlist_t *neighbours, - const struct in6_addr *addr) -{ - /* start the search from the first linked list node */ - const linkedlist_node_t *current = linkedlist_get_first(neighbours); - - while (current != NULL) { - - /* data of the 'current' node; struct s_neighbour */ - neighbour_t *current_data = (neighbour_t *) current->data; - - /* ip addresses match => neighbour found */ - if (memcmp(¤t_data->addr, addr, 16) == 0) { - /* return node's data; struct s_neighbour */ - return current_data; - } - /* get next node in the linked list */ - current = linkedlist_get_next(neighbours, current); - } - /* neighbour not found */ - return NULL; -} - /** * Add new neighbour into neighbours. * @@ -137,6 +73,33 @@ neighbour_t *add_new_neighbour(linkedlist_t *neighbours, return new_neighbour; } +/** + * Delete all neighbours. + * + * @param neighbours Linked list of our neighbours. + */ +void clear_neighbours(linkedlist_t *neighbours) +{ + neighbour_t *current; + linkedlist_node_t *current_node; + + current_node = linkedlist_get_first(neighbours); + /* safely delete data from the linked list nodes */ + while (current_node != NULL) { + /* load current node's data into 'current' */ + current = (neighbour_t *) current_node->data; + + /* deallocate neighbour's bufferevent */ + bufferevent_free(current->buffer_event); + + /* get next node in the linked list */ + current_node = linkedlist_get_next(neighbours, current_node); + } + + /* safely delete all nodes and their data in the linked list */ + linkedlist_destroy(neighbours); +} + /** * Delete neighbour from neighbours. * @@ -165,29 +128,64 @@ void delete_neighbour(linkedlist_t *neighbours, struct bufferevent *bev) } /** - * Delete all neighbours. + * Find neighbour in neighbours based on their bufferevent. * - * @param neighbours Linked list of our neighbours. + * @param neighbours Our neighbours. + * @param bev Neighbour's bufferevent. + * + * @return neighbour_t Requested neighbour. + * @return NULL If not found. */ -void clear_neighbours(linkedlist_t *neighbours) +neighbour_t *find_neighbour(const linkedlist_t *neighbours, + const struct bufferevent *bev) { - neighbour_t *current; - linkedlist_node_t *current_node; + /* start the search from the first linked list node */ + const linkedlist_node_t *current = linkedlist_get_first(neighbours); - current_node = linkedlist_get_first(neighbours); - /* safely delete data from the linked list nodes */ - while (current_node != NULL) { - /* load current node's data into 'current' */ - current = (neighbour_t *) current_node->data; + while (current != NULL) { + /* data of the 'current' node; struct s_neighbour */ + neighbour_t *current_data = (neighbour_t *) current->data; - /* deallocate neighbour's bufferevent */ - bufferevent_free(current->buffer_event); + /* bufferevents equal => neighbour found */ + if (current_data->buffer_event == bev) { + /* return node's data; struct s_neighbour */ + return current_data; + } /* get next node in the linked list */ - current_node = linkedlist_get_next(neighbours, current_node); + current = linkedlist_get_next(neighbours, current); } - - /* safely delete all nodes and their data in the linked list */ - linkedlist_destroy(neighbours); + /* neighbour not found */ + return NULL; } +/** + * Find neighbour in neighbours based on their addr. + * + * @param neighbours Our neighbours. + * @param addr Binary ip address stored in 16 bytes. + * + * @return neighbour_t Requested neighbour. + * @return NULL If not found. + */ +neighbour_t *find_neighbour_by_addr(const linkedlist_t *neighbours, + const struct in6_addr *addr) +{ + /* start the search from the first linked list node */ + const linkedlist_node_t *current = linkedlist_get_first(neighbours); + + while (current != NULL) { + /* data of the 'current' node; struct s_neighbour */ + neighbour_t *current_data = (neighbour_t *) current->data; + + /* ip addresses match => neighbour found */ + if (memcmp(¤t_data->addr, addr, 16) == 0) { + /* return node's data; struct s_neighbour */ + return current_data; + } + /* get next node in the linked list */ + current = linkedlist_get_next(neighbours, current); + } + /* neighbour not found */ + return NULL; +} diff --git a/src/neighbours.h b/src/neighbours.h index dabfb03..4ed1780 100644 --- a/src/neighbours.h +++ b/src/neighbours.h @@ -26,32 +26,32 @@ #include "linkedlist.h" /* minimum number of peers we need to be connected to */ -#define MIN_NEIGHBOURS 3 +#define MIN_NEIGHBOURS 3 /** Data type for the linkedlist of neighbours. */ typedef struct s_neighbour { - /**< Neighbours's IPv6 address; - * also allows storing IPv4-mapped IPv6 addresses. */ - struct in6_addr addr; - /**< Bufferevent belonging to this neighbour. */ - struct bufferevent *buffer_event; - /**< Number of failed ping attempts -- max 3, then disconnect. */ - size_t failed_pings; + /** Neighbour's IPv6 address. + * Also allows storing IPv4-mapped IPv6 addresses. */ + struct in6_addr addr; + /** Bufferevent belonging to this neighbour. */ + struct bufferevent *buffer_event; + /** Number of failed ping attempts -- max 3, then disconnect. */ + size_t failed_pings; } neighbour_t; -neighbour_t *find_neighbour(const linkedlist_t *neighbours, - const struct bufferevent *bev); - -neighbour_t *find_neighbour_by_addr(const linkedlist_t *neighbours, - const struct in6_addr *ip_addr); - neighbour_t *add_new_neighbour(linkedlist_t *neighbours, const struct in6_addr *ip_addr, struct bufferevent *bev); +void clear_neighbours(linkedlist_t *neighbours); + void delete_neighbour(linkedlist_t *neighbours, struct bufferevent *bev); -void clear_neighbours(linkedlist_t *neighbours); -#endif /* NEIGHBOURS_H */ +neighbour_t *find_neighbour(const linkedlist_t *neighbours, + const struct bufferevent *bev); +neighbour_t *find_neighbour_by_addr(const linkedlist_t *neighbours, + const struct in6_addr *ip_addr); + +#endif /* NEIGHBOURS_H */ diff --git a/src/p2p.c b/src/p2p.c index 849baf2..6709643 100644 --- a/src/p2p.c +++ b/src/p2p.c @@ -1,6 +1,6 @@ /* * Coincer - * Copyright (C) 2017 Coincer Developers + * Copyright (C) 2017-2018 Coincer Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,7 +16,6 @@ * along with this program. If not, see . */ - #define _POSIX_SOURCE /* strtok_r */ #include /* inet_ntop */ @@ -63,8 +62,7 @@ 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 - */ + * for the list of peers; 6 is the number of bytes to be transmitted */ evbuffer_add(bufferevent_get_output(bev), "peers", 6); } @@ -85,7 +83,7 @@ static void process_peers(global_state_t *global_state, char *peers) while (line != NULL) { if (inet_pton(AF_INET6, line, &addr) == 1) { - add_peer(&global_state->peers, &addr); + save_peer(&global_state->peers, &addr); } line = strtok_r(NULL, delim, &save_ptr); } @@ -180,17 +178,15 @@ static void timeout_process(linkedlist_t *neighbours, /* the neighbour hasn't failed enough pings to be deleted */ if (neighbour->failed_pings < 3) { - /* bufferevent was disabled when timeout flag was set */ bufferevent_enable(neighbour->buffer_event, EV_READ | EV_WRITE | EV_TIMEOUT); - log_debug("timeout_process - sending ping to %s." - " Failed pings: %lu", text_ip, - neighbour->failed_pings); + log_debug("timeout_process - sending ping to %s. " + "Failed pings: %lu", text_ip, + neighbour->failed_pings); /* send ping to the inactive neighbour; - * 5 is the length of bytes to be transmitted - */ + * 5 is the length of bytes to be transmitted */ evbuffer_add(bufferevent_get_output(neighbour->buffer_event), "ping", 5); @@ -204,12 +200,12 @@ static void timeout_process(linkedlist_t *neighbours, } /** - * Delete 'neighbour' from 'pending_neighbours' and add it into 'neighbours'. + * Delete neighbour from pending and add it into neighbours. * * @param global_state Global state. * @param neighbour Neighbour to be moved. * - * @param neighbour_t The new neighbour in the 'neighbours'. + * @param neighbour_t The new neighbour added into neighbours. * @param NULL If adding failed. */ static neighbour_t *move_neighbour_from_pending(global_state_t *global_state, @@ -233,11 +229,11 @@ static neighbour_t *move_neighbour_from_pending(global_state_t *global_state, } /** - * Process the event that occured on our pending neighbour 'neighbour'. + * Process the event that occurred on our pending neighbour. * * @param global_state Global state. - * @param neighbour The event occured on this pending neighbour. - * @param events What event occured. + * @param neighbour The event occurred on this pending neighbour. + * @param events What event occurred. */ static void process_pending_neighbour(global_state_t *global_state, neighbour_t *neighbour, @@ -254,7 +250,7 @@ static void process_pending_neighbour(global_state_t *global_state, ip_to_string(&neighbour->addr, text_ip); /* we've successfully connected to the neighbour */ - if (events & (BEV_EVENT_CONNECTED)) { + if (events & BEV_EVENT_CONNECTED) { log_info("process_pending_neighbour - connecting to " "%s was SUCCESSFUL", text_ip); /* we've got a new neighbour; @@ -272,8 +268,8 @@ 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) { - ask_for_peers(new_neighbour); + if ((int) available_peers_size < needed_conns) { + ask_for_addresses(new_neighbour); } } /* connecting to the neighbour was unsuccessful */ @@ -282,16 +278,16 @@ static void process_pending_neighbour(global_state_t *global_state, "%s was NOT SUCCESSFUL", text_ip); /* the peer is no longer a pending neighbour */ delete_neighbour(&global_state->pending_neighbours, - neighbour->buffer_event); + neighbour->buffer_event); } } /** - * Process the event that occured on our neighbour 'neighbour'. + * Process the event that occurred on our neighbour. * * @param global_state Global state. - * @param neighbour The event occured on this neighbour. - * @param events What event occured. + * @param neighbour The event occurred on this neighbour. + * @param events What event occurred. */ static void process_neighbour(global_state_t *global_state, neighbour_t *neighbour, @@ -307,7 +303,7 @@ static void process_neighbour(global_state_t *global_state, text_ip); delete_neighbour(&global_state->neighbours, neighbour->buffer_event); - } else if (events & (BEV_EVENT_EOF)) { + } else if (events & BEV_EVENT_EOF) { log_info("process_neighbour - %s disconnected", text_ip); delete_neighbour(&global_state->neighbours, neighbour->buffer_event); @@ -320,8 +316,8 @@ static void process_neighbour(global_state_t *global_state, /** * Callback for bufferevent event detection. * - * @param bev bufferevent on which the event occured. - * @param events Flags of the events occured. + * @param bev bufferevent on which the event occurred. + * @param events Flags of the events occurred. * @param ctx Pointer to global_state_t to determine the neighbour. */ static void event_cb(struct bufferevent *bev, short events, void *ctx) @@ -337,9 +333,8 @@ static void event_cb(struct bufferevent *bev, short events, void *ctx) } else { neighbour = find_neighbour(&global_state->pending_neighbours, bev); - /* 'bev' must belong either to 'neighbours' or - * 'pending_neighbours' - */ + /* 'bev' must belong to either 'neighbours' or + * 'pending_neighbours' */ assert(neighbour != NULL); process_pending_neighbour(global_state, neighbour, events); } @@ -387,8 +382,7 @@ static void accept_connection(struct evconnlistener *listener, bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); /* subscribe every received P2P message to be processed; - * p2p_process for read callback, NULL for write callback - */ + * p2p_process for read callback, NULL for write callback */ bufferevent_setcb(bev, p2p_process, NULL, event_cb, ctx); bufferevent_enable(bev, EV_READ | EV_WRITE | EV_TIMEOUT); @@ -403,8 +397,6 @@ static void accept_connection(struct evconnlistener *listener, if (!add_new_neighbour(&global_state->neighbours, new_addr, bev)) { - - /* free the bufferevent if adding failed */ log_debug("accept_connection - adding failed"); bufferevent_free(bev); return; @@ -412,13 +404,13 @@ static void accept_connection(struct evconnlistener *listener, log_info("accept_connection - new connection from [%s]:%d", text_ip, ntohs(addr_in6->sin6_port)); - add_peer(&global_state->peers, new_addr); + save_peer(&global_state->peers, new_addr); } /** * Callback for listener error detection. * - * @param listener Listener on which the error occured. + * @param listener Listener on which the error occurred. * @param ctx Pointer to global_state_t. */ static void accept_error_cb(struct evconnlistener *listener, @@ -444,8 +436,8 @@ static void accept_error_cb(struct evconnlistener *listener, * @param listener The event loop listener. * @param global_state Data for the event loop to work with. * - * @return 0 if successfully initialized. - * @return 1 if an error occured. + * @return 0 If successfully initialized. + * @return 1 If an error occurred. */ int listen_init(struct evconnlistener **listener, global_state_t *global_state) @@ -485,12 +477,12 @@ int listen_init(struct evconnlistener **listener, } /** - * Attempt to connect to the particular addr. + * Attempt to connect to a particular addr. * * @param global_state Data for the event loop to work with. * @param addr Binary IP of a peer that we want to connect to. * - * @return 0 The connection attempt was succesful. + * @return 0 The connection attempt was successful. * @return 1 The peer is already our neighbour. * @return 2 The peer is pending to become our neighbour. * @return 3 Adding new pending neighbour unsuccessful. @@ -535,8 +527,7 @@ int connect_to_addr(global_state_t *global_state, BEV_OPT_CLOSE_ON_FREE); /* subscribe every received P2P message to be processed; - * p2p_process as read callback, NULL as write callback - */ + * p2p_process as read callback, NULL as write callback */ bufferevent_setcb(bev, p2p_process, NULL, @@ -554,8 +545,7 @@ int connect_to_addr(global_state_t *global_state, bufferevent_set_timeouts(bev, &timeout, &timeout); /* add peer to the list of pending neighbours and let event_cb - * determine whether the peer is our neighbour now - */ + * determine whether the peer is our neighbour now */ if (!add_new_neighbour(&global_state->pending_neighbours, addr, bev)) { log_debug("connect_to_addr - neighbour %s NOT ADDED into " "pending neighbours", text_ip); @@ -602,7 +592,7 @@ void add_more_connections(global_state_t *global_state, size_t conns_amount) log_debug("add_more_connections - " "choosing random default peer"); /* choose random default peer */ - idx = rand()%DEFAULT_PEERS_SIZE; + idx = rand() % DEFAULT_PEERS_SIZE; memcpy(&addr, DEFAULT_PEERS[idx], 16); result = connect_to_addr(global_state, &addr); @@ -617,9 +607,7 @@ void add_more_connections(global_state_t *global_state, size_t conns_amount) */ log_debug("add_more_connections - " "connect attempt succeeded"); - /* the peer is our neighbour; - * ask them for more peers - */ + /* the peer is our neighbour; ask them for more addrs */ } else if (result == 1) { neigh = find_neighbour_by_addr(&global_state-> neighbours, diff --git a/src/p2p.h b/src/p2p.h index 549ba42..8f15d29 100644 --- a/src/p2p.h +++ b/src/p2p.h @@ -1,6 +1,6 @@ /* * Coincer - * Copyright (C) 2017 Coincer Developers + * Copyright (C) 2017-2018 Coincer Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,40 +22,39 @@ #include #include -#include "filing.h" #include "linkedlist.h" #include "neighbours.h" +#include "paths.h" /* default port for TCP listening */ -#define DEFAULT_PORT 31070 +#define DEFAULT_PORT 31070 /* after TIMEOUT_TIME seconds invoke timeout callback */ -#define TIMEOUT_TIME 30 +#define TIMEOUT_TIME 30 /** * Event loop works with the data stored in an instance of this struct. */ typedef struct s_global_state { - /**< For holding and polling events. */ + /** For holding and polling events. */ struct event_base *event_loop; - /**< Holder of paths to needed files/dirs. */ + /** Holder of paths to needed files/dirs. */ filepaths_t filepaths; - /**< Linked list of our neighbours. */ + /** Linked list of our neighbours. */ linkedlist_t neighbours; - /**< Linked list of some peers in the network. */ + /** Linked list of some peers in the network. */ linkedlist_t peers; - /**< Peers that didn't accept/reject us yet. */ + /** Peers that didn't accept/reject us yet. */ linkedlist_t pending_neighbours; } global_state_t; -int listen_init(struct evconnlistener **listener, - global_state_t *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); -void ask_for_peers(neighbour_t *neighbour); +int listen_init(struct evconnlistener **listener, + global_state_t *global_state); #endif /* P2P_H */ - diff --git a/src/filing.c b/src/paths.c similarity index 82% rename from src/filing.c rename to src/paths.c index a1ffe9b..fa5b5f0 100644 --- a/src/filing.c +++ b/src/paths.c @@ -1,6 +1,6 @@ /* * Coincer - * Copyright (C) 2017 Coincer Developers + * Copyright (C) 2017-2018 Coincer Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,17 +16,15 @@ * along with this program. If not, see . */ -#include #include #include #include -#include /* chmod */ #include "configuration.h" -#include "filing.h" #include "log.h" +#include "paths.h" -static const char *PEERS_FILE_NAME = "peers"; +#define PEERS_FILE_NAME "peers" /** * Sets path to peers file. @@ -41,9 +39,9 @@ static int set_peers_path(char *data_dir, char **peers) { FILE *peers_file; - /* size of data_dir + PEERS_FILE_NAME + '\0' */ + /* size of data_dir + PEERS_FILE_NAME */ *peers = (char *) malloc(strlen(data_dir) + - strlen(PEERS_FILE_NAME) + 1); + sizeof(PEERS_FILE_NAME)); if (*peers == NULL) { log_error("set_peers_path - peers file malloc"); return 1; @@ -52,13 +50,6 @@ static int set_peers_path(char *data_dir, char **peers) strcpy(*peers, data_dir); strcat(*peers, PEERS_FILE_NAME); - /* create file if doesn't exist */ - peers_file = fopen(*peers, "a"); - fclose(peers_file); - - /* change permissions */ - chmod(*peers, strtol("0600", 0, 8)); - return 0; } @@ -94,4 +85,3 @@ void clear_paths(filepaths_t *filepaths) free(filepaths->peers); } - diff --git a/src/filing.h b/src/paths.h similarity index 87% rename from src/filing.h rename to src/paths.h index 20de277..8587f09 100644 --- a/src/filing.h +++ b/src/paths.h @@ -1,6 +1,6 @@ /* * Coincer - * Copyright (C) 2017 Coincer Developers + * Copyright (C) 2017-2018 Coincer Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,11 +16,8 @@ * along with this program. If not, see . */ -#ifndef FILING_H -#define FILING_H - -#include -#include +#ifndef PATHS_H +#define PATHS_H /** Paths to needed files and directories. */ typedef struct s_filepaths { @@ -36,5 +33,4 @@ typedef struct s_filepaths { void clear_paths(filepaths_t *filepaths); int setup_paths(filepaths_t *filepaths); -#endif /* FILING_H */ - +#endif /* PATHS_H */ diff --git a/src/peers.c b/src/peers.c index 6158c07..2eb8065 100644 --- a/src/peers.c +++ b/src/peers.c @@ -1,6 +1,6 @@ /* * Coincer - * Copyright (C) 2017 Coincer Developers + * Copyright (C) 2017-2018 Coincer Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,84 +26,6 @@ #include "log.h" #include "peers.h" -/** - * Add new peer into sorted linkedlist of peers. - * - * @param peers The linkedlist of peers. - * @param addr Address of the new peer. - * - * @return linkedlist_node_t Newly added node in the linkedlist. - * @return NULL Peer is already added, default or - * allocation failure. - */ -linkedlist_node_t *add_peer(linkedlist_t *peers, const struct in6_addr *addr) -{ - int cmp_value; - struct in6_addr curr_addr; - linkedlist_node_t *current_node; - peer_t *current_peer; - int i; - linkedlist_node_t *new_node; - peer_t *new_peer; - char text_ip[INET6_ADDRSTRLEN]; - - /* add peer to the list of known peers, unless it's a default peer */ - for (i = 0; i < DEFAULT_PEERS_SIZE; i++) { - memcpy(&curr_addr, DEFAULT_PEERS[i], 16); - /* it's a default peer, don't add it into 'peers' */ - if (memcmp(&curr_addr, addr, 16) == 0) { - return NULL; - } - } - - /* allocate memory for a new peer */ - new_peer = (peer_t *) malloc(sizeof(peer_t)); - if (new_peer == NULL) { - log_error("add_peer - malloc"); - return NULL; - } - - /* initialize all attributes of the new peer */ - memcpy(&new_peer->addr, addr, 16); - new_peer->is_available = 1; - - /* get textual representation of 'addr' */ - inet_ntop(AF_INET6, addr, text_ip, INET6_ADDRSTRLEN); - - /* insert 'new_peer' to its proper position in the sorted linkedlist; - * start from the last node of 'peers', as 'fetch_peers' (using this - * function) is likely to add in ascending order => better performance - */ - current_node = linkedlist_get_last(peers); - while (current_node != NULL) { - current_peer = (peer_t *) current_node->data; - - cmp_value = memcmp(&new_peer->addr, ¤t_peer->addr, 16); - /* the linkedlist already contains this peer */ - if (cmp_value == 0) { - free(new_peer); - return NULL; - } else if (cmp_value > 0) { - /* the proper position found */ - new_node = linkedlist_insert_after(peers, - current_node, - new_peer); - if (new_node != NULL) { - log_debug("add_peer - %s successfully added", - text_ip); - } - return new_node; - } - current_node = linkedlist_get_prev(peers, current_node); - } - /* the new peer's addr is lexicographically the lowest */ - new_node = linkedlist_insert_after(peers, &peers->first, new_peer); - if (new_node != NULL) { - log_debug("add_peer - %s successfully added", text_ip); - } - return new_node; -} - /** * Delete all peers and their data. * @@ -116,12 +38,12 @@ void clear_peers(linkedlist_t *peers) } /** - * Fetch available peers from 'peers' into 'available_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 n The number of available peers. + * @return >=0 The number of available peers. */ size_t fetch_available_peers(const linkedlist_t *peers, peer_t *available_peers[MAX_PEERS_SIZE]) @@ -151,7 +73,7 @@ size_t fetch_available_peers(const linkedlist_t *peers, } /** - * Fetch peers from 'peers_path' file into 'peers' linkedlist. + * Fetch peers from file into linkedlist. * * @param peers_path Path to 'peers' file. * @param peers Fetch loaded peers in here. @@ -243,7 +165,8 @@ void peers_to_str(const linkedlist_t *peers, char *output) } /** - * Set all peers available. + * Set all peers as available. Definition of availability + * is within peer_t in peers.h. * * @param peers The peers to be set as available. */ @@ -262,7 +185,85 @@ void reset_peers_availability(linkedlist_t *peers) } /** - * Shuffle the input array 'peers'. + * Save new peer into sorted linkedlist of peers. + * + * @param peers The linkedlist of peers. + * @param addr Address of the new peer. + * + * @return linkedlist_node_t Newly added node in the linkedlist. + * @return NULL Peer is already added, default or + * allocation failure. + */ +linkedlist_node_t *save_peer(linkedlist_t *peers, const struct in6_addr *addr) +{ + int cmp_value; + struct in6_addr curr_addr; + linkedlist_node_t *current_node; + peer_t *current_peer; + int i; + linkedlist_node_t *new_node; + peer_t *new_peer; + char text_ip[INET6_ADDRSTRLEN]; + + /* add peer to the list of known peers, unless it's a default peer */ + for (i = 0; i < DEFAULT_PEERS_SIZE; i++) { + memcpy(&curr_addr, DEFAULT_PEERS[i], 16); + /* it's a default peer, don't add it into 'peers' */ + if (memcmp(&curr_addr, addr, 16) == 0) { + return NULL; + } + } + + /* allocate memory for a new peer */ + new_peer = (peer_t *) malloc(sizeof(peer_t)); + if (new_peer == NULL) { + log_error("add_peer - malloc"); + return NULL; + } + + /* initialize all attributes of the new peer */ + memcpy(&new_peer->addr, addr, 16); + new_peer->is_available = 1; + + /* get textual representation of 'addr' */ + inet_ntop(AF_INET6, addr, text_ip, INET6_ADDRSTRLEN); + + /* insert 'new_peer' to its proper position in the sorted linkedlist; + * start from the last node of 'peers', as 'fetch_peers' (using this + * function) is likely to add in ascending order => better performance + */ + current_node = linkedlist_get_last(peers); + while (current_node != NULL) { + current_peer = (peer_t *) current_node->data; + + cmp_value = memcmp(&new_peer->addr, ¤t_peer->addr, 16); + /* the linkedlist already contains this peer */ + if (cmp_value == 0) { + free(new_peer); + return NULL; + } else if (cmp_value > 0) { + /* the proper position found */ + new_node = linkedlist_insert_after(peers, + current_node, + new_peer); + if (new_node != NULL) { + log_debug("add_peer - %s successfully added", + text_ip); + } + return new_node; + } + current_node = linkedlist_get_prev(peers, current_node); + } + /* the new peer's addr is lexicographically the lowest */ + new_node = linkedlist_insert_after(peers, &peers->first, new_peer); + if (new_node != NULL) { + log_debug("add_peer - %s successfully added", text_ip); + } + return new_node; +} + +/** + * Shuffle the input array of peers. * * @param peers The peers to be shuffled. * @param peers_size Number of peers to be shuffled. @@ -284,7 +285,7 @@ void shuffle_peers_arr(peer_t *peers[MAX_PEERS_SIZE], size_t peers_size) } /** - * Store peers from the linkedlist 'peers' into file at 'peers_path'. + * Store peers from a linkedlist into a file. * * @param peers_path Path to 'peers' file. * @param peers Linkedlist of the peers to be stored. @@ -317,4 +318,3 @@ int store_peers(const char *peers_path, const linkedlist_t *peers) fclose(peers_file); return 0; } - diff --git a/src/peers.h b/src/peers.h index 8b0864b..74bb06d 100644 --- a/src/peers.h +++ b/src/peers.h @@ -1,6 +1,6 @@ /* * Coincer - * Copyright (C) 2017 Coincer Developers + * Copyright (C) 2017-2018 Coincer Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,11 +47,11 @@ static const unsigned char DEFAULT_PEERS[DEFAULT_PEERS_SIZE][16] = { /** Peer info holder. */ typedef struct s_peer { - /**< Binary IPv6 address. */ + /** Binary IPv6 address. */ struct in6_addr addr; - /**< A peer is not available if they is already our neighbour, - * pending to become one, or if we are unnable to connect to them. - * 1 if available, 0 if not. + /** A peer is not available if they is already our neighbour, + * pending to become one, or if we are unnable to connect to them. + * 1 if available, 0 if not. */ short is_available; /* TODO: add uptime */ @@ -78,4 +78,3 @@ void shuffle_peers_arr(peer_t *peers[MAX_PEERS_SIZE], size_t peers_size); int store_peers(const char *peers_path, const linkedlist_t *peers); #endif /* PEERS_H */ - -- GitLab From 2e3b123ebbcf94a999ce879b9004beed4788c5d1 Mon Sep 17 00:00:00 2001 From: xpetrak2 <456484@mail.muni.cz> Date: Fri, 6 Jul 2018 21:19:32 +0200 Subject: [PATCH 6/6] Merge request problems resolved --- src/coincerd.c | 32 ++++--- src/configuration.c | 25 +++--- src/linkedlist.c | 2 +- src/neighbours.c | 71 +++++++++++++++- src/neighbours.h | 11 +++ src/p2p.c | 85 ++++++++++++------- src/p2p.h | 2 - src/peers.c | 197 +++++++++++++++++++++++++------------------- src/peers.h | 47 ++++++----- 9 files changed, 306 insertions(+), 166 deletions(-) diff --git a/src/coincerd.c b/src/coincerd.c index bf90241..083fcfc 100644 --- a/src/coincerd.c +++ b/src/coincerd.c @@ -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); diff --git a/src/configuration.c b/src/configuration.c index 523916b..ecdf44a 100644 --- a/src/configuration.c +++ b/src/configuration.c @@ -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; } } diff --git a/src/linkedlist.c b/src/linkedlist.c index cb80e35..bd98ac6 100644 --- a/src/linkedlist.c +++ b/src/linkedlist.c @@ -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; } diff --git a/src/neighbours.c b/src/neighbours.c index f2f35f5..3c74f5a 100644 --- a/src/neighbours.c +++ b/src/neighbours.c @@ -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; +} diff --git a/src/neighbours.h b/src/neighbours.h index 4ed1780..79c0485 100644 --- a/src/neighbours.h +++ b/src/neighbours.h @@ -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 */ diff --git a/src/p2p.c b/src/p2p.c index 6709643..d29221b 100644 --- a/src/p2p.c +++ b/src/p2p.c @@ -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); +} diff --git a/src/p2p.h b/src/p2p.h index 8f15d29..49587a7 100644 --- a/src/p2p.h +++ b/src/p2p.h @@ -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); diff --git a/src/peers.c b/src/peers.c index 2eb8065..d7e1436 100644 --- a/src/peers.c +++ b/src/peers.c @@ -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); + } + + return n; +} + /** * Find peer in the linkedlist by their address. * @@ -130,7 +143,7 @@ peer_t *find_peer_by_addr(const linkedlist_t *peers, /* TODO: allocate memory for the 'output', don't assume any buffer size */ /** - * '\n' separated 'output' of peer addresses in readable form from 'peers'. + * '\n' separated output string of peer addresses in readable form. * * @param peers List of peers. * @param output Output string. @@ -164,37 +177,17 @@ void peers_to_str(const linkedlist_t *peers, char *output) } } -/** - * Set all peers as available. Definition of availability - * is within peer_t in peers.h. - * - * @param peers The peers to be set as available. - */ -void reset_peers_availability(linkedlist_t *peers) -{ - linkedlist_node_t *current_node; - peer_t *current_peer; - - current_node = linkedlist_get_first(peers); - while (current_node != NULL) { - current_peer = (peer_t *) current_node->data; - - current_peer->is_available = 1; - current_node = linkedlist_get_next(peers, current_node); - } -} - /** * Save new peer into sorted linkedlist of peers. * * @param peers The linkedlist of peers. * @param addr Address of the new peer. * - * @return linkedlist_node_t Newly added node in the linkedlist. - * @return NULL Peer is already added, default or + * @return peer_t Newly saved peer. + * @return NULL Peer is already saved, default or * allocation failure. */ -linkedlist_node_t *save_peer(linkedlist_t *peers, const struct in6_addr *addr) +peer_t *save_peer(linkedlist_t *peers, const struct in6_addr *addr) { int cmp_value; struct in6_addr curr_addr; @@ -205,10 +198,10 @@ linkedlist_node_t *save_peer(linkedlist_t *peers, const struct in6_addr *addr) peer_t *new_peer; char text_ip[INET6_ADDRSTRLEN]; - /* add peer to the list of known peers, unless it's a default peer */ + /* save peer to the list of known peers, unless it's a default peer */ for (i = 0; i < DEFAULT_PEERS_SIZE; i++) { memcpy(&curr_addr, DEFAULT_PEERS[i], 16); - /* it's a default peer, don't add it into 'peers' */ + /* it's a default peer, don't save it into 'peers' */ if (memcmp(&curr_addr, addr, 16) == 0) { return NULL; } @@ -217,20 +210,20 @@ linkedlist_node_t *save_peer(linkedlist_t *peers, const struct in6_addr *addr) /* allocate memory for a new peer */ new_peer = (peer_t *) malloc(sizeof(peer_t)); if (new_peer == NULL) { - log_error("add_peer - malloc"); + log_error("Saving new peer"); return NULL; } /* initialize all attributes of the new peer */ memcpy(&new_peer->addr, addr, 16); - new_peer->is_available = 1; + set_peer_flags(new_peer, PEER_AVAILABLE); /* get textual representation of 'addr' */ inet_ntop(AF_INET6, addr, text_ip, INET6_ADDRSTRLEN); /* insert 'new_peer' to its proper position in the sorted linkedlist; * start from the last node of 'peers', as 'fetch_peers' (using this - * function) is likely to add in ascending order => better performance + * function) is likely to save in ascending order => better performance */ current_node = linkedlist_get_last(peers); while (current_node != NULL) { @@ -247,40 +240,54 @@ linkedlist_node_t *save_peer(linkedlist_t *peers, const struct in6_addr *addr) current_node, new_peer); if (new_node != NULL) { - log_debug("add_peer - %s successfully added", + log_debug("save_peer - %s successfully saved", text_ip); } - return new_node; + return new_peer; } current_node = linkedlist_get_prev(peers, current_node); } /* the new peer's addr is lexicographically the lowest */ new_node = linkedlist_insert_after(peers, &peers->first, new_peer); if (new_node != NULL) { - log_debug("add_peer - %s successfully added", text_ip); + log_debug("save_peer - %s successfully saved", text_ip); } - return new_node; + + return new_peer; } /** - * Shuffle the input array of peers. + * Set flags on given peer. * - * @param peers The peers to be shuffled. - * @param peers_size Number of peers to be shuffled. + * @param peer Set flags on this peer. + * @param flags Set these flags on the peer. */ -void shuffle_peers_arr(peer_t *peers[MAX_PEERS_SIZE], size_t peers_size) +void set_peer_flags(peer_t *peer, int flags) { - size_t i; - size_t idx; + peer->flags |= flags; +} + +/** + * Shuffle an input array of peers. + * + * @param peers The array of peers to be shuffled. + * @param peers_size The number of peers to be shuffled. + */ +void shuffle_peers_arr(peer_t **peers, size_t peers_size) +{ + size_t i, j; peer_t *tmp; for (i = 0; i < peers_size; i++) { - /* don't swap with already swapped */ - idx = i + rand() % (peers_size - i); + /* don't swap with already swapped; + * swapping peers[i] with peers[j], where j is a random index + * such that j >= i AND j < peers_size + */ + j = i + rand() % (peers_size - i); tmp = peers[i]; - peers[i] = peers[idx]; - peers[idx] = tmp; + peers[i] = peers[j]; + peers[j] = tmp; } } @@ -301,20 +308,36 @@ int store_peers(const char *peers_path, const linkedlist_t *peers) peers_file = fopen(peers_path, "wb"); if (peers_file == NULL) { - log_error("store_peers - unable to create %s", peers_path); + log_error("Can not create peers file at %s", peers_path); return 1; } current = linkedlist_get_first(peers); while (current != NULL) { current_peer = (peer_t *) current->data; - fwrite(¤t_peer->addr, - sizeof(struct in6_addr), - 1, - peers_file); + /* if fwrite fails, terminate storing */ + if (fwrite(¤t_peer->addr, + sizeof(struct in6_addr), + 1, + peers_file) != 1) { + log_error("Storing peers"); + fclose(peers_file); + return 1; + } current = linkedlist_get_next(peers, current); } fclose(peers_file); return 0; } + +/** + * Unset flags on given peer. + * + * @param peer Unset flags on this peer. + * @param flags Unset these flags on the peer. + */ +void unset_peer_flags(peer_t *peer, int flags) +{ + peer->flags &= ~flags; +} diff --git a/src/peers.h b/src/peers.h index 74bb06d..5577f17 100644 --- a/src/peers.h +++ b/src/peers.h @@ -29,19 +29,26 @@ /* maximum number of peers we store */ #define MAX_PEERS_SIZE 50 +/** A peer is not available if they is already our neighbour, + * pending to become one, or if we are unnable to connect to them. + * 1 if available, 0 if not. + */ +#define PEER_AVAILABLE 0x01 + /* IPv6 addresses of peers guaranteed to be in the network */ static const unsigned char DEFAULT_PEERS[DEFAULT_PEERS_SIZE][16] = { +/* TODO: Replace with real default peers */ { - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 255, 255, - 147, 251, 210, 17 + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, + 192, 168, 0, 124 }, { - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 255, 255, - 147, 251, 210, 23 + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, + 192, 168, 0, 125 } }; @@ -49,23 +56,19 @@ static const unsigned char DEFAULT_PEERS[DEFAULT_PEERS_SIZE][16] = { typedef struct s_peer { /** Binary IPv6 address. */ struct in6_addr addr; - /** A peer is not available if they is already our neighbour, - * pending to become one, or if we are unnable to connect to them. - * 1 if available, 0 if not. - */ - short is_available; + /** A set of flags for this peer. */ + int flags; /* TODO: add uptime */ } peer_t; -linkedlist_node_t *add_peer(linkedlist_t *peers, const struct in6_addr *addr); - void clear_peers(linkedlist_t *peers); -size_t fetch_available_peers(const linkedlist_t *peers, - peer_t *available_peers[MAX_PEERS_SIZE]); - int fetch_peers(const char *peers_path, linkedlist_t *peers); +int fetch_specific_peers(const linkedlist_t *peers, + peer_t ***output, + int flags); + peer_t *find_peer_by_addr(const linkedlist_t *peers, const struct in6_addr *addr); @@ -73,8 +76,14 @@ void peers_to_str(const linkedlist_t *peers, char *output); void reset_peers_availability(linkedlist_t *peers); -void shuffle_peers_arr(peer_t *peers[MAX_PEERS_SIZE], size_t peers_size); +peer_t *save_peer(linkedlist_t *peers, const struct in6_addr *addr); + +void set_peer_flags(peer_t *peer, int flags); + +void shuffle_peers_arr(peer_t **peers, size_t peers_size); int store_peers(const char *peers_path, const linkedlist_t *peers); +void unset_peer_flags(peer_t *peer, int flags); + #endif /* PEERS_H */ -- GitLab