2008년 6월 21일 ~ 2008년 6월 22일

IPv6에 대한 구현을 위해서 가장 먼저 알아야 하는 getaddrinfo 함수에 대한 간략한 테스트 코드입니다.
설명하려고 만든것도 아니고 그냥 이것저것 고쳐가면서 특성파악했던 잔여물입니다.

특성 파악도 안하고 그냥 코딩하면 추후에 뒷감당을 할수 없는 야리꾸리한 코드가 나오기에 이를 미연에 방지하고자 수많은 검토사항중에 한가지였습니다.

블로그에 이 소스를 흔적으로 남깁니다.


검토결과
~~~~~~

getaddrinfo 에서 hints 인자는 매우 중요하다는 결론을 내렸습니다. 물론 NULL로 입력해도 대부분 무난하지만 호환성을 위해서는 hints를 잘 채워야 할것 같습니다.

service 인자는 문자열로 입력을 받게 되는데 어떻게 보면 편한데 어떻게 보면 매우 불편합니다.
하지만 깊은 뜻이 있다는 것을 알게 되었고 포트가 전부가 아니다 라는 계시를 받았습니다. ㅋ

freeaddrinfo 함수를 잊고 안해주면 안되는것은 잊으면 안되는 사항이겠구요.

AF_INET이 먼저냐 AF_INET6가 먼저 선행 노드로 존재하는냐가 결정이 되어 있으면 좋겠다 라는 생각이지만 테스트결과 현실은 순서는 믿을수 없었습니다.

ai_addr 멤버가 inet_ntop에 이용되고자 할때 sin_addr 또는 sin6_addr은 같은 offset 위치를 같지 않기 때문에 간단한 코드가 되질 않는군요. 이 부분은 매우 불편한 구조가 될수밖에 없을거 같습니다.  이래가지고는 분명 게으른 프로그래머는 대충 짜서 굉장히 불안한 코드가 나올수 있을거 같습니다. 게으른 프로그래머들에게 이부분을 맏기면 짜증 100배 될 소지가 있습니다.

inet_ntop 함수는 기존의 inet_ntoa의 단점을 제거하였지만 사용하기에는 번거로워졌네요. 하지만 이게 올바른 구조라고 생각됩니다. inet_ntoa는 되도록이면 사용안하는것이 정신건강에 좋다는 의견 한표.




일단 아래의 테스트코드를 통해서 확인된 검토결과들을 토대로 mzproxy (http://kldp.net/projects/mzproxy/) 에다가 적용하여 v2.0.0-r2 로 release 했습니다. 당연히 잘 동작하는거 실제 IPv4 + IPv6 연동망에서 테스트 했구요.


문제는 이 함수를 어떻게 GL(Glue Layer) 로 캡슐화된 API 를 설계하는가 인데 참 난감하네요.
참으로 어정쩡한 GL API가 될 가능성이 높은 함수로 getaddrinfo 를 1위로 주고 싶은 생각이...


#if defined(_WIN32) || defined(WIN32)
# include <windows.h>
# include <stdio.h>
# include <signal.h>
#else
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/times.h>
# include <sys/time.h>
# include <sys/socket.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
# include <fcntl.h>
# include <time.h>
# include <signal.h>
# include <setjmp.h>
# include <time.h>
# include <errno.h>
# include <dlfcn.h>
# include <netdb.h>
# include <netinet/in.h>
# include <arpa/inet.h>
#endif

#if 0 && (!defined(mz_dump))
#include <stdio.h>
static void * (__mz_dump_ex__)(size_t s_s, size_t s_d, void * s_da, size_t s_si)
{ size_t s_o, s_w, s_lo; unsigned char s_b[ 16 + 1 ];
 if(s_da == NULL)return(NULL); s_b[sizeof(s_b) - 1] = (unsigned char)'\0';
 for(s_o = (size_t)0;s_o < s_si;s_o += (size_t)16){
  s_w = ((s_si - s_o) <= ((size_t)16)) ? (s_si - s_o) : ((size_t)16);
  (void)fprintf(stdout, "%08lX", (unsigned long)(s_d + s_o));
  for(s_lo = (size_t)0;s_lo < s_w;s_lo++){
   if(s_lo == ((size_t)(16 >> 1)))(void)fputs(" | ", stdout);
   else (void)fputs(" ", stdout);
   s_b[s_lo] = *(((unsigned char *)s_da) + (s_s + s_o + s_lo));
   (void)fprintf(stdout, "%02X", (int)s_b[s_lo]);
   if((s_b[s_lo] & ((unsigned char)(1 << 7))) || (s_b[s_lo] < ((unsigned char)' ')) ||
      (s_b[s_lo] == ((unsigned char)0x7f)))s_b[s_lo] = (unsigned char)'.';}
  while(s_lo < ((size_t)16)){
   if(s_lo == ((size_t)(16 >> 1)))(void)fputs("     ", stdout);
   else (void)fputs("   ", stdout);
   s_b[s_lo] = (unsigned char)' '; s_lo++;}
  (void)fprintf(stdout, " [%s]\n", (char *)(&s_b[0]));}
 return(s_da);
}
static __inline void * (mz_dump_ex)(size_t s_seek_offset, size_t s_display_offset, void * s_data, size_t s_size)
{ return(__mz_dump_ex__(s_seek_offset, s_display_offset, s_data, s_size)); }
#define mz_dump(m_data,m_size) mz_dump_ex((size_t)0,(size_t)0,(void *)(m_data),(size_t)(m_size))
#endif

int main(int s_argc, char **s_argv);

void print_addrinfo(struct addrinfo *s_this)
{
    /* ai_flags */
    if(s_this->ai_flags & AI_PASSIVE) {
        (void)fprintf(stdout, "flags: AI_PASSIVE\n");
    }
    if(s_this->ai_flags & AI_CANONNAME) {
        (void)fprintf(stdout, "flags: AI_CANONNAME\n");
    }
    if(s_this->ai_flags & AI_NUMERICHOST) {
        (void)fprintf(stdout, "flags: AI_NUMERICHOST\n");
    }
    if(s_this->ai_flags & AI_V4MAPPED) {
        (void)fprintf(stdout, "flags: AI_V4MAPPED\n");
    }
    if(s_this->ai_flags & AI_ALL) {
        (void)fprintf(stdout, "flags: AI_ALL\n");
    }
    if(s_this->ai_flags & AI_ADDRCONFIG) {
        (void)fprintf(stdout, "flags: AI_ADDRCONFIG\n");
    }
#if defined(AI_IDN)
    if(s_this->ai_flags & AI_IDN) {
        (void)fprintf(stdout, "flags: AI_IDN\n");
    }
#endif
#if defined(AI_CANONIDN)
    if(s_this->ai_flags & AI_CANONIDN) {
        (void)fprintf(stdout, "flags: AI_CANONIDN\n");
    }
#endif
#if defined(AI_IDN_ALLOW_UNASSIGNED)
    if(s_this->ai_flags & AI_IDN_ALLOW_UNASSIGNED) {
        (void)fprintf(stdout, "flags: AI_IDN_ALLOW_UNASSIGNED\n");
    }
#endif
#if defined(AI_IDN_USE_STD3_ASCII_RULES)
    if(s_this->ai_flags & AI_IDN_USE_STD3_ASCII_RULES) {
        (void)fprintf(stdout, "flags: AI_IDN_USE_STD3_ASCII_RULES\n");
    }
#endif
#if defined(AI_NUMERICSERV)
    if(s_this->ai_flags & AI_NUMERICSERV) {
        (void)fprintf(stdout, "flags: NUMERICSERV\n");
    }
#endif

    /* ai_family */
    if(s_this->ai_family == AF_UNSPEC) {
        (void)fprintf(stdout, "family=%s\n", "UNSPEC");
    }
    else if(s_this->ai_family == AF_LOCAL) {
        (void)fprintf(stdout, "family=%s\n", "LOCAL");
    }
    else if(s_this->ai_family == AF_INET) {
        (void)fprintf(stdout, "family=%s\n", "AF_INET");
    }
    else if(s_this->ai_family == AF_INET6) {
        (void)fprintf(stdout, "family=%s\n", "AF_INET6");
    }
    else {
        (void)fprintf(stdout, "family=%d\n", s_this->ai_family);
    }

    /* ai_socktype */
    if(s_this->ai_socktype == SOCK_DGRAM) {
        (void)fprintf(stdout, "socktype=%s\n", "SOCK_DGRAM");
    }
    else if(s_this->ai_socktype == SOCK_STREAM) {
        (void)fprintf(stdout, "socktype=%s\n", "SOCK_STREAM");
    }
    else {
        (void)fprintf(stdout, "socktype=%d\n", s_this->ai_socktype);
    }

    /* ai_protocol */
    if(s_this->ai_protocol == IPPROTO_IP) {
        (void)fprintf(stdout, "protocol=%s\n", "IPPROTO_IP");
    }
    else if(s_this->ai_protocol == IPPROTO_IPV6) {
        (void)fprintf(stdout, "protocol=%s\n", "IPPROTO_IPV6");
    }
    else if(s_this->ai_protocol == IPPROTO_TCP) {
        (void)fprintf(stdout, "protocol=%s\n", "IPPROTO_TCP");
    }
    else if(s_this->ai_protocol == IPPROTO_UDP) {
        (void)fprintf(stdout, "protocol=%s\n", "IPPROTO_UDP");
    }
    else if(s_this->ai_protocol == IPPROTO_IGMP) {
        (void)fprintf(stdout, "protocol=%s\n", "IPPROTO_IGMP");
    }
    else if(s_this->ai_protocol == IPPROTO_ICMP) {
        (void)fprintf(stdout, "protocol=%s\n", "IPPROTO_ICMP");
    }
    else if(s_this->ai_protocol == IPPROTO_ICMPV6) {
        (void)fprintf(stdout, "protocol=%s\n", "IPPROTO_ICMPV6");
    }
    else {
        (void)fprintf(stdout, "protocol=%d\n", s_this->ai_protocol);
    }

    /* ai_addrlen */
    (void)fprintf(stdout, "addrlen=%lu\n", (unsigned long)s_this->ai_addrlen);

    /* ai_addr */
    if(s_this->ai_addr != ((struct sockaddr *)0)) {
        char s_address_local[ 128 ];
        const char *s_address;
        struct sockaddr_in *s_sockaddr_in;
        struct sockaddr_in6 *s_sockaddr_in6;

        if(s_this->ai_family == AF_INET) {
            s_sockaddr_in = (struct sockaddr_in *)s_this->ai_addr;
            s_address = inet_ntop(s_this->ai_family, (const void *)(&s_sockaddr_in->sin_addr.s_addr), (char *)(&s_address_local[0]), (socklen_t)sizeof(s_address_local));
        }
        else if(s_this->ai_family == AF_INET6) {
            s_sockaddr_in6 = (struct sockaddr_in6 *)s_this->ai_addr;
            s_address = inet_ntop(s_this->ai_family, (const void *)(&s_sockaddr_in6->sin6_addr), (char *)(&s_address_local[0]), (socklen_t)sizeof(s_address_local));
        }
        else {
            s_address = (const char *)0;
        }

        if(s_address != ((const char *)0)) {
            (void)fprintf(stdout, "addr=\"%s\"\n", s_address);
        }
        else {
            (void)fprintf(stdout, "addr=%s\n", "UNKNOWN");
        }
    }
    else {
        (void)fprintf(stdout, "addr=%s\n", "NULL");
    }

    /* ai_canonname */
    (void)fprintf(stdout, "canonname=%s\n", (s_this->ai_canonname != ((char *)0)) ? s_this->ai_canonname : "NULL");

    (void)fprintf(stdout, "\n");
}

int main(int s_argc, char **s_argv)
{

    struct addrinfo s_hints;
    struct addrinfo *s_result;
    struct addrinfo *s_this;
    int s_check;

    (void)memset((void *)(&s_hints), 0, sizeof(s_hints));
    s_hints.ai_family = AF_UNSPEC; /* IPv4 or IPv6 */
    s_hints.ai_socktype = SOCK_STREAM; /* UDP or TCP */
    s_hints.ai_flags = AI_PASSIVE; /* wildcard IP address */
    s_hints.ai_protocol = IPPROTO_TCP; /* any protocol */
    s_hints.ai_canonname = NULL;
    s_hints.ai_addr = NULL;
    s_hints.ai_next = NULL;

    s_check = getaddrinfo((s_argc >= 2) ? s_argv[1] : "minzkn.com", "http", (const struct addrinfo *)(&s_hints), (struct addrinfo **)(&s_result));
    if(s_check != 0) {
        (void)fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(s_check));

        return(EXIT_FAILURE);
    }

    s_this = s_result;
    while(s_this != ((struct addrinfo *)0)) {
        print_addrinfo(s_this);

        s_this = s_this->ai_next;
    }

    freeaddrinfo(s_result);

    return(EXIT_SUCCESS);
}

/* End of source */

크리에이티브 커먼즈 라이센스
Creative Commons License
Posted by minzkn

트랙백 주소 :: http://blog.minzkn.com/trackback/267

댓글을 달아 주세요

[로그인][오픈아이디란?]