"Fossies" - the Fresh Open Source Software Archive

Member "zsync-0.6.2/getaddrinfo.c" (16 Sep 2010, 13914 Bytes) of package /linux/privat/old/zsync-0.6.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "getaddrinfo.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (c) 2001, 02  Motoyuki Kasahara
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  * 3. Neither the name of the project nor the names of its contributors
   13  *    may be used to endorse or promote products derived from this software
   14  *    without specific prior written permission.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 /*
   30  * This program provides getaddrinfo() and getnameinfo() described in
   31  * RFC2133, 2553 and 3493.  These functions are mainly used for IPv6
   32  * application to resolve hostname or address.
   33  * 
   34  * This program is designed to be working on traditional IPv4 systems
   35  * which don't have those functions.  Therefore, this implementation
   36  * supports IPv4 only.
   37  *
   38  * This program is useful for application which should support both IPv6
   39  * and traditional IPv4 systems.  Use genuine getaddrinfo() and getnameinfo()
   40  * provided by system if the system supports IPv6.  Otherwise, use this
   41  * implementation.
   42  * 
   43  * This program is intended to be used in combination with GNU Autoconf.
   44  * 
   45  * This program also provides freeaddrinfo() and gai_strerror().
   46  *
   47  * To use this program in your application, insert the following lines to
   48  * C source files after including `sys/types.h', `sys/socket.h' and
   49  * `netdb.h'.  `getaddrinfo.h' defines `struct addrinfo' and AI_, NI_,
   50  * EAI_ macros.
   51  * 
   52  *    #ifndef HAVE_GETADDRINFO
   53  *    #include "getaddrinfo.h"
   54  *    #endif
   55  * 
   56  * Restriction:
   57  *   getaddrinfo() and getnameinfo() of this program are NOT thread
   58  *   safe, unless the cpp macro ENABLE_PTHREAD is defined.
   59  */
   60 
   61 /*
   62  * Add the following code to your configure.ac (or configure.in).
   63  *   AC_C_CONST
   64  *   AC_HEADER_STDC
   65  *   AC_CHECK_HEADERS(string.h memory.h stdlib.h)
   66  *   AC_CHECK_FUNCS(memcpy)
   67  *   AC_REPLACE_FUNCS(memset)
   68  *   AC_TYPE_SOCKLEN_T
   69  *   AC_TYPE_IN_PORT_T
   70  *   AC_DECL_H_ERRNO
   71  *
   72  *   AC_CHECK_FUNCS(getaddrinfo getnameinfo)
   73  *   if test "$ac_cv_func_getaddrinfo$ac_cv_func_getnameinfo" != yesyes ; then
   74  *       LIBOBJS="$LIBOBJS getaddrinfo.$ac_objext"
   75  *   fi
   76  */
   77 
   78 #include "zsglobal.h"
   79 
   80 #include <sys/types.h>
   81 #include <stdio.h>
   82 #include <sys/socket.h>
   83 #include <netinet/in.h>
   84 #include <arpa/inet.h>
   85 #include <netdb.h>
   86 
   87 #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
   88 #include <string.h>
   89 #if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
   90 #include <memory.h>
   91 #endif /* not STDC_HEADERS and HAVE_MEMORY_H */
   92 #else /* not STDC_HEADERS and not HAVE_STRING_H */
   93 #include <strings.h>
   94 #endif /* not STDC_HEADERS and not HAVE_STRING_H */
   95 
   96 #ifdef HAVE_STDLIB_H
   97 #include <stdlib.h>
   98 #endif
   99 
  100 #ifdef ENABLE_PTHREAD
  101 #include <pthread.h>
  102 #endif
  103 
  104 #ifdef ENABLE_NLS
  105 #include <libintl.h>
  106 #endif
  107 
  108 #ifndef HAVE_MEMCPY
  109 #define memcpy(d, s, n) bcopy((s), (d), (n))
  110 #ifdef __STDC__
  111 void *memchr(const void *, int, size_t);
  112 int memcmp(const void *, const void *, size_t);
  113 void *memmove(void *, const void *, size_t);
  114 void *memset(void *, int, size_t);
  115 #else /* not __STDC__ */
  116 char *memchr();
  117 int memcmp();
  118 char *memmove();
  119 char *memset();
  120 #endif /* not __STDC__ */
  121 #endif /* not HAVE_MEMCPY */
  122 
  123 #ifndef H_ERRNO_DECLARED
  124 extern int h_errno;
  125 #endif
  126 
  127 #include "getaddrinfo.h"
  128 
  129 #ifdef ENABLE_NLS
  130 #define _(string) gettext(string)
  131 #ifdef gettext_noop
  132 #define N_(string) gettext_noop(string)
  133 #else
  134 #define N_(string) (string)
  135 #endif
  136 #else
  137 #define gettext(string) (string)
  138 #define _(string) (string)
  139 #define N_(string) (string)
  140 #endif
  141 
  142 /*
  143  * Error messages for gai_strerror().
  144  */
  145 static const char *eai_errlist[] = {
  146     N_("Success"),
  147 
  148     /* EAI_ADDRFAMILY */
  149     N_("Address family for hostname not supported"),
  150 
  151     /* EAI_AGAIN */
  152     N_("Temporary failure in name resolution"),
  153 
  154     /* EAI_BADFLAGS */
  155     N_("Invalid value for ai_flags"),
  156 
  157     /* EAI_FAIL */
  158     N_("Non-recoverable failure in name resolution"),
  159 
  160     /* EAI_FAMILY */
  161     N_("ai_family not supported"),                      
  162 
  163     /* EAI_MEMORY */
  164     N_("Memory allocation failure"),
  165 
  166     /* EAI_NONAME */
  167     N_("hostname nor servname provided, or not known"),
  168 
  169     /* EAI_OVERFLOW */
  170     N_("An argument buffer overflowed"),
  171 
  172     /* EAI_SERVICE */
  173     N_("servname not supported for ai_socktype"),
  174 
  175     /* EAI_SOCKTYPE */
  176     N_("ai_socktype not supported"),
  177 
  178     /* EAI_SYSTEM */
  179     N_("System error returned in errno")
  180 };
  181 
  182 /*
  183  * Default hints for getaddrinfo().
  184  */
  185 static struct addrinfo default_hints = {
  186     0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL
  187 };
  188 
  189 /*
  190  * Mutex.
  191  */
  192 #ifdef ENABLE_PTHREAD
  193 static pthread_mutex_t gai_mutex = PTHREAD_MUTEX_INITIALIZER;
  194 #endif
  195 
  196 /*
  197  * Declaration of static functions.
  198  */
  199 #ifdef __STDC__
  200 static int is_integer(const char *);
  201 static int is_address(const char *);
  202 static int itoa_length(int);
  203 #else
  204 static int is_integer();
  205 static int is_address();
  206 static int itoa_length();
  207 #endif
  208 
  209 /*
  210  * gai_strerror().
  211  */
  212 const char *
  213 gai_strerror(ecode)
  214     int ecode;
  215 {
  216     if (ecode < 0 || ecode > EAI_SYSTEM)
  217     return _("Unknown error");
  218 
  219     return gettext(eai_errlist[ecode]);
  220 }
  221 
  222 /*
  223  * freeaddrinfo().
  224  */
  225 void
  226 freeaddrinfo(ai)
  227     struct addrinfo *ai;
  228 {
  229     struct addrinfo *next_ai;
  230 
  231     while (ai != NULL) {
  232     if (ai->ai_canonname != NULL)
  233         free(ai->ai_canonname);
  234     if (ai->ai_addr != NULL)
  235         free(ai->ai_addr);
  236     next_ai = ai->ai_next;
  237     free(ai);
  238     ai = next_ai;
  239     }
  240 }
  241 
  242 /*
  243  * Return 1 if the string `s' represents an integer.
  244  */
  245 static int
  246 is_integer(s)
  247     const char *s;
  248 {
  249     if (*s == '-' || *s == '+')
  250     s++;
  251     if (*s < '0' || '9' < *s)
  252     return 0;
  253 
  254     s++;
  255     while ('0' <= *s && *s <= '9')
  256     s++;
  257 
  258     return (*s == '\0');
  259 }
  260 
  261 /*
  262  * Return 1 if the string `s' represents an IPv4 address.
  263  * Unlike inet_addr(), it doesn't permit malformed nortation such
  264  * as "192.168".
  265  */
  266 static int
  267 is_address(s)
  268     const char *s;
  269 {
  270     static const char delimiters[] = {'.', '.', '.', '\0'};
  271     int i, j;
  272     int octet;
  273 
  274     for (i = 0; i < 4; i++) {
  275     if (*s == '0' && *(s + 1) != delimiters[i])
  276         return 0;
  277     for (j = 0, octet = 0; '0' <= *s && *s <= '9' && j < 3; s++, j++)
  278         octet = octet * 10 + (*s - '0');
  279     if (j == 0 || octet > 255 || *s != delimiters[i])
  280         return 0;
  281     s++;
  282     }
  283 
  284     return 1;
  285 }
  286 
  287 /*
  288  * Calcurate length of the string `s', where `s' is set by
  289  * sprintf(s, "%d", n).
  290  */
  291 static int
  292 itoa_length(n)
  293     int n;
  294 {
  295     int result = 1;
  296 
  297     if (n < 0) {
  298     n = -n;
  299     result++;
  300     }
  301 
  302     while (n >= 10) {
  303     result++;
  304     n /= 10;
  305     }
  306 
  307     return result;
  308 }
  309 
  310 /*
  311  * getaddrinfo().
  312  */
  313 int
  314 getaddrinfo(nodename, servname, hints, res)
  315     const char *nodename;
  316     const char *servname;
  317     const struct addrinfo *hints;
  318     struct addrinfo **res;
  319 {
  320     struct addrinfo *head_res = NULL;
  321     struct addrinfo *tail_res = NULL;
  322     struct addrinfo *new_res;
  323     struct sockaddr_in *sa_in;
  324     struct in_addr **addr_list;
  325     struct in_addr *addr_list_buf[2];
  326     struct in_addr addr_buf;
  327     struct in_addr **ap;
  328     struct servent *servent;
  329     struct hostent *hostent;
  330     const char *canonname = NULL;
  331     in_port_t port;
  332     int saved_h_errno;
  333     int result = 0;
  334 
  335 #ifdef ENABLE_PTHREAD
  336     pthread_mutex_lock(&gai_mutex);
  337 #endif
  338 
  339     saved_h_errno = h_errno;
  340 
  341     if (nodename == NULL && servname == NULL) {
  342     result = EAI_NONAME;
  343     goto end;
  344     }
  345 
  346     if (hints != NULL) {
  347     if (hints->ai_family != PF_INET && hints->ai_family != PF_UNSPEC) {
  348         result = EAI_FAMILY;
  349         goto end;
  350     }
  351     if (hints->ai_socktype != SOCK_DGRAM
  352         && hints->ai_socktype != SOCK_STREAM
  353         && hints->ai_socktype != 0) {
  354         result = EAI_SOCKTYPE;
  355         goto end;
  356     }
  357     } else {
  358     hints = &default_hints;
  359     }
  360 
  361     if (servname != NULL) {
  362     if (is_integer(servname))
  363         port = htons(atoi(servname));
  364     else  {
  365         if (hints->ai_flags & AI_NUMERICSERV) {
  366         result = EAI_NONAME;
  367         goto end;
  368         }
  369 
  370         if (hints->ai_socktype == SOCK_DGRAM)
  371         servent = getservbyname(servname, "udp");
  372         else if (hints->ai_socktype == SOCK_STREAM)
  373         servent = getservbyname(servname, "tcp");
  374         else if (hints->ai_socktype == 0)
  375         servent = getservbyname(servname, "tcp");
  376         else {
  377         result = EAI_SOCKTYPE;
  378         goto end;
  379         }
  380 
  381         if (servent == NULL) {
  382         result = EAI_SERVICE;
  383         goto end;
  384         }
  385         port = servent->s_port;
  386     }
  387     } else {
  388     port = htons(0);
  389     }
  390 
  391     if (nodename != NULL) {
  392     if (is_address(nodename)) {
  393         addr_buf.s_addr = inet_addr(nodename);
  394         addr_list_buf[0] = &addr_buf;
  395         addr_list_buf[1] = NULL;
  396         addr_list = addr_list_buf;
  397 
  398         if (hints->ai_flags & AI_CANONNAME
  399         && !(hints->ai_flags & AI_NUMERICHOST)) {
  400         hostent = gethostbyaddr((char *)&addr_buf,
  401             sizeof(struct in_addr), AF_INET);
  402         if (hostent != NULL)
  403             canonname = hostent->h_name;
  404         else
  405             canonname = nodename;
  406         }
  407     } else {
  408         if (hints->ai_flags & AI_NUMERICHOST) {
  409         result = EAI_NONAME;
  410         goto end;
  411         }
  412 
  413         hostent = gethostbyname(nodename);
  414         if (hostent == NULL) {
  415         switch (h_errno) {
  416         case HOST_NOT_FOUND:
  417         case NO_DATA:
  418             result = EAI_NONAME;
  419             goto end;
  420         case TRY_AGAIN:
  421             result = EAI_AGAIN;
  422             goto end;
  423         default:
  424             result = EAI_FAIL;
  425             goto end;
  426                 }
  427         }
  428         addr_list = (struct in_addr **)hostent->h_addr_list;
  429 
  430         if (hints->ai_flags & AI_CANONNAME)
  431         canonname = hostent->h_name;
  432     }
  433     } else {
  434     if (hints->ai_flags & AI_PASSIVE)
  435         addr_buf.s_addr = htonl(INADDR_ANY);
  436     else
  437         addr_buf.s_addr = htonl(0x7F000001);
  438     addr_list_buf[0] = &addr_buf;
  439     addr_list_buf[1] = NULL;
  440     addr_list = addr_list_buf;
  441     }
  442 
  443     for (ap = addr_list; *ap != NULL; ap++) {
  444     new_res = (struct addrinfo *)malloc(sizeof(struct addrinfo));
  445     if (new_res == NULL) {
  446         if (head_res != NULL)
  447         freeaddrinfo(head_res);
  448         result = EAI_MEMORY;
  449         goto end;
  450     }
  451 
  452     new_res->ai_family = PF_INET;
  453     new_res->ai_socktype = hints->ai_socktype;
  454     new_res->ai_protocol = hints->ai_protocol;
  455     new_res->ai_addr = NULL;
  456     new_res->ai_addrlen = sizeof(struct sockaddr_in);
  457     new_res->ai_canonname = NULL;
  458     new_res->ai_next = NULL;
  459 
  460     new_res->ai_addr = (struct sockaddr *)
  461         malloc(sizeof(struct sockaddr_in));
  462     if (new_res->ai_addr == NULL) {
  463         free(new_res);
  464         if (head_res != NULL)
  465         freeaddrinfo(head_res);
  466         result = EAI_MEMORY;
  467         goto end;
  468     }
  469 
  470     sa_in = (struct sockaddr_in *)new_res->ai_addr;
  471     memset(sa_in, 0, sizeof(struct sockaddr_in));
  472     sa_in->sin_family = PF_INET;
  473     sa_in->sin_port = port;
  474     memcpy(&sa_in->sin_addr, *ap, sizeof(struct in_addr));
  475 
  476     if (head_res == NULL)
  477         head_res = new_res;
  478     else
  479         tail_res->ai_next = new_res;
  480     tail_res = new_res;
  481     }
  482 
  483     if (canonname != NULL && head_res != NULL) {
  484     head_res->ai_canonname = (char *)malloc(strlen(canonname) + 1);
  485     if (head_res->ai_canonname != NULL)
  486         strcpy(head_res->ai_canonname, canonname);
  487     }
  488 
  489     *res = head_res;
  490 
  491   end:
  492     h_errno = saved_h_errno;
  493 #ifdef ENABLE_PTHREAD
  494     pthread_mutex_unlock(&gai_mutex);
  495 #endif
  496     return result;
  497 }
  498 
  499 /*
  500  * getnameinfo().
  501  */
  502 int
  503 getnameinfo(sa, salen, node, nodelen, serv, servlen, flags)
  504     const struct sockaddr *sa;
  505     socklen_t salen;
  506     char *node;
  507     socklen_t nodelen;
  508     char *serv;
  509     socklen_t servlen;
  510     int flags;
  511 {
  512     const struct sockaddr_in *sa_in = (const struct sockaddr_in *)sa;
  513     struct hostent *hostent;
  514     struct servent *servent;
  515     char *ntoa_address;
  516     int saved_h_errno;
  517     int result = 0;
  518 
  519 #ifdef ENABLE_PTHREAD
  520     pthread_mutex_lock(&gai_mutex);
  521 #endif
  522 
  523     saved_h_errno = h_errno;
  524 
  525     if (sa_in->sin_family != PF_INET) {
  526     result = EAI_FAMILY;
  527     goto end;
  528     } else if (node == NULL && serv == NULL) {
  529     result = EAI_NONAME;
  530     goto end;
  531     }
  532 
  533     if (serv != NULL && servlen > 0) {
  534     if (flags & NI_NUMERICSERV)
  535         servent = NULL;
  536     else if (flags & NI_DGRAM)
  537         servent = getservbyport(sa_in->sin_port, "udp");
  538     else
  539         servent = getservbyport(sa_in->sin_port, "tcp");
  540 
  541     if (servent != NULL) {
  542         if (servlen <= strlen(servent->s_name)) {
  543         result = EAI_OVERFLOW;
  544         goto end;
  545         }
  546         strcpy(serv, servent->s_name);
  547     } else {
  548         if (servlen <= itoa_length(ntohs(sa_in->sin_port))) {
  549         result = EAI_OVERFLOW;
  550         goto end;
  551         }
  552         sprintf(serv, "%d", ntohs(sa_in->sin_port));
  553     }
  554     }
  555 
  556     if (node != NULL && nodelen > 0) {
  557     if (flags & NI_NUMERICHOST)
  558         hostent = NULL;
  559     else {
  560         hostent = gethostbyaddr((char *)&sa_in->sin_addr, 
  561         sizeof(struct in_addr), AF_INET);
  562     }
  563     if (hostent != NULL) {
  564         if (nodelen <= strlen(hostent->h_name)) {
  565         result = EAI_OVERFLOW;
  566         goto end;
  567         }
  568         strcpy(node, hostent->h_name);
  569     } else {
  570         if (flags & NI_NAMEREQD) {
  571         result = EAI_NONAME;
  572         goto end;
  573         }
  574         ntoa_address = inet_ntoa(sa_in->sin_addr);
  575         if (nodelen <= strlen(ntoa_address)) {
  576         result = EAI_OVERFLOW;
  577         goto end;
  578         }
  579         strcpy(node, ntoa_address);
  580     }
  581         
  582     }
  583 
  584   end:
  585     h_errno = saved_h_errno;
  586 #ifdef ENABLE_PTHREAD
  587     pthread_mutex_unlock(&gai_mutex);
  588 #endif
  589     return result;
  590 }
  591