aboutsummaryrefslogtreecommitdiff
path: root/libcmix-network
diff options
context:
space:
mode:
authorDennis Brentjes <d.brentjes@gmail.com>2016-09-29 14:26:07 +0200
committerDennis Brentjes <d.brentjes@gmail.com>2016-09-29 14:26:07 +0200
commit8507aec59b92e16ed6a05c92fea6ced5dba3f753 (patch)
treeb8ae5904f74c9896ccc6662837e628400d47b829 /libcmix-network
parent3fe7a5b6a18b6841ae51f294dc58fe9c8df6d375 (diff)
downloadcmix-8507aec59b92e16ed6a05c92fea6ced5dba3f753.tar.gz
cmix-8507aec59b92e16ed6a05c92fea6ced5dba3f753.tar.bz2
cmix-8507aec59b92e16ed6a05c92fea6ced5dba3f753.zip
Added some boilerplate to enable ssl connections.
Diffstat (limited to 'libcmix-network')
-rw-r--r--libcmix-network/CMakeLists.txt4
-rw-r--r--libcmix-network/accept.cpp48
-rw-r--r--libcmix-network/accept.hpp38
-rw-r--r--libcmix-network/acceptor.cpp51
-rw-r--r--libcmix-network/acceptor.hpp47
-rw-r--r--libcmix-network/server.cpp31
-rw-r--r--libcmix-network/server.hpp38
7 files changed, 192 insertions, 65 deletions
diff --git a/libcmix-network/CMakeLists.txt b/libcmix-network/CMakeLists.txt
index 2574e82..1420d69 100644
--- a/libcmix-network/CMakeLists.txt
+++ b/libcmix-network/CMakeLists.txt
@@ -1,8 +1,11 @@
find_package(Boost COMPONENTS system REQUIRED)
find_package(Threads)
+find_package(OpenSSL REQUIRED)
+
add_library(cmix-network
acceptor.hpp acceptor.cpp
+ accept.hpp accept.cpp
connect.hpp connect.cpp
server.hpp server.cpp
client.hpp client.cpp
@@ -21,6 +24,7 @@ target_include_directories(cmix-network
target_link_libraries(cmix-network
PRIVATE Boost::boost
PUBLIC Boost::system
+ PUBLIC OpenSSL::SSL
PUBLIC ${CMAKE_THREAD_LIBS_INIT}
PRIVATE cmix
PRIVATE log
diff --git a/libcmix-network/accept.cpp b/libcmix-network/accept.cpp
new file mode 100644
index 0000000..3fa4314
--- /dev/null
+++ b/libcmix-network/accept.cpp
@@ -0,0 +1,48 @@
+
+#include "accept.hpp"
+
+#include <boost/bind.hpp>
+#include <boost/asio/placeholders.hpp>
+
+using namespace boost::asio::ip;
+using namespace boost::asio;
+
+void accept_connection(tcp::acceptor& acceptor, std::shared_ptr<tcp::socket> socket, boost::system::error_code ec, std::function<void (tcp::socket&&)> f)
+{
+ if(!bool(ec))
+ {
+ f(std::move(*socket));
+ accept_loop(acceptor, f);
+ } else {
+ std::stringstream ss;
+ ss << ec;
+ throw std::runtime_error(ss.str());
+ }
+}
+
+void accept_loop(tcp::acceptor& acceptor, std::function<void (tcp::socket&&)> f)
+{
+ std::shared_ptr<tcp::socket> new_socket = std::make_shared<tcp::socket>(acceptor.get_io_service());
+
+ acceptor.async_accept(*new_socket, boost::bind(accept_connection, boost::ref(acceptor), new_socket, placeholders::error, f));
+}
+
+void accept_connection(tcp::acceptor& acceptor, std::shared_ptr<ssl::context> ctx, std::shared_ptr<ssl::stream<tcp::socket>> socket, boost::system::error_code ec, std::function<void (ssl::stream<tcp::socket>&&)> f)
+{
+ if(!bool(ec))
+ {
+ f(std::move(*socket));
+ accept_loop(acceptor, ctx, f);
+ } else {
+ std::stringstream ss;
+ ss << ec;
+ throw std::runtime_error(ss.str());
+ }
+}
+
+void accept_loop(tcp::acceptor& acceptor, std::shared_ptr<ssl::context> ctx, std::function<void(ssl::stream<tcp::socket>&& socket)> f) {
+
+ std::shared_ptr<ssl::stream<tcp::socket>> new_socket = std::make_shared<ssl::stream<tcp::socket>>(acceptor.get_io_service(), *ctx);
+
+ acceptor.async_accept(new_socket->lowest_layer(), boost::bind(accept_connection, boost::ref(acceptor), ctx, new_socket, placeholders::error, f));
+}
diff --git a/libcmix-network/accept.hpp b/libcmix-network/accept.hpp
new file mode 100644
index 0000000..dde98a3
--- /dev/null
+++ b/libcmix-network/accept.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/ssl.hpp>
+
+#include <memory>
+
+/*!
+ * \file
+ */
+
+/*!
+ * \brief AcceptHandler Handy typedef for a function taking an tcp::socket.
+ */
+typedef std::function<void(boost::asio::ip::tcp::socket&&)> AcceptHandler;
+/*!
+ * \brief SSLAcceptHandler Handy typedef for a function taking an "SSLSocket"
+ */
+typedef std::function<void(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>&&)> SSLAcceptHandler;
+
+/*!
+ * \brief accept_loop Keeps accepting connections on the specified acceptor
+ * \param acceptor The acceptor should be in the listening state.
+ * \param f A callback function called with the accepted connection.
+ *
+ * The io_service of the acceptor is used as the io_service for the newly created socket.
+ */
+void accept_loop(boost::asio::ip::tcp::acceptor& acceptor, AcceptHandler f);
+
+/*!
+ * \brief accept_loop Keeps accepting SSL connections on the specified acceptor
+ * \param acceptor The acceptor should be in listening state.
+ * \param ctx The SSL context
+ * \param f A callback function called with the accepted connection.
+ *
+ * The io_service of the acceptor is used as the io_service for the newly created socket.
+ */
+void accept_loop(boost::asio::ip::tcp::acceptor& acceptor, std::shared_ptr<boost::asio::ssl::context> ctx, SSLAcceptHandler f); \ No newline at end of file
diff --git a/libcmix-network/acceptor.cpp b/libcmix-network/acceptor.cpp
index 69b2807..ed640a1 100644
--- a/libcmix-network/acceptor.cpp
+++ b/libcmix-network/acceptor.cpp
@@ -1,42 +1,26 @@
#include "acceptor.hpp"
-#include <boost/asio/ip/tcp.hpp>
-#include <boost/asio/ip/v6_only.hpp>
-#include <boost/asio/placeholders.hpp>
-#include <boost/bind.hpp>
+#include "accept.hpp"
+#include <boost/asio/ip/v6_only.hpp>
using namespace boost::asio;
using namespace boost::asio::ip;
-void accept_loop(tcp::acceptor& acceptor, std::function<void(tcp::socket&&)> f);
-
-void accept_connection(tcp::acceptor& acceptor, std::shared_ptr<tcp::socket> socket, boost::system::error_code ec, std::function<void(boost::asio::ip::tcp::socket&&)> f)
-{
- if(!bool(ec))
- {
- f(std::move(*socket));
- accept_loop(acceptor, f);
- } else {
- std::stringstream ss;
- ss << ec;
- throw std::runtime_error(ss.str());
- }
-}
-
-void accept_loop(tcp::acceptor& acceptor, std::function<void(tcp::socket&&)> f)
-{
- std::shared_ptr<tcp::socket> new_socket = std::make_shared<tcp::socket>(acceptor.get_io_service());
-
- acceptor.async_accept(*new_socket, boost::bind(accept_connection, boost::ref(acceptor), new_socket, boost::asio::placeholders::error, f));
-}
-
Acceptor::Acceptor(boost::asio::io_service &io_service, boost::asio::ip::address address, uint16_t port)
: acceptor(io_service)
, endpoint(address, port)
{}
-void Acceptor::bind_v6_and_v4_any(std::function<void(tcp::socket&&)> accept_handler) {
+address Acceptor::get_address() {
+ return endpoint.address();
+}
+
+bool Acceptor::is_open() {
+ return acceptor.is_open();
+}
+
+void Acceptor::listen_v6_and_v4_any() {
acceptor.open(endpoint.protocol());
v6_only option(false);
@@ -44,15 +28,22 @@ void Acceptor::bind_v6_and_v4_any(std::function<void(tcp::socket&&)> accept_hand
acceptor.bind(endpoint);
acceptor.listen();
-
- accept_loop(acceptor, accept_handler);
}
-void Acceptor::setup_listen_socket(std::function<void (tcp::socket &&)> accept_handler)
+void Acceptor::listen_socket()
{
acceptor.open(endpoint.protocol());
acceptor.bind(endpoint);
acceptor.listen();
+}
+void Acceptor::start_accepting(AcceptHandler accept_handler) {
accept_loop(acceptor, accept_handler);
}
+
+void Acceptor::start_accepting(std::shared_ptr<ssl::context> ctx, SSLAcceptHandler accept_handler)
+{
+ accept_loop(acceptor, ctx, accept_handler);
+}
+
+
diff --git a/libcmix-network/acceptor.hpp b/libcmix-network/acceptor.hpp
index 06b709d..6e4de63 100644
--- a/libcmix-network/acceptor.hpp
+++ b/libcmix-network/acceptor.hpp
@@ -1,6 +1,9 @@
#pragma once
+#include "accept.hpp"
+
#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/ssl.hpp>
#include <functional>
@@ -15,8 +18,8 @@
* Otherwise they would be side to side in the Server class.
*/
class Acceptor{
- boost::asio::ip::tcp::acceptor acceptor;
- boost::asio::ip::tcp::endpoint endpoint;
+ boost::asio::ip::tcp::acceptor acceptor; ///< The acceptor
+ boost::asio::ip::tcp::endpoint endpoint; ///< The endpoint
public:
/*!
@@ -26,25 +29,49 @@ public:
* \param port The listen port
*/
Acceptor(boost::asio::io_service& io_service, boost::asio::ip::address address, uint16_t port);
-
+
/*!
* \brief get_address
* \return The listening address
*/
- boost::asio::ip::address get_address() { return endpoint.address(); }
+ boost::asio::ip::address get_address();
+
+ /*!
+ * \brief is_open Checks if the acceptor socket is opened.
+ * \return true if the socket is open, false otherwise.
+ */
+ bool is_open();
/*!
- * \brief bind_v6_and_v4_any
- * \param accept_handler Function to call when accepting an incoming connection.
+ * \brief listen_v6_and_v4_any
*
* If you want to accept on both ipv6 and ipv any you have to do some special setup.
* This function handles that and starts listening.
*/
- void bind_v6_and_v4_any(std::function<void(boost::asio::ip::tcp::socket&&)> accept_handler);
+ void listen_v6_and_v4_any();
+
+ /*!
+ * \brief listen_socket
+ *
+ * start listening on the specified endpoint
+ */
+ void listen_socket();
+
+ /*!
+ * \brief start_accepting
+ * \param accept_handler The function called on a succesful accepted connection.
+ *
+ * Asynchronously indefinitely accepts connections.
+ */
+ void start_accepting(AcceptHandler accept_handler);
/*!
- * \brief setup_listen_socket
- * \param accept_handler Function to call when accepting an incoming connection.
+ * \brief start_accepting
+ * \param ctx The SSL context
+ * \param accept_handler The function called on a succesful accepted ssl connection.
+ *
+ * Asynchronously indefinitely accepts SSL connections.
*/
- void setup_listen_socket(std::function<void(boost::asio::ip::tcp::socket&&)> accept_handler);
+ void start_accepting(std::shared_ptr<boost::asio::ssl::context> ctx, SSLAcceptHandler accept_handler);
+
};
diff --git a/libcmix-network/server.cpp b/libcmix-network/server.cpp
index cb2bd34..8dabecb 100644
--- a/libcmix-network/server.cpp
+++ b/libcmix-network/server.cpp
@@ -3,7 +3,7 @@
using namespace boost::asio::ip;
using namespace boost::asio;
-Server::Server(io_service& io_service, const ListenSettings& listen_settings, AcceptHandler accept_handler)
+Server::Server(io_service& io_service, const ListenSettings& listen_settings)
: listen_settings(listen_settings)
, v4_acceptor(io_service, address_v4::from_string(listen_settings.ipv4_inaddr), listen_settings.port)
, v6_acceptor(io_service, address_v6::from_string(listen_settings.ipv6_inaddr), listen_settings.port)
@@ -16,16 +16,39 @@ Server::Server(io_service& io_service, const ListenSettings& listen_settings, Ac
*/
bool bind_v4_any = v4_acceptor.get_address().to_v4() == address_v4::any() && listen_settings.enable_ipv4;
bool bind_v6_any = v6_acceptor.get_address().to_v6() == address_v6::any() && listen_settings.enable_ipv6;
+
if(bind_v4_any && bind_v6_any) {
- v6_acceptor.bind_v6_and_v4_any(accept_handler);
+ v6_acceptor.listen_v6_and_v4_any();
} else if(bind_v4_any || bind_v6_any) {
throw std::runtime_error("Cannot bind an INADDR_ANY and a non INADDR_ANY address on ipv4 and ipv6");
} else {
if(listen_settings.enable_ipv4) {
- v4_acceptor.setup_listen_socket(accept_handler);
+ v4_acceptor.listen_socket();
}
if(listen_settings.enable_ipv6) {
- v6_acceptor.setup_listen_socket(accept_handler);
+ v6_acceptor.listen_socket();
}
}
+}
+
+Server::Server(io_service& io_service, const ListenSettings& listen_settings, AcceptHandler accept_handler)
+: Server(io_service, listen_settings)
+{
+ if(v4_acceptor.is_open()) {
+ v4_acceptor.start_accepting(accept_handler);
+ }
+ if(v6_acceptor.is_open()) {
+ v6_acceptor.start_accepting(accept_handler);
+ }
+}
+
+Server::Server(io_service& io_service, const ListenSettings& listen_settings, std::shared_ptr<ssl::context> ctx, SSLAcceptHandler accept_handler)
+: Server(io_service, listen_settings)
+{
+ if(v4_acceptor.is_open()) {
+ v4_acceptor.start_accepting(ctx, accept_handler);
+ }
+ if(v6_acceptor.is_open()) {
+ v6_acceptor.start_accepting(ctx, accept_handler);
+ }
} \ No newline at end of file
diff --git a/libcmix-network/server.hpp b/libcmix-network/server.hpp
index 2e5b272..fad7c71 100644
--- a/libcmix-network/server.hpp
+++ b/libcmix-network/server.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <boost/asio/io_service.hpp>
+#include <boost/asio/ssl.hpp>
#include "acceptor.hpp"
@@ -13,10 +14,11 @@
*/
struct ListenSettings {
bool enable_ipv4; ///< Should we listen on ipv4
- std::string ipv4_inaddr; ///< listen on this ipv4 address
+ std::string ipv4_inaddr; ///< Listen on this ipv4 address
bool enable_ipv6; ///< Should we listen on ipv6
- std::string ipv6_inaddr; ///< listen on this ipv6 address
- uint16_t port; ///< listen on this port.
+ std::string ipv6_inaddr; ///< Listen on this ipv6 address
+ uint16_t port; ///< Listen on this port.
+ bool use_ssl; ///< Should we use ssl
};
/*!
@@ -24,27 +26,12 @@ struct ListenSettings {
*/
class Server
{
-public:
- /*!
- * \brief AcceptHandler
- */
- typedef std::function<void(boost::asio::ip::tcp::socket&& socket)> AcceptHandler;
+ Server(boost::asio::io_service& io_service, ListenSettings const& listen_settings);
-private:
- /*!
- * \brief listen_settings
- */
- ListenSettings const& listen_settings;
-
- /*!
- * \brief v4_acceptor
- */
+ ListenSettings const& listen_settings;
Acceptor v4_acceptor;
- /*!
- * \brief v6_acceptor
- */
Acceptor v6_acceptor;
-
+
public:
/*!
* \brief Server
@@ -54,4 +41,13 @@ public:
*/
Server(boost::asio::io_service& io_service, ListenSettings const& listen_settings, AcceptHandler accept_handler);
+ /*!
+ * \brief Server
+ * \param io_service The io_service this server will use for all its connections.
+ * \param listen_settings The parameters used for determining on what endpoints to listen.
+ * \param ctx The SSL context.
+ * \param accept_handler The function to call when SSL connections are established.
+ */
+ Server(boost::asio::io_service& io_service, ListenSettings const& listen_settings, std::shared_ptr<boost::asio::ssl::context> ctx, SSLAcceptHandler accept_handler);
+
};