SSL_close_all 函数的源码如下:
voidSSL_close_all(SSL*ssl,SSL_CTX*ctx,intclient_fd)
{
s_log(eDEBUG1,"calling
shutdown(%i, SHUT_RDWR)",client_fd);
if(shutdown(client_fd,SHUT_RDWR)<0)
{
s_log(eERROR,"shutdown(%i,
SHUT_RDWR): %.100s (%i)",client_fd,strerror(errno),errno);
s_log(eDEBUG1,"calling
exit(%i)",EXIT_FAILURE);
exit(EXIT_FAILURE);
}
s_log(eDEBUG1,"calling
close(%i)",client_fd);
if(close(client_fd)<0)
{
s_log(eERROR,"close(%i):
%.100s (%i)",client_fd,strerror(errno),errno);
s_log(eDEBUG1,"calling
exit(%i)",EXIT_FAILURE);
exit(EXIT_FAILURE);
}
s_log(eDEBUG2,"calling
SSL_shutdown(%x)",ssl);
if(SSL_shutdown(ssl)<0)
{
s_log(eERROR,"SSL_shutdown:
%.100s (%i)",strerror(errno),errno);
s_log(eDEBUG1,"calling
exit(%i)",EXIT_FAILURE);
exit(EXIT_FAILURE);
}
s_log(eDEBUG2,"calling
SSL_free(%x)",ssl);
SSL_free(ssl);
s_log(eDEBUG2,"calling
SSL_CTX_free(%x)",ctx);
SSL_CTX_free(ctx);
}
|
在出现问题的服务器上使用 "strace" 对 easd 进程的系统调用进行跟踪, 发现
shutdown(client_fd, SHUT_RDWR) 使 socket 连接双方不能通过 client_fd 进行发送和接收;
close(client_fd) 关闭 socket 连接 client_fd
SSL_shutdown(ssl) 先往 client_fd 中写入数据, 再关闭 client_fd ( ssl 中应该含有 client_fd )
由上可知, 原有的代码会因为文件描述符引发 bug (关闭后还进行写入操作)
不知道原先很多系统中, 运行程序并没有报 bug, 猜测是因为不同的库对 SSL_shutdown() 的实现不同.
因此, 对于报 bug 的服务器 SSL_close_all 函数的代码应该改为:
voidSSL_close_all(SSL*ssl,SSL_CTX*ctx,intclient_fd)
{
s_log(eDEBUG2,"calling
SSL_shutdown(%x)",ssl);
if(SSL_shutdown(ssl)<0)
{
s_log(eERROR,"SSL_shutdown:
%.100s (%i)",strerror(errno),errno);
s_log(eDEBUG1,"calling
exit(%i)",EXIT_FAILURE);
exit(EXIT_FAILURE);
}
s_log(eDEBUG1,"calling
close(%i)",client_fd);
if(close(client_fd)<0)
{
s_log(eERROR,"close(%i):
%.100s (%i)",client_fd,strerror(errno),errno);
s_log(eDEBUG1,"calling
exit(%i)",EXIT_FAILURE);
exit(EXIT_FAILURE);
}
s_log(eDEBUG2,"calling
SSL_free(%x)",ssl);
SSL_free(ssl);
s_log(eDEBUG2,"calling
SSL_CTX_free(%x)",ctx);
SSL_CTX_free(ctx);
}
|