getaddrinfo_a(3) Library Functions Manual getaddrinfo_a(3) getaddrinfo_a, gai_suspend, gai_error, gai_cancel - LIBRARY Asynchronous name lookup library (libanl, -lanl) #define _GNU_SOURCE /* . feature_test_macros(7) */ #include 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. : o list. o . o 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(), | | MT-Safe | |gai_suspend(), gai_error(), | | | |gai_cancel() | | | +----------------------------+----------------------------------------------------------+--------------------------+ 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 #include #include #include #include #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 #include #include #include #include #include #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 , Dmitry Bolkhovskikh , Vladislav , Yuri Kozlov ; GNU 3 , . . , , . Linux man-pages 6.06 31 2023 . getaddrinfo_a(3)