File:  [local] / rpl / src / getaddrinfo.c
Revision 1.55: download - view: text, annotated - select for diffs - revision graph
Fri Jan 10 11:15:43 2020 UTC (4 years, 2 months ago) by bertrand
Branches: MAIN
CVS tags: rpl-4_1_32, HEAD
Modification du copyright.

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

CVSweb interface <joel.bertrand@systella.fr>