Provided by: manpages-fr-dev_4.27.0-1_all 

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).
┌──────────────────────────────────────────────────────────────────────┬──────────────────────┬─────────┐
│ Interface │ Attribut │ Valeur │
├──────────────────────────────────────────────────────────────────────┼──────────────────────┼─────────┤
│ 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, "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 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)