File:  [local] / rpl / src / getaddrinfo.c
Revision 1.12: download - view: text, annotated - select for diffs - revision graph
Tue Jun 21 15:26:29 2011 UTC (12 years, 10 months ago) by bertrand
Branches: MAIN
CVS tags: HEAD
Correction d'une réinitialisation sauvage de la pile des variables par niveau
dans la copie de la structure de description du processus. Cela corrige
la fonction SPAWN qui échouait sur un segmentation fault car la pile des
variables par niveau était vide alors même que l'arbre des variables contenait
bien les variables. Passage à la prerelease 2.

    1: /*
    2: ================================================================================
    3:   RPL/2 (R) version 4.1.0.prerelease.2
    4:   Copyright (C) 1989-2011 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>