NOM
getaddrinfo, freeaddrinfo, gai_strerror - Traduction d’adresses et de
services réseau.
SYNOPSIS
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
struct addrinfo **res);
void freeaddrinfo(struct addrinfo *res);
const char *gai_strerror(int errcode);
Exigences de macros de test de fonctionnalités pour la glibc (voir
feature_test_macros(7)) :
getaddrinfo(), freeaddrinfo(), gai_strerror() : _POSIX_C_SOURCE>= 1 ||
_XOPEN_SOURCE || _POSIX_SOURCE
Étant donnés node et service, qui identifient un hôte Internet et un
service, getaddrinfo() renvoie une ou plusieurs structure addrinfo,
chacune d’entre elles contenant une adresse Internet qui puisse être
indiquée dans un appel à bind(2) ou connect(2). La fonction
getaddrinfo() combine la fonctionnalité fournie par les fonctions
getservbyname(3) et getservbyport(3) en une interface unique, mais à
l’inverse de ces fonctions, getaddrinfo() est ré-entrante et permet aux
programmes d’éliminer la dépendance envers IPv4 ou IPv6.
La structure addrinfo utilisée par getaddrinfo() contient les membres
suivants :
struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *ai_next;
};
Le paramètre hints pointe sur une structure addrinfo qui spécifie les
critères de sélection des structures d’adresses de sockets renvoyées
dans la liste pointée par res. Si hints n’est pas NULL, il doit pointer
sur une structure addrinfo dont les membres ai_family, ai_socktype, et
ai_protocol indiquent les critères limitant l’ensemble d’adresses de
sockets renvoyées par getaddrinfo(), de la façon suivante :
ai_family Ce champ indique la famille d’adresse désirée des adresses
renvoyées. Les valeurs valides de ce champ inclues AF_INET
et AF_INET6. La valeur AF_UNSPEC indique que getaddrinfo()
doit renvoyer les adresses de socket de n’importe quelle
famille d’adresses (par exemple, IPv4 ou IPv6) pouvant être
utilisées avec node et service.
ai_socktype Ce champ indique le type préféré de socket, par exemple
SOCK_STREAM ou SOCK_DGRAM. Mettre 0 dans ce champ indique
que getaddrinfo() peut renvoyer n’importe quel type
d’adresse de socket.
ai_protocol Ce champ indique le protocole des adresses de socket
renvoyées. Mettre 0 dans ce champ indique que getaddrinfo()
peut renvoyer des adresses de socket de n’importe quel
type.
ai_flags Ce champ indique des options supplémentaires, décrites plus
loin. Divers attributs peuvent être indiqués en les
regroupant par un OU binaire.
Tous les autres membres de la structure pointée par hints doivent
contenir 0 ou être des pointeurs NULL. Spécifier hints à NULL est
équivalent à définir ai_socktype et ai_protocol à 0, ai_family à
AF_UNSPEC et ai_flags à (AI_V4MAPPED | AI_ADDRCONFIG).
node indique soit une adresse réseau en format numérique (décimal
pointé pour l’IPv4, comme prise en charge par inet_aton(3) ;
hexadécimal pour l’IPv6, comme prise en charge par inet_pton(3)), soit
un nom d’hôte, dont l’adresse réseau est alors résolue. Si le membre
hints.ai_flags contient l’attribut AI_NUMERICHOST alors node devra être
une adresse réseau numérique. L’attribut AI_NUMERICHOST empêche toute
tentative, éventuellement longue, de résolution de nom d’hôte.
Si l’attribut AI_PASSIVE est indiqué dans hints.ai_flags, et si node
est NULL, les adresses de socket renvoyées seront pertinentes pour lier
(bind(2)) un socket qui acceptera (accept(2)) les connexions. Les
adresses de socket renvoyées contiendront l’« adresse joker » (wildcard
adress) (INADDR_ANY pour les adresses IPv4, IN6ADDR_ANY_INIT pour les
adresses IPv6). L’« adresse joker » est utilisée par des applications
(typiquement des serveurs) qui ont l’intention d’accepter des
connexions de n’importe quel hôte. Si node n’est pas NULL, l’attribut
AI_PASSIVE est ignoré.
Si l’attribut AI_PASSIVE n’est pas positionné dans hints.ai_flags, les
adresses de socket renvoyées seront pertinentes pour être utilisées
avec connect(2), sendto(2) ou sendmsg(2). Si node est NULL, l’adresse
réseau sera définie avec l’adresse de l’interface de boucle (loopback)
(INADDR_LOOPBACK pour les adresses IPv4, IN6ADDR_LOOPBACK_INIT pour les
adresses IPv6) ; cela est utilisé par les applications qui doivent
communiquer avec des correspondants s’exécutant sur la même machine.
service définit le port dans chacune des structures d’adresses
renvoyées. Si cet argument est un nom de service (voir services(5)), il
est convertit en son numéro de port correspondant. Cet argument peut
également être indiqué sous forme décimale, qui est simplement converti
en binaire. Si service est NULL, le numéro de port des adresses de
socket renvoyées n’est pas initialisé. Si AI_NUMERICSERV est indiqué
dans hints.ai_flags et si service n’est pas NULL, service doit pointer
vers une chaîne contenant une valeur numérique de port. Cet attribut
est utilisé pour inhiber l’invocation du service de résolution des noms
dans les cas où l’on sait qu’il n’est pas nécessaire.
node ou service peuvent être NULL, mais pas les deux à la fois.
La fonction getaddrinfo() alloue et initialise une liste chaînée de
structures addrinfo, une pour chaque adresse réseau correspondant à
node et service, soumise aux restrictions imposées par l’argument
hints, et renvoie dans res un pointeur sur le début de la liste. Les
éléments de la liste sont chaînés par le champ ai_next.
Il y a plusieurs raisons pour lesquelles la liste chaînée peut avoir
plus d’une structure addrinfo : l’hôte réseau est « multi-homed » ; le
même service est accessible depuis plusieurs protocoles (par exemple
AF_INET et AF_INET6) ou accessible depuis plusieurs types de socket
(par exemple, une adresse de type SOCK_STREAM et une autre de type
SOCK_DGRAM). Normalement, l’application essaie d’utiliser les adresses
dans l’ordre où elles sont renvoyées. La fonction de tri utilisée dans
getaddrinfo() est définie dans la RFC 3484 ; le tri peut être configuré
pour un système particulier avec le fichier /etc/gai.conf (disponible
depuis la glibc 2.5).
Si hints.ai_flags contient l’attribut AI_CANONNAME, le champ
ai_canonname de la première structure addrinfo de la liste renvoyée est
défini pour pointer vers le nom officiel de l’hôte.
Les champs restants de chaque structure addrinfo renvoyée sont
initialisés de la façon suivante :
* Les champs ai_family, ai_socktype et ai_protocol renvoient les
paramètres de création de la socket (c’est-à-dire que ces champs ont
la même signification que les paramètres correspondants de
socket(2)). Par exemple, ai_family pourrait renvoyer AF_INET ou
AF_INET6 ; ai_socktype pourrait renvoyer SOCK_DGRAM ou SOCK_STREAM ;
et ai_protocol renvoie le protocole de la socket.
* Un pointeur vers l’adresse de la socket est placé dans le champ
ai_addr, et la longueur de l’adresse de la socket, en octets, est
inscrite dans le champ ai_addrlen de la structure.
Si hints.ai_flags inclut le drapeau AI_ADDRCONFIG, alors des adresses
IPv4 sont renvoyées dans la liste pointée par res seulement si le
système local possède au moins une adresse IPv4 configurée. Des
adresses IPv6 sont seulement renvoyées si le système local possède au
moins une adresse IPv6 configurée.
Si hint.ai_flags spécifie le drapeau AI_V4MAPPED, et si hints.ai_family
a été spécifié avec AF_INET6 et qu’aucune adresse IPv6 correspondante
n’a pu être trouvée, alors des adresses IPv4 au format IPv6 sont
renvoyées dans la liste pointée par res. Si AI_V4MAPPED et AI_ALL sont
spécifiés dans hints.ai_family, des adresses IPv6 et des adresses IPv4
au format IPv6 sont renvoyées dans la liste pointée par res. AI_ALL est
ignoré si AI_V4MAPPED n’est pas aussi spécifié.
La fonction freeaddrinfo() libère la mémoire qui a été allouée
dynamiquement pour la liste chaînée res.
Extensions de getaddrinfo() pour les noms de domaines internationalisés
Depuis la glibc 2.3.4, getaddrinfo() a été modifié pour sélectivement
permettre que les noms d’hôtes entrant et sortant soient convertis vers
ou depuis le format des noms de domaines internationalisés (IDN).
Consultez la RFC 3490, Internationalizing Domain Names in Applications
(IDNA). Quatre nouveaux attributs ont été ajoutés :
AI_IDN Si cet attribut est défini, alors le nom du nœud contenu dans
node est converti dans le format IDN si nécessaire. Le format
d’encodage choisi est celui de la locale du système.
Si le nom du nœud contient des caractères non ASCII, alors le
format IDN est utilisé. Ces parties du nom du nœud (séparées par
des points) qui contiennent des caractères non ASCI sont
encodées avec « ASCII Compatible Encoding (ACE) » avant d’être
transférées aux fonctions de résolution de noms.
AI_CANONIDN
À la suite d’une résolution de nom réussie et si AI_CANONNAME a
été spécifié, getaddrinfo() retournera le nom canonique du nœud
correspondant à la valeur de la structure addrinfo passée. La
valeur renvoyée est une copie exacte de la valeur retournée par
la fonction de résolution de noms.
Si le nom est encodé avec ACE, alors une ou plusieurs
composantes de son nom sont préfixées par xn--. Pour convertir
ces composantes dans un format lisible, l’attribut AI_CANONIDN
peut être utilisé en plus de AI_CANONNAME. La chaîne résultante
est encodée selon la locale du système.
AI_IDN_ALLOW_UNASSIGNED, AI_IDN_USE_STD3_ASCII_RULES
Utiliser ces attributs permet d’activer respectivement les
attributs «IDNA_ALLOW_UNASSIGNED » (permettre des caractères
Unicode non assignés) et « IDNA_USE_STD3_ASCII_RULES » (vérifier
la sortie pour être sûr que le nom d’hôte est conforme à STD3)
utilisés dans la gestion de l’IDNA.
VALEUR RENVOYÉE
getaddrinfo() renvoie 0 si elle réussit, ou l’un des codes d’erreur non
nuls suivants :
EAI_ADDRFAMILY
L’hôte indiqué n’a pas d’adresse dans la famille réseau
demandée.
EAI_AGAIN
Le serveur de noms a renvoyé une erreur temporaire. Réessayez
plus tard.
EAI_BADFLAGS
hints.ai_flags contient des drapeaux invalides ; ou
hints.ai_flags inclut AI_CANONNAME et name est NULL.
EAI_FAIL
Le serveur de noms a renvoyé une erreur définitive.
EAI_FAMILY
La famille d’adresse réclamée n’est pas supportée.
EAI_MEMORY
Plus de mémoire disponible.
EAI_NODATA
L’hôte existe mais n’a pas d’adresse réseau définie.
EAI_NONAME
node ou service sont inconnus ou ils sont tous les deux NULL ;
ou AI_NUMERICSERV a été spécifié dans hints.ai_flags mais
service n’est pas un numéro de port.
EAI_SERVICE
Le service demandé n’est pas disponible pour le type de socket
demandé. Il est probablement disponible avec un autre type de
socket. Par exemple, cette erreur peut se produire si service
est « shell » (un service uniquement disponible avec les sockets
de type flux), et soit si hints.ai_protocol est égal à
IPPROTO_UDP ou soit si hints.ai_socktype est égal à SOCK_DGRAM.
L’erreur peut aussi se produire si service est non NULL et
hints.ai_socktype est égal à SOCK_RAW (un type de socket qui ne
gère pas le concept de service).
EAI_SOCKTYPE
Le type de socket demandé n’est pas géré. Cela peut se produire,
par exemple si hints.ai_socktype et hints.ai_protocol sont
inconsistants (par exemple, SOCK_DGRAM et IPPROTO_TCP,
respectivement).
EAI_SYSTEM
Autre erreur système, voir errno pour plus de détail.
La fonction gai_strerror() traduit ces codes d’erreur en une chaîne de
caractères compréhensible, utilisable pour rendre compte du problème.
FICHIERS
/etc/gai.conf
CONFORMITÉ
POSIX.1-2001. La fonction getaddrinfo() est documentée dans la
RFC 2553.
NOTES
getaddrinfo() gère la notation address%scope-id pour indiquer
l’identifiant scope de IPv6.
AI_ADDRCONFIG, AI_ALL et AI_V4MAPPED sont disponibles depuis la
glibc 2.3.3. AI_NUMERICSERV est disponible depuis glibc 2.3.4.
Selon POSIX.1-2001, définir hints comme NULL devrait supposer que
ai_flags soit égal à 0. La bibliothèque GNU C suppose à la place que
ai_flags est égal à of (AI_V4MAPPED | AI_ADDRCONFIG) dans ce cas,
puisque cette valeur est considérée comme une amélioration de la
spécification.
EXEMPLE
Le programme suivant explique l’utilisation de getaddrinfo(),
gai_strerror(), freeaddrinfo(), et getnameinfo(3). Les programmes sont
des clients et serveurs
Programme du serveur
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#define BUF_SIZE 500
int
main(int argc, char *argv[])
{
struct addrinfo hints;
struct addrinfo *result, *rp;
int sfd, s;
struct sockaddr_storage peer_addr;
socklen_t peer_addr_len;
ssize_t nread;
char buf[BUF_SIZE];
if (argc != 2) {
fprintf(stderr, "Usage: %s port\n", argv[0]);
exit(EXIT_FAILURE);
}
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
hints.ai_protocol = 0; /* Any protocol */
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
s = getaddrinfo(NULL, argv[1], &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully bind(2).
If socket(2) (or bind(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sfd == -1)
continue;
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
break; /* Success */
close(sfd);
}
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not bind\n");
exit(EXIT_FAILURE);
}
freeaddrinfo(result); /* No longer needed */
/* Read datagrams and echo them back to sender */
for (;;) {
peer_addr_len = sizeof(struct sockaddr_storage);
nread = recvfrom(sfd, buf, BUF_SIZE, 0,
(struct sockaddr *) &peer_addr, &peer_addr_len);
if (nread == -1)
continue; /* Ignore failed request */
char host[NI_MAXHOST], service[NI_MAXSERV];
s = getnameinfo((struct sockaddr *) &peer_addr,
peer_addr_len, host, NI_MAXHOST,
service, NI_MAXSERV, NI_NUMERICSERV);
if (s == 0)
printf("Received %ld bytes from %s:%s\n",
(long) nread, host, service);
else
fprintf(stderr, "getnameinfo: %s\n", gai_strerror(s));
if (sendto(sfd, buf, nread, 0,
(struct sockaddr *) &peer_addr,
peer_addr_len) != nread)
fprintf(stderr, "Error sending response\n");
}
}
Programme du client
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define BUF_SIZE 500
int
main(int argc, char *argv[])
{
struct addrinfo hints;
struct addrinfo *result, *rp;
int sfd, s, j;
size_t len;
ssize_t nread;
char buf[BUF_SIZE];
if (argc < 3) {
fprintf(stderr, "Usage: %s host port msg...\n", argv[0]);
exit(EXIT_FAILURE);
}
/* Obtain address(es) matching host/port */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = 0;
hints.ai_protocol = 0; /* Any protocol */
s = getaddrinfo(argv[1], argv[2], &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully connect(2).
If socket(2) (or connect(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sfd == -1)
continue;
if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
break; /* Success */
close(sfd);
}
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not connect\n");
exit(EXIT_FAILURE);
}
freeaddrinfo(result); /* No longer needed */
/* Send remaining command-line arguments as separate
datagrams, and read responses from server */
for (j = 3; j < argc; j++) {
len = strlen(argv[j]) + 1;
/* +1 for terminating null byte */
if (len + 1 > BUF_SIZE) {
fprintf(stderr,
"Ignoring long message in argument %d\n", j);
continue;
}
if (write(sfd, argv[j], len) != len) {
fprintf(stderr, "partial/failed write\n");
exit(EXIT_FAILURE);
}
nread = read(sfd, buf, BUF_SIZE);
if (nread == -1) {
perror("read");
exit(EXIT_FAILURE);
}
printf("Received %ld bytes: %s\n", (long) nread, buf);
}
exit(EXIT_SUCCESS);
}
VOIR AUSSI
gethostbyname(3), getnameinfo(3), inet(3), hostname(7), ip(7)
COLOPHON
Cette page fait partie de la publication 3.23 du projet man-pages
Linux. Une description du projet et des instructions pour signaler des
anomalies peuvent être trouvées à l’adresse
http://www.kernel.org/doc/man-pages/.
TRADUCTION
Cette page de manuel a été traduite et mise à jour par Christophe
Blaess <http://www.blaess.fr/christophe/> entre 1996 et 2003, puis par
Alain Portal <aportal AT univ-montp2 DOT fr> jusqu’en 2006, et mise à
disposition sur http://manpagesfr.free.fr/.
Les mises à jour et corrections de la version présente dans Debian sont
directement gérées par Florentin Duneau <fduneau@gmail.com> et l’équipe
francophone de traduction de Debian.
Veuillez signaler toute erreur de traduction en écrivant à
<debian-l10n-french@lists.debian.org> ou par un rapport de bogue sur le
paquet manpages-fr.
Vous pouvez toujours avoir accès à la version anglaise de ce document
en utilisant la commande « man -L C <section> <page_de_man> ».