gethostbyname/getaddrinfo продолжает сбой, даже когда подключение к Интернету установлено

Задний план

У нас есть небольшая безголовая коробка с ядром 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() выполнять поиск.

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

Вопрос

Итак, вопрос: есть ли у вас какие-либо указания, где искать решение или где может быть реальная проблема?


person Nicolai Henriksen    schedule 03.02.2014    source источник
comment
это не удается при поиске того же имени хоста или по «случайным» именам? DNS по умолчанию использует UDP, который может незаметно терять пакеты. Но DNS также может использовать TCP, если ответ будет слишком большим для одного пакета UDP, а если DNS/TCP защищен брандмауэром, вы не получите ответа, а также не удастся выполнить поиск.   -  person Marc B    schedule 03.02.2014
comment
Если вы выполняете DNS-запрос из командной строки с помощью nslookup (например, nslookup google.com), разрешается ли он? Если это так, это может указывать на проблему внутри вашей программы. Если нет, это может указывать на какую-то основную проблему DNS на вашей платформе.   -  person mti2935    schedule 03.02.2014
comment
У нас есть только одно конкретное имя хоста, и мы не пробовали никаких других, так как это конкретный хост, к которому нам нужно подключиться. Но, как уже упоминалось, он не терпит неудачу последовательно. Другой поток в том же процессе может выполнить поиск без проблем, и перезапуск потока восстанавливает ситуацию.   -  person Nicolai Henriksen    schedule 03.02.2014
comment
@ mti2935 Мы уверены, что это внутренняя проблема. Поиск из командной строки работает.   -  person Nicolai Henriksen    schedule 03.02.2014
comment
Какую libc (glibc/eglibc/uclibc/etc.) и версию вы используете? Также сообщается о типе ошибки (с errno или возвращаемым значением getaddrinfo )   -  person nos    schedule 03.02.2014
comment
@nos Код ошибки от getaddrinfo(): EAI_NONAME ~ Имя или служба неизвестны. Ошибка от gethostbyname() была эквивалентной, но я забыл ее записать.   -  person Nicolai Henriksen    schedule 04.02.2014
comment
@nos Я думаю, что мы используем glibc версии 2.10.1, но среда сборки bitbake достаточно сложна, чтобы я сомневался. ldd сообщает о зависимости от libc.so.6   -  person Nicolai Henriksen    schedule 04.02.2014


Ответы (1)


person    schedule
comment
Хотя этот код может помочь решить проблему, он не объясняет, почему и/или как отвечает на вопрос. Предоставление этого дополнительного контекста значительно повысит его долгосрочную образовательную ценность. Пожалуйста, отредактируйте свой ответ, чтобы добавить пояснение, включая применимые ограничения и предположения. - person Toby Speight; 23.08.2016