I am trying to write a https flex server, that can upgrade to websocket based on upgrade request. https class does the ssl handshake on std::shared_ptr<boost::beast::ssl_stream<boost::beast::tcp_stream>> m_ptls_stream

Now I need to transfer this stream to websocket class and transform it into type

std::shared_ptr<boost::beast::websocket::stream<
        boost::beast::ssl_stream<boost::beast::tcp_stream>>>

But for some reason the constructor of websocket stream doesn't accept a shared pointer, and I am unable to dereference the ssl_stream shared_ptr as I get the error that the copy constructor is deleted

Severity Code Description Project File Line Suppression State Error C2280 'boost::beast::ssl_streamboost::beast::tcp_stream::ssl_stream(const boost::beast::ssl_streamboost::beast::tcp_stream &)': attempting to reference a deleted function D:\Work\remote_pc\out\build\x64-Debug\remote_pc D:\Work\boost_1_73_0\boost\asio\impl\executor.hpp 218

void async_ws_client::add_stream(std::shared_ptr<boost::beast::ssl_stream<boost::beast::tcp_stream>>&& ptls_stream)
{   
    if (m_ptls_context)
    {       
        m_p_wss_stream = std::make_shared<
            boost::beast::websocket::stream<
            boost::beast::ssl_stream<
            boost::beast::tcp_stream>>>(std::move(*ptls_stream), *m_ptls_context);
    }
}

Feels like im missing something, unable to figure it out for a couple of days. Please help..!!

Also, if I do it this way

m_p_wss_stream = std::make_shared<
                boost::beast::websocket::stream<
                boost::beast::ssl_stream<
                boost::beast::tcp_stream>>>(std::move(ptls_stream->next_layer()),
                    *m_ptls_context);

The socket throws error : uninitialized when I do async_accept() on the stream after creating it.

2

There are 2 best solutions below

0
On

Dereferencing works. It's just that you can't construct the type you want from the arguments you pass.

Simplifying your code so it becomes readable and self-contained:

Live On Coliru

#include <boost/beast.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio.hpp>

namespace net   = boost::asio;
namespace beast = boost::beast;
namespace ws    = beast::websocket;
namespace ssl   = net::ssl;

struct async_ws_client {
    using tcp_stream = beast::tcp_stream;
    using ssl_stream = beast::ssl_stream<tcp_stream>;

    void add_stream(std::shared_ptr<ws::stream<tcp_stream>> ptls_stream)
    {
        if (m_ptls_context) {
            m_p_wss_stream = std::make_shared<ws::stream<ssl_stream>>(
                std::move(*ptls_stream), *m_ptls_context);
        }
    }

    std::shared_ptr<ws::stream<tcp_stream>> m_p_tls_stream;
    std::shared_ptr<ssl::context>           m_ptls_context;
    std::shared_ptr<ws::stream<ssl_stream>> m_p_wss_stream;
};

int main() {
}

The error novel hides the messages deep inside the shared_ptr construction forwarding machinery. However, the equivalent, much simpler code also will not compile, and for the same reason:

Live On Coliru

struct simple_async_ws_client {
    using tcp_stream = beast::tcp_stream;
    using ssl_stream = beast::ssl_stream<tcp_stream>;

    void add_stream(ws::stream<tcp_stream>&& tls_stream) {
        m_wss_stream.emplace(std::move(tls_stream), m_tls_context);
    }

    net::io_context        m_io;
    ws::stream<tcp_stream> m_tls_stream{m_io};

    ssl::context                          m_tls_context;
    std::optional<ws::stream<ssl_stream>> m_wss_stream;
};

A quick glance at your link tells me that ought to have been more like: Live On Coliru

    m_wss_stream.emplace(tls_stream.next_layer().release_socket(),
                         m_tls_context);

Now, you can translate that back to the fully shared_ptr-overgrown version of the code:

struct async_ws_client {
    using tcp_stream = beast::tcp_stream;
    using ssl_stream = beast::ssl_stream<tcp_stream>;

    void add_stream(std::shared_ptr<ws::stream<tcp_stream>> const& p_tls_stream)
    {
        if (m_p_tls_context) {
            m_p_wss_stream = std::make_shared<ws::stream<ssl_stream>>(
                p_tls_stream->next_layer().release_socket(), *m_p_tls_context);
        }
    }

    std::shared_ptr<ws::stream<tcp_stream>> m_p_tls_stream;

    std::shared_ptr<ssl::context>           m_p_tls_context;
    std::shared_ptr<ws::stream<ssl_stream>> m_p_wss_stream;
};

Note though that (ab)using shared pointers at this scale is a bit of an anti-pattern. You should probably considerunique_ptr or optional (for lazy-constructed types), or indeed enable_shared_from_this for the entire class, so all members have shared ownership by extension. This is also used in the linked documentation sample.

0
On

made a stupid mistake in understanding, cannot pass tls_context into websocket::stream constructor. The following code worked

void async_ws_client::add_stream(
std::shared_ptr<boost::beast::ssl_stream<boost::beast::tcp_stream>>&& ptls_stream)
    {           
        if (m_ptls_context)
        {
            m_p_wss_stream = std::make_shared<
                boost::beast::websocket::stream<
                boost::beast::ssl_stream<
                boost::beast::tcp_stream>>>(std::move(*ptls_stream));
         }
    }