diff --git a/CMakeLists.txt b/CMakeLists.txt index 484609e..9dfa99a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ # License along with this program. If not, see # . -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.1) project(NeoComm) set(TARGET_NAME "neocomm") @@ -31,14 +31,18 @@ message(STATUS "Build Type: ${CMAKE_BUILD_TYPE}") option(BUILD_SHARED_LIBS "Whether to build a shared object instead of a static." OFF) +find_package(Threads REQUIRED) + +set(CMAKE_THREAD_PREFER_PTHREAD TRUE) +set(THREADS_PREFER_PTHREAD_FLAG TRUE) + include_directories( "include/") set(SRCS - src/connection.c + src/connectivity.c src/error.c - src/neocomm.c - src/nodes.c) + src/neocomm.c) set(CMAKE_C_FLAGS "-std=c99 -Wall -Wextra -Werror -Wfatal-errors -Wmissing-declarations -pedantic-errors") set(CMAKE_C_FLAGS_DEBUG "-g -O0") @@ -53,4 +57,11 @@ else() add_definitions("-DDEBUG") endif() -add_library(${TARGET_NAME} ${SRCS}) +if(BUILD_SHARED_LIBS) + add_library(${TARGET_NAME} SHARED ${SRCS}) +else() + add_library(${TARGET_NAME} STATIC ${SRCS}) +endif() + +target_link_libraries(${TARGET_NAME} + Threads::Threads) diff --git a/README.md b/README.md index 23ce77b..4efec9b 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,6 @@ What follows is a list roadmap of features and the (approximate) versions in whi - [ ] Message encryption - [ ] Private messages - v1.0: - - [ ] Special snowflake (Winblows) socket support - [ ] SOCKS4a/SOCKS5 proxy support - [ ] HTTP proxy support - v2.0: @@ -49,7 +48,7 @@ _There are currently no clients available._ Compiling --------- -To build this project you will need a C99 compatible compiler ([GCC](https://gcc.gnu.org/) is recommended) and the [CMake build system](https://cmake.org/). To build run the following commands from the root directory of the project. +To build this project you will need a C99 compatible compiler ([GCC](https://gcc.gnu.org/) is recommended), a POSIX threads compatible system, and the [CMake build system](https://cmake.org/). To build run the following commands from the root directory of the project. ``` $ cd build/ $ cmake .. diff --git a/include/neocomm/connectivity.h b/include/neocomm/connectivity.h new file mode 100644 index 0000000..5ee4efc --- /dev/null +++ b/include/neocomm/connectivity.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2017 Ortega Froysa, Nicolás + * Author: Ortega Froysa, Nicolás + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * . + */ + +#pragma once + +/** + * @file connectivity.h + * @brief Interfaces relating to node connections. + */ + +/** + * @brief Simple address structure providing IP/DNS and port information. + */ +struct NeoComm_address { + const char *address; ///< IP/DNS string. + unsigned short port; ///< Port of address. +}; + +/** + * @brief Structure used for NeoComm nodes. + */ +struct NeoComm_node { + /// The address of the node. + struct NeoComm_address address; + /// Whether or not it is a directory node/server. + int directory; + /// Number of connections a directory has. + unsigned int connections; + /// Maximum number of connections the directory can have. + unsigned int max_connections; +}; + + +/** + * @brief Initialize the directory aspect of the node. + * + * @param max_num_nodes Maximum number of nodes in the directory. + * @param portnum Public facing port which other nodes can connect to. + * + * @return If the operation failed then a 0 will be returned and the error can + * be read from the NeoComm_get_last_error function, else 1 is returned. + */ +int NeoComm_init_directory(const unsigned int max_num_nodes, + const unsigned short portnum); + +/** + * @brief Disconnect from all nodes and free memory. + */ +void NeoComm_shutdown_directory(); + +/** + * @brief Resize the directory. + * @note This function only increments the size, it currently does not have + * the ability to decrease size. + * + * @param new_max_num_nodes The new maximum number of nodes in the directory. + * + * @return If the operation failed then a 0 will be returned and the error can + * be read from the NeoComm_get_last_error function, else 1 is returned. + */ +int NeoComm_resize_directory(const unsigned int new_max_num_nodes); + +/** + * @brief Get the current maximum number of nodes for the directory. + * + * @return The current maximum number of nodes for the directory. + */ +unsigned int NeoComm_get_directory_size(); + +/** + * @brief Get the current number of nodes registered in the directory. + * + * @return The current number of nodes in the directory. + */ +unsigned int NeoComm_get_num_nodes(); + +/** + * @brief Add and connect to a new node to the directory. + * + * @param addr The address of the new node to connect to. + * + * @return If the operation failed then a 0 will be returned and the error can + * be read from the NeoComm_get_last_error function, else 1 is returned. + */ +int NeoComm_add_node(const struct NeoComm_address addr); + +/** + * @brief Disconnect and remove a node from the directory. + * + * @param addr The address of the node to remove. + * + * @return If the operation failed then a 0 will be returned and the error can + * be read from the NeoComm_get_last_error function, else 1 is returned. + */ +int NeoComm_remove_node(const struct NeoComm_address addr); + +/** + * @brief Retrieve information on a specific node. + * + * @param addr The address of the node to retrieve. + * + * @return A NeoComm_node structure of the node. + */ +struct NeoComm_node NeoComm_get_node(const struct NeoComm_address addr); diff --git a/include/neocomm/neocomm.h b/include/neocomm/neocomm.h index 0ffba4a..d44eea3 100644 --- a/include/neocomm/neocomm.h +++ b/include/neocomm/neocomm.h @@ -19,9 +19,8 @@ #pragma once -#include "neocomm/connection.h" #include "neocomm/error.h" -#include "neocomm/nodes.h" +#include "neocomm/connectivity.h" /** * @file neocomm.h diff --git a/src/connection.c b/src/connectivity.c similarity index 56% rename from src/connection.c rename to src/connectivity.c index 062d532..d50f412 100644 --- a/src/connection.c +++ b/src/connectivity.c @@ -17,19 +17,49 @@ * . */ -#include "neocomm/connection.h" +#include "neocomm/connectivity.h" +#include "iconnectivity.h" -#include "internal_error.h" +#include "ierror.h" #include #include #include #include +#include #include #include +#include +#include + +/* + * This is an internal OS specific structure for nodes. + */ +struct NeoComm_directory_node { + int in_use; + struct sockaddr_in addr; + int sockfd; + pthread_t thread; + int open_directory; + unsigned int connections; + unsigned int max_connections; +}; + +static struct NeoComm_directory_node *node_list; +static unsigned int max_nodes; +static unsigned int num_nodes; + +static int run; +static int sockfd; + +static pthread_t accept_thread; + +/* + * This is a protected bind function that is not accessible as a public + * interface. + */ int NeoComm_bind(const unsigned short port) { - int sockfd;//, newsockfd; struct sockaddr_in serv_addr; sockfd = socket(AF_INET, SOCK_STREAM, 0); @@ -100,3 +130,71 @@ int NeoComm_bind(const unsigned short port) { return 1; } + +void *NeoComm_connect_manager() { + while(run) + { + int cli_sockfd; + struct sockaddr_in cli_addr; + socklen_t size_cli_addr = sizeof(cli_addr); + cli_sockfd = accept(sockfd, (struct sockaddr*) &cli_addr, + &size_cli_addr); + if(cli_sockfd < 0) + { + NeoComm_error("Error on accept"); + continue; + } + // TODO: Add the new connection and have it listen on a new thread. + } + pthread_exit(NULL); +} + +int NeoComm_init_directory(const unsigned int max_num_nodes, + const unsigned short portnum) { + if(max_num_nodes == 0) + { + NeoComm_error("Insufficient number of nodes"); + return 0; + } + + if(!NeoComm_bind(portnum)) + return 0; + + node_list = calloc(max_num_nodes, sizeof(struct NeoComm_directory_node)); + if(!node_list) + { + NeoComm_error("Failed to allocate memory to directory node list"); + return 0; + } + + max_nodes = max_num_nodes; + num_nodes = 0; + + for(unsigned int i = 0; i < max_nodes; ++i) + node_list[i].in_use = 0; + + run = 1; + int err = pthread_create(&accept_thread, NULL, + NeoComm_connect_manager, NULL); + if(err != 0) + { + NeoComm_error("Insufficient resources to create thread"); + return 0; + } + + return 1; +} + +void NeoComm_shutdown_directory() { + run = 0; + void *res; + for(unsigned int i = 0; i < num_nodes; ++i) + { + // in case the threads are still running, we wait + pthread_join(node_list[i].thread, &res); + close(node_list[i].sockfd); + } + pthread_join(accept_thread, &res); + close(sockfd); + pthread_exit(NULL); +} diff --git a/src/error.c b/src/error.c index 1b9ef38..f086907 100644 --- a/src/error.c +++ b/src/error.c @@ -18,7 +18,7 @@ */ #include "neocomm/error.h" -#include "internal_error.h" +#include "ierror.h" #include diff --git a/src/globals.h b/src/globals.h deleted file mode 100644 index 6f8820f..0000000 --- a/src/globals.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2017 Ortega Froysa, Nicolás - * Author: Ortega Froysa, Nicolás - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * . - */ - -#pragma once - -#include "neocomm/nodes.h" - -// List of nodes -extern struct NeoComm_node *node_list; -// Maximum number of nodes -extern unsigned int node_max; -// Number of nodes in the list -extern unsigned int node_count; diff --git a/include/neocomm/connection.h b/src/iconnectivity.h similarity index 91% rename from include/neocomm/connection.h rename to src/iconnectivity.h index b0ece99..4f813b4 100644 --- a/include/neocomm/connection.h +++ b/src/iconnectivity.h @@ -19,6 +19,6 @@ #pragma once -int NeoComm_bind(const unsigned short port); +int NeoComm_bind(unsigned short portnum); -void NeoComm_close_connections(); +void *NeoComm_connect_manager(); diff --git a/src/internal_error.h b/src/ierror.h similarity index 100% rename from src/internal_error.h rename to src/ierror.h diff --git a/src/neocomm.c b/src/neocomm.c index 5a08fd1..00ac28a 100644 --- a/src/neocomm.c +++ b/src/neocomm.c @@ -18,13 +18,3 @@ */ #include "neocomm/neocomm.h" - -int NeoComm_init(unsigned int max_nodes) { - if(!NeoComm_init_nodes(max_nodes)) - return 0; - return 1; -} - -void NeoComm_shutdown() { - NeoComm_shutdown_nodes(); -} diff --git a/src/nodes.c b/src/nodes.c index 8e01a06..fff1ccb 100644 --- a/src/nodes.c +++ b/src/nodes.c @@ -19,13 +19,19 @@ #include "neocomm/nodes.h" -#include "globals.h" #include "internal_error.h" #include #include #include +// List of nodes +static struct NeoComm_node *node_list; +// Maximum number of nodes +static unsigned int node_max; +// Number of nodes in the list +static unsigned int node_count; + int NeoComm_init_nodes(unsigned int max_nodes) { if(max_nodes == 0) {