[iocp openssl对等服务器与ConnectEx连接后关闭连接

问题描述 投票:0回答:1

我在使openssl在Windows上与iocp一起使用时遇到问题,目前仅尝试使用客户端模式

我可以使用内存BIOS进行异步写入和读取,但是我正在努力使异步连接和握手工作有效

如果我使用SSL_connect进行连接,然后使用SSL_do_handshake进行握手,然后将BIOS替换为我可以很好地读写异步的内存BIOS

在异步连接中,我执行以下操作:

  • 与ConnectEx建立连接
  • 使用iocp处理结果
  • 调用SSL_do_handshake并检索结果
  • 检查SSL_WANT_READ或SSL_WANT_WRITE是否出错,并且我总是得到前者
  • 然后,我尝试将一些数据接收到bio中(尝试进行异步和同步),但失败了。我尝试使用recv并完成了握手同步,但是recv返回0。还尝试了WSARecv,但在完成通知中我得到了0字节的传输,因此我结束了连接

这是我正在使用的一些相关代码:

class AsyncSSLSocket;
using SSLOnConnect = std::function<void(AsyncSSLSocket&, std::error_code, SockAddr&)>;

struct SSLConnectCtx : public io::BaseIoCtx
{
    AsyncSSLSocket *sslsock;
    std::variant<IpV4Addr, IpV6Addr> addr;
    SSLOnConnect OnConnect;

    virtual void HandleIocpPacket(io::iocp::CompletionResult& IocpPacket) override;

    void CompleteHandShake();

};

inline void SSLConnectCtx::HandleIocpPacket(io::iocp::CompletionResult& IocpPacket)
{

    DWORD Transferred, RecvFlags;
    WSAGetOverlappedResult(sock->GetHandle().get(), reinterpret_cast<LPWSAOVERLAPPED>(IocpPacket.Ctx), &Transferred, 0, &RecvFlags);
    auto error = sock->LastError(); // WSAGetLastError()

    if (!error)
    {
        IocpPacket.Ctx = nullptr;
        sslsock->sslhandle.SetClientMode(); // SSL_set_connect_state
        CompleteHandShake();
        return;
    }

    auto& peer_addr = ExtractAddr(addr);
    OnConnect(*sslsock, error, peer_addr);
}

inline void SSLConnectCtx::CompleteHandShake()
{
    auto& sslhandle = sslsock->sslhandle;
    int ret = sslhandle.DoHandShake(); // SSL_do_handshake
    std::error_code error;

    if (ret < 0)
    {
        error = sslhandle.LastError(ret);

        if (sslhandle.WantRead(error.value())) // always get here
        {
            error = sslsock->FillInBIO([this](auto&, auto error, uint32_t trans)
            {
                MakeErrorIfZeroIsRecved(trans, error); // set error to std::errc::connection_abort (106) if WSARecv received 0 bytes
                if (!error)
                {
                    CompleteHandShake();
                    return;
                }
                // always get here 
                // prints : [!] failed to get data for the handshake !, error : generic:106 ==> connection aborted
                std::cout << "[!] failed to get data for the handshake !, error : " << error << " ==> " << error.message() << std::endl;
                OnConnect(*sslsock, error, ExtractAddr(addr));
                delete this;
            });
            if (!error)
                return;
        }

        else if (sslhandle.WantWrite(error.value()))
        {
            error = sslsock->FlushOutBIO([this](auto&, auto error, uint32_t) 
            {
                if (!error)
                {
                    CompleteHandShake();
                    return;
                }
                OnConnect(*sslsock, error, ExtractAddr(addr));
                delete this;
            });
            if (!error)
                return;
        }
    }

    OnConnect(*sslsock, error, ExtractAddr(addr));
    delete this;
}

void AsyncSSLSocket::AsyncConnect(SockAddr& addr, const SSLOnConnect& OnConnect)
    {
        SSLConnectCtx * ctx{ new SSLConnectCtx{} };
        ctx->sslsock = this;
        ctx->sock = &sock;
        SetAddrs(ctx->addr, addr);
        ctx->OnConnect = OnConnect;

        auto result = sock.AsyncConnect(addr, *ctx);
        if (result)
            return;
        delete ctx;
        OnConnect(*this, sock.LastError(), addr);
    }

    std::error_code AsyncSSLSocket::FillInBIO(SSLOnRead&& OnRead)
    {
        char *buff = new char[1024];
        CachedReadBuff = io::IoBuffer(buff, 1024);
        CachedOnRead = std::move(OnRead);

        SockRecvCtx * ctx{ new SockRecvCtx{} };
        ctx->sock = &sock;
        ctx->OnRecv = [this](Socket&, std::error_code error, uint32_t transferred)
        {
            MakeErrorIfZeroIsRecved(transferred, error);
            if (!error)
                inBIO.Write(CachedReadBuff.data(), static_cast<int>(transferred));              
            delete CachedReadBuff.data();
            CachedOnRead(*this, error, transferred);
        };

        auto result = sock.AsyncRecv(CachedReadBuff, *ctx);
        if (result)
            return std::error_code{};
        delete ctx;
        return result.error;
    }
c++ asynchronous openssl iocp
1个回答
0
投票
似乎SSL_do_handshake在out bio中放入了一些数据,并返回SSL_get_error返回了SSL_ERROR_WANT_READ,所以当服务器正在等待从客户端接收一些数据时,我去了从服务器读取更多数据,因此WSARecv或recv等待几秒钟(也许服务器超时了?)直到服务器关闭连接并且我收到了0个字节。

所以我用了这个代码:

inline void SSLConnectCtx::CompleteHandShake() { auto& sslhandle = sslsock->sslhandle; int ret = sslhandle.DoHandShake(); // SSL_do_handshake std::error_code error; if (ret < 0) { int pending = sslsock->outBIO.Pending(); if (pending > 0) { std::cout << "[!!!] there is some data to send !" << std::endl; error = sslsock->FlushOutBIO([this](auto&, auto error, uint32_t) { if (!error) { CompleteHandShake(); return; } OnConnect(*sslsock, error, ExtractAddr(addr)); delete this; }); if (!error) return; std::cout << "[!] failed to flush ! , error " << error << " ==> " << error.message() << std::endl; } error = sslhandle.LastError(ret); if (sslhandle.WantRead(error.value())) // always get here { std::cout << "[!!!] needs to read in the bio" << std::endl; error = sslsock->FillInBIO([this](auto&, auto error, uint32_t trans) { MakeErrorIfZeroIsRecved(trans, error); // set error to std::errc::connection_abort (106) if WSARecv received 0 bytes if (!error) { CompleteHandShake(); return; } // always get here // prints : [!] failed to get data for the handshake !, error : generic:106 ==> connection aborted std::cout << "[!] failed to get data for the handshake !, error : " << error << " ==> " << error.message() << std::endl; OnConnect(*sslsock, error, ExtractAddr(addr)); delete this; }); if (!error) return; } else if (sslhandle.WantWrite(error.value())) { error = sslsock->FlushOutBIO([this](auto&, auto error, uint32_t) { if (!error) { CompleteHandShake(); return; } OnConnect(*sslsock, error, ExtractAddr(addr)); delete this; }); if (!error) return; } } OnConnect(*sslsock, error, ExtractAddr(addr)); delete this; }

但是现在错误是如何通过SSL_ERROR_WANT_READ读取的,而需要在读取之前进行写入!

我听说在通信过程中的任何时候都可能需要重新协商,因此,如果SSL_write返回SSL_ERROR_WANT_READ,我应该开始读取或发送未决数据吗?同样,如果SSL_read返回了SSL_ERROR_WANT_WRITE,我应该开始发送数据还是接收数据?

© www.soinside.com 2019 - 2024. All rights reserved.