Provided by: manpages-ru-dev_4.27.0-1_all bug

НАИМЕНОВАНИЕ

       getaddrinfo_a, gai_suspend, gai_error, gai_cancel - асинхронная трансляция сетевого адреса и службы

БИБЛИОТЕКА

       Asynchronous name lookup library (libanl, -lanl)

ОБЗОР

       #define _GNU_SOURCE         /* См. feature_test_macros(7) */
       #include <netdb.h>

       int getaddrinfo_a(int mode, struct gaicb *list[restrict],
                         int nitems, struct sigevent *restrict sevp);
       int gai_suspend(const struct gaicb *const list[], int nitems,
                         const struct timespec *timeout);

       int gai_error(struct gaicb *req);
       int gai_cancel(struct gaicb *req);

ОПИСАНИЕ

       Функция  getaddrinfo_a()  выполняет  ту  же  задачу  что  и  getaddrinfo(3), но позволяет выполнять поиск
       нескольких имён асинхронно, с дополнительным уведомлением о завершении операций поиска.

       В аргументе mode указывается одно из следующих значений:

       GAI_WAIT
              Выполнять поиск синхронно. Вызов блокирует выполнение пока поиск не завершится.

       GAI_NOWAIT
              Выполнять поиск асинхронно. Вызов сразу завершается и запросы  обрабатываются  в  фоновом  режиме.
              Смотрите далее описание параметра sevp.

       В  массиве  list  задаются запросы на обработку. В аргументе nitems задаётся количество элементов в list.
       Запрашиваемые операции поиска начинаются параллельно. Элементы NULL в списке  list  игнорируются.  Каждый
       запрос описывается структурой gaicb, которая определена следующим образом:

           struct gaicb {
               const char            *ar_name;
               const char            *ar_service;
               const struct addrinfo *ar_request;
               struct addrinfo       *ar_result;
           };

       Элементы данной структуры совпадают с аргументами getaddrinfo(3). То есть ar_name соответствует аргументу
       node,   а  ar_service  аргументу  service  (определяют  узел  Интернета  и  службу).  Элемент  ar_request
       соответствует аргументу hints; им задаётся критерий выбора  структуры  возвращаемого  адреса  сокета.  И,
       наконец,  ar_result  соответствует  аргументу  res;  вам не нужно инициализировать этот элемент, он будет
       заполнен автоматически в результате запроса. Структура  addrinfo,  на  которую  ссылаются  последние  два
       элемента, описана в getaddrinfo(3).

       When  mode is specified as GAI_NOWAIT, notifications about resolved requests can be obtained by employing
       the sigevent structure pointed to by the sevp argument.  For the definition and general details  of  this
       structure, see sigevent(3type).  The sevp->sigev_notify field can have the following values:

       SIGEV_NONE
              Отключить уведомление.

       SIGEV_SIGNAL
              When  a  look-up  completes, generate the signal sigev_signo for the process.  See sigevent(3type)
              for general details.  The si_code field of the siginfo_t structure will be set to SI_ASYNCNL.

       SIGEV_THREAD
              When a look-up completes, invoke sigev_notify_function as if it were the start function of  a  new
              thread.  See sigevent(3type)  for details.

       При SIGEV_SIGNAL и SIGEV_THREAD, может быть полезно, чтобы sevp->sigev_value.sival_ptr указывала на list.

       Функция  gai_suspend()  приостанавливает  выполнение вызывающей нити, ожидая завершения поиска одного или
       более запросов из массива list.  В  аргументе  nitems  задаётся  размер  массива  list.  Вызов  блокирует
       выполнение пока не произойдёт одно из следующего:

       •  Завершится операция для одного или более запросов из list.

       •  Вызов прервётся пойманным сигналом.

       •  Временной  интервал  ожидания задаётся в timeout. В данном аргумента указывается промежуток в секундах
          плюс наносекундах (о структуре timespec смотрите nanosleep(2)). Если  timeout  равно  NULL,  то  вызов
          блокирует выполнение навсегда (пока не произойдёт одно из событий выше).

       При  выполнении явно не указывается какие запросы завершены; для определения вам нужно обойти весь список
       запросов с помощью gai_error().

       Функция gai_error() возвращает состояние запроса req: EAI_INPROGRESS —  запрос  пока  не  выполнен,  0  —
       обработан успешно, код ошибки — запрос невозможно обработать.

       Функция  gai_cancel()   отменяет  запрос  req.  При  успешной  отмене  состояние ошибки устанавливается в
       EAI_CANCELED и выполняется обычное асинхронное уведомление. Запрос не может быть отменён, если  он  начал
       обрабатываться;  в  этом  случае  действие  будет  доведено  до конца, как если бы вызова gai_cancel() не
       происходило. Если req равно NULL, то будет предпринята попытка отменить все имеющиеся запросы.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

       Функция getaddrinfo_a() возвращает 0, если все запросы были успешно  обработаны  или  один  из  следующих
       ненулевых кодов ошибки:

       EAI_AGAIN
              Недоступны  ресурсы,  необходимые,  чтобы  постановки  запросов  поиска  в очередь. Для нахождения
              проблемного приложение может проверить состояние ошибки каждого запроса.

       EAI_MEMORY
              Не хватает памяти.

       EAI_SYSTEM
              Неверное значение mode.

       Функция gai_suspend() возвращает  0,  если  завершён  хотя  бы  один  из  запросов.  В  противном  случае
       возвращается один из следующих ненулевых кодов ошибки:

       EAI_AGAIN
              Указанный интервал истёк до завершения хотят бы одного из запросов.

       EAI_ALLDONE
              В функцию не было передано никаких фактических запросов.

       EAI_INTR
              Функция прервана сигналом. Заметим, что такое прерывание может быть вызвано сигналом уведомления о
              каком-то выполненном запросе.

       Функция gai_error() может вернуть EAI_INPROGRESS для незаконченных запросов поиска, 0 при успешном поиске
       (как  описано  выше),  один  из  кодов  ошибок,  которые  может  вернуть  getaddrinfo(3)  или  код ошибки
       EAI_CANCELED, если запрос был отменён явно до завершения.

       Функция gai_cancel() может вернуть одно из следующих значений:

       EAI_CANCELED
              Запрос успешно отменён.

       EAI_NOTCANCELED
              Запрос не был отменён.

       EAI_ALLDONE
              Запрос уже выполнен.

       Функция gai_strerror(3) транслирует эти коды ошибок  в  читаемый  формат,  подходящий  для  сообщений  об
       ошибке.

АТРИБУТЫ

       Описание терминов данного раздела смотрите в attributes(7).
       ┌─────────────────────────────────────────────────────────────────────┬──────────────────────┬──────────┐
       │ ИнтерфейсАтрибутЗначение │
       ├─────────────────────────────────────────────────────────────────────┼──────────────────────┼──────────┤
       │ getaddrinfo_a(), gai_suspend(), gai_error(), gai_cancel()           │ Безвредность в нитях │ MT-Safe  │
       └─────────────────────────────────────────────────────────────────────┴──────────────────────┴──────────┘

СТАНДАРТЫ

       GNU.

ИСТОРИЯ

       glibc 2.2.3.

       Интерфейс getaddrinfo_a() был создан после интерфейса lio_listio(3).

ПРИМЕРЫ

       Вот  два примера: простой пример выполнения нескольких запросов синхронно одновременно, и сложный пример,
       показывающий асинхронные возможности.

   Синхронный пример
       Эта программа определяет несколько имён узлов параллельно, что быстрее по сравнению с  определением  имён
       последовательно с помощью getaddrinfo(3). Результат работы программы:

           $ ./a.out mirrors.kernel.org enoent.linuxfoundation.org gnu.org
           mirrors.kernel.org: 139.178.88.99
           enoent.linuxfoundation.org: Name or service not known
           gnu.org: 209.51.188.116

       Исходный код программы

       #define _GNU_SOURCE
       #include <err.h>
       #include <netdb.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>

       #define MALLOC(n, type)  ((type *) reallocarray(NULL, n, sizeof(type)))

       int
       main(int argc, char *argv[])
       {
           int ret;
           struct gaicb *reqs[argc - 1];
           char host[NI_MAXHOST];
           struct addrinfo *res;

           if (argc < 2) {
               fprintf(stderr, "Usage: %s HOST...\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           for (size_t i = 0; i < argc - 1; i++) {
               reqs[i] = MALLOC(1, struct gaicb);
               if (reqs[i] == NULL)
                   err(EXIT_FAILURE, "malloc");

               memset(reqs[i], 0, sizeof(*reqs[0]));
               reqs[i]->ar_name = argv[i + 1];
           }

           ret = getaddrinfo_a(GAI_WAIT, reqs, argc - 1, NULL);
           if (ret != 0) {
               fprintf(stderr, "getaddrinfo_a() failed: %s\n",
                       gai_strerror(ret));
               exit(EXIT_FAILURE);
           }

           for (size_t i = 0; i < argc - 1; i++) {
               printf("%s: ", reqs[i]->ar_name);
               ret = gai_error(reqs[i]);
               if (ret == 0) {
                   res = reqs[i]->ar_result;

                   ret = getnameinfo(res->ai_addr, res->ai_addrlen,
                                     host, sizeof(host),
                                     NULL, 0, NI_NUMERICHOST);
                   if (ret != 0) {
                       fprintf(stderr, "getnameinfo() failed: %s\n",
                               gai_strerror(ret));
                       exit(EXIT_FAILURE);
                   }
                   puts(host);

               } else {
                   puts(gai_strerror(ret));
               }
           }
           exit(EXIT_SUCCESS);
       }

   Асинхронный пример
       Данный   пример   —   простая  интерактивная  оболочка  к  getaddrinfo_a().  Возможности  уведомления  не
       используются.

       Результат работы программы:

           $ ./a.out
           > a mirrors.kernel.org enoent.linuxfoundation.org gnu.org
           > c 2
           [2] gnu.org: Request not canceled
           > w 0 1
           [00] mirrors.kernel.org: Finished
           > l
           [00] mirrors.kernel.org: 139.178.88.99
           [01] enoent.linuxfoundation.org: Processing request in progress
           [02] gnu.org: 209.51.188.116
           > l
           [00] mirrors.kernel.org: 139.178.88.99
           [01] enoent.linuxfoundation.org: Name or service not known
           [02] gnu.org: 209.51.188.116

       Исходный код программы:

       #define _GNU_SOURCE
       #include <assert.h>
       #include <err.h>
       #include <netdb.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>

       #define CALLOC(n, type)  ((type *) calloc(n, sizeof(type)))

       #define REALLOCF(ptr, n, type)                                          \
       ({                                                                      \
           static_assert(__builtin_types_compatible_p(typeof(ptr), type *));   \
                                                                               \
           (type *) reallocarrayf(ptr, n, sizeof(type));                       \
       })

       static struct gaicb **reqs = NULL;
       static size_t nreqs = 0;

       static inline void *
       reallocarrayf(void *p, size_t nmemb, size_t size)
       {
           void  *q;

           q = reallocarray(p, nmemb, size);
           if (q == NULL && nmemb != 0 && size != 0)
               free(p);
           return q;
       }

       static char *
       getcmd(void)
       {
           static char buf[256];

           fputs("> ", stdout); fflush(stdout);
           if (fgets(buf, sizeof(buf), stdin) == NULL)
               return NULL;

           if (buf[strlen(buf) - 1] == '\n')
               buf[strlen(buf) - 1] = 0;

           return buf;
       }

       /* Add requests for specified hostnames. */
       static void
       add_requests(void)
       {
           size_t nreqs_base = nreqs;
           char *host;
           int ret;

           while ((host = strtok(NULL, " "))) {
               nreqs++;
               reqs = REALLOCF(reqs, nreqs, struct gaicb *);
               if (reqs == NULL)
                   err(EXIT_FAILURE, "reallocf");

               reqs[nreqs - 1] = CALLOC(1, struct gaicb);
               if (reqs[nreqs - 1] == NULL)
                   err(EXIT_FAILURE, "calloc");

               reqs[nreqs - 1]->ar_name = strdup(host);
           }

           /* Queue nreqs_base..nreqs requests. */

           ret = getaddrinfo_a(GAI_NOWAIT, &reqs[nreqs_base],
                               nreqs - nreqs_base, NULL);
           if (ret) {
               fprintf(stderr, "getaddrinfo_a() failed: %s\n",
                       gai_strerror(ret));
               exit(EXIT_FAILURE);
           }
       }

       /* Wait until at least one of specified requests completes. */
       static void
       wait_requests(void)
       {
           char *id;
           int ret;
           size_t n;
           struct gaicb const **wait_reqs;

           wait_reqs = CALLOC(nreqs, const struct gaicb *);
           if (wait_reqs == NULL)
               err(EXIT_FAILURE, "calloc");

                       /* NULL elements are ignored by gai_suspend(). */

           while ((id = strtok(NULL, " ")) != NULL) {
               n = atoi(id);

               if (n >= nreqs) {
                   printf("Bad request number: %s\n", id);
                   return;
               }

               wait_reqs[n] = reqs[n];
           }

           ret = gai_suspend(wait_reqs, nreqs, NULL);
           if (ret) {
               printf("gai_suspend(): %s\n", gai_strerror(ret));
               return;
           }

           for (size_t i = 0; i < nreqs; i++) {
               if (wait_reqs[i] == NULL)
                   continue;

               ret = gai_error(reqs[i]);
               if (ret == EAI_INPROGRESS)
                   continue;

               printf("[%02zu] %s: %s\n", i, reqs[i]->ar_name,
                      ret == 0 ? "Finished" : gai_strerror(ret));
           }
       }

       /* Cancel specified requests. */
       static void
       cancel_requests(void)
       {
           char *id;
           int ret;
           size_t n;

           while ((id = strtok(NULL, " ")) != NULL) {
               n = atoi(id);

               if (n >= nreqs) {
                   printf("Bad request number: %s\n", id);
                   return;
               }

               ret = gai_cancel(reqs[n]);
               printf("[%s] %s: %s\n", id, reqs[atoi(id)]->ar_name,
                      gai_strerror(ret));
           }
       }

       /* List all requests. */
       static void
       list_requests(void)
       {
           int ret;
           char host[NI_MAXHOST];
           struct addrinfo *res;

           for (size_t i = 0; i < nreqs; i++) {
               printf("[%02zu] %s: ", i, reqs[i]->ar_name);
               ret = gai_error(reqs[i]);

               if (!ret) {
                   res = reqs[i]->ar_result;

                   ret = getnameinfo(res->ai_addr, res->ai_addrlen,
                                     host, sizeof(host),
                                     NULL, 0, NI_NUMERICHOST);
                   if (ret) {
                       fprintf(stderr, "getnameinfo() failed: %s\n",
                               gai_strerror(ret));
                       exit(EXIT_FAILURE);
                   }
                   puts(host);
               } else {
                   puts(gai_strerror(ret));
               }
           }
       }

       int
       main(void)
       {
           char *cmdline;
           char *cmd;

           while ((cmdline = getcmd()) != NULL) {
               cmd = strtok(cmdline, " ");

               if (cmd == NULL) {
                   list_requests();
               } else {
                   switch (cmd[0]) {
                   case 'a':
                       add_requests();
                       break;
                   case 'w':
                       wait_requests();
                       break;
                   case 'c':
                       cancel_requests();
                       break;
                   case 'l':
                       list_requests();
                       break;
                   default:
                       fprintf(stderr, "Bad command: %c\n", cmd[0]);
                       break;
                   }
               }
           }
           exit(EXIT_SUCCESS);
       }

СМОТРИТЕ ТАКЖЕ

       getaddrinfo(3), inet(3), lio_listio(3), hostname(7), ip(7), sigevent(3type)

ПЕРЕВОД

       Русский перевод этой страницы  руководства  разработал(и)  Azamat  Hackimov  <azamat.hackimov@gmail.com>,
       Dmitry   Bolkhovskikh   <d20052005@yandex.ru>,   Vladislav   <ivladislavefimov@gmail.com>,   Yuri  Kozlov
       <yuray@komyakino.ru>, Иван Павлов <pavia00@gmail.com> и Kirill Rekhov <krekhov.dev@gmail.com>

       Этот перевод является свободной программной документацией; он распространяется на условиях  общедоступной
       лицензии  GNU  (GNU  General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или
       более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.

       Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите  об  этом
       разработчику(ам)   по   его(их)  адресу(ам)  электронной  почты  или  по  адресу  списка рассылки русских
       переводчиков.

Справочные страницы Linux 6.9.1                  15 июня 2024 г.                                getaddrinfo_a(3)