Provided by: manpages-fr-dev_4.23.1-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(),            │ Sécurité des threads │ MT-Safe │
       │gai_cancel()                                            │                      │         │
       └────────────────────────────────────────────────────────┴──────────────────────┴─────────┘

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, "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 échoué : %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 échoué : %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;
       }

       /* Ajout des requêtes pour les noms d'hôte spécifiés. */
       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 requêtes nreqs_base..nreqs. */

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

       /* Attendre qu'au moins une des requêtes spécifiées soit achevée. */
       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 éléments NULL sont ignorés par gai_suspend(). */

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

               if (n >= nreqs) {
                   printf("Mauvais nombre de requêtes : %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 ? "Terminé" : gai_strerror(ret));
           }
       }

       /* Annuler les requêtes spécifiées. */
       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 requêtes : %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 requêtes. */
       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 échoué : %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 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  ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩  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⟩.