C++ La fonction getaddrinfo(...)

Par Cinux, le 10 février 2017

J'utilisais habituellement la fonction gethostbyname2() pour récupérer l'adresse IP d'un nom de domaine pour mes softs en C++. En relisant la man page je suis tombé sur ceci:
" gethostbyname*(), gethostbyaddr*(), herror() et hstrerror() sont déconseillées. Les applications devraient utiliser getaddrinfo(3), getnameinfo(3) et gai_strerror(3) à la place."
La fonction getaddrindo() permet de récupérer des informations une ou plusieurs machines distantes. Voyons en premier lieu, les différents prototypes dont nous aurons besoin:

/************* P R O T O *************/
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int getaddrinfo(const char *nodename, const char *servname,
                const struct addrinfo *hints, struct addrinfo **res);

void freeaddrinfo(struct addrinfo *ai);

const char* gai_strerror(int ecode);

struct addrinfo {
  int     ai_flags;              // AI_PASSIVE, AI_CANONNAME, ...
  int     ai_family;            // AF_xxx
  int     ai_socktype;       // SOCK_xxx
  int     ai_protocol;         // 0 (auto) or IPPROTO_TCP, IPPROTO_UDP 

  socklen_t  ai_addrlen;        // length of ai_addr
  char   *ai_canonname;       // canonical name for nodename
  struct sockaddr  *ai_addr;  // binary address
  struct addrinfo  *ai_next;    // next structure in linked list
};
/******************* E N D   C O D E *****************/


La fonction getaddrinfo():
Elle retourne 0 si elle réussi et un code d'erreur en cas de problème (voir man getaddrinfo).
  • const char* nodename est le nom de l'hôte. Il peut être une IP de la forme 123.123.123.123 ou un nom de domaine comme un.exemple.com.
  • const char* servname est le nom du service. Il s'agit typiquement d'un port, mais on peut aussi lui passer des chaînes de caractères comme ftp, http... Ce paramètre peut être NULL.
  • struct addrinfo* hints pointe sur une structure addrinfo qui indique 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().
  • struct addrinfo** res pointe sur une liste de structures addrinfo qui auront été créé par la fonction grâce aux paramètres passés via 'hints'.

    Exemple:
    #include <itostream>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    
    int main() 
    {
        const  std::string       hostname = "qwant.com";
        struct addrinfo          hints; 
        struct addrinfo         *addrLst;
        struct sockaddr_in       sin;
    
        memset(&hints, 0, sizeof(hints)); // initialisation à 0 de la structure
        // On paramètre ensuite hints
        hints.ai_family     =   AF_INET; // AF_INET6 pour de l'ipv6
        hints.ai_socktype   =   SOCK_STREAM; // On est en TCP. Pour l'UDP on utilisera SOCK_DGRAM
        hints.ai_protocol   =   0;
        hints.ai_addr       =   NULL;
        hints.ai_canonname  =   NULL;
        hints.ai_next       =   NULL;
    
    
        int info = getaddrinfo(hostname.c_str(), NULL, &hints, &addrLst);
        if (info != 0) // On vérifie que tout se soit bien passé
        {
            // gai_strerror prend en arg le code d'erreur. 
            std::cout << hostname.c_str() << " : " <<  gai_strerror(info) <<  std::endl; 
            return 1;
        }
    
         // On stock l'adresse du serveur dans sin pour pouvoir l'utiliser au format sockaddr_in
        sin.sin_addr    = *(struct sockaddr_in*)info_retv->ai_addr; 
        sin.sin_family  = AF_INET;
    
        std::cout << "IP du serveur = " << inet_ntoa(sin.sin_addr) << std::endl; 
    
        freeaddrinfo(addrLst);    // On n'oublie pas de rendre la mémoire au système 
        return 0;
    }
  • Mots clés : aucun
    Classé dans : Dev