Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add SSL support
Add basic SSL support to async_server. Use stream_handler class to make
sure we don't copy code.
  • Loading branch information
jellevdd committed Apr 25, 2014
commit b7488ddb9eb1dc703e31a74afd215fd00627ee3b
46 changes: 33 additions & 13 deletions boost/network/protocol/http/server/async_connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <boost/asio/strand.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/make_shared.hpp>
#include <boost/network/protocol/stream_handler.hpp>
#include <boost/network/protocol/http/server/request_parser.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/optional.hpp>
Expand Down Expand Up @@ -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<boost::asio::ssl::context> ctx = boost::shared_ptr<boost::asio::ssl::context>( )
)
: 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();
}
Expand Down Expand Up @@ -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<boost::system::system_error> error()
Expand Down Expand Up @@ -319,12 +322,13 @@ namespace boost { namespace network { namespace http {
typedef boost::lock_guard<boost::recursive_mutex> lock_guard;
typedef std::list<boost::function<void()> > 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_;
Expand All @@ -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<Tag,Handler>::handle_read_data,
async_connection<Tag,Handler>::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<Tag,Handler>::shared_from_this(),
boost::asio::placeholders::error, state));
} else {
socket_.async_read_some(
asio::buffer(read_buffer_)
, strand.wrap(
boost::bind(
&async_connection<Tag,Handler>::handle_read_data,
async_connection<Tag,Handler>::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;
Expand Down Expand Up @@ -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<boost::system::system_error>(ec);
}
}
};

} /* http */
Expand Down
15 changes: 9 additions & 6 deletions boost/network/protocol/http/server/async_server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace boost { namespace network { namespace http {
, listening_mutex_()
, stopping_mutex_()
, listening(false)
, ctx_(options.context())
{}

void run() {
Expand Down Expand Up @@ -79,6 +80,7 @@ namespace boost { namespace network { namespace http {
boost::mutex listening_mutex_;
boost::mutex stopping_mutex_;
bool listening;
boost::shared_ptr<boost::asio::ssl::context> ctx_;

void handle_stop() {
scoped_mutex_lock stopping_lock(stopping_mutex_);
Expand All @@ -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<Tag, Handler>::handle_accept,
new_connection->socket().next_layer(),
boost::bind(&async_server_base<Tag, Handler>::handle_accept,
this,
boost::asio::placeholders::error));
}
Expand Down Expand Up @@ -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<Tag,Handler>::handle_accept
, this
Expand Down
8 changes: 7 additions & 1 deletion boost/network/protocol/http/server/options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <boost/asio/io_service.hpp>
#include <boost/asio/socket_base.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/network/traits/string.hpp>
#include <boost/network/utils/thread_pool.hpp>
#include <boost/optional.hpp>
Expand All @@ -35,6 +36,7 @@ struct server_options {
, receive_low_watermark_()
, send_low_watermark_()
, thread_pool_()
, context_()
{}

server_options(const server_options &other)
Expand All @@ -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) {
Expand All @@ -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<boost::asio::ssl::context> v) { context_ = v; return *this; }
server_options &io_service(boost::shared_ptr<boost::asio::io_service> 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; }
Expand Down Expand Up @@ -104,8 +109,9 @@ struct server_options {
boost::optional<boost::asio::socket_base::receive_low_watermark> receive_low_watermark() const { return receive_low_watermark_; }
boost::optional<boost::asio::socket_base::send_low_watermark> send_low_watermark() const { return send_low_watermark_; }
boost::shared_ptr<utils::thread_pool> thread_pool() const { return thread_pool_; }

boost::shared_ptr<boost::asio::ssl::context> context() const { return context_; }
private:
boost::shared_ptr<boost::asio::ssl::context> context_;
boost::shared_ptr<boost::asio::io_service> io_service_;
Handler &handler_;
string_type address_;
Expand Down
185 changes: 185 additions & 0 deletions boost/network/protocol/stream_handler.hpp
Original file line number Diff line number Diff line change
@@ -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 <cstddef>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/asio/detail/push_options.hpp>
#include <boost/asio/detail/config.hpp>
#include <boost/asio/detail/handler_type_requirements.hpp>
#include <boost/asio/stream_socket_service.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/make_shared.hpp>
#include <boost/asio/detail/config.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/basic_socket.hpp>


namespace boost { namespace network {

typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
typedef boost::asio::ip::tcp::socket tcp_socket;

struct stream_handler {
public:
stream_handler(boost::shared_ptr<tcp_socket> socket) : tcp_sock_(socket), ssl_enabled(false) {
}

~stream_handler() {
}

stream_handler(boost::shared_ptr<ssl_socket> socket) : ssl_sock_(socket), ssl_enabled(true) {
}

stream_handler(boost::asio::io_service& io, boost::shared_ptr<boost::asio::ssl::context> ctx = boost::shared_ptr<boost::asio::ssl::context>()) {
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 <typename ConstBufferSequence, typename WriteHandler>
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 <typename MutableBufferSequence, typename ReadHandler>
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 <typename HandshakeHandler>
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<tcp_socket> get_tcp_socket() {
return tcp_sock_;
}
boost::shared_ptr<ssl_socket> get_ssl_socket() {
return ssl_sock_;
}

bool is_ssl_enabled() {
return ssl_enabled;
}


private:
boost::shared_ptr<tcp_socket> tcp_sock_;
boost::shared_ptr<ssl_socket> ssl_sock_;
bool ssl_enabled;

};
}
}

#endif