Added boost header
This commit is contained in:
388
test/external/boost/asio/ssl/old/detail/openssl_context_service.hpp
vendored
Normal file
388
test/external/boost/asio/ssl/old/detail/openssl_context_service.hpp
vendored
Normal file
@@ -0,0 +1,388 @@
|
||||
//
|
||||
// ssl/old/detail/openssl_context_service.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
|
||||
// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
|
||||
#ifndef BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP
|
||||
#define BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/asio/detail/throw_error.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/ssl/context_base.hpp>
|
||||
#include <boost/asio/ssl/detail/openssl_init.hpp>
|
||||
#include <boost/asio/ssl/detail/openssl_types.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
namespace ssl {
|
||||
namespace old {
|
||||
namespace detail {
|
||||
|
||||
class openssl_context_service
|
||||
: public boost::asio::detail::service_base<openssl_context_service>
|
||||
{
|
||||
public:
|
||||
// The native type of the context.
|
||||
typedef ::SSL_CTX* impl_type;
|
||||
|
||||
// The type for the password callback function object.
|
||||
typedef boost::function<std::string(std::size_t,
|
||||
context_base::password_purpose)> password_callback_type;
|
||||
|
||||
// Constructor.
|
||||
openssl_context_service(boost::asio::io_service& io_service)
|
||||
: boost::asio::detail::service_base<openssl_context_service>(io_service)
|
||||
{
|
||||
}
|
||||
|
||||
// Destroy all user-defined handler objects owned by the service.
|
||||
void shutdown_service()
|
||||
{
|
||||
}
|
||||
|
||||
// Return a null context implementation.
|
||||
static impl_type null()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create a new context implementation.
|
||||
void create(impl_type& impl, context_base::method m)
|
||||
{
|
||||
switch (m)
|
||||
{
|
||||
#if defined(OPENSSL_NO_SSL2)
|
||||
case context_base::sslv2:
|
||||
case context_base::sslv2_client:
|
||||
case context_base::sslv2_server:
|
||||
boost::asio::detail::throw_error(boost::asio::error::invalid_argument);
|
||||
break;
|
||||
#else // defined(OPENSSL_NO_SSL2)
|
||||
case context_base::sslv2:
|
||||
impl = ::SSL_CTX_new(::SSLv2_method());
|
||||
break;
|
||||
case context_base::sslv2_client:
|
||||
impl = ::SSL_CTX_new(::SSLv2_client_method());
|
||||
break;
|
||||
case context_base::sslv2_server:
|
||||
impl = ::SSL_CTX_new(::SSLv2_server_method());
|
||||
break;
|
||||
#endif // defined(OPENSSL_NO_SSL2)
|
||||
case context_base::sslv3:
|
||||
impl = ::SSL_CTX_new(::SSLv3_method());
|
||||
break;
|
||||
case context_base::sslv3_client:
|
||||
impl = ::SSL_CTX_new(::SSLv3_client_method());
|
||||
break;
|
||||
case context_base::sslv3_server:
|
||||
impl = ::SSL_CTX_new(::SSLv3_server_method());
|
||||
break;
|
||||
case context_base::tlsv1:
|
||||
impl = ::SSL_CTX_new(::TLSv1_method());
|
||||
break;
|
||||
case context_base::tlsv1_client:
|
||||
impl = ::SSL_CTX_new(::TLSv1_client_method());
|
||||
break;
|
||||
case context_base::tlsv1_server:
|
||||
impl = ::SSL_CTX_new(::TLSv1_server_method());
|
||||
break;
|
||||
case context_base::sslv23:
|
||||
impl = ::SSL_CTX_new(::SSLv23_method());
|
||||
break;
|
||||
case context_base::sslv23_client:
|
||||
impl = ::SSL_CTX_new(::SSLv23_client_method());
|
||||
break;
|
||||
case context_base::sslv23_server:
|
||||
impl = ::SSL_CTX_new(::SSLv23_server_method());
|
||||
break;
|
||||
default:
|
||||
impl = ::SSL_CTX_new(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy a context implementation.
|
||||
void destroy(impl_type& impl)
|
||||
{
|
||||
if (impl != null())
|
||||
{
|
||||
if (impl->default_passwd_callback_userdata)
|
||||
{
|
||||
password_callback_type* callback =
|
||||
static_cast<password_callback_type*>(
|
||||
impl->default_passwd_callback_userdata);
|
||||
delete callback;
|
||||
impl->default_passwd_callback_userdata = 0;
|
||||
}
|
||||
|
||||
::SSL_CTX_free(impl);
|
||||
impl = null();
|
||||
}
|
||||
}
|
||||
|
||||
// Set options on the context.
|
||||
boost::system::error_code set_options(impl_type& impl,
|
||||
context_base::options o, boost::system::error_code& ec)
|
||||
{
|
||||
::SSL_CTX_set_options(impl, o);
|
||||
|
||||
ec = boost::system::error_code();
|
||||
return ec;
|
||||
}
|
||||
|
||||
// Set peer verification mode.
|
||||
boost::system::error_code set_verify_mode(impl_type& impl,
|
||||
context_base::verify_mode v, boost::system::error_code& ec)
|
||||
{
|
||||
::SSL_CTX_set_verify(impl, v, 0);
|
||||
|
||||
ec = boost::system::error_code();
|
||||
return ec;
|
||||
}
|
||||
|
||||
// Load a certification authority file for performing verification.
|
||||
boost::system::error_code load_verify_file(impl_type& impl,
|
||||
const std::string& filename, boost::system::error_code& ec)
|
||||
{
|
||||
if (::SSL_CTX_load_verify_locations(impl, filename.c_str(), 0) != 1)
|
||||
{
|
||||
ec = boost::asio::error::invalid_argument;
|
||||
return ec;
|
||||
}
|
||||
|
||||
ec = boost::system::error_code();
|
||||
return ec;
|
||||
}
|
||||
|
||||
// Add a directory containing certification authority files to be used for
|
||||
// performing verification.
|
||||
boost::system::error_code add_verify_path(impl_type& impl,
|
||||
const std::string& path, boost::system::error_code& ec)
|
||||
{
|
||||
if (::SSL_CTX_load_verify_locations(impl, 0, path.c_str()) != 1)
|
||||
{
|
||||
ec = boost::asio::error::invalid_argument;
|
||||
return ec;
|
||||
}
|
||||
|
||||
ec = boost::system::error_code();
|
||||
return ec;
|
||||
}
|
||||
|
||||
// Use a certificate from a file.
|
||||
boost::system::error_code use_certificate_file(impl_type& impl,
|
||||
const std::string& filename, context_base::file_format format,
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
int file_type;
|
||||
switch (format)
|
||||
{
|
||||
case context_base::asn1:
|
||||
file_type = SSL_FILETYPE_ASN1;
|
||||
break;
|
||||
case context_base::pem:
|
||||
file_type = SSL_FILETYPE_PEM;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
ec = boost::asio::error::invalid_argument;
|
||||
return ec;
|
||||
}
|
||||
}
|
||||
|
||||
if (::SSL_CTX_use_certificate_file(impl, filename.c_str(), file_type) != 1)
|
||||
{
|
||||
ec = boost::asio::error::invalid_argument;
|
||||
return ec;
|
||||
}
|
||||
|
||||
ec = boost::system::error_code();
|
||||
return ec;
|
||||
}
|
||||
|
||||
// Use a certificate chain from a file.
|
||||
boost::system::error_code use_certificate_chain_file(impl_type& impl,
|
||||
const std::string& filename, boost::system::error_code& ec)
|
||||
{
|
||||
if (::SSL_CTX_use_certificate_chain_file(impl, filename.c_str()) != 1)
|
||||
{
|
||||
ec = boost::asio::error::invalid_argument;
|
||||
return ec;
|
||||
}
|
||||
|
||||
ec = boost::system::error_code();
|
||||
return ec;
|
||||
}
|
||||
|
||||
// Use a private key from a file.
|
||||
boost::system::error_code use_private_key_file(impl_type& impl,
|
||||
const std::string& filename, context_base::file_format format,
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
int file_type;
|
||||
switch (format)
|
||||
{
|
||||
case context_base::asn1:
|
||||
file_type = SSL_FILETYPE_ASN1;
|
||||
break;
|
||||
case context_base::pem:
|
||||
file_type = SSL_FILETYPE_PEM;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
ec = boost::asio::error::invalid_argument;
|
||||
return ec;
|
||||
}
|
||||
}
|
||||
|
||||
if (::SSL_CTX_use_PrivateKey_file(impl, filename.c_str(), file_type) != 1)
|
||||
{
|
||||
ec = boost::asio::error::invalid_argument;
|
||||
return ec;
|
||||
}
|
||||
|
||||
ec = boost::system::error_code();
|
||||
return ec;
|
||||
}
|
||||
|
||||
// Use an RSA private key from a file.
|
||||
boost::system::error_code use_rsa_private_key_file(impl_type& impl,
|
||||
const std::string& filename, context_base::file_format format,
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
int file_type;
|
||||
switch (format)
|
||||
{
|
||||
case context_base::asn1:
|
||||
file_type = SSL_FILETYPE_ASN1;
|
||||
break;
|
||||
case context_base::pem:
|
||||
file_type = SSL_FILETYPE_PEM;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
ec = boost::asio::error::invalid_argument;
|
||||
return ec;
|
||||
}
|
||||
}
|
||||
|
||||
if (::SSL_CTX_use_RSAPrivateKey_file(
|
||||
impl, filename.c_str(), file_type) != 1)
|
||||
{
|
||||
ec = boost::asio::error::invalid_argument;
|
||||
return ec;
|
||||
}
|
||||
|
||||
ec = boost::system::error_code();
|
||||
return ec;
|
||||
}
|
||||
|
||||
// Use the specified file to obtain the temporary Diffie-Hellman parameters.
|
||||
boost::system::error_code use_tmp_dh_file(impl_type& impl,
|
||||
const std::string& filename, boost::system::error_code& ec)
|
||||
{
|
||||
::BIO* bio = ::BIO_new_file(filename.c_str(), "r");
|
||||
if (!bio)
|
||||
{
|
||||
ec = boost::asio::error::invalid_argument;
|
||||
return ec;
|
||||
}
|
||||
|
||||
::DH* dh = ::PEM_read_bio_DHparams(bio, 0, 0, 0);
|
||||
if (!dh)
|
||||
{
|
||||
::BIO_free(bio);
|
||||
ec = boost::asio::error::invalid_argument;
|
||||
return ec;
|
||||
}
|
||||
|
||||
::BIO_free(bio);
|
||||
int result = ::SSL_CTX_set_tmp_dh(impl, dh);
|
||||
::DH_free(dh);
|
||||
if (result != 1)
|
||||
{
|
||||
ec = boost::asio::error::invalid_argument;
|
||||
return ec;
|
||||
}
|
||||
|
||||
ec = boost::system::error_code();
|
||||
return ec;
|
||||
}
|
||||
|
||||
static int password_callback(char* buf, int size, int purpose, void* data)
|
||||
{
|
||||
using namespace std; // For strncat and strlen.
|
||||
|
||||
if (data)
|
||||
{
|
||||
password_callback_type* callback =
|
||||
static_cast<password_callback_type*>(data);
|
||||
std::string passwd = (*callback)(static_cast<std::size_t>(size),
|
||||
purpose ? context_base::for_writing : context_base::for_reading);
|
||||
*buf = '\0';
|
||||
strncat(buf, passwd.c_str(), size);
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set the password callback.
|
||||
template <typename Password_Callback>
|
||||
boost::system::error_code set_password_callback(impl_type& impl,
|
||||
Password_Callback callback, boost::system::error_code& ec)
|
||||
{
|
||||
// Allocate callback function object if not already present.
|
||||
if (impl->default_passwd_callback_userdata)
|
||||
{
|
||||
password_callback_type* callback_function =
|
||||
static_cast<password_callback_type*>(
|
||||
impl->default_passwd_callback_userdata);
|
||||
*callback_function = callback;
|
||||
}
|
||||
else
|
||||
{
|
||||
password_callback_type* callback_function =
|
||||
new password_callback_type(callback);
|
||||
impl->default_passwd_callback_userdata = callback_function;
|
||||
}
|
||||
|
||||
// Set the password callback.
|
||||
SSL_CTX_set_default_passwd_cb(impl,
|
||||
&openssl_context_service::password_callback);
|
||||
|
||||
ec = boost::system::error_code();
|
||||
return ec;
|
||||
}
|
||||
|
||||
private:
|
||||
// Ensure openssl is initialised.
|
||||
boost::asio::ssl::detail::openssl_init<> init_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace old
|
||||
} // namespace ssl
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP
|
||||
526
test/external/boost/asio/ssl/old/detail/openssl_operation.hpp
vendored
Normal file
526
test/external/boost/asio/ssl/old/detail/openssl_operation.hpp
vendored
Normal file
@@ -0,0 +1,526 @@
|
||||
//
|
||||
// ssl/old/detail/openssl_operation.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
|
||||
#ifndef BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_OPERATION_HPP
|
||||
#define BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_OPERATION_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/detail/socket_ops.hpp>
|
||||
#include <boost/asio/placeholders.hpp>
|
||||
#include <boost/asio/ssl/detail/openssl_types.hpp>
|
||||
#include <boost/asio/ssl/error.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
namespace ssl {
|
||||
namespace old {
|
||||
namespace detail {
|
||||
|
||||
typedef boost::function<int (::SSL*)> ssl_primitive_func;
|
||||
typedef boost::function<void (const boost::system::error_code&, int)>
|
||||
user_handler_func;
|
||||
|
||||
// Network send_/recv buffer implementation
|
||||
//
|
||||
//
|
||||
class net_buffer
|
||||
{
|
||||
static const int NET_BUF_SIZE = 16*1024 + 256; // SSL record size + spare
|
||||
|
||||
unsigned char buf_[NET_BUF_SIZE];
|
||||
unsigned char* data_start_;
|
||||
unsigned char* data_end_;
|
||||
|
||||
public:
|
||||
net_buffer()
|
||||
{
|
||||
data_start_ = data_end_ = buf_;
|
||||
}
|
||||
unsigned char* get_unused_start() { return data_end_; }
|
||||
unsigned char* get_data_start() { return data_start_; }
|
||||
size_t get_unused_len() { return (NET_BUF_SIZE - (data_end_ - buf_)); }
|
||||
size_t get_data_len() { return (data_end_ - data_start_); }
|
||||
void data_added(size_t count)
|
||||
{
|
||||
data_end_ += count;
|
||||
data_end_ = data_end_ > (buf_ + NET_BUF_SIZE)?
|
||||
(buf_ + NET_BUF_SIZE):
|
||||
data_end_;
|
||||
}
|
||||
void data_removed(size_t count)
|
||||
{
|
||||
data_start_ += count;
|
||||
if (data_start_ >= data_end_) reset();
|
||||
}
|
||||
void reset() { data_start_ = buf_; data_end_ = buf_; }
|
||||
bool has_data() { return (data_start_ < data_end_); }
|
||||
}; // class net_buffer
|
||||
|
||||
//
|
||||
// Operation class
|
||||
//
|
||||
//
|
||||
template <typename Stream>
|
||||
class openssl_operation
|
||||
{
|
||||
public:
|
||||
|
||||
// Constructor for asynchronous operations
|
||||
openssl_operation(ssl_primitive_func primitive,
|
||||
Stream& socket,
|
||||
net_buffer& recv_buf,
|
||||
SSL* session,
|
||||
BIO* ssl_bio,
|
||||
user_handler_func handler,
|
||||
boost::asio::io_service::strand& strand
|
||||
)
|
||||
: primitive_(primitive)
|
||||
, user_handler_(handler)
|
||||
, strand_(&strand)
|
||||
, recv_buf_(recv_buf)
|
||||
, socket_(socket)
|
||||
, ssl_bio_(ssl_bio)
|
||||
, session_(session)
|
||||
{
|
||||
write_ = boost::bind(
|
||||
&openssl_operation::do_async_write,
|
||||
this, boost::arg<1>(), boost::arg<2>()
|
||||
);
|
||||
read_ = boost::bind(
|
||||
&openssl_operation::do_async_read,
|
||||
this
|
||||
);
|
||||
handler_= boost::bind(
|
||||
&openssl_operation::async_user_handler,
|
||||
this, boost::arg<1>(), boost::arg<2>()
|
||||
);
|
||||
}
|
||||
|
||||
// Constructor for synchronous operations
|
||||
openssl_operation(ssl_primitive_func primitive,
|
||||
Stream& socket,
|
||||
net_buffer& recv_buf,
|
||||
SSL* session,
|
||||
BIO* ssl_bio)
|
||||
: primitive_(primitive)
|
||||
, strand_(0)
|
||||
, recv_buf_(recv_buf)
|
||||
, socket_(socket)
|
||||
, ssl_bio_(ssl_bio)
|
||||
, session_(session)
|
||||
{
|
||||
write_ = boost::bind(
|
||||
&openssl_operation::do_sync_write,
|
||||
this, boost::arg<1>(), boost::arg<2>()
|
||||
);
|
||||
read_ = boost::bind(
|
||||
&openssl_operation::do_sync_read,
|
||||
this
|
||||
);
|
||||
handler_ = boost::bind(
|
||||
&openssl_operation::sync_user_handler,
|
||||
this, boost::arg<1>(), boost::arg<2>()
|
||||
);
|
||||
}
|
||||
|
||||
// Start operation
|
||||
// In case of asynchronous it returns 0, in sync mode returns success code
|
||||
// or throws an error...
|
||||
int start()
|
||||
{
|
||||
int rc = primitive_( session_ );
|
||||
|
||||
bool is_operation_done = (rc > 0);
|
||||
// For connect/accept/shutdown, the operation
|
||||
// is done, when return code is 1
|
||||
// for write, it is done, when is retcode > 0
|
||||
// for read, is is done when retcode > 0
|
||||
|
||||
int error_code = !is_operation_done ?
|
||||
::SSL_get_error( session_, rc ) :
|
||||
0;
|
||||
int sys_error_code = ERR_get_error();
|
||||
|
||||
if (error_code == SSL_ERROR_SSL)
|
||||
return handler_(boost::system::error_code(
|
||||
sys_error_code, boost::asio::error::get_ssl_category()), rc);
|
||||
|
||||
bool is_read_needed = (error_code == SSL_ERROR_WANT_READ);
|
||||
bool is_write_needed = (error_code == SSL_ERROR_WANT_WRITE ||
|
||||
::BIO_ctrl_pending( ssl_bio_ ));
|
||||
bool is_shut_down_received =
|
||||
((::SSL_get_shutdown( session_ ) & SSL_RECEIVED_SHUTDOWN) ==
|
||||
SSL_RECEIVED_SHUTDOWN);
|
||||
bool is_shut_down_sent =
|
||||
((::SSL_get_shutdown( session_ ) & SSL_SENT_SHUTDOWN) ==
|
||||
SSL_SENT_SHUTDOWN);
|
||||
|
||||
if (is_shut_down_sent && is_shut_down_received
|
||||
&& is_operation_done && !is_write_needed)
|
||||
// SSL connection is shut down cleanly
|
||||
return handler_(boost::system::error_code(), 1);
|
||||
|
||||
if (is_shut_down_received && !is_operation_done)
|
||||
// Shutdown has been requested, while we were reading or writing...
|
||||
// abort our action...
|
||||
return handler_(boost::asio::error::shut_down, 0);
|
||||
|
||||
if (!is_operation_done && !is_read_needed && !is_write_needed
|
||||
&& !is_shut_down_sent)
|
||||
{
|
||||
// The operation has failed... It is not completed and does
|
||||
// not want network communication nor does want to send shutdown out...
|
||||
if (error_code == SSL_ERROR_SYSCALL)
|
||||
{
|
||||
return handler_(boost::system::error_code(
|
||||
sys_error_code, boost::asio::error::system_category), rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
return handler_(boost::system::error_code(
|
||||
sys_error_code, boost::asio::error::get_ssl_category()), rc);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_operation_done && !is_write_needed)
|
||||
{
|
||||
// We may have left over data that we can pass to SSL immediately
|
||||
if (recv_buf_.get_data_len() > 0)
|
||||
{
|
||||
// Pass the buffered data to SSL
|
||||
int written = ::BIO_write
|
||||
(
|
||||
ssl_bio_,
|
||||
recv_buf_.get_data_start(),
|
||||
recv_buf_.get_data_len()
|
||||
);
|
||||
|
||||
if (written > 0)
|
||||
{
|
||||
recv_buf_.data_removed(written);
|
||||
}
|
||||
else if (written < 0)
|
||||
{
|
||||
if (!BIO_should_retry(ssl_bio_))
|
||||
{
|
||||
// Some serios error with BIO....
|
||||
return handler_(boost::asio::error::no_recovery, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return start();
|
||||
}
|
||||
else if (is_read_needed || (is_shut_down_sent && !is_shut_down_received))
|
||||
{
|
||||
return read_();
|
||||
}
|
||||
}
|
||||
|
||||
// Continue with operation, flush any SSL data out to network...
|
||||
return write_(is_operation_done, rc);
|
||||
}
|
||||
|
||||
// Private implementation
|
||||
private:
|
||||
typedef boost::function<int (const boost::system::error_code&, int)>
|
||||
int_handler_func;
|
||||
typedef boost::function<int (bool, int)> write_func;
|
||||
typedef boost::function<int ()> read_func;
|
||||
|
||||
ssl_primitive_func primitive_;
|
||||
user_handler_func user_handler_;
|
||||
boost::asio::io_service::strand* strand_;
|
||||
write_func write_;
|
||||
read_func read_;
|
||||
int_handler_func handler_;
|
||||
|
||||
net_buffer send_buf_; // buffers for network IO
|
||||
|
||||
// The recv buffer is owned by the stream, not the operation, since there can
|
||||
// be left over bytes after passing the data up to the application, and these
|
||||
// bytes need to be kept around for the next read operation issued by the
|
||||
// application.
|
||||
net_buffer& recv_buf_;
|
||||
|
||||
Stream& socket_;
|
||||
BIO* ssl_bio_;
|
||||
SSL* session_;
|
||||
|
||||
//
|
||||
int sync_user_handler(const boost::system::error_code& error, int rc)
|
||||
{
|
||||
if (!error)
|
||||
return rc;
|
||||
|
||||
throw boost::system::system_error(error);
|
||||
}
|
||||
|
||||
int async_user_handler(boost::system::error_code error, int rc)
|
||||
{
|
||||
if (rc < 0)
|
||||
{
|
||||
if (!error)
|
||||
error = boost::asio::error::no_recovery;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
user_handler_(error, rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Writes bytes asynchronously from SSL to NET
|
||||
int do_async_write(bool is_operation_done, int rc)
|
||||
{
|
||||
int len = ::BIO_ctrl_pending( ssl_bio_ );
|
||||
if ( len )
|
||||
{
|
||||
// There is something to write into net, do it...
|
||||
len = (int)send_buf_.get_unused_len() > len?
|
||||
len:
|
||||
send_buf_.get_unused_len();
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
// In case our send buffer is full, we have just to wait until
|
||||
// previous send to complete...
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read outgoing data from bio
|
||||
len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
unsigned char *data_start = send_buf_.get_unused_start();
|
||||
send_buf_.data_added(len);
|
||||
|
||||
BOOST_ASSERT(strand_);
|
||||
boost::asio::async_write
|
||||
(
|
||||
socket_,
|
||||
boost::asio::buffer(data_start, len),
|
||||
strand_->wrap
|
||||
(
|
||||
boost::bind
|
||||
(
|
||||
&openssl_operation::async_write_handler,
|
||||
this,
|
||||
is_operation_done,
|
||||
rc,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if (!BIO_should_retry(ssl_bio_))
|
||||
{
|
||||
// Seems like fatal error
|
||||
// reading from SSL BIO has failed...
|
||||
handler_(boost::asio::error::no_recovery, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_operation_done)
|
||||
{
|
||||
// Finish the operation, with success
|
||||
handler_(boost::system::error_code(), rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// OPeration is not done and writing to net has been made...
|
||||
// start operation again
|
||||
start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void async_write_handler(bool is_operation_done, int rc,
|
||||
const boost::system::error_code& error, size_t bytes_sent)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
// Remove data from send buffer
|
||||
send_buf_.data_removed(bytes_sent);
|
||||
|
||||
if (is_operation_done)
|
||||
handler_(boost::system::error_code(), rc);
|
||||
else
|
||||
// Since the operation was not completed, try it again...
|
||||
start();
|
||||
}
|
||||
else
|
||||
handler_(error, rc);
|
||||
}
|
||||
|
||||
int do_async_read()
|
||||
{
|
||||
// Wait for new data
|
||||
BOOST_ASSERT(strand_);
|
||||
socket_.async_read_some
|
||||
(
|
||||
boost::asio::buffer(recv_buf_.get_unused_start(),
|
||||
recv_buf_.get_unused_len()),
|
||||
strand_->wrap
|
||||
(
|
||||
boost::bind
|
||||
(
|
||||
&openssl_operation::async_read_handler,
|
||||
this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred
|
||||
)
|
||||
)
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void async_read_handler(const boost::system::error_code& error,
|
||||
size_t bytes_recvd)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
recv_buf_.data_added(bytes_recvd);
|
||||
|
||||
// Pass the received data to SSL
|
||||
int written = ::BIO_write
|
||||
(
|
||||
ssl_bio_,
|
||||
recv_buf_.get_data_start(),
|
||||
recv_buf_.get_data_len()
|
||||
);
|
||||
|
||||
if (written > 0)
|
||||
{
|
||||
recv_buf_.data_removed(written);
|
||||
}
|
||||
else if (written < 0)
|
||||
{
|
||||
if (!BIO_should_retry(ssl_bio_))
|
||||
{
|
||||
// Some serios error with BIO....
|
||||
handler_(boost::asio::error::no_recovery, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// and try the SSL primitive again
|
||||
start();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error in network level...
|
||||
// SSL can't continue either...
|
||||
handler_(error, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Syncronous functions...
|
||||
int do_sync_write(bool is_operation_done, int rc)
|
||||
{
|
||||
int len = ::BIO_ctrl_pending( ssl_bio_ );
|
||||
if ( len )
|
||||
{
|
||||
// There is something to write into net, do it...
|
||||
len = (int)send_buf_.get_unused_len() > len?
|
||||
len:
|
||||
send_buf_.get_unused_len();
|
||||
|
||||
// Read outgoing data from bio
|
||||
len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
size_t sent_len = boost::asio::write(
|
||||
socket_,
|
||||
boost::asio::buffer(send_buf_.get_unused_start(), len)
|
||||
);
|
||||
|
||||
send_buf_.data_added(len);
|
||||
send_buf_.data_removed(sent_len);
|
||||
}
|
||||
else if (!BIO_should_retry(ssl_bio_))
|
||||
{
|
||||
// Seems like fatal error
|
||||
// reading from SSL BIO has failed...
|
||||
throw boost::system::system_error(boost::asio::error::no_recovery);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_operation_done)
|
||||
// Finish the operation, with success
|
||||
return rc;
|
||||
|
||||
// Operation is not finished, start again.
|
||||
return start();
|
||||
}
|
||||
|
||||
int do_sync_read()
|
||||
{
|
||||
size_t len = socket_.read_some
|
||||
(
|
||||
boost::asio::buffer(recv_buf_.get_unused_start(),
|
||||
recv_buf_.get_unused_len())
|
||||
);
|
||||
|
||||
// Write data to ssl
|
||||
recv_buf_.data_added(len);
|
||||
|
||||
// Pass the received data to SSL
|
||||
int written = ::BIO_write
|
||||
(
|
||||
ssl_bio_,
|
||||
recv_buf_.get_data_start(),
|
||||
recv_buf_.get_data_len()
|
||||
);
|
||||
|
||||
if (written > 0)
|
||||
{
|
||||
recv_buf_.data_removed(written);
|
||||
}
|
||||
else if (written < 0)
|
||||
{
|
||||
if (!BIO_should_retry(ssl_bio_))
|
||||
{
|
||||
// Some serios error with BIO....
|
||||
throw boost::system::system_error(boost::asio::error::no_recovery);
|
||||
}
|
||||
}
|
||||
|
||||
// Try the operation again
|
||||
return start();
|
||||
}
|
||||
}; // class openssl_operation
|
||||
|
||||
} // namespace detail
|
||||
} // namespace old
|
||||
} // namespace ssl
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_OPERATION_HPP
|
||||
573
test/external/boost/asio/ssl/old/detail/openssl_stream_service.hpp
vendored
Normal file
573
test/external/boost/asio/ssl/old/detail/openssl_stream_service.hpp
vendored
Normal file
@@ -0,0 +1,573 @@
|
||||
//
|
||||
// ssl/old/detail/stream_service.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com
|
||||
// Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
|
||||
#ifndef BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP
|
||||
#define BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#include <cstddef>
|
||||
#include <climits>
|
||||
#include <memory>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/ssl/basic_context.hpp>
|
||||
#include <boost/asio/ssl/stream_base.hpp>
|
||||
#include <boost/asio/ssl/old/detail/openssl_operation.hpp>
|
||||
#include <boost/asio/ssl/detail/openssl_types.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
namespace ssl {
|
||||
namespace old {
|
||||
namespace detail {
|
||||
|
||||
class openssl_stream_service
|
||||
: public boost::asio::detail::service_base<openssl_stream_service>
|
||||
{
|
||||
private:
|
||||
enum { max_buffer_size = INT_MAX };
|
||||
|
||||
//Base handler for asyncrhonous operations
|
||||
template <typename Stream>
|
||||
class base_handler
|
||||
{
|
||||
public:
|
||||
typedef boost::function<
|
||||
void (const boost::system::error_code&, size_t)> func_t;
|
||||
|
||||
base_handler(boost::asio::io_service& io_service)
|
||||
: op_(NULL)
|
||||
, io_service_(io_service)
|
||||
, work_(io_service)
|
||||
{}
|
||||
|
||||
void do_func(const boost::system::error_code& error, size_t size)
|
||||
{
|
||||
func_(error, size);
|
||||
}
|
||||
|
||||
void set_operation(openssl_operation<Stream>* op) { op_ = op; }
|
||||
void set_func(func_t func) { func_ = func; }
|
||||
|
||||
~base_handler()
|
||||
{
|
||||
delete op_;
|
||||
}
|
||||
|
||||
private:
|
||||
func_t func_;
|
||||
openssl_operation<Stream>* op_;
|
||||
boost::asio::io_service& io_service_;
|
||||
boost::asio::io_service::work work_;
|
||||
}; // class base_handler
|
||||
|
||||
// Handler for asynchronous IO (write/read) operations
|
||||
template<typename Stream, typename Handler>
|
||||
class io_handler
|
||||
: public base_handler<Stream>
|
||||
{
|
||||
public:
|
||||
io_handler(Handler handler, boost::asio::io_service& io_service)
|
||||
: base_handler<Stream>(io_service)
|
||||
, handler_(handler)
|
||||
{
|
||||
this->set_func(boost::bind(
|
||||
&io_handler<Stream, Handler>::handler_impl,
|
||||
this, boost::arg<1>(), boost::arg<2>() ));
|
||||
}
|
||||
|
||||
private:
|
||||
Handler handler_;
|
||||
void handler_impl(const boost::system::error_code& error, size_t size)
|
||||
{
|
||||
std::auto_ptr<io_handler<Stream, Handler> > this_ptr(this);
|
||||
handler_(error, size);
|
||||
}
|
||||
}; // class io_handler
|
||||
|
||||
// Handler for asyncrhonous handshake (connect, accept) functions
|
||||
template <typename Stream, typename Handler>
|
||||
class handshake_handler
|
||||
: public base_handler<Stream>
|
||||
{
|
||||
public:
|
||||
handshake_handler(Handler handler, boost::asio::io_service& io_service)
|
||||
: base_handler<Stream>(io_service)
|
||||
, handler_(handler)
|
||||
{
|
||||
this->set_func(boost::bind(
|
||||
&handshake_handler<Stream, Handler>::handler_impl,
|
||||
this, boost::arg<1>(), boost::arg<2>() ));
|
||||
}
|
||||
|
||||
private:
|
||||
Handler handler_;
|
||||
void handler_impl(const boost::system::error_code& error, size_t)
|
||||
{
|
||||
std::auto_ptr<handshake_handler<Stream, Handler> > this_ptr(this);
|
||||
handler_(error);
|
||||
}
|
||||
|
||||
}; // class handshake_handler
|
||||
|
||||
// Handler for asyncrhonous shutdown
|
||||
template <typename Stream, typename Handler>
|
||||
class shutdown_handler
|
||||
: public base_handler<Stream>
|
||||
{
|
||||
public:
|
||||
shutdown_handler(Handler handler, boost::asio::io_service& io_service)
|
||||
: base_handler<Stream>(io_service),
|
||||
handler_(handler)
|
||||
{
|
||||
this->set_func(boost::bind(
|
||||
&shutdown_handler<Stream, Handler>::handler_impl,
|
||||
this, boost::arg<1>(), boost::arg<2>() ));
|
||||
}
|
||||
|
||||
private:
|
||||
Handler handler_;
|
||||
void handler_impl(const boost::system::error_code& error, size_t)
|
||||
{
|
||||
std::auto_ptr<shutdown_handler<Stream, Handler> > this_ptr(this);
|
||||
handler_(error);
|
||||
}
|
||||
}; // class shutdown_handler
|
||||
|
||||
public:
|
||||
// The implementation type.
|
||||
typedef struct impl_struct
|
||||
{
|
||||
::SSL* ssl;
|
||||
::BIO* ext_bio;
|
||||
net_buffer recv_buf;
|
||||
} * impl_type;
|
||||
|
||||
// Construct a new stream socket service for the specified io_service.
|
||||
explicit openssl_stream_service(boost::asio::io_service& io_service)
|
||||
: boost::asio::detail::service_base<openssl_stream_service>(io_service),
|
||||
strand_(io_service)
|
||||
{
|
||||
}
|
||||
|
||||
// Destroy all user-defined handler objects owned by the service.
|
||||
void shutdown_service()
|
||||
{
|
||||
}
|
||||
|
||||
// Return a null stream implementation.
|
||||
impl_type null() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create a new stream implementation.
|
||||
template <typename Stream, typename Context_Service>
|
||||
void create(impl_type& impl, Stream& /*next_layer*/,
|
||||
basic_context<Context_Service>& context)
|
||||
{
|
||||
impl = new impl_struct;
|
||||
impl->ssl = ::SSL_new(context.impl());
|
||||
::SSL_set_mode(impl->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
||||
::SSL_set_mode(impl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
::BIO* int_bio = 0;
|
||||
impl->ext_bio = 0;
|
||||
::BIO_new_bio_pair(&int_bio, 8192, &impl->ext_bio, 8192);
|
||||
::SSL_set_bio(impl->ssl, int_bio, int_bio);
|
||||
}
|
||||
|
||||
// Destroy a stream implementation.
|
||||
template <typename Stream>
|
||||
void destroy(impl_type& impl, Stream& /*next_layer*/)
|
||||
{
|
||||
if (impl != 0)
|
||||
{
|
||||
::BIO_free(impl->ext_bio);
|
||||
::SSL_free(impl->ssl);
|
||||
delete impl;
|
||||
impl = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform SSL handshaking.
|
||||
template <typename Stream>
|
||||
boost::system::error_code handshake(impl_type& impl, Stream& next_layer,
|
||||
stream_base::handshake_type type, boost::system::error_code& ec)
|
||||
{
|
||||
try
|
||||
{
|
||||
openssl_operation<Stream> op(
|
||||
type == stream_base::client ?
|
||||
&ssl_wrap<mutex_type>::SSL_connect:
|
||||
&ssl_wrap<mutex_type>::SSL_accept,
|
||||
next_layer,
|
||||
impl->recv_buf,
|
||||
impl->ssl,
|
||||
impl->ext_bio);
|
||||
op.start();
|
||||
}
|
||||
catch (boost::system::system_error& e)
|
||||
{
|
||||
ec = e.code();
|
||||
return ec;
|
||||
}
|
||||
|
||||
ec = boost::system::error_code();
|
||||
return ec;
|
||||
}
|
||||
|
||||
// Start an asynchronous SSL handshake.
|
||||
template <typename Stream, typename Handler>
|
||||
void async_handshake(impl_type& impl, Stream& next_layer,
|
||||
stream_base::handshake_type type, Handler handler)
|
||||
{
|
||||
typedef handshake_handler<Stream, Handler> connect_handler;
|
||||
|
||||
connect_handler* local_handler =
|
||||
new connect_handler(handler, get_io_service());
|
||||
|
||||
openssl_operation<Stream>* op = new openssl_operation<Stream>
|
||||
(
|
||||
type == stream_base::client ?
|
||||
&ssl_wrap<mutex_type>::SSL_connect:
|
||||
&ssl_wrap<mutex_type>::SSL_accept,
|
||||
next_layer,
|
||||
impl->recv_buf,
|
||||
impl->ssl,
|
||||
impl->ext_bio,
|
||||
boost::bind
|
||||
(
|
||||
&base_handler<Stream>::do_func,
|
||||
local_handler,
|
||||
boost::arg<1>(),
|
||||
boost::arg<2>()
|
||||
),
|
||||
strand_
|
||||
);
|
||||
local_handler->set_operation(op);
|
||||
|
||||
strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
|
||||
}
|
||||
|
||||
// Shut down SSL on the stream.
|
||||
template <typename Stream>
|
||||
boost::system::error_code shutdown(impl_type& impl, Stream& next_layer,
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
try
|
||||
{
|
||||
openssl_operation<Stream> op(
|
||||
&ssl_wrap<mutex_type>::SSL_shutdown,
|
||||
next_layer,
|
||||
impl->recv_buf,
|
||||
impl->ssl,
|
||||
impl->ext_bio);
|
||||
op.start();
|
||||
}
|
||||
catch (boost::system::system_error& e)
|
||||
{
|
||||
ec = e.code();
|
||||
return ec;
|
||||
}
|
||||
|
||||
ec = boost::system::error_code();
|
||||
return ec;
|
||||
}
|
||||
|
||||
// Asynchronously shut down SSL on the stream.
|
||||
template <typename Stream, typename Handler>
|
||||
void async_shutdown(impl_type& impl, Stream& next_layer, Handler handler)
|
||||
{
|
||||
typedef shutdown_handler<Stream, Handler> disconnect_handler;
|
||||
|
||||
disconnect_handler* local_handler =
|
||||
new disconnect_handler(handler, get_io_service());
|
||||
|
||||
openssl_operation<Stream>* op = new openssl_operation<Stream>
|
||||
(
|
||||
&ssl_wrap<mutex_type>::SSL_shutdown,
|
||||
next_layer,
|
||||
impl->recv_buf,
|
||||
impl->ssl,
|
||||
impl->ext_bio,
|
||||
boost::bind
|
||||
(
|
||||
&base_handler<Stream>::do_func,
|
||||
local_handler,
|
||||
boost::arg<1>(),
|
||||
boost::arg<2>()
|
||||
),
|
||||
strand_
|
||||
);
|
||||
local_handler->set_operation(op);
|
||||
|
||||
strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
|
||||
}
|
||||
|
||||
// Write some data to the stream.
|
||||
template <typename Stream, typename Const_Buffers>
|
||||
std::size_t write_some(impl_type& impl, Stream& next_layer,
|
||||
const Const_Buffers& buffers, boost::system::error_code& ec)
|
||||
{
|
||||
size_t bytes_transferred = 0;
|
||||
try
|
||||
{
|
||||
boost::asio::const_buffer buffer =
|
||||
boost::asio::detail::buffer_sequence_adapter<
|
||||
boost::asio::const_buffer, Const_Buffers>::first(buffers);
|
||||
|
||||
std::size_t buffer_size = boost::asio::buffer_size(buffer);
|
||||
if (buffer_size > max_buffer_size)
|
||||
buffer_size = max_buffer_size;
|
||||
else if (buffer_size == 0)
|
||||
{
|
||||
ec = boost::system::error_code();
|
||||
return 0;
|
||||
}
|
||||
|
||||
boost::function<int (SSL*)> send_func =
|
||||
boost::bind(boost::type<int>(), &::SSL_write, boost::arg<1>(),
|
||||
boost::asio::buffer_cast<const void*>(buffer),
|
||||
static_cast<int>(buffer_size));
|
||||
openssl_operation<Stream> op(
|
||||
send_func,
|
||||
next_layer,
|
||||
impl->recv_buf,
|
||||
impl->ssl,
|
||||
impl->ext_bio
|
||||
);
|
||||
bytes_transferred = static_cast<size_t>(op.start());
|
||||
}
|
||||
catch (boost::system::system_error& e)
|
||||
{
|
||||
ec = e.code();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ec = boost::system::error_code();
|
||||
return bytes_transferred;
|
||||
}
|
||||
|
||||
// Start an asynchronous write.
|
||||
template <typename Stream, typename Const_Buffers, typename Handler>
|
||||
void async_write_some(impl_type& impl, Stream& next_layer,
|
||||
const Const_Buffers& buffers, Handler handler)
|
||||
{
|
||||
typedef io_handler<Stream, Handler> send_handler;
|
||||
|
||||
boost::asio::const_buffer buffer =
|
||||
boost::asio::detail::buffer_sequence_adapter<
|
||||
boost::asio::const_buffer, Const_Buffers>::first(buffers);
|
||||
|
||||
std::size_t buffer_size = boost::asio::buffer_size(buffer);
|
||||
if (buffer_size > max_buffer_size)
|
||||
buffer_size = max_buffer_size;
|
||||
else if (buffer_size == 0)
|
||||
{
|
||||
get_io_service().post(boost::asio::detail::bind_handler(
|
||||
handler, boost::system::error_code(), 0));
|
||||
return;
|
||||
}
|
||||
|
||||
send_handler* local_handler = new send_handler(handler, get_io_service());
|
||||
|
||||
boost::function<int (SSL*)> send_func =
|
||||
boost::bind(boost::type<int>(), &::SSL_write, boost::arg<1>(),
|
||||
boost::asio::buffer_cast<const void*>(buffer),
|
||||
static_cast<int>(buffer_size));
|
||||
|
||||
openssl_operation<Stream>* op = new openssl_operation<Stream>
|
||||
(
|
||||
send_func,
|
||||
next_layer,
|
||||
impl->recv_buf,
|
||||
impl->ssl,
|
||||
impl->ext_bio,
|
||||
boost::bind
|
||||
(
|
||||
&base_handler<Stream>::do_func,
|
||||
local_handler,
|
||||
boost::arg<1>(),
|
||||
boost::arg<2>()
|
||||
),
|
||||
strand_
|
||||
);
|
||||
local_handler->set_operation(op);
|
||||
|
||||
strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
|
||||
}
|
||||
|
||||
// Read some data from the stream.
|
||||
template <typename Stream, typename Mutable_Buffers>
|
||||
std::size_t read_some(impl_type& impl, Stream& next_layer,
|
||||
const Mutable_Buffers& buffers, boost::system::error_code& ec)
|
||||
{
|
||||
size_t bytes_transferred = 0;
|
||||
try
|
||||
{
|
||||
boost::asio::mutable_buffer buffer =
|
||||
boost::asio::detail::buffer_sequence_adapter<
|
||||
boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers);
|
||||
|
||||
std::size_t buffer_size = boost::asio::buffer_size(buffer);
|
||||
if (buffer_size > max_buffer_size)
|
||||
buffer_size = max_buffer_size;
|
||||
else if (buffer_size == 0)
|
||||
{
|
||||
ec = boost::system::error_code();
|
||||
return 0;
|
||||
}
|
||||
|
||||
boost::function<int (SSL*)> recv_func =
|
||||
boost::bind(boost::type<int>(), &::SSL_read, boost::arg<1>(),
|
||||
boost::asio::buffer_cast<void*>(buffer),
|
||||
static_cast<int>(buffer_size));
|
||||
openssl_operation<Stream> op(recv_func,
|
||||
next_layer,
|
||||
impl->recv_buf,
|
||||
impl->ssl,
|
||||
impl->ext_bio
|
||||
);
|
||||
|
||||
bytes_transferred = static_cast<size_t>(op.start());
|
||||
}
|
||||
catch (boost::system::system_error& e)
|
||||
{
|
||||
ec = e.code();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ec = boost::system::error_code();
|
||||
return bytes_transferred;
|
||||
}
|
||||
|
||||
// Start an asynchronous read.
|
||||
template <typename Stream, typename Mutable_Buffers, typename Handler>
|
||||
void async_read_some(impl_type& impl, Stream& next_layer,
|
||||
const Mutable_Buffers& buffers, Handler handler)
|
||||
{
|
||||
typedef io_handler<Stream, Handler> recv_handler;
|
||||
|
||||
boost::asio::mutable_buffer buffer =
|
||||
boost::asio::detail::buffer_sequence_adapter<
|
||||
boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers);
|
||||
|
||||
std::size_t buffer_size = boost::asio::buffer_size(buffer);
|
||||
if (buffer_size > max_buffer_size)
|
||||
buffer_size = max_buffer_size;
|
||||
else if (buffer_size == 0)
|
||||
{
|
||||
get_io_service().post(boost::asio::detail::bind_handler(
|
||||
handler, boost::system::error_code(), 0));
|
||||
return;
|
||||
}
|
||||
|
||||
recv_handler* local_handler = new recv_handler(handler, get_io_service());
|
||||
|
||||
boost::function<int (SSL*)> recv_func =
|
||||
boost::bind(boost::type<int>(), &::SSL_read, boost::arg<1>(),
|
||||
boost::asio::buffer_cast<void*>(buffer),
|
||||
static_cast<int>(buffer_size));
|
||||
|
||||
openssl_operation<Stream>* op = new openssl_operation<Stream>
|
||||
(
|
||||
recv_func,
|
||||
next_layer,
|
||||
impl->recv_buf,
|
||||
impl->ssl,
|
||||
impl->ext_bio,
|
||||
boost::bind
|
||||
(
|
||||
&base_handler<Stream>::do_func,
|
||||
local_handler,
|
||||
boost::arg<1>(),
|
||||
boost::arg<2>()
|
||||
),
|
||||
strand_
|
||||
);
|
||||
local_handler->set_operation(op);
|
||||
|
||||
strand_.post(boost::bind(&openssl_operation<Stream>::start, op));
|
||||
}
|
||||
|
||||
// Peek at the incoming data on the stream.
|
||||
template <typename Stream, typename Mutable_Buffers>
|
||||
std::size_t peek(impl_type& /*impl*/, Stream& /*next_layer*/,
|
||||
const Mutable_Buffers& /*buffers*/, boost::system::error_code& ec)
|
||||
{
|
||||
ec = boost::system::error_code();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Determine the amount of data that may be read without blocking.
|
||||
template <typename Stream>
|
||||
std::size_t in_avail(impl_type& /*impl*/, Stream& /*next_layer*/,
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
ec = boost::system::error_code();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::asio::io_service::strand strand_;
|
||||
|
||||
typedef boost::asio::detail::mutex mutex_type;
|
||||
|
||||
template<typename Mutex>
|
||||
struct ssl_wrap
|
||||
{
|
||||
static Mutex ssl_mutex_;
|
||||
|
||||
static int SSL_accept(SSL *ssl)
|
||||
{
|
||||
typename Mutex::scoped_lock lock(ssl_mutex_);
|
||||
return ::SSL_accept(ssl);
|
||||
}
|
||||
|
||||
static int SSL_connect(SSL *ssl)
|
||||
{
|
||||
typename Mutex::scoped_lock lock(ssl_mutex_);
|
||||
return ::SSL_connect(ssl);
|
||||
}
|
||||
|
||||
static int SSL_shutdown(SSL *ssl)
|
||||
{
|
||||
typename Mutex::scoped_lock lock(ssl_mutex_);
|
||||
return ::SSL_shutdown(ssl);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template<typename Mutex>
|
||||
Mutex openssl_stream_service::ssl_wrap<Mutex>::ssl_mutex_;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace old
|
||||
} // namespace ssl
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP
|
||||
Reference in New Issue
Block a user