**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 ناسازگار هستند.

getaddrinfo()‎
--------------

getaddrinfo()‎، اسامی میزبان و آدرس‌های آی‌پی که به صورت رشته‌های متنی قابل فهم برای انسان هستند را به یک لیست پیوندی پویا که از ساختارهای addrinfo تشکیل شده، تبدیل می‌کند. نمونه اولیه (به انگلیسی: prototype) این تابع بدین شکل است:

```
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int getaddrinfo(const char \*hostname,
 const char \*service,
 const struct addrinfo \*hints,
 struct addrinfo \*\*res);

```

* پارامتر hostname هم می‌تواند یک دامنه مانند «nice.com» یا یک آدرس آی‌پی مانند "127.0.0.1" یا حتی مقدار NULL باشد. اگر NULL باشد، یکی از آدرس‌های 0.0.0.0 یا 127.0.0.1 بسته به فلگ‌های پارامتر hints انتخاب می‌شود.
* پارامتر service مشخص کننده یک شماره پورت همانند "80" یا مشخص کننده نام سرویس همانند "echo" است. در صورت استفاده کردن از نام سرویس، تابع gethostbyname()‎ فراخوانی شده و این نام با استفاده از فایل ‎/etc/services به شماره پورت، در اینجا 7 تبدیل میشود.
* پارامتر hints یا می‌تواند NULL باشد یا می‌تواند یک ساختار addrinfo باشد که نوع سرویس مورد نظر برنامه‌نویس را مشخص می‌کند. به عنوان مثال، یک سوکت می‌تواند یا TCP یا UDP باشد، می‌توان نوع مورد نظر خود را انتخاب کرد.
* پارامتر res اشاره‌گری دوتایی به یک ساختار addrinfo است. gethostbyname()‎ یک لیست حاوی اطلاعات خواسته شده ایجاد می‌کند که این پارامتر اشاره‌گری به اولین گره آن خواهد بود. با دنبال کردن اشاره‌گر ai\_next می‌توان این لیست را پیمایش کرد.

تابع در صورت موفقیت مقدار صفر و در صورت شکست یک مقدار منفی را برمیگرداند.

هر چند که این تابع به شکل متفاوتی در هر سیستم‌عامل پیاده‌سازی شده است، اما روش کار آن معمولاً به این صورت است که ابتدا سعی می‌کند شماره پورت مورد نظر که توسط پارامتر service مشخص شده را بدست آورد. اگر پارامتر service یک شماره پورت بود، به کمک تابع htons()‎ شماره پورت مورد نظر را به صورت Network byte order در می‌آورد. اگر پارامتر service یک نام مانند www بود، تابع getservbyname()‎ را اجرا می‌کند تا شماره پورت معادل www را بدست آورد (در اینجا 80). hints->ai\_socktype به عنوان پارامتر دوم به تابع getservbyname()‎ فرستاده می‌شود. اگر مقدار پارامتر hostname مشخص شده باشد و NULL نباشد، تابع gethostbyname()‎ را هم اجرا خواهد کرد تا آدرس آی‌پی دامنه خواسته شده را بدست آورد. در غیر این صورت، اگر پارامتر hostname برابر NULL باشد، و همچنین اگر hints->ai\_flags هم برابر AI\_PASSIVE باشد، مقدار 0.0.0.0 را در نظر می‌گیرد. اگر hints->ai\_flags برابر AI\_PASSIVE نباشد، مقدار 127.0.0.1 در نظر گرفته خواهد شد. سپس malloc\_ai فراخوانی می‌شود و شماره پورتی که در ابتدا بدست آمده بود را به آن ارسال می‌کند تا یک ساختار addrinfo که با sockaddr\_in مناسب پر شده است، بدست آید. سپس پارامتر ‎\*\*res را تغییر می‌دهد تا به یک ساختار addrinfo که به تازگی اختصاص داده شده، اشاره کند. در برخی از پیاده‌سازی‌ها، hints->ai\_protocol مقدار hints->ai\_socktype را بی‌اثر می‌کند، در حالی که در برخی دیگر از پیاده‌سازی‌ها، برعکس این قضیه صادق است، بنابراین، برای پورتابل بودن کد، هر دو فیلد ساختار باید توسط برنامه‌نویس مشخص شوند.

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
#endif

int 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);

```

منابع
-----

مشارکت‌کنندگان ویکی‌پدیا. «getaddrinfo». در *دانشنامهٔ ویکی‌پدیای انگلیسی*، بازبینی‌شده در ۲۷ فوریه ۲۰۱۵.