WebRTC DTLS-SRTP OpenSSL 服务器握手失败
WebRTC DTLS-SRTP OpenSSL Server Handshake Failure
这是我在 OpenSSL 服务器模式下的程序,
初始化部分SSL和BIO变量:
map<int, SSL> m_SSLMap;
map<int, BIO> m_BioWriteMap;
map<int, BIO> m_BioReadMap;
int InitializeServerNegotiationMode(int iFd)
{
SSL *pServSslFd;
BIO *pWb, *pRb;
pServSslFd = SSL_new(m_pCtx);
assert(pServSslFd);
if ( SSL_version(pServSslFd) == DTLS1_VERSION)
{
pWb = BIO_new(BIO_s_mem());
pRb = BIO_new(BIO_s_mem());
assert(pWb);
assert(pRb);
SSL_set_bio(pServSslFd, pRb, pWb);
SSL_set_accept_state(pServSslFd);
}
m_SSLMap[iFd] = *pServSslFd;
m_BioReadMap[iFd] = *pRb;
m_BioWriteMap[iFd] = *pWb;
return INITIALIZATION_SUCCESS;
}
DTLS数据到达服务器时的服务器模式协商操作:
int ServerModeDTLSNegotiation(int iChannel, const char *pBuff, const int iLen, int iFd)
{
SSL *pServSslFd;
BIO *pRbio;
BIO *pWbio;
pServSslFd = &m_SSLMap[iFd];
pRbio = &m_BioReadMap[iFd];
pWbio = &m_BioWriteMap[iFd];
char buff[4096];
memset(buff, 0, strlen(buff));
BIO_write(pRbio, pBuff, iLen);
if(!SSL_is_init_finished(pServSslFd))
{
int iRet = SSL_do_handshake(pServSslFd);
}
int iNewLen = BIO_read(pWbio, buff, 2048);
if(iNewLen>0)
{
char *pNewData = new char[iNewLen+1];
for(int i=0;i<iNewLen;i++)
pNewData[i] = buff[i];
m_pEventHandler->SendReply(iChannel, (unsigned char *)pNewData, iNewLen);
}
else
{
printf("[DTLS]:: HandShaking Response failed for this data,
return -1;
}
return NEGOTIATION_SUCCESS;
}
我在这里附加了 Wireshark TCP-Dump 以便更好地监控问题。
https://www.dropbox.com/s/quidcs6gilnvt2o/WebRTC%20DTLS%20Handshake%20Failure.pcapng?dl=0
现在,我对 SSL_CTX 变量的初始化很有信心了。因为,有时握手成功协商每个端口。但有时握手会因一个或两个端口而失败。我工作了 5 天来解决 Google Chrome 的 WebRTC DTLS 服务器模式协商。但是我还没有找到这个问题的根本原因。
TCP-Dump 的 link 不工作。
无论如何,您的解决方案似乎应该有效。
作为服务器程序,肯定是多线程。但是 初始化 SSL 变量 或 执行握手过程 而不 锁定 是非常危险的。在那种情况下,如果这两个方法由多个线程处理,那么很多事情都会发生。
我的建议是为这些方法添加锁定机制。
这是我在 OpenSSL 服务器模式下的程序,
初始化部分SSL和BIO变量:
map<int, SSL> m_SSLMap;
map<int, BIO> m_BioWriteMap;
map<int, BIO> m_BioReadMap;
int InitializeServerNegotiationMode(int iFd)
{
SSL *pServSslFd;
BIO *pWb, *pRb;
pServSslFd = SSL_new(m_pCtx);
assert(pServSslFd);
if ( SSL_version(pServSslFd) == DTLS1_VERSION)
{
pWb = BIO_new(BIO_s_mem());
pRb = BIO_new(BIO_s_mem());
assert(pWb);
assert(pRb);
SSL_set_bio(pServSslFd, pRb, pWb);
SSL_set_accept_state(pServSslFd);
}
m_SSLMap[iFd] = *pServSslFd;
m_BioReadMap[iFd] = *pRb;
m_BioWriteMap[iFd] = *pWb;
return INITIALIZATION_SUCCESS;
}
DTLS数据到达服务器时的服务器模式协商操作:
int ServerModeDTLSNegotiation(int iChannel, const char *pBuff, const int iLen, int iFd)
{
SSL *pServSslFd;
BIO *pRbio;
BIO *pWbio;
pServSslFd = &m_SSLMap[iFd];
pRbio = &m_BioReadMap[iFd];
pWbio = &m_BioWriteMap[iFd];
char buff[4096];
memset(buff, 0, strlen(buff));
BIO_write(pRbio, pBuff, iLen);
if(!SSL_is_init_finished(pServSslFd))
{
int iRet = SSL_do_handshake(pServSslFd);
}
int iNewLen = BIO_read(pWbio, buff, 2048);
if(iNewLen>0)
{
char *pNewData = new char[iNewLen+1];
for(int i=0;i<iNewLen;i++)
pNewData[i] = buff[i];
m_pEventHandler->SendReply(iChannel, (unsigned char *)pNewData, iNewLen);
}
else
{
printf("[DTLS]:: HandShaking Response failed for this data,
return -1;
}
return NEGOTIATION_SUCCESS;
}
我在这里附加了 Wireshark TCP-Dump 以便更好地监控问题。
https://www.dropbox.com/s/quidcs6gilnvt2o/WebRTC%20DTLS%20Handshake%20Failure.pcapng?dl=0
现在,我对 SSL_CTX 变量的初始化很有信心了。因为,有时握手成功协商每个端口。但有时握手会因一个或两个端口而失败。我工作了 5 天来解决 Google Chrome 的 WebRTC DTLS 服务器模式协商。但是我还没有找到这个问题的根本原因。
TCP-Dump 的 link 不工作。
无论如何,您的解决方案似乎应该有效。
作为服务器程序,肯定是多线程。但是 初始化 SSL 变量 或 执行握手过程 而不 锁定 是非常危险的。在那种情况下,如果这两个方法由多个线程处理,那么很多事情都会发生。
我的建议是为这些方法添加锁定机制。