Using SSL sockets and non-SSL sockets simultaneously in Boost.Asio?

前端 未结 4 1710
盖世英雄少女心
盖世英雄少女心 2020-12-24 06:58

I\'m in the process of converting a library to Boost.Asio (which has worked very well so far), but I\'ve hit something of a stumbling block with regards to a design decision

4条回答
  •  攒了一身酷
    2020-12-24 07:48

    I'm rather late in answering this question, but I hope this will help others. Sam's answer contains the germ of an idea, but doesn't quit go far enough in my opinion.

    The idea came about from the observation that asio wraps an SSL socket in a stream. All this solution does is that it wraps the non-SSL socket similarly.

    The desired result of having a uniform external interface between SSL and non-SSL sockets is done with three classes. One, the base, effectively defines the interface:

    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));
        }
    };
    

    Two sub-classes wrap SSL and non-SSL sockets.

    typedef boost::asio::ssl::stream 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();
        }
    };
    

    and

    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();
        }
    };
    

    Every time you call an asio function use getSocketForAsio(), rather than pass a reference to the Socket object. For example:

    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));
    

    Notice that the Socket is stored as pointer. I cannot think how else the polymorphism can be hidden.

    The penalty (which I don't think great) is the extra level of indirection used to obtain non-SSL sockets.

提交回复
热议问题