این یک نگارش قدیمی از این مطلب است!
تابع ()getaddrinfo
معمولا از تابع ()getaddrinfo برای پر کردن استراکچر های مورد نیاز توابع دیگر یا ترجمه آدرس های اینترنتی استفاده میشود.
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
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 <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <arpa/inet.h> int main() { char *node = "www.yahoo.com"; int errcode; struct addrinfo hints, *res ,*p; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; 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 (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); } printf("\n"); 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 از طریق header در دسترس باشد (expost شود) در gcc های ورژن بالاتر از 2.22 باید ماکرو زیر تعریف شود
#define _POSIX_C_SOURCE 200112L
برای بررسی کار کرد ماکرو فوق، می توان یک بار بدون ماکرو بالا و یک بار با وجود ماکرو بالا از دستور زیر استفاده کنیم و در خروجی دنبال تعریف struct addrinfo بگردیم. خواهیم دید که بدون ماکرو فوق این استراکچر تعریف نمیشود
gcc -std=c99 -E getaddrinfo.c
