iocp openssl peer server 在与 ConnectEx 连接后关闭连接
iocp openssl peer server closes the connection after connecting with ConnectEx
我在 windows 上使 openssl 与 iocp 一起工作时遇到问题,目前仅尝试客户端模式
我可以使用内存 bios 进行异步写入和读取,但我正在努力让异步连接和握手工作
如果我使用 SSL_connect 连接,然后使用 SSL_do_handshake 进行握手,然后用内存 bios 替换 bios 我可以很好地读写异步
在异步连接中,我执行以下操作:
- 与 ConnectEx 建立连接
- 用iocp处理结果
- 调用SSL_do_handshake并检索结果
- 如果SSL_WANT_READ或SSL_WANT_WRITE检查是否有错误,我总是得到前者
- 然后我尝试将一些数据接收到 in 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;
}
好像是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 我应该开始发送数据还是接收数据?
我在 windows 上使 openssl 与 iocp 一起工作时遇到问题,目前仅尝试客户端模式
我可以使用内存 bios 进行异步写入和读取,但我正在努力让异步连接和握手工作
如果我使用 SSL_connect 连接,然后使用 SSL_do_handshake 进行握手,然后用内存 bios 替换 bios 我可以很好地读写异步
在异步连接中,我执行以下操作:
- 与 ConnectEx 建立连接
- 用iocp处理结果
- 调用SSL_do_handshake并检索结果
- 如果SSL_WANT_READ或SSL_WANT_WRITE检查是否有错误,我总是得到前者
- 然后我尝试将一些数据接收到 in 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;
}
好像是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 我应该开始发送数据还是接收数据?