Задний план
У нас есть небольшая безголовая коробка с ядром Linux 2.6.35 и некоторым вариантом дистрибутива Open Embedded на оборудовании ARM.
Насколько мы можем судить, мы используем glibc 2.10.1.
Коробка имеет несвязанный Ethernet и последовательный модем GSM/3G. Мы настроили PPP для обеспечения непрерывного подключения к Интернету. Эта часть работает без проблем.
У нас есть программа, написанная на C (на самом деле C++), которая устанавливает соединение с помощью сокетов. Программа сильно многопоточная с использованием pthreads.
Чтобы найти IP-адрес для подключения, мы используем gethostbyname().
Когда нет подключения к Интернету, т.е. во время начальной загрузки или когда SIM-карта удаляется из модема, gethostbyname() возвращает NULL, как и должно быть.
Симптом
Но время от времени gethostbyname() продолжает возвращать NULL, даже если подключение к Интернету установлено и работает.
Код ошибки от getaddrinfo() при использовании EAI_NONAME ~ "Имя или служба не известны". У нас нет под рукой кода ошибки от gethostbyname(), но он был эквивалентен.
Наш анализ
Мы убедились, что подключение к Интернету в порядке (через последовательную консоль)
- Пункт списка
- Просматривая /var/log/messages и убеждаясь, что pppd говорит, что все в порядке
- ping имя хоста (переводится в IP и отвечает нормально)
- подключиться к ящику по ssh через публичный IP
У нас есть два потока в процессе, которые используют gethostbyname() для одного и того же хоста. У них немного разные пути кода и функции, но используется общий код для функций сокета, включая ту часть, которая вызывает gethostbyname().
В ситуациях, когда gethostbyname() продолжает возвращать NULL, это обычно верно только для ОДНОГО из потоков, а не для одного и того же каждый раз. Другой делает поиск отлично.
Кроме того, поток с ошибкой gethostbyname() может быть легко приведен в действие простой управляемой остановкой этого потока и перезапуском функции, что затем приводит к созданию нового потока по принципу pthread.
В целом мы убеждены, что трансляция DNS и интернет-соединение работают нормально на уровне ОС.
Чтобы исключить проблемы с многопоточностью, мы повторно реализовали код поиска, используя getaddrinfo(), который является реентерабельным в соответствии с справочной страницей. И с точно таким же результатом.
Нам кажется, что выход из потока приводит к некоторой очистке, которая влияет на способность gethostbyname()/getaddrinfo() выполнять поиск.
Обходным путем может быть принудительный выход из сбойного потока, но это будет означать серьезное изменение в структуре приложения и на самом деле не вариант.
Вопрос
Итак, вопрос: есть ли у вас какие-либо указания, где искать решение или где может быть реальная проблема?