Skip to content

Commit 6550c55

Browse files
committed
Add SSL support
Add basic SSL support to async_server. Use stream_handler class to make sure we don't copy code.
1 parent f40a20f commit 6550c55

File tree

4 files changed

+234
-20
lines changed

4 files changed

+234
-20
lines changed

boost/network/protocol/http/server/async_connection.hpp

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <boost/asio/strand.hpp>
1919
#include <boost/asio/buffer.hpp>
2020
#include <boost/make_shared.hpp>
21+
#include <boost/network/protocol/stream_handler.hpp>
2122
#include <boost/network/protocol/http/server/request_parser.hpp>
2223
#include <boost/range/iterator_range.hpp>
2324
#include <boost/optional.hpp>
@@ -149,14 +150,16 @@ namespace boost { namespace network { namespace http {
149150
asio::io_service & io_service
150151
, Handler & handler
151152
, utils::thread_pool & thread_pool
153+
, boost::shared_ptr<boost::asio::ssl::context> ctx = boost::shared_ptr<boost::asio::ssl::context>( )
152154
)
153-
: socket_(io_service)
154-
, strand(io_service)
155+
: strand(io_service)
155156
, handler(handler)
156157
, thread_pool_(thread_pool)
157158
, headers_already_sent(false)
158159
, headers_in_progress(false)
160+
, handshake_done(false)
159161
, headers_buffer(BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE)
162+
, socket_(io_service, ctx)
160163
{
161164
new_start = read_buffer_.begin();
162165
}
@@ -285,7 +288,7 @@ namespace boost { namespace network { namespace http {
285288
, asio::placeholders::error, asio::placeholders::bytes_transferred)));
286289
}
287290

288-
asio::ip::tcp::socket & socket() { return socket_; }
291+
boost::network::stream_handler & socket() { return socket_; }
289292
utils::thread_pool & thread_pool() { return thread_pool_; }
290293
bool has_error() { return (!!error_encountered); }
291294
optional<boost::system::system_error> error()
@@ -319,12 +322,13 @@ namespace boost { namespace network { namespace http {
319322
typedef boost::lock_guard<boost::recursive_mutex> lock_guard;
320323
typedef std::list<boost::function<void()> > pending_actions_list;
321324

322-
asio::ip::tcp::socket socket_;
325+
boost::network::stream_handler socket_;
323326
asio::io_service::strand strand;
324327
Handler & handler;
325328
utils::thread_pool & thread_pool_;
326329
volatile bool headers_already_sent, headers_in_progress;
327330
asio::streambuf headers_buffer;
331+
bool handshake_done;
328332

329333
boost::recursive_mutex headers_mutex;
330334
buffer_type read_buffer_;
@@ -350,21 +354,29 @@ namespace boost { namespace network { namespace http {
350354
read_more(method);
351355
}
352356

357+
353358
void read_more(state_t state) {
354-
socket_.async_read_some(
355-
asio::buffer(read_buffer_)
356-
, strand.wrap(
357-
boost::bind(
358-
&async_connection<Tag,Handler>::handle_read_data,
359-
async_connection<Tag,Handler>::shared_from_this(),
360-
state,
361-
boost::asio::placeholders::error,
362-
boost::asio::placeholders::bytes_transferred
359+
if(socket_.is_ssl_enabled() && !handshake_done) {
360+
socket_.async_handshake(boost::asio::ssl::stream_base::server,
361+
boost::bind(&async_connection::handle_handshake, async_connection<Tag,Handler>::shared_from_this(),
362+
boost::asio::placeholders::error, state));
363+
} else {
364+
socket_.async_read_some(
365+
asio::buffer(read_buffer_)
366+
, strand.wrap(
367+
boost::bind(
368+
&async_connection<Tag,Handler>::handle_read_data,
369+
async_connection<Tag,Handler>::shared_from_this(),
370+
state,
371+
boost::asio::placeholders::error,
372+
boost::asio::placeholders::bytes_transferred
363373
)
364374
)
365375
);
376+
}
366377
}
367378

379+
368380
void handle_read_data(state_t state, boost::system::error_code const & ec, std::size_t bytes_transferred) {
369381
if (!ec) {
370382
logic::tribool parsed_ok;
@@ -645,6 +657,14 @@ namespace boost { namespace network { namespace http {
645657
,asio::placeholders::bytes_transferred)
646658
);
647659
}
660+
void handle_handshake(const boost::system::error_code& ec, state_t state) {
661+
if (!ec) {
662+
handshake_done = true;
663+
read_more(state);
664+
} else {
665+
error_encountered = in_place<boost::system::system_error>(ec);
666+
}
667+
}
648668
};
649669

650670
} /* http */

boost/network/protocol/http/server/async_server.hpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ namespace boost { namespace network { namespace http {
3838
, listening_mutex_()
3939
, stopping_mutex_()
4040
, listening(false)
41+
, ctx_(options.context())
4142
{}
4243

4344
void run() {
@@ -79,6 +80,7 @@ namespace boost { namespace network { namespace http {
7980
boost::mutex listening_mutex_;
8081
boost::mutex stopping_mutex_;
8182
bool listening;
83+
boost::shared_ptr<boost::asio::ssl::context> ctx_;
8284

8385
void handle_stop() {
8486
scoped_mutex_lock stopping_lock(stopping_mutex_);
@@ -96,13 +98,14 @@ namespace boost { namespace network { namespace http {
9698
<< ec);
9799
}
98100

99-
socket_options_base::socket_options(new_connection->socket());
101+
socket_options_base::socket_options(new_connection->socket().next_layer());
102+
100103
new_connection->start();
101104
new_connection.reset(
102-
new connection(service_, handler, *thread_pool));
105+
new connection(service_, handler, *thread_pool, ctx_));
103106
acceptor.async_accept(
104-
new_connection->socket(),
105-
boost::bind(&async_server_base<Tag, Handler>::handle_accept,
107+
new_connection->socket().next_layer(),
108+
boost::bind(&async_server_base<Tag, Handler>::handle_accept,
106109
this,
107110
boost::asio::placeholders::error));
108111
}
@@ -135,8 +138,8 @@ namespace boost { namespace network { namespace http {
135138
BOOST_NETWORK_MESSAGE("Error listening on socket: '" << error << "' on " << address_ << ":" << port_);
136139
return;
137140
}
138-
new_connection.reset(new connection(service_, handler, *thread_pool));
139-
acceptor.async_accept(new_connection->socket(),
141+
new_connection.reset(new connection(service_, handler, *thread_pool, ctx_));
142+
acceptor.async_accept(new_connection->socket().next_layer(),
140143
boost::bind(
141144
&async_server_base<Tag,Handler>::handle_accept
142145
, this

boost/network/protocol/http/server/options.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <boost/asio/io_service.hpp>
1111
#include <boost/asio/socket_base.hpp>
12+
#include <boost/asio/ssl.hpp>
1213
#include <boost/network/traits/string.hpp>
1314
#include <boost/network/utils/thread_pool.hpp>
1415
#include <boost/optional.hpp>
@@ -35,6 +36,7 @@ struct server_options {
3536
, receive_low_watermark_()
3637
, send_low_watermark_()
3738
, thread_pool_()
39+
, context_()
3840
{}
3941

4042
server_options(const server_options &other)
@@ -52,6 +54,7 @@ struct server_options {
5254
, receive_low_watermark_(other.receive_low_watermark_)
5355
, send_low_watermark_(other.send_low_watermark_)
5456
, thread_pool_(other.thread_pool_)
57+
, context_(other.context_)
5558
{}
5659

5760
server_options &operator= (server_options other) {
@@ -74,8 +77,10 @@ struct server_options {
7477
swap(receive_low_watermark_, other.receive_low_watermark_);
7578
swap(send_low_watermark_, other.send_low_watermark_);
7679
swap(thread_pool_, other.thread_pool_);
80+
swap(context_, other.context_);
7781
}
7882

83+
server_options &context(boost::shared_ptr<boost::asio::ssl::context> v) { context_ = v; return *this; }
7984
server_options &io_service(boost::shared_ptr<boost::asio::io_service> v) { io_service_ = v; return *this; }
8085
server_options &address(string_type const &v) { address_ = v; return *this; }
8186
server_options &port(string_type const &v) { port_ = v; return *this; }
@@ -104,8 +109,9 @@ struct server_options {
104109
boost::optional<boost::asio::socket_base::receive_low_watermark> receive_low_watermark() const { return receive_low_watermark_; }
105110
boost::optional<boost::asio::socket_base::send_low_watermark> send_low_watermark() const { return send_low_watermark_; }
106111
boost::shared_ptr<utils::thread_pool> thread_pool() const { return thread_pool_; }
107-
112+
boost::shared_ptr<boost::asio::ssl::context> context() const { return context_; }
108113
private:
114+
boost::shared_ptr<boost::asio::ssl::context> context_;
109115
boost::shared_ptr<boost::asio::io_service> io_service_;
110116
Handler &handler_;
111117
string_type address_;
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
#ifndef NETLIB_IO_STREAM_HANDLER_HPP
2+
#define NETLIB_IO_STREAM_HANDLER_HPP
3+
4+
// Copyright 2014 Jelle Van den Driessche.
5+
// Distributed under the Boost Software License, Version 1.0.
6+
// (See accompanying file LICENSE_1_0.txt or copy at
7+
// http://www.boost.org/LICENSE_1_0.txt)
8+
9+
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
10+
# pragma once
11+
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
12+
13+
14+
#include <cstddef>
15+
#include <boost/asio/detail/throw_error.hpp>
16+
#include <boost/asio/error.hpp>
17+
#include <boost/asio.hpp>
18+
#include <boost/asio/ssl.hpp>
19+
#include <boost/asio/detail/push_options.hpp>
20+
#include <boost/asio/detail/config.hpp>
21+
#include <boost/asio/detail/handler_type_requirements.hpp>
22+
#include <boost/asio/stream_socket_service.hpp>
23+
#include <boost/asio/async_result.hpp>
24+
#include <boost/make_shared.hpp>
25+
#include <boost/asio/detail/config.hpp>
26+
#include <boost/asio/async_result.hpp>
27+
#include <boost/asio/basic_socket.hpp>
28+
29+
30+
namespace boost { namespace network {
31+
32+
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
33+
typedef boost::asio::ip::tcp::socket tcp_socket;
34+
35+
struct stream_handler {
36+
public:
37+
stream_handler(boost::shared_ptr<tcp_socket> socket) : tcp_sock_(socket), ssl_enabled(false) {
38+
}
39+
40+
~stream_handler() {
41+
}
42+
43+
stream_handler(boost::shared_ptr<ssl_socket> socket) : ssl_sock_(socket), ssl_enabled(true) {
44+
}
45+
46+
stream_handler(boost::asio::io_service& io, boost::shared_ptr<boost::asio::ssl::context> ctx = boost::shared_ptr<boost::asio::ssl::context>()) {
47+
tcp_sock_ = boost::make_shared< tcp_socket >(io);
48+
ssl_enabled = false;
49+
if(ctx) {
50+
/// SSL is enabled
51+
ssl_sock_ = boost::make_shared< ssl_socket >(io, *ctx);
52+
ssl_enabled = true;
53+
}
54+
}
55+
56+
57+
template <typename ConstBufferSequence, typename WriteHandler>
58+
BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
59+
void (boost::system::error_code, std::size_t))
60+
async_write_some(const ConstBufferSequence& buffers,
61+
BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
62+
{
63+
try {
64+
if(ssl_enabled) {
65+
ssl_sock_->async_write_some(buffers,handler);
66+
} else {
67+
tcp_sock_->async_write_some(buffers,handler);
68+
}
69+
} catch(const boost::system::error_code & e) {
70+
std::cerr << e.message() << std::endl;
71+
} catch(const boost::system::system_error &e) {
72+
std::cerr << e.code() << ": " << e.what() << std::endl;
73+
}
74+
}
75+
76+
template <typename MutableBufferSequence, typename ReadHandler>
77+
BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
78+
void (boost::system::error_code, std::size_t))
79+
async_read_some(const MutableBufferSequence& buffers,
80+
BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
81+
{
82+
try {
83+
if(ssl_enabled) {
84+
ssl_sock_->async_read_some(buffers,handler);
85+
} else {
86+
tcp_sock_->async_read_some(buffers,handler);
87+
}
88+
} catch(const boost::system::error_code & e) {
89+
std::cerr << e.message() << std::endl;
90+
} catch(const boost::system::system_error &e) {
91+
std::cerr << e.code() << ": " << e.what() << std::endl;
92+
}
93+
}
94+
95+
void close(boost::system::error_code &e)
96+
{
97+
if(ssl_enabled) {
98+
ssl_sock_->next_layer().close();
99+
} else {
100+
tcp_sock_->close();
101+
}
102+
}
103+
104+
tcp_socket::endpoint_type remote_endpoint() const
105+
{
106+
if(ssl_enabled) {
107+
return ssl_sock_->next_layer().remote_endpoint();
108+
} else {
109+
return tcp_sock_->remote_endpoint();
110+
}
111+
}
112+
113+
void shutdown(boost::asio::socket_base::shutdown_type st, boost::system::error_code& e)
114+
{
115+
try {
116+
if(ssl_enabled) {
117+
return ssl_sock_->shutdown();
118+
} else {
119+
return tcp_sock_->shutdown(boost::asio::ip::tcp::socket::shutdown_send);
120+
}
121+
} catch(const boost::system::error_code & e) {
122+
std::cerr << e.message() << std::endl;
123+
} catch(const boost::system::system_error &e) {
124+
std::cerr << e.code() << ": " << e.what() << std::endl;
125+
}
126+
}
127+
128+
ssl_socket::next_layer_type& next_layer() const
129+
{
130+
if(ssl_enabled) {
131+
return ssl_sock_->next_layer();
132+
} else {
133+
return *tcp_sock_;
134+
}
135+
}
136+
137+
ssl_socket::lowest_layer_type& lowest_layer() const
138+
{
139+
if(ssl_enabled) {
140+
return ssl_sock_->lowest_layer();
141+
} else {
142+
return tcp_sock_->lowest_layer();
143+
}
144+
}
145+
146+
template <typename HandshakeHandler>
147+
BOOST_ASIO_INITFN_RESULT_TYPE(HandshakeHandler,
148+
void (boost::system::error_code))
149+
async_handshake(ssl_socket::handshake_type type,
150+
BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler)
151+
{
152+
try {
153+
if(ssl_enabled) {
154+
return ssl_sock_->async_handshake(type,handler);
155+
} else {
156+
// NOOP
157+
}
158+
} catch(const boost::system::error_code & e) {
159+
std::cerr << e.message() << std::endl;
160+
} catch(const boost::system::system_error &e) {
161+
std::cerr << e.code() << ": " << e.what() << std::endl;
162+
}
163+
}
164+
boost::shared_ptr<tcp_socket> get_tcp_socket() {
165+
return tcp_sock_;
166+
}
167+
boost::shared_ptr<ssl_socket> get_ssl_socket() {
168+
return ssl_sock_;
169+
}
170+
171+
bool is_ssl_enabled() {
172+
return ssl_enabled;
173+
}
174+
175+
176+
private:
177+
boost::shared_ptr<tcp_socket> tcp_sock_;
178+
boost::shared_ptr<ssl_socket> ssl_sock_;
179+
bool ssl_enabled;
180+
181+
};
182+
}
183+
}
184+
185+
#endif

0 commit comments

Comments
 (0)