diff options
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | libcmix-network/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | libcmix-network/acceptor.cpp | 1 | ||||
| -rw-r--r-- | libcmix-network/client.cpp | 5 | ||||
| -rw-r--r-- | libcmix-network/client.hpp | 4 | ||||
| -rw-r--r-- | libcmix-network/connect.cpp | 38 | ||||
| -rw-r--r-- | libcmix-network/connect.hpp | 3 | ||||
| -rw-r--r-- | libcmix-network/uriparser.cpp | 3 | ||||
| -rw-r--r-- | libcmix-network/uriparser.hpp | 59 | ||||
| -rw-r--r-- | libcmix-protobuf/CMakeLists.txt | 19 | ||||
| -rw-r--r-- | libcmix-protobuf/cmix.proto | 3 | ||||
| -rw-r--r-- | liblog/logging.cpp | 3 | ||||
| -rw-r--r-- | network-handler/nodemanager.cpp | 2 | ||||
| -rw-r--r-- | network-handler/nodemanager.hpp | 1 | ||||
| -rw-r--r-- | node/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | node/main.cpp | 51 | ||||
| -rw-r--r-- | node/nextnode.cpp | 27 | ||||
| -rw-r--r-- | node/nextnode.hpp | 4 | ||||
| -rw-r--r-- | node/node.cpp | 52 | ||||
| -rw-r--r-- | node/node.hpp | 17 |
20 files changed, 274 insertions, 23 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d1cbc8..2c1710c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,8 @@ add_subdirectory(libcmix) add_subdirectory(liblog) add_subdirectory(libcmix-network) +add_subdirectory(libcmix-protobuf) + add_subdirectory(network-handler) add_subdirectory(node) diff --git a/libcmix-network/CMakeLists.txt b/libcmix-network/CMakeLists.txt index 6986eea..2574e82 100644 --- a/libcmix-network/CMakeLists.txt +++ b/libcmix-network/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(cmix-network server.hpp server.cpp client.hpp client.cpp nodeclient.hpp nodeclient.cpp + uriparser.hpp uriparser.cpp ) target_compile_options(cmix-network @@ -22,6 +23,7 @@ target_link_libraries(cmix-network PUBLIC Boost::system PUBLIC ${CMAKE_THREAD_LIBS_INIT} PRIVATE cmix + PRIVATE log ) if(WIN32) diff --git a/libcmix-network/acceptor.cpp b/libcmix-network/acceptor.cpp index 34b5f0e..69b2807 100644 --- a/libcmix-network/acceptor.cpp +++ b/libcmix-network/acceptor.cpp @@ -22,7 +22,6 @@ void accept_connection(tcp::acceptor& acceptor, std::shared_ptr<tcp::socket> soc ss << ec; throw std::runtime_error(ss.str()); } - } void accept_loop(tcp::acceptor& acceptor, std::function<void(tcp::socket&&)> f) diff --git a/libcmix-network/client.cpp b/libcmix-network/client.cpp index 544dd87..ce9fd4d 100644 --- a/libcmix-network/client.cpp +++ b/libcmix-network/client.cpp @@ -1,5 +1,7 @@ #include "client.hpp" +#include "logging.hpp" + #include <boost/asio/placeholders.hpp> #include <boost/bind.hpp> @@ -19,10 +21,11 @@ void Client::handle_receive(MessageHandler message_handler, const error_code &ec buffer.commit(read_bytes); std::istream is(&buffer); + BOOST_LOG_TRIVIAL(trace) << "handling receive"; + if(!ec) { std::vector<uint8_t> data(std::istream_iterator<uint8_t>(is), {}); message_handler(data); - receive(message_handler); } else { if(done) { done(); diff --git a/libcmix-network/client.hpp b/libcmix-network/client.hpp index 2b6a6df..46b989d 100644 --- a/libcmix-network/client.hpp +++ b/libcmix-network/client.hpp @@ -10,8 +10,10 @@ public: typedef std::function<void(void)> OnDoneFT; typedef std::function<void(std::vector<uint8_t>)> MessageHandler; -private: +protected: boost::asio::ip::tcp::socket socket; + +private: boost::asio::streambuf buffer; OnDoneFT done; diff --git a/libcmix-network/connect.cpp b/libcmix-network/connect.cpp index 679748e..bf200d5 100644 --- a/libcmix-network/connect.cpp +++ b/libcmix-network/connect.cpp @@ -1,23 +1,24 @@ #include "connect.hpp" +#include "logging.hpp" + #include <boost/asio/ip/basic_resolver.hpp> +#include <boost/asio/ip/address.hpp> using namespace boost::asio::ip; using boost::asio::io_service; -boost::asio::ip::tcp::socket connect(std::string host, std::string port, io_service& io_service) { +boost::asio::ip::tcp::socket connect(std::string host, io_service& io_service) { boost::asio::ip::basic_resolver<tcp> resolver(io_service); - boost::asio::ip::basic_resolver_query<tcp> query(host, port); - boost::asio::ip::basic_endpoint<tcp> endpoint; + boost::asio::ip::basic_resolver_query<tcp> query(host, ""); for(auto it = resolver.resolve(query); it != boost::asio::ip::tcp::resolver::iterator(); ++it) { - endpoint = *it; boost::system::error_code ec; boost::asio::ip::tcp::socket socket(io_service); - socket.connect(endpoint, ec); + socket.connect(*it, ec); if(ec) { continue; } else { @@ -27,3 +28,30 @@ boost::asio::ip::tcp::socket connect(std::string host, std::string port, io_serv throw std::runtime_error("None of the supplied endpoints responded"); } + +void async_connect_iteration(tcp::socket& socket, boost::asio::ip::tcp::resolver::iterator it, std::function<void()> on_connect) { + if(it == boost::asio::ip::tcp::resolver::iterator()) { + throw std::runtime_error("None of the supplied endpoints responded"); + } + + auto handler = [&socket, it, on_connect](boost::system::error_code const& ec) { + if(ec) { + BOOST_LOG_TRIVIAL(info) << ec << std::endl; + async_connect_iteration(socket, std::next(it), on_connect); + } else { + on_connect(); + } + }; + + socket.async_connect(*it, handler); +} + +void async_connect(tcp::socket& socket, std::string host, std::string next_port, std::function<void()> on_connect) +{ + boost::asio::ip::basic_resolver<tcp> resolver(socket.get_io_service()); + boost::asio::ip::basic_resolver_query<tcp> query(host, next_port); + + auto it = resolver.resolve(query); + + async_connect_iteration(socket, it, on_connect); +} diff --git a/libcmix-network/connect.hpp b/libcmix-network/connect.hpp index 7f5b5c3..071ed9b 100644 --- a/libcmix-network/connect.hpp +++ b/libcmix-network/connect.hpp @@ -3,4 +3,5 @@ #include <boost/asio/ip/tcp.hpp> #include <boost/asio/io_service.hpp> -boost::asio::ip::tcp::socket connect(std::string host, std::string port, boost::asio::io_service& io_service); +boost::asio::ip::tcp::socket connect(std::string host, boost::asio::io_service& io_service); +void async_connect(boost::asio::ip::tcp::socket& socket, std::string host, std::string next_port, std::function<void()> on_connect); diff --git a/libcmix-network/uriparser.cpp b/libcmix-network/uriparser.cpp new file mode 100644 index 0000000..9cea452 --- /dev/null +++ b/libcmix-network/uriparser.cpp @@ -0,0 +1,3 @@ +#include "uriparser.hpp" + + diff --git a/libcmix-network/uriparser.hpp b/libcmix-network/uriparser.hpp new file mode 100644 index 0000000..c46b70a --- /dev/null +++ b/libcmix-network/uriparser.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include <string> +#include <regex> +#include <iostream> + +struct Uri { + std::string scheme; + std::string username; + std::string password; + std::string host; + std::string port; + std::string query; + std::string hash; +}; + +Uri parse_uri(std::string str) { + std::string scheme = "(?:(.+?)://)?"; + std::string uname_pass = "(?:(.*?)?(?::(.*?))@)?"; + std::string host = "(.+?)"; + std::string port = "(?::(\\d+?))?"; + std::string query = "(?:\\?(.+?))?"; + std::string hash = "(?:#(.+?))?"; + + std::regex expr("^" + scheme + uname_pass + host + port + query + hash + "$"); + std::smatch matches; + std::regex_match(str, matches, expr); + + return { + matches[1].str(), + matches[2].str(), + matches[3].str(), + matches[4].str(), + matches[5].str(), + matches[6].str(), + matches[7].str() + }; +} + +std::string debug_uri(Uri uri) { + std::stringstream ss; + ss << "scheme: " << uri.scheme << std::endl + << "username: " << uri.username << std::endl + << "password: " << uri.password << std::endl + << "host: " << uri.host << std::endl + << "port: " << uri.port << std::endl + << "query: " << uri.query << std::endl + << "hash: " << uri.hash << std::endl; + return ss.str(); +} + +std::string uri_to_string(Uri uri) { + return + (!uri.scheme.empty() ? uri.scheme + "://" : "") + + (!uri.username.empty() ? uri.username + (!uri.password.empty() ? ":" + uri.password : "") + "@" : "") + + uri.host + + (!uri.port.empty() ? ":" + uri.port : "") + + (!uri.query.empty() ? "?" + uri.query : ""); +} diff --git a/libcmix-protobuf/CMakeLists.txt b/libcmix-protobuf/CMakeLists.txt new file mode 100644 index 0000000..f2a8f3d --- /dev/null +++ b/libcmix-protobuf/CMakeLists.txt @@ -0,0 +1,19 @@ +find_package(Protobuf REQUIRED) + +set(proto_files cmix.proto) + +protobuf_generate_cpp(proto_sources proto_headers + ${proto_files} +) + +add_library(cmix-protobuf + ${proto_files} + ${proto_headers} ${proto_sources} +) + +target_include_directories(cmix-protobuf + PUBLIC ${PROTOBUF_INCLUDE_DIRS} + PUBLIC ${CMAKE_CURRENT_BINARY_DIR} +) + +target_link_libraries(cmix-protobuf ${PROTOBUF_LIBRARIES})
\ No newline at end of file diff --git a/libcmix-protobuf/cmix.proto b/libcmix-protobuf/cmix.proto new file mode 100644 index 0000000..f0c1dc3 --- /dev/null +++ b/libcmix-protobuf/cmix.proto @@ -0,0 +1,3 @@ +message initialization { + required bytes public_share = 1; +} diff --git a/liblog/logging.cpp b/liblog/logging.cpp index c92247c..6bbf070 100644 --- a/liblog/logging.cpp +++ b/liblog/logging.cpp @@ -18,7 +18,8 @@ void init_logging(boost::log::trivial::severity_level log_level) ( boost::log::keywords::file_name = "node%N.log", boost::log::keywords::rotation_size = 10 * 1024 * 1024, - boost::log::keywords::format = "[%Severity%] (%TimeStamp%): %Message%" + boost::log::keywords::format = "[%Severity%] (%TimeStamp%): %Message%", + boost::log::keywords::auto_flush = true ); boost::log::core::get()->set_filter diff --git a/network-handler/nodemanager.cpp b/network-handler/nodemanager.cpp index 165cb3b..179f239 100644 --- a/network-handler/nodemanager.cpp +++ b/network-handler/nodemanager.cpp @@ -9,6 +9,6 @@ NodeManager::NodeManager(std::vector<ConnectionInfo> connections) , nodes() { for(auto&& ci : connections) { - nodes.emplace_back(connect(ci.host, ci.port, io_service)); + nodes.emplace_back(connect(ci.host, io_service)); } } diff --git a/network-handler/nodemanager.hpp b/network-handler/nodemanager.hpp index 651e6a4..8f6e7af 100644 --- a/network-handler/nodemanager.hpp +++ b/network-handler/nodemanager.hpp @@ -8,7 +8,6 @@ struct ConnectionInfo { std::string host; - std::string port; }; class NodeManager diff --git a/node/CMakeLists.txt b/node/CMakeLists.txt index a4e1f09..c3c8e46 100644 --- a/node/CMakeLists.txt +++ b/node/CMakeLists.txt @@ -17,4 +17,5 @@ target_link_libraries(node PRIVATE log PRIVATE cmix PRIVATE cmix-network + PRIVATE cmix-protobuf ) diff --git a/node/main.cpp b/node/main.cpp index 970e150..1327ac5 100644 --- a/node/main.cpp +++ b/node/main.cpp @@ -1,4 +1,53 @@ -int main() { +#include "node.hpp" +#include "uriparser.hpp" +#include "logging.hpp" +#include <boost/program_options.hpp> + +#include <iostream> + +int main(int argc, char* argv[]) { + namespace po = boost::program_options; + + init_logging(boost::log::trivial::severity_level::trace); + + po::options_description desc("Allowed options"); + desc.add_options() + ("help,h", "produce help message.") + ("port,p", po::value<uint16_t>()->default_value(9200), "Set listening port.") + ("enable_v4", po::value<bool>()->default_value(true), "Enable/disable ipv4 accept support.") + ("interface4,4", po::value<std::string>()->default_value("0.0.0.0"), "Set the ipv4 address to listen on.") + ("enable_v6", po::value<bool>()->default_value(true), "Enable/disable ipv6 accept support.") + ("interface6,6", po::value<std::string>()->default_value("::"), "Set the ipv6 address to listen on.") + ("next_node,n", po::value<std::string>()->required(), "The address of the next node in the network") + ("first,f", "This is the first node and will be the communication point for the clients.") + ; + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << desc << "\n"; + return 0; + } + + bool en4 = vm["enable_v4"].as<bool>(); + std::string if4 = vm["interface4"].as<std::string>(); + bool en6 = vm["enable_v6"].as<bool>(); + std::string if6 = vm["interface6"].as<std::string>(); + uint16_t port = vm["port"].as<uint16_t>(); + + ListenSettings lsettings{en4, if4, en6, if6, port}; + + bool is_first = bool(vm.count("first")); + std::string next_node = vm["next_node"].as<std::string>(); + + Uri uri = parse_uri(next_node); + + NodeNetworkSettings nsettings{is_first, uri.host, uri.port}; + + Node node(lsettings, nsettings); + node.run(); } diff --git a/node/nextnode.cpp b/node/nextnode.cpp index 3045462..d38200d 100644 --- a/node/nextnode.cpp +++ b/node/nextnode.cpp @@ -1,7 +1,34 @@ #include "nextnode.hpp" +#include "connect.hpp" + +#include "logging.hpp" + using namespace boost::asio::ip; NextNode::NextNode(tcp::socket&& socket) : Client(std::move(socket)) {} + +void NextNode::send(std::string message) +{ + auto handler = [](boost::system::error_code const& ec, std::size_t bytes_transferred) { + BOOST_LOG_TRIVIAL(trace) << "sent message"; + if(ec) { + BOOST_LOG_TRIVIAL(fatal) << ec; + throw std::runtime_error("unable to send message"); + } + }; + + socket.async_send(boost::asio::buffer(message), 0, handler); +} + +void NextNode::connect(std::string next_host, std::string next_port, std::function<void ()> on_connect) +{ + async_connect(socket, next_host, next_port, on_connect); +} + +void NextNode::close() +{ + socket.close(); +} diff --git a/node/nextnode.hpp b/node/nextnode.hpp index c1ce6a1..42206bb 100644 --- a/node/nextnode.hpp +++ b/node/nextnode.hpp @@ -8,5 +8,9 @@ class NextNode : public Client { public: NextNode(boost::asio::ip::tcp::socket&& socket); + + void send(std::string message); + void connect(std::string next_host, std::string next_port, std::function<void()> on_connect); + void close(); }; diff --git a/node/node.cpp b/node/node.cpp index 4b4bc2b..b33f8a5 100644 --- a/node/node.cpp +++ b/node/node.cpp @@ -1,17 +1,31 @@ #include "node.hpp" -#include "connect.hpp" + +#include "logging.hpp" + +using namespace boost::asio::ip; Node::Node(ListenSettings const& listen_settings, NodeNetworkSettings network_settings) : io_service() , server(io_service, listen_settings, [this](boost::asio::ip::tcp::socket&& socket){accept_handler(std::move(socket));}) , clients() -, next_node(connect(network_settings.next_host, network_settings.next_port, io_service)) +, network_settings(network_settings) +, next_node(tcp::socket(io_service)) , api(get_curve25519_implementation()) , keypair(api.create_key_pair()) +, network_pub_key() { - if(network_settings.is_first) { - start_initialisation(); - } + auto on_connect = [this, network_settings](){ + BOOST_LOG_TRIVIAL(trace) << "is first: " << std::boolalpha << network_settings.is_first; + if(network_settings.is_first) { + start_initialisation(); + } + }; + + next_node.connect(network_settings.next_host, network_settings.next_port, on_connect); +} + +Node::~Node() { + api.free_key_pair(keypair); } void Node::accept_handler(boost::asio::ip::tcp::socket&& socket) @@ -24,6 +38,32 @@ void Node::accept_handler(boost::asio::ip::tcp::socket&& socket) clients.erase(it); } ); +} + +void Node::start_initialisation() { + initialization init; + init.set_public_share(keypair.pub, keypair.pub_len); + + BOOST_LOG_TRIVIAL(trace) << "length of keypair.pub: " << keypair.pub_len; + + std::string message; + init.SerializeToString(&message); + BOOST_LOG_TRIVIAL(trace) << init.DebugString(); + next_node.send(message); + + auto f = [this](std::vector<uint8_t> bytes) { + network_pub_key = bytes; + + if(network_settings.is_first) { + start_precomputation(); + } + }; + + BOOST_LOG_TRIVIAL(trace) << "number of clients: " << clients.size(); + for(auto&& client : clients) { + client.receive(f); + } +} - clients.back().receive(); +void Node::start_precomputation() { } diff --git a/node/node.hpp b/node/node.hpp index 9e321df..5668dec 100644 --- a/node/node.hpp +++ b/node/node.hpp @@ -7,6 +7,8 @@ #include "api.h" #include "curve25519.h" +#include "cmix.pb.h" + #include <boost/asio/io_service.hpp> #include <list> @@ -21,20 +23,27 @@ class Node { boost::asio::io_service io_service; Server server; - std::list<NodeClient> clients; + std::list<Client> clients; + + NodeNetworkSettings network_settings; NextNode next_node; Api api; KeyPair keypair; + std::vector<uint8_t> network_pub_key; void accept_handler(boost::asio::ip::tcp::socket&& socket); - void start_initialisation() { - - } + void start_precomputation(); + void start_initialisation(); public: Node(ListenSettings const& listen_settings, NodeNetworkSettings network_settings); + ~Node(); + + void run() { + io_service.run(); + } }; |
