From b7488ddb9eb1dc703e31a74afd215fd00627ee3b Mon Sep 17 00:00:00 2001 From: jellevdd Date: Fri, 25 Apr 2014 16:45:14 +0200 Subject: [PATCH 1/2] Add SSL support Add basic SSL support to async_server. Use stream_handler class to make sure we don't copy code. --- .../protocol/http/server/async_connection.hpp | 46 +++-- .../protocol/http/server/async_server.hpp | 15 +- .../network/protocol/http/server/options.hpp | 8 +- boost/network/protocol/stream_handler.hpp | 185 ++++++++++++++++++ 4 files changed, 234 insertions(+), 20 deletions(-) create mode 100644 boost/network/protocol/stream_handler.hpp diff --git a/boost/network/protocol/http/server/async_connection.hpp b/boost/network/protocol/http/server/async_connection.hpp index 9d47e9b33..23aefdf77 100644 --- a/boost/network/protocol/http/server/async_connection.hpp +++ b/boost/network/protocol/http/server/async_connection.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -149,14 +150,16 @@ namespace boost { namespace network { namespace http { asio::io_service & io_service , Handler & handler , utils::thread_pool & thread_pool + , boost::shared_ptr ctx = boost::shared_ptr( ) ) - : socket_(io_service) - , strand(io_service) + : strand(io_service) , handler(handler) , thread_pool_(thread_pool) , headers_already_sent(false) , headers_in_progress(false) + , handshake_done(false) , headers_buffer(BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE) + , socket_(io_service, ctx) { new_start = read_buffer_.begin(); } @@ -285,7 +288,7 @@ namespace boost { namespace network { namespace http { , asio::placeholders::error, asio::placeholders::bytes_transferred))); } - asio::ip::tcp::socket & socket() { return socket_; } + boost::network::stream_handler & socket() { return socket_; } utils::thread_pool & thread_pool() { return thread_pool_; } bool has_error() { return (!!error_encountered); } optional error() @@ -319,12 +322,13 @@ namespace boost { namespace network { namespace http { typedef boost::lock_guard lock_guard; typedef std::list > pending_actions_list; - asio::ip::tcp::socket socket_; + boost::network::stream_handler socket_; asio::io_service::strand strand; Handler & handler; utils::thread_pool & thread_pool_; volatile bool headers_already_sent, headers_in_progress; asio::streambuf headers_buffer; + bool handshake_done; boost::recursive_mutex headers_mutex; buffer_type read_buffer_; @@ -350,21 +354,29 @@ namespace boost { namespace network { namespace http { read_more(method); } + void read_more(state_t state) { - socket_.async_read_some( - asio::buffer(read_buffer_) - , strand.wrap( - boost::bind( - &async_connection::handle_read_data, - async_connection::shared_from_this(), - state, - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred + if(socket_.is_ssl_enabled() && !handshake_done) { + socket_.async_handshake(boost::asio::ssl::stream_base::server, + boost::bind(&async_connection::handle_handshake, async_connection::shared_from_this(), + boost::asio::placeholders::error, state)); + } else { + socket_.async_read_some( + asio::buffer(read_buffer_) + , strand.wrap( + boost::bind( + &async_connection::handle_read_data, + async_connection::shared_from_this(), + state, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred ) ) ); + } } + void handle_read_data(state_t state, boost::system::error_code const & ec, std::size_t bytes_transferred) { if (!ec) { logic::tribool parsed_ok; @@ -645,6 +657,14 @@ namespace boost { namespace network { namespace http { ,asio::placeholders::bytes_transferred) ); } + void handle_handshake(const boost::system::error_code& ec, state_t state) { + if (!ec) { + handshake_done = true; + read_more(state); + } else { + error_encountered = in_place(ec); + } + } }; } /* http */ diff --git a/boost/network/protocol/http/server/async_server.hpp b/boost/network/protocol/http/server/async_server.hpp index 3bda33fca..c214b6766 100644 --- a/boost/network/protocol/http/server/async_server.hpp +++ b/boost/network/protocol/http/server/async_server.hpp @@ -38,6 +38,7 @@ namespace boost { namespace network { namespace http { , listening_mutex_() , stopping_mutex_() , listening(false) + , ctx_(options.context()) {} void run() { @@ -79,6 +80,7 @@ namespace boost { namespace network { namespace http { boost::mutex listening_mutex_; boost::mutex stopping_mutex_; bool listening; + boost::shared_ptr ctx_; void handle_stop() { scoped_mutex_lock stopping_lock(stopping_mutex_); @@ -96,13 +98,14 @@ namespace boost { namespace network { namespace http { << ec); } - socket_options_base::socket_options(new_connection->socket()); + socket_options_base::socket_options(new_connection->socket().next_layer()); + new_connection->start(); new_connection.reset( - new connection(service_, handler, *thread_pool)); + new connection(service_, handler, *thread_pool, ctx_)); acceptor.async_accept( - new_connection->socket(), - boost::bind(&async_server_base::handle_accept, + new_connection->socket().next_layer(), + boost::bind(&async_server_base::handle_accept, this, boost::asio::placeholders::error)); } @@ -135,8 +138,8 @@ namespace boost { namespace network { namespace http { BOOST_NETWORK_MESSAGE("Error listening on socket: '" << error << "' on " << address_ << ":" << port_); return; } - new_connection.reset(new connection(service_, handler, *thread_pool)); - acceptor.async_accept(new_connection->socket(), + new_connection.reset(new connection(service_, handler, *thread_pool, ctx_)); + acceptor.async_accept(new_connection->socket().next_layer(), boost::bind( &async_server_base::handle_accept , this diff --git a/boost/network/protocol/http/server/options.hpp b/boost/network/protocol/http/server/options.hpp index 766345758..1495e46d0 100644 --- a/boost/network/protocol/http/server/options.hpp +++ b/boost/network/protocol/http/server/options.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,7 @@ struct server_options { , receive_low_watermark_() , send_low_watermark_() , thread_pool_() + , context_() {} server_options(const server_options &other) @@ -52,6 +54,7 @@ struct server_options { , receive_low_watermark_(other.receive_low_watermark_) , send_low_watermark_(other.send_low_watermark_) , thread_pool_(other.thread_pool_) + , context_(other.context_) {} server_options &operator= (server_options other) { @@ -74,8 +77,10 @@ struct server_options { swap(receive_low_watermark_, other.receive_low_watermark_); swap(send_low_watermark_, other.send_low_watermark_); swap(thread_pool_, other.thread_pool_); + swap(context_, other.context_); } + server_options &context(boost::shared_ptr v) { context_ = v; return *this; } server_options &io_service(boost::shared_ptr v) { io_service_ = v; return *this; } server_options &address(string_type const &v) { address_ = v; return *this; } server_options &port(string_type const &v) { port_ = v; return *this; } @@ -104,8 +109,9 @@ struct server_options { boost::optional receive_low_watermark() const { return receive_low_watermark_; } boost::optional send_low_watermark() const { return send_low_watermark_; } boost::shared_ptr thread_pool() const { return thread_pool_; } - + boost::shared_ptr context() const { return context_; } private: + boost::shared_ptr context_; boost::shared_ptr io_service_; Handler &handler_; string_type address_; diff --git a/boost/network/protocol/stream_handler.hpp b/boost/network/protocol/stream_handler.hpp new file mode 100644 index 000000000..4f386736f --- /dev/null +++ b/boost/network/protocol/stream_handler.hpp @@ -0,0 +1,185 @@ +#ifndef NETLIB_IO_STREAM_HANDLER_HPP +#define NETLIB_IO_STREAM_HANDLER_HPP + +// Copyright 2014 Jelle Van den Driessche. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace boost { namespace network { + + typedef boost::asio::ssl::stream ssl_socket; + typedef boost::asio::ip::tcp::socket tcp_socket; + + struct stream_handler { + public: + stream_handler(boost::shared_ptr socket) : tcp_sock_(socket), ssl_enabled(false) { + } + + ~stream_handler() { + } + + stream_handler(boost::shared_ptr socket) : ssl_sock_(socket), ssl_enabled(true) { + } + + stream_handler(boost::asio::io_service& io, boost::shared_ptr ctx = boost::shared_ptr()) { + tcp_sock_ = boost::make_shared< tcp_socket >(io); + ssl_enabled = false; + if(ctx) { + /// SSL is enabled + ssl_sock_ = boost::make_shared< ssl_socket >(io, *ctx); + ssl_enabled = true; + } + } + + + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + try { + if(ssl_enabled) { + ssl_sock_->async_write_some(buffers,handler); + } else { + tcp_sock_->async_write_some(buffers,handler); + } + } catch(const boost::system::error_code & e) { + std::cerr << e.message() << std::endl; + } catch(const boost::system::system_error &e) { + std::cerr << e.code() << ": " << e.what() << std::endl; + } + } + + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + try { + if(ssl_enabled) { + ssl_sock_->async_read_some(buffers,handler); + } else { + tcp_sock_->async_read_some(buffers,handler); + } + } catch(const boost::system::error_code & e) { + std::cerr << e.message() << std::endl; + } catch(const boost::system::system_error &e) { + std::cerr << e.code() << ": " << e.what() << std::endl; + } + } + + void close(boost::system::error_code &e) + { + if(ssl_enabled) { + ssl_sock_->next_layer().close(); + } else { + tcp_sock_->close(); + } + } + + tcp_socket::endpoint_type remote_endpoint() const + { + if(ssl_enabled) { + return ssl_sock_->next_layer().remote_endpoint(); + } else { + return tcp_sock_->remote_endpoint(); + } + } + + void shutdown(boost::asio::socket_base::shutdown_type st, boost::system::error_code& e) + { + try { + if(ssl_enabled) { + return ssl_sock_->shutdown(); + } else { + return tcp_sock_->shutdown(boost::asio::ip::tcp::socket::shutdown_send); + } + } catch(const boost::system::error_code & e) { + std::cerr << e.message() << std::endl; + } catch(const boost::system::system_error &e) { + std::cerr << e.code() << ": " << e.what() << std::endl; + } + } + + ssl_socket::next_layer_type& next_layer() const + { + if(ssl_enabled) { + return ssl_sock_->next_layer(); + } else { + return *tcp_sock_; + } + } + + ssl_socket::lowest_layer_type& lowest_layer() const + { + if(ssl_enabled) { + return ssl_sock_->lowest_layer(); + } else { + return tcp_sock_->lowest_layer(); + } + } + + template + BOOST_ASIO_INITFN_RESULT_TYPE(HandshakeHandler, + void (boost::system::error_code)) + async_handshake(ssl_socket::handshake_type type, + BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler) + { + try { + if(ssl_enabled) { + return ssl_sock_->async_handshake(type,handler); + } else { + // NOOP + } + } catch(const boost::system::error_code & e) { + std::cerr << e.message() << std::endl; + } catch(const boost::system::system_error &e) { + std::cerr << e.code() << ": " << e.what() << std::endl; + } + } + boost::shared_ptr get_tcp_socket() { + return tcp_sock_; + } + boost::shared_ptr get_ssl_socket() { + return ssl_sock_; + } + + bool is_ssl_enabled() { + return ssl_enabled; + } + + + private: + boost::shared_ptr tcp_sock_; + boost::shared_ptr ssl_sock_; + bool ssl_enabled; + + }; +} +} + +#endif \ No newline at end of file From a9e23a8af2f49f0945c20da5f89b2bb7d30eecaa Mon Sep 17 00:00:00 2001 From: jellevdd Date: Thu, 15 May 2014 11:33:20 +0200 Subject: [PATCH 2/2] Add copyright --- boost/network/protocol/http/server/async_connection.hpp | 1 + boost/network/protocol/http/server/async_server.hpp | 1 + boost/network/protocol/http/server/options.hpp | 1 + 3 files changed, 3 insertions(+) diff --git a/boost/network/protocol/http/server/async_connection.hpp b/boost/network/protocol/http/server/async_connection.hpp index 23aefdf77..ac4324d47 100644 --- a/boost/network/protocol/http/server/async_connection.hpp +++ b/boost/network/protocol/http/server/async_connection.hpp @@ -2,6 +2,7 @@ #define BOOST_NETWORK_PROTOCOL_HTTP_SERVER_CONNECTION_HPP_20101027 // Copyright 2010 Dean Michael Berris. +// Copyright 2014 Jelle Van den Driessche. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) diff --git a/boost/network/protocol/http/server/async_server.hpp b/boost/network/protocol/http/server/async_server.hpp index c214b6766..818238a7e 100644 --- a/boost/network/protocol/http/server/async_server.hpp +++ b/boost/network/protocol/http/server/async_server.hpp @@ -2,6 +2,7 @@ #define BOOST_NETWORK_PROTOCOL_HTTP_SERVER_ASYNC_SERVER_HPP_20101025 // Copyright 2010 Dean Michael Berris. +// Copyright 2014 Jelle Van den Driessche. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) diff --git a/boost/network/protocol/http/server/options.hpp b/boost/network/protocol/http/server/options.hpp index 1495e46d0..6d7bbe0ac 100644 --- a/boost/network/protocol/http/server/options.hpp +++ b/boost/network/protocol/http/server/options.hpp @@ -3,6 +3,7 @@ // Copyright 2013 Google, Inc. // Copyright 2013 Dean Michael Berris +// Copyright 2014 Jelle Van den Driessche // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt)