NOM
getaddrinfo_a, gai_suspend, gai_error, gai_cancel - Traduction asynchrone d'adresses et de services réseauBIBLIOTHÈ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.
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(7). 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(7) 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(7) pour plus détails.
- •
- 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).
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.
- 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.
- 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.
ATTRIBUTS
Pour une explication des termes utilisés dans cette section, consulter attributes(7).Interface | Attribut | Valeur |
getaddrinfo_a(), gai_suspend(), gai_error(), gai_cancel() | Sécurité des threads | MT-Safe |
STANDARDS
Ces fonctions sont des extensions GNU. Elles ont été introduites dans la glibc 2.2.3.NOTES
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 <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> 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(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() 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 <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> static struct gaicb **reqs = NULL; static size_t nreqs = 0; 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 = realloc(reqs, sizeof(reqs[0]) * nreqs); reqs[nreqs - 1] = calloc(1, sizeof(*reqs[0])); 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 = calloc(nreqs, sizeof(*wait_reqs)); /* 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(7)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 <[email protected]>, Thierry Vignaud <[email protected]>, François Micaux, Alain Portal <[email protected]>, Jean-Philippe Guérard <[email protected]>, Jean-Luc Coulon (f5ibh) <[email protected]>, Julien Cristau <[email protected]>, Thomas Huriaux <[email protected]>, Nicolas François <[email protected]>, Florentin Duneau <[email protected]>, Simon Paillard <[email protected]>, Denis Barbier <[email protected]> et David Prévot <[email protected]> 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 à [email protected]5 février 2023 | Pages du manuel de Linux 6.03 |