Annotation of rpl/src/getaddrinfo.c, revision 1.55

1.1       bertrand    1: /*
                      2: ================================================================================
1.54      bertrand    3:   RPL/2 (R) version 4.1.32
1.55    ! bertrand    4:   Copyright (C) 1989-2020 Dr. BERTRAND Joël
1.1       bertrand    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: 
1.4       bertrand   22: 
1.1       bertrand   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>