getaddrinfo_a(3) Library Functions Manual getaddrinfo_a(3) NOM getaddrinfo_a, gai_suspend, gai_error, gai_cancel - Traduction asynchrone d'adresses et de services reseau BIBLIOTHEQUE Bibliotheque de resolution de noms asynchrone (libanl, -lanl) SYNOPSIS #define _GNU_SOURCE /* Consultez 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); DESCRIPTION La fonction getaddrinfo_a() effectue la meme operation que getaddrinfo(3), mais permet d'effectuer plusieurs resolutions de maniere asynchrone et de recevoir une notification a chaque resolution effectuee. Le champ mode peut prendre une des valeurs suivantes : GAI_WAIT Effectue les resolutions de maniere synchrone. L'appel bloque tant que les resolutions ne sont pas terminees. GAI_NOWAIT Effectue les resolutions de maniere asynchrone. L'appel s'acheve immediatement et les requetes sont resolues en arriere-plan. Consultez la description du parametre sevp ci-dessous. Le tableau list indique les requetes de recherche a traiter. Le parametre nitems indique le nombre d'elements dans list. Les operations de recherche demandees sont lancees en parallele. Les elements egal a NULL de list sont ignores. Chaque requete est decrite par une structure gaicb definie ci-dessous : struct gaicb { const char *ar_name; const char *ar_service; const struct addrinfo *ar_request; struct addrinfo *ar_result; }; Les elements de cette structure correspondent aux parametres de getaddrinfo(3). Ainsi, ar_name correspond au parametre node et ar_service au parametre service, identifiant respectivement un hote et un service Internet. L'element ar_request correspond au parametre hints, indiquant le critere de selection des structures d'adresse de socket renvoyees. Enfin, ar_result correspond au parametre res ; vous n'avez pas besoin d'initialiser ce parametre, il sera automatiquement defini lorsque la requete sera resolue. La structure addrinfo referencee par les deux derniers elements est decrite dans getaddrinfo(3). Lorsque mode est defini a GAI_NOWAIT, les notifications des requetes resolues peuvent etre obtenues avec la structure sigevent pointee par le parametre sevp. Pour la definition et les details generaux de cette structure, consultez sigevent(3type). Le champ sevp->sigev_notify peut prendre l'une des valeurs suivantes : SIGEV_NONE Ne fournit pas de notification. SIGEV_SIGNAL Lorsqu'une recherche se termine, generer le signal sigev_signo a destination du processus. Consultez sigevent(3type) pour plus de details. Le champ si_code de la structure siginfo_t sera defini a SI_ASYNCNL. SIGEV_THREAD Lors d'une resolution, invoquer sigev_notify_function comme si c'etait la fonction de creation d'un nouveau processus leger. Consultez sigevent(3type) pour plus details. Pour SIGEV_SIGNAL et SIGEV_THREAD, il peut etre utile de faire pointer sevp->sigev_value.sival_ptr vers list. La fonction gai_suspend() suspend l'execution du processus leger appelant, attendant la fin d'une ou plusieurs requetes du tableau list. L'argument nitems indique la taille du tableau list. L'appel est bloquant tant que l'un des evenements suivants ne se produisent : - Une ou plusieurs des operations de list se sont terminees. - L'appel a ete interrompu par un signal qui a ete interrompu. - L'intervalle de temps indique dans timeout s'est ecoule. Ce parametre indique un delai en seconds plus nanosecondes (consultez nanosleep(2) pour plus de details sur la structure timespec). Si timeout est NULL, alors l'appel est bloque indefiniment (a moins que l'un des evenement ci-dessus se produisent). Aucune indication explicite sur la requete qui s'est terminee est fournie ; vous devez determiner quelle requete s'est terminee en parcourant avec gai_error() la liste des requete (il peut y avoir plusieurs requetes). La fonction gai_error() renvoie l'etat de la requete req : soit EAI_INPROGRESS si la requete ne s'est pas encore terminee, soit 0 si elle s'est termine correctement ou soit un code d'erreur si elle ne peut pas etre resolue. La fonction gai_cancel() annule la requete req. Si la requete a ete annulee avec succes, le statut d'erreur de la requete sera defini a EAI_CANCELED et un notification asynchrone normale sera executee. La requete ne peut pas etre annulee si elle est en cours d'utilisation ; dans ce cas, elle continuera comme si gai_cancel() n'avait jamais ete appelee. Si req est NULL, une tentative d'annulation de toutes les requetes en cours que le processus a fait sera executee. VALEUR RENVOYEE La fonction getaddrinfo_a() renvoie 0 si toutes les requetes ont ete mises en file d'attente avec succes, ou un des codes d'erreur non nuls suivants : EAI_AGAIN Les ressources necessaires pour mettre en file d'attente les requetes de recherche ne sont pas disponibles. L'application devrait verifier le statut d'erreur de chaque requete pour determiner laquelle a echoue. EAI_MEMORY Plus assez de memoire. EAI_SYSTEM mode est non valable. La fonction gai_suspend() renvoie 0 si au moins une des requetes listees s'est terminee. Sinon, elle renvoie un des codes d'erreur non nuls suivants : EAI_AGAIN Le delai d'attente a expire avant que toute requete ne soit terminee. EAI_ALLDONE Il n'y a actuellement aucune requete fournie a la fonction. EAI_INTR Un signal a interrompu la fonction. Notez que cette interruption pourrait avoir ete cause par une notification de signal de fin de certaines requetes de recherche. La fonction gai_error() peut renvoyer EAI_INPROGRESS pour une requete de recherche non terminee, 0 pour une recherche terminee avec succes (cas decrit ci-dessus), un des codes d'erreur qui peut etre renvoye par getaddrinfo(3), ou le code d'erreur EAI_CANCELED si la requete a ete annulee explicitement avant quelle ne soit terminee. La fonction gai_cancel() peut renvoyer une des valeurs suivantes : EAI_CANCELED La requete a ete annulee avec succes. EAI_NOTCANCELED La requete n'a pas ete annulee. EAI_ALLDONE La requete est deja terminee. La fonction gai_strerror(3) traduit ces codes d'erreur en une chaine de caracteres comprehensible, utilisable pour rendre compte du probleme. ATTRIBUTS Pour une explication des termes utilises dans cette section, consulter attributes(7). +---------------------------------+--------------------------+---------+ |Interface | Attribut | Valeur | +---------------------------------+--------------------------+---------+ |getaddrinfo_a(), gai_suspend(), | Securite des threads | MT-Safe | |gai_error(), gai_cancel() | | | +---------------------------------+--------------------------+---------+ STANDARDS GNU. HISTORIQUE glibc 2.2.3. L'interface de getaddrinfo_a() a ete modifiee apres l'interface lio_listio(3). EXEMPLES Deux exemples sont fournis : un simple exemple qui resout plusieurs requete en parallele de facon synchrone et un exemple complexe montrant certaines des capacites asynchrones. Exemple synchrone Le programme ci-dessous resout simplement plusieurs noms d'hote en parallele, ameliorant le temps de resolution des noms d'hotes compare a des appels sequentiels a getaddrinfo(3). Le programme peut etre utilise comme suit : $ ./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 Voila le code source du programme #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, "Utilisation : %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() a echoue : %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() a echoue : %s\n", gai_strerror(ret)); exit(EXIT_FAILURE); } puts(host); } else { puts(gai_strerror(ret)); } } exit(EXIT_SUCCESS); } Exemple asynchrone Cet exemple est une simple application interactive utilisant getaddrinfo_a(). Les fonctionnalites de notification ne sont pas exploitees. Un exemple de session pourrait ressembler a ceci : $ ./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 Le code source du programme est : #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; } /* Ajout des requetes pour les noms d'hote specifies. */ 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); } /* Mettre en file d'attente les requetes nreqs_base..nreqs. */ ret = getaddrinfo_a(GAI_NOWAIT, &reqs[nreqs_base], nreqs - nreqs_base, NULL); if (ret) { fprintf(stderr, "getaddrinfo_a() a echoue : %s\n", gai_strerror(ret)); exit(EXIT_FAILURE); } } /* Attendre qu'au moins une des requetes specifiees soit achevee. */ 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"); /* Les elements NULL sont ignores par gai_suspend(). */ while ((id = strtok(NULL, " ")) != NULL) { n = atoi(id); if (n >= nreqs) { printf("Mauvais nombre de requetes : %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 ? "Termine" : gai_strerror(ret)); } } /* Annuler les requetes specifiees. */ static void cancel_requests(void) { char *id; int ret; size_t n; while ((id = strtok(NULL, " ")) != NULL) { n = atoi(id); if (n >= nreqs) { printf("Mauvais nombre de requetes : %s\n", id); return; } ret = gai_cancel(reqs[n]); printf("[%s] %s: %s\n", id, reqs[atoi(id)]->ar_name, gai_strerror(ret)); } } /* Lister toutes les requetes. */ 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() a echoue : %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, "Mauvaise commande : %c\n", cmd[0]); break; } } } exit(EXIT_SUCCESS); } VOIR AUSSI getaddrinfo(3), inet(3), lio_listio(3), hostname(7), ip(7), sigevent(3type) TRADUCTION La traduction francaise de cette page de manuel a ete creee par Christophe Blaess , Stephan Rafin , Thierry Vignaud , Francois Micaux, Alain Portal , Jean-Philippe Guerard , Jean-Luc Coulon (f5ibh) , Julien Cristau , Thomas Huriaux , Nicolas Francois , Florentin Duneau , Simon Paillard , Denis Barbier , David Prevot et Jean-Pierre Giraud Cette traduction est une documentation libre ; veuillez vous reporter a la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITE LEGALE. Si vous decouvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message a . Pages du manuel de Linux 6.06 31 octobre 2023 getaddrinfo_a(3)