Program Listing for File ssl_stream_socket.ipp¶
↰ Return to documentation for file (stream-client/stream/impl/ssl_stream_socket.ipp
)
#pragma once
namespace stream_client {
namespace ssl {
template <typename Socket>
stream_socket<Socket>::stream_socket(const endpoint_type& peer_endpoint, time_duration_type connect_timeout,
time_duration_type operation_timeout, const std::string& upstream_host,
bool rfc2818_handshake)
: ssl_context_(boost::asio::ssl::context::sslv23)
{
const auto deadline = clock_type::now() + connect_timeout;
ssl_context_.set_default_verify_paths();
ssl_stream_ = std::make_unique<ssl_layer_type>(next_layer_config{peer_endpoint, std::move(connect_timeout),
std::move(operation_timeout)},
ssl_context_);
if (!SSL_set_tlsext_host_name(ssl_stream_->native_handle(), upstream_host.c_str())) {
boost::system::error_code ec{static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()};
throw boost::system::system_error{ec};
}
if (rfc2818_handshake) {
ssl_stream_->set_verify_mode(boost::asio::ssl::verify_peer);
ssl_stream_->set_verify_callback(boost::asio::ssl::rfc2818_verification(upstream_host));
handshake(deadline);
}
}
template <typename Socket>
boost::system::error_code stream_socket<Socket>::close()
{
boost::system::error_code ec;
ssl_layer().shutdown(ec);
// http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error
#if BOOST_VERSION >= 106200
bool ssl_short_read_err = (ec.value() == boost::asio::ssl::error::stream_truncated);
#else // older Boost supports only OpenSSL 1.0, so 1.0-only macro is appropriate
bool ssl_short_read_err = (ERR_GET_REASON(ec.value()) == SSL_R_SHORT_READ);
#endif
if (ec.category() == boost::asio::error::get_ssl_category() && ssl_short_read_err) {
ec.assign(0, ec.category());
}
if (ec) {
return ec;
}
lowest_layer().close(ec);
return ec;
}
/* Wrappers to perform SSL handshaking within ssl::stream */
template <typename Socket>
template <typename Time>
boost::system::error_code stream_socket<Socket>::handshake(boost::system::error_code& ec,
const Time& timeout_or_deadline)
{
bool orig_io_timeout_mode = io_timeout_enabled(false);
const auto expire = scope_expire(timeout_or_deadline);
auto err = ssl_layer().handshake(boost::asio::ssl::stream_base::client, ec);
io_timeout_enabled(orig_io_timeout_mode);
return err;
}
template <typename Socket>
template <typename Time>
void stream_socket<Socket>::handshake(const Time& timeout_or_deadline)
{
boost::system::error_code ec;
handshake(ec, timeout_or_deadline);
if (ec) {
throw boost::system::system_error(ec);
}
}
template <typename Socket>
template <typename ConstBufferSequence>
std::size_t stream_socket<Socket>::send(const ConstBufferSequence& buffers, boost::system::error_code& ec,
const time_point_type& deadline)
{
std::size_t transfered_bytes = 0;
while (transfered_bytes != boost::asio::buffer_size(buffers)) {
transfered_bytes += write_some(buffers, ec, deadline);
if (ec) {
break;
}
}
return transfered_bytes;
}
template <typename Socket>
template <typename ConstBufferSequence>
std::size_t stream_socket<Socket>::send(const ConstBufferSequence& buffers, const time_point_type& deadline)
{
boost::system::error_code ec;
std::size_t transfered_bytes = send(buffers, ec, deadline);
if (ec) {
throw boost::system::system_error{ec, "Socket send() failed"};
}
return transfered_bytes;
}
template <typename Socket>
template <typename MutableBufferSequence>
std::size_t stream_socket<Socket>::receive(const MutableBufferSequence& buffers, boost::system::error_code& ec,
const time_point_type& deadline)
{
std::size_t transfered_bytes = 0;
while (transfered_bytes != boost::asio::buffer_size(buffers)) {
transfered_bytes += read_some(buffers, ec, deadline);
if (ec) {
break;
}
}
return transfered_bytes;
}
template <typename Socket>
template <typename MutableBufferSequence>
std::size_t stream_socket<Socket>::receive(const MutableBufferSequence& buffers, const time_point_type& deadline)
{
boost::system::error_code ec;
std::size_t transfered_bytes = receive(buffers, ec, deadline);
if (ec) {
throw boost::system::system_error{ec, "Socket receive() failed"};
}
return transfered_bytes;
}
/* Wrappers to write some data to an ssl::stream */
template <typename Socket>
template <typename ConstBufferSequence, typename Time>
std::size_t stream_socket<Socket>::write_some(const ConstBufferSequence& buffers, boost::system::error_code& ec,
const Time& timeout_or_deadline)
{
bool orig_io_timeout_mode = io_timeout_enabled(false);
const auto expire = scope_expire(timeout_or_deadline);
std::size_t n_bytes = ssl_layer().write_some(buffers, ec);
io_timeout_enabled(orig_io_timeout_mode);
return n_bytes;
}
template <typename Socket>
template <typename ConstBufferSequence, typename Time>
std::size_t stream_socket<Socket>::write_some(const ConstBufferSequence& buffers, const Time& timeout_or_deadline)
{
boost::system::error_code ec;
std::size_t transfered_bytes = write_some(buffers, ec, timeout_or_deadline);
if (ec) {
throw boost::system::system_error(ec);
}
return transfered_bytes;
}
/* Wrappers to read some data from an ssl::stream */
template <typename Socket>
template <typename MutableBufferSequence, typename Time>
std::size_t stream_socket<Socket>::read_some(const MutableBufferSequence& buffers, boost::system::error_code& ec,
const Time& timeout_or_deadline)
{
bool orig_io_timeout_mode = io_timeout_enabled(false);
const auto expire = scope_expire(timeout_or_deadline);
std::size_t n_bytes = ssl_layer().read_some(buffers, ec);
io_timeout_enabled(orig_io_timeout_mode);
return n_bytes;
}
template <typename Socket>
template <typename MutableBufferSequence, typename Time>
std::size_t stream_socket<Socket>::read_some(const MutableBufferSequence& buffers, const Time& timeout_or_deadline)
{
boost::system::error_code ec;
std::size_t transfered_bytes = read_some(buffers, ec, timeout_or_deadline);
if (ec) {
throw boost::system::system_error(ec);
}
return transfered_bytes;
}
} // namespace ssl
} // namespace stream_client