Linux — C ++ & amp; OpenSSL: SIGPIPE при записи в закрытом канале

Я пишу C ++ SSL-сервер для TCP-соединений в Linux.
Когда программа использует SSL_write() для записи в закрытый канал генерируется исключение SIGPIPE-Exception, которое приводит к закрытию программы. Я знаю, что это нормальное поведение. Но программа не всегда должна умирать, когда узел не закрывает соединение правильно.

Я уже много гуглил и перепробовал почти все, что нашел, но, похоже, у меня ничего не работает. signal(SIGPIPE,SIG_IGN) не работает — исключение по-прежнему выдается (то же самое для signal(SIGPIPE, SomeKindOfHandler),

Вывод GDB:

Program received signal SIGPIPE, Broken pipe.
0x00007ffff6b23ccd in write () from /lib/x86_64-linux-gnu/libpthread.so.0
(gdb) where
#0  0x00007ffff6b23ccd in write () from /lib/x86_64-linux-gnu/libpthread.so.0
#1  0x00007ffff7883835 in ?? () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
#2  0x00007ffff7881687 in BIO_write () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0
#3  0x00007ffff7b9d3e0 in ?? () from /lib/x86_64-linux-gnu/libssl.so.1.0.0
#4  0x00007ffff7b9db04 in ?? () from /lib/x86_64-linux-gnu/libssl.so.1.0.0
#5  0x000000000042266a in NetInterface::SendToSubscribers(bool) () at ../Bether/NetInterface.h:181
#6  0x0000000000425834 in main () at ../Bether/main.cpp:111

О коде:

Я использую поток, который ждет новых подключений и принимает их. Затем поток помещает информацию о соединении (BIO & SSL) в статическую карту внутри NetInterface учебный класс.
Каждые 5 секунд NetInterface::sendTOSubscribers() выполнен из main(), Эта функция обращается к статической карте и отправляет данные каждому подключенному там. Эта функция также является источником SIGPIPE.
я использовал signal(SIGPIPE,SIG_IGN) в main() (очевидно, перед 5-секундным циклом) и в NetInterface::SendToSubscribers(), но это нигде не работает.

Спасибо за вашу помощь!

2

Решение

Вы должны вызвать функцию sigaction, чтобы изменить это поведение, либо игнорировать SIGPIPE, либо обрабатывать его особым образом с помощью собственного обработчика сигнала. Пожалуйста, не используйте функциональный сигнал, он устарел.

http://man7.org/linux/man-pages/man2/sigaction.2.html

Один из способов сделать это (я не скомпилировал этот код, но должен быть примерно таким):

void sigpipe_handler(int signal)
{
...
}

int main()
{
struct sigaction sh;
struct sigaction osh;

sh.sa_handler = &sigpipe_handler; //Can set to SIG_IGN
// Restart interrupted system calls
sh.sa_flags = SA_RESTART;

// Block every signal during the handler
sigemptyset(&sh.sa_mask);

if (sigaction(SIGPIPE, &sh, &osh) < 0)
{
return -1;
}

...
}

Если программа многопоточная, она немного отличается, так как у вас меньше контроля над тем, какой поток получит сигнал. Это зависит от типа сигнала. Для SIGPIPE он будет отправлен в pthread, который сгенерировал сигнал. Тем не менее, sigaction должен работать хорошо.

Можно установить маску в основном потоке, и все последующие созданные потоки будут наследовать маску сигнала. В противном случае маска сигнала может быть установлена ​​в каждом потоке.

sigset_t blockedSignal;
sigemptyset(&blockedSignal);
sigaddset(&blockedSignal, SIGPIPE);
pthread_sigmask(SIG_BLOCK, &blockedSignal, NULL);

Однако, если вы заблокируете сигнал, он будет в ожидании процесса и, как только это станет возможным, он будет доставлен. Для этого случая используйте sigtimedwait в конце потока. sigaction, установленный в главном потоке или в потоке, который генерировал SIGPIPE, также должен работать.

2

Другие решения

Я нашел решение, оно работает с pthread_sigmask.

sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGPIPE);
if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0)
return -1;

Спасибо всем за помощь!

0

По вопросам рекламы [email protected]