Provided by: manpages-fr-dev_4.26.0-1_all bug

NOM

       getaddrinfo_a,  gai_suspend,  gai_error,  gai_cancel  –  Traduction  asynchrone d'adresses et de services
       réseau

BIBLIOTHÈQUE

       Bibliothèque de résolution de noms asynchrone (libanl, -lanl)

SYNOPSIS

       #define _GNU_SOURCE         /* Consultez 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);

DESCRIPTION

       La fonction getaddrinfo_a() effectue la  même  opération  que  getaddrinfo(3),  mais  permet  d'effectuer
       plusieurs  résolutions  de  manière  asynchrone  et  de  recevoir  une  notification  à chaque résolution
       effectuée.

       Le champ mode peut prendre une des valeurs suivantes :

       GAI_WAIT
              Effectue les résolutions de manière synchrone. L'appel bloque tant que les résolutions ne sont pas
              terminées.

       GAI_NOWAIT
              Effectue les résolutions de manière asynchrone. L'appel s'achève  immédiatement  et  les  requêtes
              sont résolues en arrière-plan. Consultez la description du paramètre sevp ci-dessous.

       Le  tableau  list  indique  les  requêtes  de  recherche à traiter. Le paramètre nitems indique le nombre
       d'éléments dans list. Les opérations de recherche demandées sont lancées en parallèle. Les éléments  égal
       à NULL de list sont ignorés. Chaque requête est décrite par une structure gaicb définie ci-dessous :

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

       Les éléments de cette structure correspondent aux paramètres de getaddrinfo(3). Ainsi, ar_name correspond
       au  paramètre  node  et ar_service au paramètre service, identifiant respectivement un hôte et un service
       Internet. L'élément ar_request correspond au paramètre hints,  indiquant  le  critère  de  sélection  des
       structures  d'adresse de socket renvoyées. Enfin, ar_result correspond au paramètre res ; vous n'avez pas
       besoin d'initialiser ce paramètre, il sera automatiquement défini lorsque la  requête  sera  résolue.  La
       structure addrinfo référencée par les deux derniers éléments est décrite dans getaddrinfo(3).

       Lorsque  mode est défini à GAI_NOWAIT, les notifications des requêtes résolues peuvent être obtenues avec
       la structure sigevent pointée par le paramètre sevp. Pour la définition et les détails généraux 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,  générer  le  signal  sigev_signo  à  destination  du  processus.
              Consultez  sigevent(3type)  pour  plus de détails. Le champ si_code de la structure siginfo_t sera
              défini à SI_ASYNCNL.

       SIGEV_THREAD
              Lors d'une résolution, invoquer sigev_notify_function comme si c'était  la  fonction  de  création
              d'un nouveau processus léger. Consultez sigevent(3type) pour plus détails.

       Pour  SIGEV_SIGNAL  et SIGEV_THREAD, il peut être utile de faire pointer sevp->sigev_value.sival_ptr vers
       list.

       La fonction gai_suspend() suspend l'exécution du processus léger appelant,  attendant  la  fin  d'une  ou
       plusieurs  requêtes  du  tableau  list.  L'argument nitems indique la taille du tableau list. L'appel est
       bloquant tant que l'un des événements suivants ne se produisent :

       -  Une ou plusieurs des opérations de list se sont terminées.

       -  L'appel a été interrompu par un signal qui a été interrompu.

       -  L'intervalle de temps indiqué dans timeout s'est écoulé. Ce paramètre indique un délai en seconds plus
          nanosecondes (consultez nanosleep(2) pour plus de détails sur la structure timespec). Si  timeout  est
          NULL, alors l'appel est bloqué indéfiniment (à moins que l'un des événement ci-dessus se produisent).

       Aucune  indication explicite sur la requête qui s'est terminée est fournie ; vous devez déterminer quelle
       requête s'est terminée en parcourant avec gai_error() la liste des requête (il  peut  y  avoir  plusieurs
       requêtes).

       La fonction gai_error() renvoie l'état de la requête req : soit EAI_INPROGRESS si la requête ne s'est pas
       encore  terminée,  soit 0 si elle s'est terminé correctement ou soit un code d'erreur si elle ne peut pas
       être résolue.

       La fonction gai_cancel() annule la requête req. Si la requête  a  été  annulée  avec  succès,  le  statut
       d'erreur de la requête sera défini à EAI_CANCELED et un notification asynchrone normale sera exécutée. La
       requête  ne peut pas être annulée si elle est en cours d'utilisation ; dans ce cas, elle continuera comme
       si gai_cancel() n'avait jamais été appelée. Si req est NULL, une tentative  d'annulation  de  toutes  les
       requêtes en cours que le processus a fait sera exécutée.

VALEUR RENVOYÉE

       La fonction getaddrinfo_a() renvoie 0 si toutes les requêtes ont été mises en file d'attente avec succès,
       ou un des codes d'erreur non nuls suivants :

       EAI_AGAIN
              Les  ressources  nécessaires  pour  mettre en file d'attente les requêtes de recherche ne sont pas
              disponibles. L'application devrait vérifier le statut d'erreur de chaque requête  pour  déterminer
              laquelle a échoué.

       EAI_MEMORY
              Plus assez de mémoire.

       EAI_SYSTEM
              mode est non valable.

       La  fonction  gai_suspend()  renvoie  0  si au moins une des requêtes listées s'est terminée. Sinon, elle
       renvoie un des codes d'erreur non nuls suivants :

       EAI_AGAIN
              Le délai d'attente a expiré avant que toute requête ne soit terminée.

       EAI_ALLDONE
              Il n'y a actuellement aucune requête fournie à la fonction.

       EAI_INTR
              Un signal a interrompu la fonction. Notez que cette interruption pourrait avoir été causé par  une
              notification de signal de fin de certaines requêtes de recherche.

       La  fonction  gai_error() peut renvoyer EAI_INPROGRESS pour une requête de recherche non terminée, 0 pour
       une recherche terminée avec succès (cas décrit ci-dessus), un des codes d'erreur qui  peut  être  renvoyé
       par  getaddrinfo(3),  ou  le  code  d'erreur EAI_CANCELED si la requête a été annulée explicitement avant
       quelle ne soit terminée.

       La fonction gai_cancel() peut renvoyer une des valeurs suivantes :

       EAI_CANCELED
              La requête a été annulée avec succès.

       EAI_NOTCANCELED
              La requête n'a pas été annulée.

       EAI_ALLDONE
              La requête est déjà terminée.

       La fonction gai_strerror(3) traduit ces codes  d'erreur  en  une  chaîne  de  caractères  compréhensible,
       utilisable pour rendre compte du problème.

ATTRIBUTS

       Pour une explication des termes utilisés dans cette section, consulter attributes(7).
       ┌──────────────────────────────────────────────────────────────────────┬──────────────────────┬─────────┐
       │ InterfaceAttributValeur  │
       ├──────────────────────────────────────────────────────────────────────┼──────────────────────┼─────────┤
       │ getaddrinfo_a(), gai_suspend(), gai_error(), gai_cancel()            │ Sécurité des threads │ MT-Safe │
       └──────────────────────────────────────────────────────────────────────┴──────────────────────┴─────────┘

STANDARDS

       GNU.

HISTORIQUE

       glibc 2.2.3.

       L'interface de getaddrinfo_a() a été modifiée après l'interface lio_listio(3).

EXEMPLES

       Deux  exemples  sont  fournis :  un  simple  exemple  qui  résout plusieurs requête en parallèle de façon
       synchrone et un exemple complexe montrant certaines des capacités asynchrones.

   Exemple synchrone
       Le programme ci-dessous résout simplement plusieurs noms d'hôte en  parallèle,  améliorant  le  temps  de
       résolution  des  noms  d'hôtes  comparé à des appels séquentiels à getaddrinfo(3). Le programme peut être
       utilisé 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

       Voilà le code source du programme

       #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);
       }

   Exemple asynchrone
       Cet exemple est une simple application interactive  utilisant  getaddrinfo_a().  Les  fonctionnalités  de
       notification ne sont pas exploitées.

       Un exemple de session pourrait ressembler à 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 <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);
       }

VOIR AUSSI

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

TRADUCTION

       La   traduction   française   de   cette   page   de   manuel   a   été   créée   par  Christophe  Blaess
       <https://www.blaess.fr/christophe/>,   Stéphan   Rafin   <stephan.rafin@laposte.net>,   Thierry   Vignaud
       <tvignaud@mandriva.com>,  François  Micaux,  Alain Portal <aportal@univ-montp2.fr>, Jean-Philippe Guérard
       <fevrier@tigreraye.org>,   Jean-Luc   Coulon   (f5ibh)   <jean-luc.coulon@wanadoo.fr>,   Julien   Cristau
       <jcristau@debian.org>,      Thomas      Huriaux      <thomas.huriaux@gmail.com>,     Nicolas     François
       <nicolas.francois@centraliens.net>,    Florentin    Duneau    <fduneau@gmail.com>,     Simon     Paillard
       <simon.paillard@resel.enst-bretagne.fr>,     Denis    Barbier    <barbier@debian.org>,    David    Prévot
       <david@tilapin.org> et Jean-Pierre Giraud <jean-pierregiraud@neuf.fr>

       Cette traduction est une documentation libre ; veuillez vous  reporter  à  la  GNU General Public License
       version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.

       Si  vous  découvrez  un  bogue  dans la traduction de cette page de manuel, veuillez envoyer un message à
       debian-l10n-french@lists.debian.org.

Pages du manuel de Linux 6.9.1                    15 juin 2024                                  getaddrinfo_a(3)