Russian Qt Forum

Qt => Работа с сетью => Тема начата: Igors от Ноябрь 20, 2011, 10:57



Название: gethostbyname, getaddrinfo
Отправлено: Igors от Ноябрь 20, 2011, 10:57
Добрый день

Сетью приходится заниматься раз в несколько лет, устранять баги в чужом коде. Поэтому мои познания здесь нулевые :) Отловил такой баг
Код
C++ (Qt)
void DomainToIP(const char* iDomainAddress, UInt32 & oIPAddress)
{
struct hostent * hostinfo = gethostbyname(iDomainAddress);
if (hostinfo)
oIPAddress = *(reinterpret_cast<UInt32*>(hostinfo->h_addr_list[0]));
else
throw BadNameException();
 
oIPAddress = ntohl(oIPAddress);
}
 
Раз на несколько тысяч вызовов gethostbyname возвращает NULL. Входная строка (iDomainAddress) всегда одна и та же: Macinrosh.local
Ладно, гуглю. Ага, gethostbyname использовать не рекомендуют. Подлатал  так

Код
C++ (Qt)
void DomainToIP(const char* iDomainAddress, UInt32 & oIPAddress)
{
struct hostent * hostinfo = gethostbyname(iDomainAddress);
if (hostinfo)
oIPAddress = *(reinterpret_cast<UInt32*>(hostinfo->h_addr_list[0]));
else {
struct addrinfo * result = 0;
int error = getaddrinfo(iDomainAddress, NULL, NULL, &result);
if (!error && !result) error = -1;
if (!error)
oIPAddress = *(reinterpret_cast<UInt32*> (result->ai_addr->sa_data + 2));
 
if (result)
freeaddrinfo(result);
 
if (error || oIPAddress == 0)
throw BadNameException();
}
 
oIPAddress = ntohl(oIPAddress);
}
Это работает заметно лучше но все же иногда oIPAddress получается = 0.

Вопросы:

1) Есть ли ф-ция для взятия IP адреса без уродливого reinterpret_cast ?

2) Не понимаю "прынцыпов" - конфигурацию сети никто не трогал, почему ф-ции иногда не видят IP ?

3) Могу ли я (корректно ли) поставить кэш std::map <std::string, UInt32> рассчитывая что IP останется неизменным для того же имени ?

Спасибо


Название: Re: gethostbyname, getaddrinfo
Отправлено: SimpleSunny от Ноябрь 20, 2011, 12:11
При неудачном вызове gethostbyname проверяйте код ошибки в h_errno
Цитировать
Переменная h_errno может принимать следующие значения:
HOST_NOT_FOUND
    Указанный хост неизвестен.
NO_ADDRESS или NO_DATA
    Запрошенное имя существует, но не имеет IP-адреса.
NO_RECOVERY
    Hепоправимая ошибка сервера имен.
TRY_AGAIN
    Временная ошибка на официальном сервере имен. Повторите попытку позже.
const char *hstrerror(int err); - вернет текстовое описание ошибки

Для getaddrinfo проверяйте код возвращаемой ошибки.
const char *gai_strerror(int errcode);

Возможно ошибка просто во временной недоступности ДНС сервера.

И используйте какой-то один из методов либо gethostbyname, либо getaddrinfo, а то смотрится как-то странно.


Название: Re: gethostbyname, getaddrinfo
Отправлено: BRE от Ноябрь 20, 2011, 13:00
И используйте какой-то один из методов либо gethostbyname, либо getaddrinfo, а то смотрится как-то странно.
плюс к сказанному... gethostbyname не умеет IPv6, в отличие от...


Название: Re: gethostbyname, getaddrinfo
Отправлено: Igors от Ноябрь 20, 2011, 13:26
плюс к сказанному... gethostbyname не умеет IPv6, в отличие от...
Ну говорят "doesn't work well with IPv6."  http://beej.us/guide/bgnet/output/html/multipage/gethostbynameman.html (http://beej.us/guide/bgnet/output/html/multipage/gethostbynameman.html)

При неудачном вызове gethostbyname проверяйте код ошибки в h_errno
...
Для getaddrinfo проверяйте код возвращаемой ошибки.
...
Возможно ошибка просто во временной недоступности ДНС сервера.
Понял, спасибо

И используйте какой-то один из методов либо gethostbyname, либо getaddrinfo, а то смотрится как-то странно.
То да, но если я чужой код снесу - я потом его не вспомню. А закомментированный смотрится никак не лучше  :)


Название: Re: gethostbyname, getaddrinfo
Отправлено: Igors от Ноябрь 20, 2011, 13:57
Хмм... если gethostbyname возвращает NULL, то h_errno = 1 (HOST_NOT_FOUND).
А getaddrinfo не выдает ошибок, но IP = 0  :'(

Не хочу быть навязчивым, но все же
3) Могу ли я (корректно ли) поставить кэш std::map <std::string, UInt32> рассчитывая что IP останется неизменным для того же имени ?
Т.к. ситуация возникает раз на много тысяч вызовов


Название: Re: gethostbyname, getaddrinfo
Отправлено: BRE от Ноябрь 20, 2011, 15:33
3) Могу ли я (корректно ли) поставить кэш std::map <std::string, UInt32> рассчитывая что IP останется неизменным для того же имени ?
А какое время жизни этого кеша?


Название: Re: gethostbyname, getaddrinfo
Отправлено: Igors от Ноябрь 20, 2011, 15:38
А какое время жизни этого кеша?
От одного запуска до другого (просто static). Пользователь (давно) предупрежден что надо выйти из приложения если понадобилось поменять настройки сети


Название: Re: gethostbyname, getaddrinfo
Отправлено: BRE от Ноябрь 20, 2011, 15:40
От одного запуска до другого (просто static). Пользователь (давно) предупрежден что надо выйти из приложения если понадобилось поменять настройки сети
Думаю можно сделать так. Вести свой кеш, а если вдруг удаленная сторона перестала отвечать по адресу из кеша - перезапрашивать заново информацию у DNS-сервера и обновлять кеш.


Название: Re: gethostbyname, getaddrinfo
Отправлено: Igors от Ноябрь 20, 2011, 16:37
Думаю можно сделать так. Вести свой кеш, а если вдруг удаленная сторона перестала отвечать по адресу из кеша - перезапрашивать заново информацию у DNS-сервера и обновлять кеш.
В чужом (и весьма обильном) коде сложно понять как же полученный IP используется. Как минимум вижу что он участвует в вычислении имени фолдера куда складываются полученные файлы. Рискну и поставлю кэш (если что верну назад)

Спасибо


Название: Re: gethostbyname, getaddrinfo
Отправлено: LisandreL от Ноябрь 20, 2011, 17:48
Раз на несколько тысяч вызовов gethostbyname возвращает NULL
Посмотреть, возвращает ли раз в те же тысячу раз QHostInfo::fromName( "Macinrosh.local" ).addresses() пустой список.
Если нет, то смотреть реализацию.
Но вероятнее всего просто затупы местного DNS-сервера (не отвечает или не укладывается в тайм-аут) и можно в случае NULL'а надо запрашивать повторно (ограничив максимальное число повторений.