GNU
2019-03-06
Aliases: gai_cancel(3), gai_cancel(3), gai_cancel(3), gai_cancel(3), gai_cancel(3), gai_cancel(3), gai_error(3), gai_error(3), gai_error(3), gai_error(3), gai_error(3), gai_error(3), gai_suspend(3), gai_suspend(3), gai_suspend(3), gai_suspend(3), gai_suspend(3), gai_suspend(3)
man-pages-ru
Russian man pages from the Linux Documentation Project
manpages-dev
Manual pages about using GNU/Linux for development
man-pages
Linux kernel and C library user-space interface documentation
ИМЯ
getaddrinfo_a, gai_suspend, gai_error, gai_cancel - асинхронная трансляция сетевого адреса и службы
ОБЗОР
#define _GNU_SOURCE /* См. feature_test_macros(7) */ #include <netdb.h>
int getaddrinfo_a(int mode, struct gaicb *list[], int nitems, struct sigevent *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);
Компонуется при указании параметра -lanl.
ОПИСАНИЕ
Функция getaddrinfo_a() выполняет ту же задачу что и getaddrinfo(3), но позволяет выполнять поиск нескольких имён асинхронно, с дополнительным уведомлением о завершении операций поиска.
При выполнении явно не указывается какие запросы завершены; для определения вам нужно обойти весь список запросов с помощью gai_error().
В аргументе 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). | |
Если значение mode равно GAI_NOWAIT, то уведомления о обработанных запросах можно получить из структуры sigevent, на которую указывает аргумент sevp. Определение и описание данной структуры приведено в sigevent(7). Поле sevp->sigev_notify может иметь следующие значения: | |
SIGEV_NONE | |
Отключить уведомление. | |
SIGEV_SIGNAL | |
При завершении поиска послать процессу сигнал sigev_signo. Подробности смотрите в sigevent(7). Полю si_code структуры siginfo_t присваивается значение SI_ASYNCNL. | |
SIGEV_THREAD | |
При завершении поиска вызвать sigev_notify_function, как если бы с этой функции начиналась бы новая нить. Подробности смотрите в sigevent(7). | |
При SIGEV_SIGNAL и SIGEV_THREAD, может быть полезно, чтобы sevp->sigev_value.sival_ptr указывала на list. | |
Функция gai_suspend() приостанавливает выполнение вызывающей нити, ожидая завершения поиска одного или более запросов из массива list. В аргументе nitems задаётся размер массива list. Вызов блокирует выполнение пока не произойдёт одно из следующего: |
* | Завершится операция для одного или более запросов из list. |
* | Вызов прервётся пойманным сигналом. |
* | Временной интервал ожидания задаётся в timeout. В данном аргумента указывается промежуток в секундах плюс наносекундах (о структуре timespec смотрите nanosleep(2)). Если timeout равно NULL, то вызов блокирует выполнение навсегда (пока не произойдёт одно из событий выше). |
Функция gai_error() возвращает состояние запроса req: EAI_INPROGRESS — запрос пока не выполнен, 0 — обработан успешно, код ошибки — запрос невозможно обработать.
Функция gai_cancel() отменяет запрос req. При успешной отмене состояние ошибки устанавливается в EAI_CANCELED и выполняется обычное асинхронное уведомление. Запрос не может быть отменён, если он начал обрабатываться; в этом случае действие будет доведено до конца, как если бы вызова gai_cancel() не происходило. Если req равно NULL, то будет предпринята попытка отменить все имеющиеся запросы.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
Функция getaddrinfo_a() возвращает 0, если все запросы были успешно обработаны или один из следующих ненулевых кодов ошибки:
Функция gai_strerror(3) транслирует эти коды ошибок в читаемый формат, подходящий для сообщений об ошибке.
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 | |
Запрос уже выполнен. |
АТРИБУТЫ
Описание терминов данного раздела смотрите в 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 ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz ftp.us.kernel.org: 128.30.2.36 enoent.linuxfoundation.org: Name or service not known gnu.cz: 87.236.197.13
Исходный код программы
#define _GNU_SOURCE #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h>
int main(int argc, char *argv[]) {
int i, ret;
struct gaicb *reqs[argc - 1];
char host[NI_MAXHOST];
struct addrinfo *res;
int i, ret;
struct gaicb *reqs[argc - 1];
char host[NI_MAXHOST];
struct addrinfo *res;
if (argc < 2) {
fprintf(stderr, "Использование: %s УЗЕЛ...\n", argv[0]);
exit(EXIT_FAILURE);
}
fprintf(stderr, "Использование: %s УЗЕЛ...\n", argv[0]);
exit(EXIT_FAILURE);
}
for (i = 0; i < argc - 1; i++) {
reqs[i] = malloc(sizeof(*reqs[0]));
if (reqs[i] == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
memset(reqs[i], 0, sizeof(*reqs[0]));
reqs[i]->ar_name = argv[i + 1];
}
reqs[i] = malloc(sizeof(*reqs[0]));
if (reqs[i] == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
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(): %s\n",
gai_strerror(ret));
exit(EXIT_FAILURE);
}
if (ret != 0) {
fprintf(stderr, "ошибка getaddrinfo_a(): %s\n",
gai_strerror(ret));
exit(EXIT_FAILURE);
}
for (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;
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(): %s\n",
gai_strerror(ret));
exit(EXIT_FAILURE);
}
puts(host);
host, sizeof(host),
NULL, 0, NI_NUMERICHOST);
if (ret != 0) {
fprintf(stderr, "ошибка getnameinfo(): %s\n",
gai_strerror(ret));
exit(EXIT_FAILURE);
}
puts(host);
} else {
puts(gai_strerror(ret));
}
}
exit(EXIT_SUCCESS); }
puts(gai_strerror(ret));
}
}
exit(EXIT_SUCCESS); }
Асинхронный пример
Данный пример — простая интерактивная оболочка к getaddrinfo_a(). Возможности уведомления не используются.
Результат работы программы:
$ ./a.out > a ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz > c 2 [2] gnu.cz: Request not canceled > w 0 1 [00] ftp.us.kernel.org: Выполнено > l [00] ftp.us.kernel.org: 216.165.129.139 [01] enoent.linuxfoundation.org: Processing request in progress [02] gnu.cz: 87.236.197.13 > l [00] ftp.us.kernel.org: 216.165.129.139 [01] enoent.linuxfoundation.org: Name or service not known [02] gnu.cz: 87.236.197.13
Исходный код программы:
#define _GNU_SOURCE #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h>
static struct gaicb **reqs = NULL; static int nreqs = 0;
static char * getcmd(void) {
static char buf[256];
static char buf[256];
fputs("> ", stdout); fflush(stdout);
if (fgets(buf, sizeof(buf), stdin) == NULL)
return NULL;
if (fgets(buf, sizeof(buf), stdin) == NULL)
return NULL;
if (buf[strlen(buf) - 1] == \(aq\n\(aq)
buf[strlen(buf) - 1] = 0;
buf[strlen(buf) - 1] = 0;
return buf; }
/* добавление запросов задаваемых имён */ static void add_requests(void) {
int nreqs_base = nreqs;
char *host;
int ret;
int nreqs_base = nreqs;
char *host;
int ret;
while ((host = strtok(NULL, " "))) {
nreqs++;
reqs = realloc(reqs, nreqs * sizeof(reqs[0]));
nreqs++;
reqs = realloc(reqs, nreqs * sizeof(reqs[0]));
reqs[nreqs - 1] = calloc(1, sizeof(*reqs[0]));
reqs[nreqs - 1]->ar_name = strdup(host);
}
reqs[nreqs - 1]->ar_name = strdup(host);
}
/* очередь запросов nreqs_base..nreqs. */
ret = getaddrinfo_a(GAI_NOWAIT, &reqs[nreqs_base],
nreqs - nreqs_base, NULL);
if (ret) {
fprintf(stderr, "ошибка getaddrinfo_a(): %s\n",
gai_strerror(ret));
exit(EXIT_FAILURE);
} }
nreqs - nreqs_base, NULL);
if (ret) {
fprintf(stderr, "ошибка getaddrinfo_a(): %s\n",
gai_strerror(ret));
exit(EXIT_FAILURE);
} }
/* ждём, пока один из запросов не выполнится */ static void wait_requests(void) {
char *id;
int i, ret, n;
struct gaicb const **wait_reqs = calloc(nreqs, sizeof(*wait_reqs));
/* элементы NULL игнорируются gai_suspend(). */
char *id;
int i, ret, n;
struct gaicb const **wait_reqs = calloc(nreqs, sizeof(*wait_reqs));
/* элементы NULL игнорируются gai_suspend(). */
while ((id = strtok(NULL, " ")) != NULL) {
n = atoi(id);
n = atoi(id);
if (n >= nreqs) {
printf("Неправильный номер запроса: %s\n", id);
return;
}
printf("Неправильный номер запроса: %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;
}
if (ret) {
printf("gai_suspend(): %s\n", gai_strerror(ret));
return;
}
for (i = 0; i < nreqs; i++) {
if (wait_reqs[i] == NULL)
continue;
if (wait_reqs[i] == NULL)
continue;
ret = gai_error(reqs[i]);
if (ret == EAI_INPROGRESS)
continue;
if (ret == EAI_INPROGRESS)
continue;
printf("[%02d] %s: %s\n", i, reqs[i]->ar_name,
ret == 0 ? "Выполнено" : gai_strerror(ret));
} }
ret == 0 ? "Выполнено" : gai_strerror(ret));
} }
/* отменяет заданные запросы */ static void cancel_requests(void) {
char *id;
int ret, n;
char *id;
int ret, n;
while ((id = strtok(NULL, " ")) != NULL) {
n = atoi(id);
n = atoi(id);
if (n >= nreqs) {
printf("Неправильный номер запроса: %s\n", id);
return;
}
printf("Неправильный номер запроса: %s\n", id);
return;
}
ret = gai_cancel(reqs[n]);
printf("[%s] %s: %s\n", id, reqs[atoi(id)]->ar_name,
gai_strerror(ret));
} }
printf("[%s] %s: %s\n", id, reqs[atoi(id)]->ar_name,
gai_strerror(ret));
} }
/* перечислим все запросы */ static void list_requests(void) {
int i, ret;
char host[NI_MAXHOST];
struct addrinfo *res;
int i, ret;
char host[NI_MAXHOST];
struct addrinfo *res;
for (i = 0; i < nreqs; i++) {
printf("[%02d] %s: ", i, reqs[i]->ar_name);
ret = gai_error(reqs[i]);
printf("[%02d] %s: ", i, reqs[i]->ar_name);
ret = gai_error(reqs[i]);
if (!ret) {
res = reqs[i]->ar_result;
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(): %s\n",
gai_strerror(ret));
exit(EXIT_FAILURE);
}
puts(host);
} else {
puts(gai_strerror(ret));
}
} }
host, sizeof(host),
NULL, 0, NI_NUMERICHOST);
if (ret) {
fprintf(stderr, "ошибка getnameinfo(): %s\n",
gai_strerror(ret));
exit(EXIT_FAILURE);
}
puts(host);
} else {
puts(gai_strerror(ret));
}
} }
int main(int argc, char *argv[]) {
char *cmdline;
char *cmd;
char *cmdline;
char *cmd;
while ((cmdline = getcmd()) != NULL) {
cmd = strtok(cmdline, " ");
cmd = strtok(cmdline, " ");
if (cmd == NULL) {
list_requests();
} else {
switch (cmd[0]) {
case \(aqa\(aq:
add_requests();
break;
case \(aqw\(aq:
wait_requests();
break;
case \(aqc\(aq:
cancel_requests();
break;
case \(aql\(aq:
list_requests();
break;
default:
fprintf(stderr, "Неверная команда: %c\n", cmd[0]);
break;
}
}
}
exit(EXIT_SUCCESS); }
list_requests();
} else {
switch (cmd[0]) {
case \(aqa\(aq:
add_requests();
break;
case \(aqw\(aq:
wait_requests();
break;
case \(aqc\(aq:
cancel_requests();
break;
case \(aql\(aq:
list_requests();
break;
default:
fprintf(stderr, "Неверная команда: %c\n", cmd[0]);
break;
}
}
}
exit(EXIT_SUCCESS); }