====== تابع ()getaddrinfo ======
معمولا از تابع ()getaddrinfo برای پر کردن استراکچر های مورد نیاز توابع دیگر یا ترجمه آدرس های اینترنتی استفاده میشود.
#include
#include
#include
int getaddrinfo(const char *restrict node,
const char *restrict service,
const struct addrinfo *restrict hints,
struct addrinfo **restrict res);
void freeaddrinfo(struct addrinfo *res);
const char *gai_strerror(int errcode);
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
getaddrinfo(), freeaddrinfo(), gai_strerror():
Since glibc 2.22:
_POSIX_C_SOURCE >= 200112L
glibc 2.21 and earlier:
_POSIX_C_SOURCE
تابع ()getaddrinfo یک node به عنوان Internet Host یک service و یک struct addrinfo به نام hints وارد میکند و نتیجه را در یک linked-list از نوع struct addrinfo به نام res باز میگرداند. خروجی این تابع در [[bind]] و [[connect]] قابل استفاده است.
تابع ()freeaddrinfo برای آزاد کردن حافظه اختصاص داده شده به linked-list و از تابع ()gai_strerror برای کنترل error ها استفاده میشود.
استراکچر addrinfo :
struct addrinfo {
int ai_flags; // AI_PASSIVE, AI_CANONNAME, etc.
int ai_family; // AF_INET, AF_INET6, AF_UNSPEC
int ai_socktype; // SOCK_STREAM, SOCK_DGRAM
int ai_protocol; // use 0 for "any"
size_t ai_addrlen; // size of ai_addr in bytes
struct sockaddr *ai_addr; // struct sockaddr_in or _in6
char *ai_canonname; // full canonical hostname
struct addrinfo *ai_next; // linked list, next node
};
در استراکچر فوق متغییر ai_addr از نوع *struct sockaddr است :
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
استراکچر فوق به تنهایی قابل استفاده نیست و تنها با cast شدن از struct sockaddr_in یا struct sockaddr_in6 استفاده میشود :
struct sockaddr_in {
short int sin_family; // Address family, AF_INET
unsigned short int sin_port; // Port number, Network Byte Order with htons()
struct in_addr sin_addr; // Internet address
unsigned char sin_zero[8]; // Same size as struct sockaddr, set to zero with memset()
};
struct sockaddr_in6 {
u_int16_t sin6_family; // address family, AF_INET6
u_int16_t sin6_port; // port number, Network Byte Order
u_int32_t sin6_flowinfo; // IPv6 flow information
struct in6_addr sin6_addr; // IPv6 address
u_int32_t sin6_scope_id; // Scope ID
};
در استراکچر های فوق struct in_addr و struct in6_addr وجود دارند که در [[inet_ntop]] و [[inet_pton]] قابل استفاده هستند:
typedef uint32_t in_addr_t;
struct in_addr {
in_addr_t s_addr; // that's a 32-bit int (4 bytes)
};
struct in6_addr {
unsigned char s6_addr[16]; // IPv6 address
};
در مثال زیر برای ترجمه نام اینترنتی به IP با کمک DNS ، از تابع ()getaddrinfo استفاده شده است. hints باید از قبل با memset صفر شده باشد و لااقل فیلد های ai_family و ai_socktype و ai_protocol مقدار دهی شده باشند :
// getaddrinfo.c
// gcc -std=c99 -Wall -Wextra -Werror -pedantic -o getaddrinfo getaddrinfo.c
#define _POSIX_C_SOURCE 200112L
#include
#include
#include
#include
#include
#include
#include
int main()
{
char *node = "www.yahoo.com";
struct addrinfo hints, *res;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; // defined in /usr/include/bits/socket_type.h
hints.ai_protocol = 0;
int errcode = getaddrinfo(node, NULL, &hints, &res);
if (errcode != 0) {
fprintf(stderr, "getaddrinfo() error: %s\n", gai_strerror(errcode));
exit(EXIT_FAILURE);
}
printf("\nInternet addresses of %s :\n\n", node);
for (struct addrinfo *p = res; p != NULL; p = p->ai_next) {
char *ipver, ipstr[INET6_ADDRSTRLEN];
void *addr;
if (p->ai_family == AF_INET) {
ipver = "IPv4";
struct sockaddr_in *ipv4 = (struct sockaddr_in *)(p->ai_addr);
addr = &(ipv4->sin_addr);
} else if (p->ai_family == AF_INET6) {
ipver = "IPv6";
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)(p->ai_addr);
addr = &(ipv6->sin6_addr);
} else {
printf("Unknown\n");
}
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
printf(" %s: %s\n", ipver, ipstr);
}
freeaddrinfo(res);
return 0;
}
خروجی
Internet addresses of www.yahoo.com :
IPv4: 87.248.100.216
IPv4: 87.248.100.215
IPv6: 2a00:1288:110:c305::1:8000
IPv6: 2a00:1288:110:c305::1:8001
همانطور که در قسمت Feature Test Macro در manual نوشته شده برای اینکه تعریف توابع ()getaddrinfo و ()freeaddrinfo و ()gai_strerror و استراکچر های مورد نیاز، از طریق header در دسترس باشند (expose شوند) در gcc های ورژن بالاتر از 2.22 باید ماکرو زیر تعریف شود
#define _POSIX_C_SOURCE 200112L
برای بررسی کار کرد ماکرو فوق، می توان یک بار بدون ماکرو و یک بار با وجود ماکرو، از دستور زیر استفاده کنیم و در خروجی، تعریف struct addrinfo را جستجو کنیم. خواهیم دید که بدون ماکرو فوق این استراکچر تعریف نمیشود
gcc -std=c99 -E getaddrinfo.c