48: hints.ai_flags |= AI_ADDRCONFIG;
49: else if (!strcmp(*ptr, "--tcp")) {
50: hints.ai_protocol = IPPROTO_TCP;
51: } else if (!strcmp(*ptr, "--udp")) {
52: hints.ai_protocol = IPPROTO_UDP;
53: } else if (!strcmp(*ptr, "--host")) {
54: ptr++;
55: if (!*ptr) usage();
56: hostName = *ptr;
57: } else if (!strcmp(*ptr, "--service")) {
58: ptr++;
59: if (!*ptr) usage();
60: serviceName = *ptr;
61: } else
62: usage();
63:
64: ptr++;
65: }
66:
67: /* необходимы имена hostName, serviceName или оба */
68: if (!hostName && !serviceName)
69: usage();
70:
71: if ((rc = getaddrinfo(hostName, serviceName, &hints,
72: &cresult))) {
73: fprintf(stderr, "сбой поиска службы: %s\n",
74: gai_strerror(rc));
75: return 1;
76: }
77:
78: /* проходит по связному списку, отображая все результаты */
79: addr = result;
80: while (addr) {
81: switch (addr->ai_family) {
82: case PF_INETs: printf("IPv4");
83: break;
84: case PF_INET6: printf("IPv6");
85: break;
86: default: printf("(%d) addr->ai_family);
87: break;
88: }
89:
90: switch (addr->ai_socktype) {
91: case SOCK_STREAM: printf("\tstream");
92: break;
93: case SOCK_DGRAM: printf("\tdgram");
94: break;
95: case SOCK_RAW: printf("\traw");
96: break;
97: default: printf("\t(%d)
98: addr->ai_socktype);
99: break;
100: }
101:
102: if (addr->ai_family == PF_INET ||
103: addr->ai_family == PF_INET6)
104: switch (addr->ai_protocol) {
105: case IPPROTO_TCP: printf("\ttcp");
106: break;
107: case IPPROTO_UDP: printf("\tudp");
108: break;
109: case IPPROTO_RAW: printf("\traw");
110: break;
111: default: printf("\t(%d)
112: addr->ai_protocol);
113: break;
114: }
115: else
116: printf("\t");
117:
118: /* отобразить информацию и для IPv4-, и для IPv6-адресов */
119:
120: if (addr->ai_family == PF_INET) {
121: struct sockaddr_in * inetaddr = (void*)addr->ai_addr;
122: char nameBuf[INET_ADDRSTRLEN];
123:
124: if (serviceName)
125: printf("\tпорт%d", ntohs(inetaddr->sin_port));
126:
127: if (hostName)
128: printf("\tхост%s",
129: inet_ntop(AF_INET, &inetaddr->sin_addr,
130: nameBuf, sizeof(nameBuf)));
131: } else if (addr->ai_family == PF_INET6) {
132: struct sockaddr_in6 * inetaddr =
133: (void*)addr->ai_addr;
134: char nameBuf[INET6_ADDRSTRLEN];
135:
136: if (serviceName)
137: printf("\tпорт%d", ntohs(inetaddr->sin6_port));
138:
139: if (hostName)
140: printf("\tхост%s",
141: inet_ntop(AF_INET6, &inetaddr->sin6_addr,
142: nameBuf, sizeof(nameBuf)));
143: }
144:
145: if (addr->ai_canonname)
146: printf("\tname%s", addr->ai_canonname);
147:
148: printf("\n");
149:
150: addr = addr->ai_next;
151: }
152:
153: /* очистить результаты getaddrinfo() */
154: freeaddrinfo(result);
155:
156: return 0;
157: }
В отличие от большинства библиотечных функций, getaddrinfo()
возвращает целое число, которое равно нулю в случае успеха, и описывает ошибку в случае неудачи. Такие функции, как правило, не используют errno
. В табл. 17.3 описаны различные коды ошибок, которые могут возвращать подобные функции.
Таблица 17.3. Ошибки поиска соответствия адреса и имени
Ошибка |
Описание |
EAI_AGAIN |
Имя не может быть найдено. Повторный поиск может оказаться успешным. |
EAI_BADFLAGS |
В функцию переданы недействительные флаги. |
EAI_FAIL |
В процессе поиска соответствия возникла постоянная ошибка. |
EAI_FAMILY |
Семейство адресов не распознано. |
EAI_MEMORY |
Запрос на выделение памяти не выполнен. |
EAI_NONAME |
Имя или адрес невозможно преобразовать. |
EAI_OVERFLOW |
Переданный буфер слишком мал. |
EAI_SERVICE |
Для данного типа сокета служба не существует. |
EAI_SOCKTYPE |
Был передан недействительный тип сокета. |
EAI_SYSTEM |
Произошла системная ошибка; сама ошибка содержится в переменной errno . |
Коды ошибок можно преобразовать в строки, описывающие проблему, с помощью функции gai_strerror()
.
#include
const char * gai_strerror(int error);
Здесь параметр error
должен быть ненулевым значением, возвращенным функцией getaddrinfo()
. Если произошла ошибка EAI_SYSTEM
, то для получения более точного описания программа должна использовать strerror(errno)
.
17.5.6. Преобразование адресов в имена
К счастью, переводить IP-адреса и номера портов в имена хостов и служб гораздо проще, чем наоборот.
Читать дальше