Я довольно поздно отвечаю на этот вопрос, но я надеюсь, что это поможет другим. Ответ Сэма содержит зародыш идеи, но, на мой взгляд, не уходит слишком далеко.
Идея возникла из наблюдения, что asio оборачивает сокет SSL в поток. Все, что делает это решение, это то, что оно аналогично оборачивает сокет без SSL.
Желаемый результат наличия единого внешнего интерфейса между сокетами SSL и не-SSL достигается тремя классами. Один, база, эффективно определяет интерфейс:
class Socket {
public:
virtual boost::asio::ip::tcp::socket &getSocketForAsio() = 0;
static Socket* create(boost::asio::io_service& iIoService, boost::asio::ssl::context *ipSslContext) {
// Obviously this has to be in a separate source file since it makes reference to subclasses
if (ipSslContext == nullptr) {
return new NonSslSocket(iIoService);
}
return new SslSocket(iIoService, *ipSslContext);
}
size_t _read(void *ipData, size_t iLength) {
return boost::asio::read(getSocketForAsio(), boost::asio::buffer(ipData, iLength));
}
size_t _write(const void *ipData, size_t iLength) {
return boost::asio::write(getSocketForAsio(), boost::asio::buffer(ipData, iLength));
}
};
Два подкласса обертывают сокеты SSL и не-SSL.
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SslSocket_t;
class SslSocket: public Socket, private SslSocket_t {
public:
SslSocket(boost::asio::io_service& iIoService, boost::asio::ssl::context &iSslContext) :
SslSocket_t(iIoService, iSslContext) {
}
private:
boost::asio::ip::tcp::socket &getSocketForAsio() {
return next_layer();
}
};
и
class NonSslSocket: public Socket, private Socket_t {
public:
NonSslSocket(boost::asio::io_service& iIoService) :
Socket_t(iIoService) {
}
private:
boost::asio::ip::tcp::socket &getSocketForAsio() {
return next_layer();
}
};
Каждый раз, когда вы вызываете функцию asio, используйте getSocketForAsio (), а не передавайте ссылку на объект Socket. Например:
boost::asio::async_read(pSocket->getSocketForAsio(),
boost::asio::buffer(&buffer, sizeof(buffer)),
boost::bind(&Connection::handleRead,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
Обратите внимание, что сокет хранится как указатель. Я не могу думать, как иначе полиморфизм может быть скрыт.
Наказанием (которое я не считаю хорошим) является дополнительный уровень косвенности, используемый для получения сокетов без SSL.