我编写的静态库引用了静态OpenSSL库。 OpenSSL有时会生成SIGPIPE
并崩溃程序。我知道可以使用signal
函数全局禁用SIGPIPE
。但是,对于静态库,这样的要求并不优雅(与可以在初始化函数中调用signal
的共享库不同)。此外,不需要在程序中进行全局更改的方法要好得多,因为谁知道可能是任何其他库需要SIGPIPE
,并且会与需要忽略此信号的库冲突。我认为良好的做法是仅改变BIO
而不改变其他任何东西。
OpenSSL使用套接字,套接字send
函数包含良好的解决方案(MSG_NOSIGNAL
标志)。 OpenSSL有没有类似的解决方案?有没有办法以这样的方式设置OpenSSL BIO,它不会生成SIGPIPE
而不会导致整个程序崩溃?
答案 0 :(得分:2)
OpenSSL本身不会生成SIGPIPE
。但是,OpenSSL使用套接字,如果您写入另一端关闭的套接字,则会生成SIGPIPE
。如果您不想这样做,则必须处理SIGPIPE
(例如将其设置为SIG_IGN
)。这将导致写入返回EPIPE
错误。
因为此行为不是特定于OpenSSL,而是所有套接字都通用,并且因为这是一个全局设置,所以不应在库中更改它。您可以在文档中提及它,但只有在您希望用户不熟悉套接字的标准行为时才应该这样做。
答案 1 :(得分:1)
OpenSSL有时会生成SIGPIPE并崩溃程序
我不相信它的OpenSSL;相反,它是操作系统响应对等体以“脏”的方式关闭SSL套接字。
Eric Rescorla触及它An Introduction to OpenSSL Programming (Part I):
当我们发送
close_notify
时,另一方可能会发送TCP RST 段,在这种情况下,程序将捕获SIGPIPE
。我们安装SIGPIPE
中的虚拟initialize_ctx()
处理程序,以防范。{1}} 这个问题。
我不同意“除了记录它之外什么都不做”。如果RTFM会起作用,那么它现在就会发生。它的不确定崩溃应用程序并声明答案在手册的某个地方。您应该开箱即用,并记录如何更改行为。
如果程序没有自行安装,可能应该安装SIGPIPE
处理程序。如果程序安装了一个,那么你可能应该提供一个代码路径回到你的库中,以便在它发生时通知你(如果你需要的话)。
您可以使用以下内容测试现有的SIGPIPE
处理程序(如果不存在,则安装一个)。我在Debug版本中使用类似的方法来安装SIGTRAP
处理程序,因此我的断言不会使我正在调试的程序崩溃。 (完全覆盖断言创建自调试代码。我很少花时间在调试器下,因为代码告诉我问题在哪里)。
struct SigPipeHandler
{
SigPipeHandler()
{
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/sigaction.html
struct sigaction old_handler, new_handler={ };
do
{
int ret = 0;
ret = sigaction (SIGPIPE, NULL, &old_handler);
if (ret != 0) break; // Failed
// Don't step on another's handler
if (old_handler.sa_handler != NULL) break;
// Set up the structure to specify the null action.
new_handler.sa_handler = &SigPipeHandler::NullSigPipeHandler;
new_handler.sa_flags = 0;
ret = sigemptyset (&new_handler.sa_mask);
if (ret != 0) break; // Failed
// Install it
ret = sigaction (SIGPIPE, &new_handler, NULL);
if (ret != 0) break; // Failed
} while(0);
}
static void NullSigPipeHandler(int /*unused*/) { }
}
答案 2 :(得分:1)
这取决于您如何在套接字上设置SSL。如果您使用SSL_set_fd
,则可以阻止使用setsocketopt
和SO_NOSIGPIPE
生成SIG_PIPE。