Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用boost beast和openssl进行异步握手时的内存泄漏_C++_Memory Leaks_Openssl_Boost Asio_Boost Beast - Fatal编程技术网

C++ 使用boost beast和openssl进行异步握手时的内存泄漏

C++ 使用boost beast和openssl进行异步握手时的内存泄漏,c++,memory-leaks,openssl,boost-asio,boost-beast,C++,Memory Leaks,Openssl,Boost Asio,Boost Beast,我正在使用OpenSSL 1.1.1b和Boost 1.68创建一个使用https的简单服务器 我遵循boost beast提供的示例,尤其是 应用程序似乎工作正常。我可以接受https会话,也可以接受wss会话 问题是当我退出应用程序时,视觉泄漏检测器发现16个内存泄漏,目标是: c:\openssl-1.1.1b\crypto\mem.c (233): abc.exe!CRYPTO_zalloc c:\openssl-1.1.1b\crypto\err\err.c (716): ab

我正在使用OpenSSL 1.1.1b和Boost 1.68创建一个使用https的简单服务器

我遵循boost beast提供的示例,尤其是

应用程序似乎工作正常。我可以接受https会话,也可以接受wss会话

问题是当我退出应用程序时,视觉泄漏检测器发现16个内存泄漏,目标是:

c:\openssl-1.1.1b\crypto\mem.c (233): abc.exe!CRYPTO_zalloc
    c:\openssl-1.1.1b\crypto\err\err.c (716): abc.exe!ERR_get_state + 0x17 bytes
    c:\openssl-1.1.1b\crypto\err\err.c (443): abc.exe!ERR_clear_error + 0x5 bytes
    c:\usr\work\abc_repo\ext\boost_1_68_0\boost\asio\ssl\detail\impl\engine.ipp (235): abc.exe!boost::asio::ssl::detail::engine::perform
    c:\usr\work\abc_repo\ext\boost_1_68_0\boost\asio\ssl\detail\impl\engine.ipp (137): abc.exe!boost::asio::ssl::detail::engine::handshake
我修改了原始boost beast代码中http会话的模式,但它应该执行完全相同的操作

我试图了解内存泄漏是否会随着连接数的增加而增加,但似乎不是这样。我不明白如何解决这个问题

遵循我使用的代码。 首先是一个基于http的会话类

class CApplicationServerBaseHttpSession
{

public:
    std::shared_ptr<CApplicationServerSharedState> m_state = nullptr;
    CApplicationServerHttpQueue m_queue;

    // The parser is stored in an optional container so we can
    // construct it from scratch it at the beginning of each new message.
    boost::optional<boost::beast::http::request_parser<boost::beast::http::string_body>> parser_;

protected:
    boost::asio::steady_timer m_timer;
    boost::beast::flat_buffer buffer_;
    boost::log::sources::severity_channel_logger<boost::log::trivial::severity_level> m_Logger{boost::log::keywords::channel = LOG_APPLICATION_SERVER_CHANNEL_ID};
    boost::asio::strand<boost::asio::io_context::executor_type> m_strand;

public:
    // Construct the session
    CApplicationServerBaseHttpSession(
        boost::asio::io_context& ioc,
        boost::beast::flat_buffer buffer,
        std::shared_ptr<CApplicationServerSharedState> const& state)
        : m_state(state)
        , m_strand(ioc.get_executor())
        , m_timer(ioc,
            (std::chrono::steady_clock::time_point::max)()
        )
        , m_queue(*this)
        , buffer_(std::move(buffer))
    {
    }

    void DoRead();

    void OnRead(boost::system::error_code ec);

    void OnWrite(boost::system::error_code ec, bool close);

    virtual void WriteRequestStringBody(boost::beast::http::response<boost::beast::http::string_body> & msg) = 0;
    virtual void WriteRequestFileBody(boost::beast::http::response<boost::beast::http::file_body> & msg) = 0;

protected:

    virtual void ReadRequest() = 0;


    virtual void DoEof() = 0;

    virtual std::string GetRemoteAddress() = 0;

    virtual void MakeWebSocketSession(boost::beast::http::request<boost::beast::http::string_body> req) = 0;
};
class CApplicationServerBaseHttpSession
{
公众:
std::shared_ptr m_state=nullptr;
CAPApplicationServerHttpQueue m_队列;
//解析器存储在一个可选的容器中,因此我们可以
//从头开始构建它,并在每个新消息的开头创建它。
boost::可选解析器;
受保护的:
升压::asio::稳定定时器m定时器;
boost::beast::扁平缓冲区;
boost::log::sources::severity\u channel\u logger m\u logger{boost::log::keywords::channel=log\u APPLICATION\u SERVER\u channel\u ID};
boost::asio::strand m_strand;
公众:
//构建会话
CapApplicationServerBaseHttpSession(
boost::asio::io_上下文和ioc,
boost::beast::flat_缓冲区,
std::共享(ptr常量和状态)
:m_状态(状态)
,m_strand(ioc.get_executor())
,m_定时器(国际奥委会,
(标准::时钟::稳定时钟::时间点::最大值)()
)
,m_队列(*此)
,缓冲区(标准::移动(缓冲区))
{
}
void DoRead();
void OnRead(boost::system::error_code ec);
void OnWrite(boost::system::error_code ec,bool close);
虚拟void WriteRequestStringBody(boost::beast::http::response&msg)=0;
虚拟void WriteRequestFileBody(boost::beast::http::response&msg)=0;
受保护的:
虚拟void ReadRequest()=0;
虚空DoEof()=0;
虚拟std::string GetRemoteAddress()=0;
虚拟void MakeWebSocketSession(boost::beast::http::request req)=0;
};
以下是实施情况:

void CApplicationServerBaseHttpSession::DoRead()
{
    // Set the timer
    m_timer.expires_after(std::chrono::seconds(OCV_HTTP_SESSION_TIMER_EXPIRE_AFTER));

    // Construct a new parser for each message
    parser_.emplace();

    // Apply a reasonable limit to the allowed size
    // of the body in bytes to prevent abuse.
    parser_->body_limit(HTTP_BODY_LIMIT);

    this->ReadRequest();

}

void CApplicationServerBaseHttpSession::OnRead(boost::system::error_code ec)
{
// Happens when the timer closes the socket
    if(ec == boost::asio::error::operation_aborted)
        return;

    // This means they closed the connection
    if(ec == http::error::end_of_stream)
        return this->DoEof();

    if(ec == boost::asio::ssl::error::stream_truncated){
        // "stream truncated" means that the other end closed the connection abruptly.
        return warning(ec, "Http read", m_Logger);
    }

    if(ec)
        return fail(ec, "Http read", m_Logger);

    // See if it is a WebSocket Upgrade
    if(websocket::is_upgrade(parser_->get())) {

        // Get a websocket request handler to execute operation as authentication and authorization
        // If these steps are allowed than the websocket session will be started
        std::shared_ptr<CApplicationServerWsApiBase> endpointWs = m_state->GetEndpointWs(parser_->get().target().to_string());

        if(endpointWs) {
            int endpointErrorDefault = endpointWs->HandleRequest(parser_->get());
            if(endpointErrorDefault > 0) { // Success Auth

                // Make timer expire immediately, by setting expiry to time_point::min we can detect
                // the upgrade to websocket in the timer handler
                m_timer.expires_at((std::chrono::steady_clock::time_point::min)());

                // Transfer the stream to a new WebSocket session
                return MakeWebSocketSession(parser_->release());

            } else {
                // Authentication or Authorization failed
                m_queue(endpointWs->GetResponseError(parser_->get(), endpointErrorDefault));
                return;
            }
        } else {
            // Wrong endpoint called: BadRequest
            std::shared_ptr<CApplicationServerApiBase> endpoint = m_state->GetEndpoint(ApiURI::REQUEST_NOT_IMPLEMENTED);
            if(endpoint) {
                endpoint->HandleRequest(m_state->GetDocRoot(), parser_->release(), m_queue);
            }
            return;
        }

    }

    BOOST_LOG_SEV(m_Logger, boost::log::trivial::trace) <<
        "Request From: " <<
        this->GetRemoteAddress() <<
        " Request Target: " <<
        parser_->get().target().to_string();

    std::shared_ptr<CApplicationServerApiBase> endpoint = m_state->GetEndpoint(parser_->get().target().to_string());

    if(endpoint) {
        endpoint->HandleRequest(m_state->GetDocRoot(), parser_->release(), m_queue);
    }


    // If we aren't at the queue limit, try to pipeline another request
    if(!m_queue.IsFull()) {
        DoRead();
    }
}

void  CApplicationServerBaseHttpSession::OnWrite(boost::system::error_code ec, bool close)
{
// Happens when the timer closes the socket
    if(ec == boost::asio::error::operation_aborted)
        return;

    if(ec)
        return fail(ec, "write", m_Logger);

    if(close) {
        // This means we should close the connection, usually because
        // the response indicated the "Connection: close" semantic.
        return this->DoEof();
    }

    // Inform the queue that a write completed
    if(m_queue.OnWrite()) {
        // Read another request
        DoRead();
    }
}
void CApplicationServerBaseHttpSession::DoRead()
{
//设置计时器
m_timer.expires_after(std::chrono::seconds(OCV_HTTP_SESSION_timer_EXPIRE_after));
//为每条消息构造一个新的解析器
解析器uu.emplace();
//对允许的尺寸施加合理的限制
//以字节为单位的正文,以防止滥用。
解析器->body\u limit(HTTP\u body\u limit);
此->ReadRequest();
}
void CApplicationServerBaseHttpSession::OnRead(boost::system::error_code ec)
{
//当计时器关闭套接字时发生
如果(ec==boost::asio::error::operation_中止)
返回;
//这意味着他们关闭了连接
if(ec==http::error::结束\u流的\u)
返回此->DoEof();
if(ec==boost::asio::ssl::error::stream\u截断){
//“流截断”表示另一端突然关闭连接。
返回警告(ec,“Http读取”,m_记录器);
}
国际单项体育联合会(欧共体)
返回失败(ec,“Http读取”,m_记录器);
//查看是否是WebSocket升级
if(websocket::is_升级(解析器->get()){
//获取websocket请求处理程序以执行操作作为身份验证和授权
//如果允许执行这些步骤,则将启动websocket会话
std::shared_ptr endpointWs=m_state->GetEndpointWs(解析器\->get().target().to_string());
if(endpointWs){
int endpointErrorDefault=endpointWs->HandleRequest(解析器\->get());
如果(endpointErrorDefault>0){//Success Auth
//使计时器立即过期,通过将过期设置为time_point::min,我们可以检测到
//在计时器处理程序中升级到websocket
m_timer.expires_在((标准::时钟::稳定时钟::时间点::分钟)();
//将流传输到新的WebSocket会话
返回MakeWebSocketSession(解析器->release());
}否则{
//身份验证或授权失败
m_队列(endpointWs->GetResponseError(解析器->get(),endpointErrorDefault));
返回;
}
}否则{
//调用了错误的端点:BadRequest
std::shared\u ptr endpoint=m\u state->GetEndpoint(ApiURI::REQUEST\u未实现);
如果(端点){
端点->HandlerRequest(m_状态->GetDocRoot(),解析器->释放(),m_队列);
}
返回;
}
}
BOOST_LOG_SEV(m_Logger,BOOST::LOG::trival::trace)get().target().to_string());
如果(端点){
端点->HandlerRequest(m_状态->GetDocRoot(),解析器->释放(),m_队列);
}
//如果我们没有达到队列限制,请尝试通过管道发送另一个请求
如果(!m_queue.IsFull()){
多里德();
}
}
void CApplicationServerBaseHttpSession::OnWrite(boost::system::error_code ec,bool close)
{
//当计时器关闭套接字时发生
如果(ec==boost::asio::error::operation_中止)
返回;
国际单项体育联合会(欧共体)
返回失败(ec,“写入”,m_记录器);
如果(关闭){
//这意味着我们应该关闭连接,通常是因为
//响应表示“连接:关闭”语义。
返回此->DoEof();
}
//通知队列写入已完成
if(m_queue.OnWrite()){
//阅读另一个请求
多里德();
}
}
https会话:

class COcvApplicationServerHttpSessionSSL 
    : public std::enable_shared_from_this<COcvApplicationServerHttpSessionSSL>
    , public CApplicationServerBaseHttpSession
{

public:


public:
    COcvApplicationServerHttpSessionSSL(boost::asio::ip::tcp::socket&& socket,boost::asio::ssl::context& ctx, boost::beast::flat_buffer&& buffer, std::shared_ptr<CApplicationServerSharedState> const& state);
    ~COcvApplicationServerHttpSessionSSL();

    // Called by the base class
    boost::beast::ssl_stream<boost::asio::ip::tcp::socket>& Stream();
    boost::beast::ssl_stream<boost::asio::ip::tcp::socket> ReleaseStream();
    void DoTimeout();


    // Start the asynchronous operation
    void Run();

    void OnHandshake(boost::system::error_code ec, std::size_t bytes_used);

    void OnShutdown(boost::system::error_code ec);

    void OnTimer(boost::system::error_code ec);

private:

public:
    boost::beast::ssl_stream<boost::asio::ip::tcp::socket> m_stream;
    bool m_eof = false;

protected:

    // Inherited via COcvApplicationServerBaseHttpSession
    virtual void ReadRequest() override;

    virtual void WriteRequestStringBody(boost::beast::http::response<boost::beast::http::string_body> & msg) override;
    virtual void WriteRequestFileBody(boost::beast::http::response<boost::beast::http::file_body> & msg) override;

    virtual void DoEof() override;

    virtual std::string GetRemoteAddress() override;

    virtual void MakeWebSocketSession(boost::beast::http::request<boost::beast::http::string_body> req) override;

};
类CocvaApplicationServerHttpSessionsL
:public std::从\u中启用\u共享\u
,公共CAPApplicationServerBaseHttpSession
{
公众:
公众:
CocvaApplicationServerHttpSessionsL(boost::asio::ip::tcp::socket&socket,boost::asio::ssl::context&ctx,boost::beast::flat_buffer&buffer,std::shared_ptr const
COcvApplicationServerHttpSessionSSL::COcvApplicationServerHttpSessionSSL(tcp::socket&& socket, ssl::context & ctx, beast::flat_buffer&& buffer, std::shared_ptr<CApplicationServerSharedState> const & state)
    : CApplicationServerBaseHttpSession(
        socket.get_executor().context(),
        std::move(buffer),
        state)
    , m_stream(std::move(socket), ctx)
{
}

COcvApplicationServerHttpSessionSSL::~COcvApplicationServerHttpSessionSSL()
{
}

beast::ssl_stream<tcp::socket> & COcvApplicationServerHttpSessionSSL::Stream()
{
    return m_stream;
}

beast::ssl_stream<tcp::socket> COcvApplicationServerHttpSessionSSL::ReleaseStream()
{
    return std::move(m_stream);
}

void COcvApplicationServerHttpSessionSSL::DoTimeout()
{
    // If this is true it means we timed out performing the shutdown
    if(m_eof)
        return;

    // Start the timer again
    m_timer.expires_at(
        (std::chrono::steady_clock::time_point::max)());
    OnTimer({});
    DoEof();
}

std::string COcvApplicationServerHttpSessionSSL::GetRemoteAddress()
{
    return Stream().next_layer().remote_endpoint().address().to_string();
}

void COcvApplicationServerHttpSessionSSL::MakeWebSocketSession(boost::beast::http::request<boost::beast::http::string_body> req)
{
    std::make_shared<CApplicationServerWebSocketSessionSSL>(
        std::move(m_stream), m_state)->Run(std::move(req));
}

void COcvApplicationServerHttpSessionSSL::Run()
{
    // Make sure we run on the strand
    if(!m_strand.running_in_this_thread())
        return boost::asio::post(
            boost::asio::bind_executor(
                m_strand,
                std::bind(
                    &COcvApplicationServerHttpSessionSSL::Run,
                    shared_from_this())));

    // Run the timer. The timer is operated
    // continuously, this simplifies the code.
    OnTimer({});

    // Set the timer
    m_timer.expires_after(std::chrono::seconds(OCV_HTTP_SESSION_TIMER_EXPIRE_AFTER));

    // Perform the SSL handshake
    // Note, this is the buffered version of the handshake.
    m_stream.async_handshake(
        ssl::stream_base::server,
        buffer_.data(),
        boost::asio::bind_executor(
            m_strand,
            std::bind(
                &COcvApplicationServerHttpSessionSSL::OnHandshake,
                shared_from_this(),
                std::placeholders::_1,
                std::placeholders::_2)));
}

void COcvApplicationServerHttpSessionSSL::OnHandshake(boost::system::error_code ec, std::size_t bytes_used)
{
    // Happens when the handshake times out
    if(ec == boost::asio::error::operation_aborted)
        return;

    if(ec)
        return fail(ec, "handshake", m_Logger);

    // Consume the portion of the buffer used by the handshake
    buffer_.consume(bytes_used);

    DoRead();
}

void COcvApplicationServerHttpSessionSSL::OnShutdown(boost::system::error_code ec)
{
    // Happens when the shutdown times out
    if(ec == boost::asio::error::operation_aborted || ec == boost::asio::ssl::error::stream_truncated)
        return;

    if(ec)
        return fail(ec, "shutdown HTTPS", m_Logger);

    // At this point the connection is closed gracefully
}


void COcvApplicationServerHttpSessionSSL::OnTimer(boost::system::error_code ec)
{
    if(ec && ec != boost::asio::error::operation_aborted)
            return fail(ec, "timer", m_Logger);

        // Check if this has been upgraded to Websocket
        if(m_timer.expires_at() == (std::chrono::steady_clock::time_point::min)())
            return;

        // Verify that the timer really expired since the deadline may have moved.
        if(m_timer.expiry() <= std::chrono::steady_clock::now())
            return DoTimeout();

        // Wait on the timer
        m_timer.async_wait(
            boost::asio::bind_executor(
                m_strand,
                std::bind(
                    &COcvApplicationServerHttpSessionSSL::OnTimer,
                    shared_from_this(),
                    std::placeholders::_1)));
}

void COcvApplicationServerHttpSessionSSL::ReadRequest()
{
    // Read a request
    http::async_read(
        Stream(),
        buffer_,
        *parser_,
        boost::asio::bind_executor(
            m_strand,
            std::bind(
                &CApplicationServerBaseHttpSession::OnRead,
                shared_from_this(),
                std::placeholders::_1)));
}

void COcvApplicationServerHttpSessionSSL::WriteRequestStringBody(boost::beast::http::response<boost::beast::http::string_body> & msg)
{
    boost::beast::http::async_write(
        Stream(),
        msg,
        boost::asio::bind_executor(
            m_strand,
            std::bind(
                &CApplicationServerBaseHttpSession::OnWrite,
                shared_from_this(),
                std::placeholders::_1,
                msg.need_eof()
            )
        )
    );
}

void COcvApplicationServerHttpSessionSSL::WriteRequestFileBody(boost::beast::http::response<boost::beast::http::file_body> & msg)
{
    boost::beast::http::async_write(
        Stream(),
        msg,
        boost::asio::bind_executor(
            m_strand,
            std::bind(
                &CApplicationServerBaseHttpSession::OnWrite,
                shared_from_this(),
                std::placeholders::_1,
                msg.need_eof()
            )
        )
    );
}

void COcvApplicationServerHttpSessionSSL::DoEof()
{
    m_eof = true;

    // Set the timer
    m_timer.expires_after(std::chrono::seconds(OCV_HTTP_SESSION_TIMER_EXPIRE_DO_EOF));

    // Perform the SSL shutdown
    m_stream.async_shutdown(
        boost::asio::bind_executor(
            m_strand,
            std::bind(
                &COcvApplicationServerHttpSessionSSL::OnShutdown,
                shared_from_this(),
                std::placeholders::_1)));
}
c:\openssl-1.1.1b\crypto\mem.c (233): abc.exe!CRYPTO_zalloc
c:\openssl-1.1.1b\crypto\err\err.c (716): abc.exe!ERR_get_state + 0x17 bytes
c:\openssl-1.1.1b\crypto\err\err.c (443): abc.exe!ERR_clear_error + 0x5 bytes
c:\usr\work\abc_repo\ext\boost_1_68_0\boost\asio\ssl\detail\impl\engine.ipp (235): abc.exe!boost::asio::ssl::detail::engine::perform
c:\usr\work\abc_repo\ext\boost_1_68_0\boost\asio\ssl\detail\impl\engine.ipp (137): abc.exe!boost::asio::ssl::detail::engine::handshake
c:\usr\work\abc_repo\ext\boost_1_68_0\boost\asio\ssl\detail\buffered_handshake_op.hpp (70): abc.exe!boost::asio::ssl::detail::buffered_handshake_op<boost::asio::const_buffer>::process<boost::asio::const_buffer const * __ptr64> + 0x1F bytes
c:\usr\work\abc_repo\ext\boost_1_68_0\boost\asio\ssl\detail\buffered_handshake_op.hpp (48): abc.exe!boost::asio::ssl::detail::buffered_handshake_op<boost::asio::const_buffer>::operator()
c:\usr\work\abc_repo\ext\boost_1_68_0\boost\asio\ssl\detail\io.hpp (136): abc.exe!boost::asio::ssl::detail::io_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp>,boost::asio::ssl::detail::buffered_handshake_op<boost::asio::const_buffer>,boost::asio::executor_binder<std::_Binder<std::_Unforced,void (__cdecl CabcApplicationServerH + 0x50 bytes
c:\usr\work\abc_repo\ext\boost_1_68_0\boost\asio\ssl\detail\io.hpp (333): abc.exe!boost::asio::ssl::detail::async_io<boost::asio::basic_stream_socket<boost::asio::ip::tcp>,boost::asio::ssl::detail::buffered_handshake_op<boost::asio::const_buffer>,boost::asio::executor_binder<std::_Binder<std::_Unforced,void (__cdecl CabcApplicationServ + 0x87 bytes
c:\usr\work\abc_repo\ext\boost_1_68_0\boost\asio\ssl\stream.hpp (505): abc.exe!boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >::async_handshake<boost::asio::const_buffer,boost::asio::executor_binder<std::_Binder<std::_Unforced,void (__cdecl CabcApplicationServerHttpSessionSSL::*)(boost::system::erro + 0x5E bytes
c:\usr\work\abc_repo\ext\boost_1_68_0\boost\beast\experimental\core\ssl_stream.hpp (485): abc.exe!boost::beast::ssl_stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >::async_handshake<boost::asio::const_buffer,boost::asio::executor_binder<std::_Binder<std::_Unforced,void (__cdecl CabcApplicationServerHttpSessionSSL::*)(boost::system::erro
c:\usr\work\abc_repo\util\capplicationserverhttpsession.cpp (343): abc.exe!CabcApplicationServerHttpSessionSSL::Run + 0x154 bytes