Getaddrinfo

getaddrinfo()‎ و getnameinfo()‎ دو تابع در استاندارد پازیکس هستند که برای تبدیل کردن اسامی میزبان (به انگلیسی: hostname) و آدرس‌های آی‌پی، از فرم متنی قابل فهم برای انسان، به قالب دودویی ساختارمند که برای رایانه قابل فهم است (و برعکس)، مورد استفاده قرار می‌گیرند. این دو تابع معکوس همدیگر هستند. getaddrinfo نام دامنه یا آدرس IP را به نمایش دودویی قابل فهم برای رایانه تبدیل می‌کند و getnameinfo هم برعکس، نمایش دودویی یک آدرس را به فرم قابل فهم برای انسان تبدیل می‌کند. این توابع هم از IPv4 و هم از IPv6 پشتیبانی می‌کنند. برای ساخت برنامه‌های غیر وابسته به یک پروتکل خاص و همینطور برای گذار و مهاجرت از IPv4 به IPv6، استفاده از این توابع توصیه شده است. از نظر داخلی، این دو تابع برای انجام پرسوجوی DNS توابع دیگر و سطح پایینتری مانند gethostbyname()‎ را فراخوانی می‌کنند. فایل resolv.conf نحوه انجام این پرس و جو را مشخص می‌کند و از طریق این فایل می‌توان این رفتار را تغییر داد.

ساختار addrinfo

ساختاری که در زبان برنامه‌نویسی سی برای کار با این توابع استفاده می‌شود addrinfo نام دارد و نمایش‌دهنده آدرس‌های آی‌پی و اسامی میزبان است. این ساختار در فایل سرایند netdb.h تعریف شده است:

     struct addrinfo {
             int ai_flags;           /* input flags */
             int ai_family;          /* protocol family for socket */
             int ai_socktype;        /* socket type */
             int ai_protocol;        /* protocol for socket */
             socklen_t ai_addrlen;   /* length of socket-address */
             struct sockaddr *ai_addr; /* socket-address for socket */
             char *ai_canonname;     /* canonical name for service location */
             struct addrinfo *ai_next; /* pointer to next in list */
     };
در سیستم‌عاملهای قدیمی، عضو ai_addrlen به جای اینکه از نوع socklen_t باشد، از نوع size_t تعریف شده بود که در سیستم‌های جدید تغییر یافته است. بیشتر توابع مربوط به سوکت‌ها، همانند accept()‎ و getpeername()‎، معمولاً پارامتری از نوع socklen_t*‎ دارند و برنامه‌نویس معمولاً آدرس عضو ai_addrlen در ساختار addrinfo را به عنوان آرگومان برای این توابع ارسال می‌کند. اگر این نوع داده‌ها سازگار نباشند، امکان بروز خطای زمان اجرا وجود دارد. برای مثال در سیستم‌عامل ۶۴بیتی و big-endian سولاریس ۹، اندازه size_t هشت بایت است و socklen_t چهار بایت است که size_t و socklen_t ناسازگار هستند.

getnameinfo

تابع getnameinfo نمایش دودویی یک آدرس IP که به فرم struct sockaddr است را به فرم قابل فهم برای انسان تبدیل می‌کند. در صورتی که آدرس بدست آمده قابل بازگردانی به نام دامنه متناظرش باشد، نام دامنه، در غیر این صورت، آدرس IP هم همراه شماره پورت و سرویس برمی‌گردد.
#include <sys/socket.h>#include <netdb.h>int getnameinfo(const struct sockaddr *sa, socklen_t salen,
                char *host, size_t hostlen,
                char *serv, size_t servlen,
                int flags);

freeaddrinfo

این تابع حافظه‌ای که توسط تابع getaddrinfo اختصاص داده شده را آزاد می‌کند. getaddrinfo یک لیست پیوندی از ساختارهای addrinfo برمی‌گرداند، در نتیجه freeaddrinfo تمام این لیست را پیمایش کرده و حافظه مربوط به کلیه عناصر آن را آزاد می‌کند.
#include <sys/socket.h>#include <netdb.h>void freeaddrinfo(struct addrinfo *ai);
پارامتر ai گره ابتدایی لیست را مشخص می‌کند.

مثال

مثال زیر از تابع getaddrinfo برای ترجمه دامنه www.example.com به آدرس‌های IP متناظرش استفاده می‌کند و سپس getnameinfo را بر روی این آدرس‌ها فراخوانی می‌کند تا نام متعارف هر کدام را پیدا کند. به طور کلی، انجام این کار موجب می‌شود همان نام دامنه اولیه بدست آید، مگر اینکه یک آدرس خاص، چندین نام دامنه داشته باشد، که در این صورت نام متعارف بازگردانده می‌شود. در این مثال، نام دامنه در کل سه بار چاپ می‌شود، یکی به ازای هر نتیجه بدست آمده.
#include <stdio.h>#include <stdlib.h>#include <netdb.h>#include <netinet/in.h>#include <sys/socket.h>#ifndef NI_MAXHOST#define NI_MAXHOST 1025#endifint main(void){
    struct addrinfo *result;
    struct addrinfo *res;
    int error;

    /* resolve the domain name into a list of addresses */
    error = getaddrinfo("www.example.com", NULL, NULL, &result);
    if (error != 0)
    {   
        if (error == EAI_SYSTEM)
        {
            perror("getaddrinfo");
        }
        else
        {
            fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error));
        }   
        exit(EXIT_FAILURE);
    }

    /* loop over all returned results and do inverse lookup */
    for (res = result; res != NULL; res = res->ai_next)
    {   
        char hostname[NI_MAXHOST];

        error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0); 
        if (error != 0)
        {
            fprintf(stderr, "error in getnameinfo: %s\n", gai_strerror(error));
            continue;
        }
        if (*hostname != '\0')
            printf("hostname: %s\n", hostname);
    }

    freeaddrinfo(result);
    return 0;}
یک مثال دیگر:
int sockfd, error;struct addrinfo hints, *res, *res0;const char *cause = NULL;(void)memset(&hints, '\0', sizeof(struct addrinfo));hints.ai_family = AF_INET;hints.ai_protocol = IPPROTO_TCP;hints.ai_socktype = SOCK_STREAM;error = getaddrinfo(argv[1], argv[2], &hints, &res0);if (error){
errx(1, "%s", gai_strerror(error));
/* NOTREACHED */}

sockfd = -1;for (res = res0; res; res = res->ai_next){
if (-1 == (sockfd = socket(res->ai_family, res->ai_socktype,
 res->ai_protocol)))
{
cause = "socket";
continue;
}

if (-1 == connect(sockfd, res->ai_addr, res->ai_addrlen))
{
cause = "connect()";
close(sockfd);
                sockfd = -1;
continue;
}

break;
/* NOTREACHED */}if (-1 == sockfd)
perror(cause);
        exit(EXIT_FAILURE);