Commit 7098f83f authored by xHire's avatar xHire
Browse files

Merge management of peers

parents f0144a75 2e3b123e
......@@ -4,9 +4,13 @@ bin_PROGRAMS = src/coincerd src/coincer
src_coincerd_SOURCES = \
src/coincerd.c \
src/configuration.c src/configuration.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/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)
src_coincerd_LDADD = $(AM_LDADD) $(JANSSON_LIBS) $(LIBEVENT_LIBS) $(LIBSODIUM_LIBS)
......
/*
* 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
......@@ -18,9 +18,18 @@
#include <event2/event.h>
#include <event2/listener.h>
#include <signal.h>
#include <stdlib.h>
#include <time.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);
static void conns_cb(evutil_socket_t fd, short events, void *ctx);
int main(void)
{
......@@ -42,21 +51,128 @@ 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;
struct event *sigterm_event;
global_state.event_loop = NULL;
neighbours_init(&global_state.neighbours);
/* TODO: use randombytes (from libsodium?) for the seed of randomness */
srand((unsigned) time(NULL));
if (listen_init(&listener, &global_state) != 0) {
/* 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;
}
linkedlist_init(&global_state.pending_neighbours);
linkedlist_init(&global_state.neighbours);
linkedlist_init(&global_state.peers);
fetch_peers(global_state.filepaths.peers, &global_state.peers);
/* setup everything needed for TCP listening */
if (listen_init(&listener, &global_state) != 0) {
log_error("Initialization of TCP listening");
return 2;
}
/* 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("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 */
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("Creating or adding Connections event");
return 3;
}
/* 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(sigterm_event);
event_free(conns_event);
event_base_free(global_state.event_loop);
return 0;
}
/**
* Callback function for a received signal.
*
* @param signal What signal was invoked.
* @param events Flags of the event occurred.
* @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) {
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);
}
}
/*
* Coincer
* 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
* 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 <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#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("Can not 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("Setting configdir");
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("Setting configdir");
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("Setting datadir");
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("Setting datadir");
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("Could not create configuration "
"directory %s", config_dir);
return 1;
} else {
log_debug("create_dirs - created configuration "
"directory %s", config_dir);
}
} else {
log_error("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("Could not create "
"data directory %s", data_dir);
return 1;
} else {
log_debug("create_dirs - created data "
"directory %s", data_dir);
}
} else {
log_error("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;
}
/*
* Coincer
* 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
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef CONFIGURATION_H
#define CONFIGURATION_H
int setup_directories(char **config_dir, char **data_dir);
#endif /* CONFIGURATION_H */
/*
* 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
......@@ -20,30 +20,96 @@
#include <stdlib.h>
#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.
*
* @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.
*
* @return First node of the linked list.
* @return NULL if linkedlist is empty.
* @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,116 @@ 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 linkedlist after 'node'. In case of 'node' being the
* last (stub) node, insert before it.
*
* @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.
*