Annotation of embedaddon/rsync/lib/getaddrinfo.c, revision 1.1.1.1

1.1       misho       1: /*
                      2: PostgreSQL Database Management System
                      3: (formerly known as Postgres, then as Postgres95)
                      4: 
                      5: Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group
                      6: 
                      7: Portions Copyright (c) 1994, The Regents of the University of California
                      8: 
                      9: Permission to use, copy, modify, and distribute this software and its
                     10: documentation for any purpose, without fee, and without a written agreement
                     11: is hereby granted, provided that the above copyright notice and this paragraph
                     12: and the following two paragraphs appear in all copies.
                     13: 
                     14: IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
                     15: DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
                     16: LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
                     17: EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
                     18: SUCH DAMAGE.
                     19: 
                     20: THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
                     21: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
                     22: AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
                     23: ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS
                     24: TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
                     25: 
                     26: */
                     27: 
                     28: /*-------------------------------------------------------------------------
                     29:  *
                     30:  * getaddrinfo.c
                     31:  *       Support getaddrinfo() on platforms that don't have it.
                     32:  *
                     33:  * We also supply getnameinfo() here, assuming that the platform will have
                     34:  * it if and only if it has getaddrinfo().     If this proves false on some
                     35:  * platform, we'll need to split this file and provide a separate configure
                     36:  * test for getnameinfo().
                     37:  *
                     38:  * Copyright (c) 2003-2007, PostgreSQL Global Development Group
                     39:  *
                     40:  * Copyright (C) 2007 Jeremy Allison.
                     41:  * Modified to return multiple IPv4 addresses for Samba.
                     42:  *
                     43:  *-------------------------------------------------------------------------
                     44:  */
                     45: 
                     46: #include "rsync.h"
                     47: 
                     48: #ifndef SMB_MALLOC
                     49: #define SMB_MALLOC(s) malloc(s)
                     50: #endif
                     51: 
                     52: #ifndef SMB_STRDUP
                     53: #define SMB_STRDUP(s) strdup(s)
                     54: #endif
                     55: 
                     56: #ifndef HOST_NAME_MAX
                     57: #define HOST_NAME_MAX 255
                     58: #endif
                     59: 
                     60: static int check_hostent_err(struct hostent *hp)
                     61: {
                     62: #ifndef INET6
                     63:        extern int h_errno;
                     64: #endif
                     65:        if (!hp) {
                     66:                switch (h_errno) {
                     67:                        case HOST_NOT_FOUND:
                     68:                        case NO_DATA:
                     69:                                return EAI_NONAME;
                     70:                        case TRY_AGAIN:
                     71:                                return EAI_AGAIN;
                     72:                        case NO_RECOVERY:
                     73:                        default:
                     74:                                return EAI_FAIL;
                     75:                }
                     76:        }
                     77:        if (!hp->h_name || hp->h_addrtype != AF_INET) {
                     78:                return EAI_FAIL;
                     79:        }
                     80:        return 0;
                     81: }
                     82: 
                     83: static char *canon_name_from_hostent(struct hostent *hp,
                     84:                                int *perr)
                     85: {
                     86:        char *ret = NULL;
                     87: 
                     88:        *perr = check_hostent_err(hp);
                     89:        if (*perr) {
                     90:                return NULL;
                     91:        }
                     92:        ret = SMB_STRDUP(hp->h_name);
                     93:        if (!ret) {
                     94:                *perr = EAI_MEMORY;
                     95:        }
                     96:        return ret;
                     97: }
                     98: 
                     99: static char *get_my_canon_name(int *perr)
                    100: {
                    101:        char name[HOST_NAME_MAX+1];
                    102: 
                    103:        if (gethostname(name, HOST_NAME_MAX) == -1) {
                    104:                *perr = EAI_FAIL;
                    105:                return NULL;
                    106:        }
                    107:        /* Ensure null termination. */
                    108:        name[HOST_NAME_MAX] = '\0';
                    109:        return canon_name_from_hostent(gethostbyname(name), perr);
                    110: }
                    111: 
                    112: static char *get_canon_name_from_addr(struct in_addr ip,
                    113:                                int *perr)
                    114: {
                    115:        return canon_name_from_hostent(
                    116:                        gethostbyaddr((void *)&ip, sizeof ip, AF_INET),
                    117:                        perr);
                    118: }
                    119: 
                    120: static struct addrinfo *alloc_entry(const struct addrinfo *hints,
                    121:                                struct in_addr ip,
                    122:                                unsigned short port)
                    123: {
                    124:        struct sockaddr_in *psin = NULL;
                    125:        struct addrinfo *ai = SMB_MALLOC(sizeof(*ai));
                    126: 
                    127:        if (!ai) {
                    128:                return NULL;
                    129:        }
                    130:        memset(ai, '\0', sizeof(*ai));
                    131: 
                    132:        psin = SMB_MALLOC(sizeof(*psin));
                    133:        if (!psin) {
                    134:                free(ai);
                    135:                return NULL;
                    136:        }
                    137: 
                    138:        memset(psin, '\0', sizeof(*psin));
                    139: 
                    140:        psin->sin_family = AF_INET;
                    141:        psin->sin_port = htons(port);
                    142:        psin->sin_addr = ip;
                    143: 
                    144:        ai->ai_flags = 0;
                    145:        ai->ai_family = AF_INET;
                    146:        ai->ai_socktype = hints->ai_socktype;
                    147:        ai->ai_protocol = hints->ai_protocol;
                    148:        ai->ai_addrlen = sizeof(*psin);
                    149:        ai->ai_addr = (struct sockaddr *) psin;
                    150:        ai->ai_canonname = NULL;
                    151:        ai->ai_next = NULL;
                    152: 
                    153:        return ai;
                    154: }
                    155: 
                    156: /*
                    157:  * get address info for a single ipv4 address.
                    158:  *
                    159:  *     Bugs:   - servname can only be a number, not text.
                    160:  */
                    161: 
                    162: static int getaddr_info_single_addr(const char *service,
                    163:                                uint32 addr,
                    164:                                const struct addrinfo *hints,
                    165:                                struct addrinfo **res)
                    166: {
                    167: 
                    168:        struct addrinfo *ai = NULL;
                    169:        struct in_addr ip;
                    170:        unsigned short port = 0;
                    171: 
                    172:        if (service) {
                    173:                port = (unsigned short)atoi(service);
                    174:        }
                    175:        ip.s_addr = htonl(addr);
                    176: 
                    177:        ai = alloc_entry(hints, ip, port);
                    178:        if (!ai) {
                    179:                return EAI_MEMORY;
                    180:        }
                    181: 
                    182:        /* If we're asked for the canonical name,
                    183:         * make sure it returns correctly. */
                    184:        if (!(hints->ai_flags & AI_NUMERICSERV) &&
                    185:                        hints->ai_flags & AI_CANONNAME) {
                    186:                int err;
                    187:                if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) {
                    188:                        ai->ai_canonname = get_my_canon_name(&err);
                    189:                } else {
                    190:                        ai->ai_canonname =
                    191:                        get_canon_name_from_addr(ip,&err);
                    192:                }
                    193:                if (ai->ai_canonname == NULL) {
                    194:                        freeaddrinfo(ai);
                    195:                        return err;
                    196:                }
                    197:        }
                    198: 
                    199:        *res = ai;
                    200:        return 0;
                    201: }
                    202: 
                    203: /*
                    204:  * get address info for multiple ipv4 addresses.
                    205:  *
                    206:  *     Bugs:   - servname can only be a number, not text.
                    207:  */
                    208: 
                    209: static int getaddr_info_name(const char *node,
                    210:                                const char *service,
                    211:                                const struct addrinfo *hints,
                    212:                                struct addrinfo **res)
                    213: {
                    214:        struct addrinfo *listp = NULL, *prevp = NULL;
                    215:        char **pptr = NULL;
                    216:        int err;
                    217:        struct hostent *hp = NULL;
                    218:        unsigned short port = 0;
                    219: 
                    220:        if (service) {
                    221:                port = (unsigned short)atoi(service);
                    222:        }
                    223: 
                    224:        hp = gethostbyname(node);
                    225:        err = check_hostent_err(hp);
                    226:        if (err) {
                    227:                return err;
                    228:        }
                    229: 
                    230:        for(pptr = hp->h_addr_list; *pptr; pptr++) {
                    231:                struct in_addr ip = *(struct in_addr *)*pptr;
                    232:                struct addrinfo *ai = alloc_entry(hints, ip, port);
                    233: 
                    234:                if (!ai) {
                    235:                        freeaddrinfo(listp);
                    236:                        return EAI_MEMORY;
                    237:                }
                    238: 
                    239:                if (!listp) {
                    240:                        listp = ai;
                    241:                        prevp = ai;
                    242:                        ai->ai_canonname = SMB_STRDUP(hp->h_name);
                    243:                        if (!ai->ai_canonname) {
                    244:                                freeaddrinfo(listp);
                    245:                                return EAI_MEMORY;
                    246:                        }
                    247:                } else {
                    248:                        prevp->ai_next = ai;
                    249:                        prevp = ai;
                    250:                }
                    251:        }
                    252:        *res = listp;
                    253:        return 0;
                    254: }
                    255: 
                    256: /*
                    257:  * get address info for ipv4 sockets.
                    258:  *
                    259:  *     Bugs:   - servname can only be a number, not text.
                    260:  */
                    261: 
                    262: int getaddrinfo(const char *node,
                    263:                const char *service,
                    264:                const struct addrinfo * hintp,
                    265:                struct addrinfo ** res)
                    266: {
                    267:        struct addrinfo hints;
                    268: 
                    269:        /* Setup the hints struct. */
                    270:        if (hintp == NULL) {
                    271:                memset(&hints, 0, sizeof(hints));
                    272:                hints.ai_family = AF_INET;
                    273:                hints.ai_socktype = SOCK_STREAM;
                    274:        } else {
                    275:                memcpy(&hints, hintp, sizeof(hints));
                    276:        }
                    277: 
                    278:        if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) {
                    279:                return EAI_FAMILY;
                    280:        }
                    281: 
                    282:        if (hints.ai_socktype == 0) {
                    283:                hints.ai_socktype = SOCK_STREAM;
                    284:        }
                    285: 
                    286:        if (!node && !service) {
                    287:                return EAI_NONAME;
                    288:        }
                    289: 
                    290:        if (node) {
                    291:                if (node[0] == '\0') {
                    292:                        return getaddr_info_single_addr(service,
                    293:                                        INADDR_ANY,
                    294:                                        &hints,
                    295:                                        res);
                    296:                } else if (hints.ai_flags & AI_NUMERICHOST) {
                    297:                        struct in_addr ip;
                    298:                        if (inet_pton(AF_INET, node, &ip) <= 0)
                    299:                                return EAI_FAIL;
                    300:                        return getaddr_info_single_addr(service,
                    301:                                        ntohl(ip.s_addr),
                    302:                                        &hints,
                    303:                                        res);
                    304:                } else {
                    305:                        return getaddr_info_name(node,
                    306:                                                service,
                    307:                                                &hints,
                    308:                                                res);
                    309:                }
                    310:        } else if (hints.ai_flags & AI_PASSIVE) {
                    311:                return getaddr_info_single_addr(service,
                    312:                                        INADDR_ANY,
                    313:                                        &hints,
                    314:                                        res);
                    315:        }
                    316:        return getaddr_info_single_addr(service,
                    317:                                        INADDR_LOOPBACK,
                    318:                                        &hints,
                    319:                                        res);
                    320: }
                    321: 
                    322: 
                    323: void freeaddrinfo(struct addrinfo *res)
                    324: {
                    325:        struct addrinfo *next = NULL;
                    326: 
                    327:        for (;res; res = next) {
                    328:                next = res->ai_next;
                    329:                if (res->ai_canonname) {
                    330:                        free(res->ai_canonname);
                    331:                }
                    332:                if (res->ai_addr) {
                    333:                        free(res->ai_addr);
                    334:                }
                    335:                free(res);
                    336:        }
                    337: }
                    338: 
                    339: 
                    340: const char *gai_strerror(int errcode)
                    341: {
                    342: #ifdef HAVE_HSTRERROR
                    343:        int                     hcode;
                    344: 
                    345:        switch (errcode)
                    346:        {
                    347:                case EAI_NONAME:
                    348:                        hcode = HOST_NOT_FOUND;
                    349:                        break;
                    350:                case EAI_AGAIN:
                    351:                        hcode = TRY_AGAIN;
                    352:                        break;
                    353:                case EAI_FAIL:
                    354:                default:
                    355:                        hcode = NO_RECOVERY;
                    356:                        break;
                    357:        }
                    358: 
                    359:        return hstrerror(hcode);
                    360: #else                                                  /* !HAVE_HSTRERROR */
                    361: 
                    362:        switch (errcode)
                    363:        {
                    364:                case EAI_NONAME:
                    365:                        return "Unknown host";
                    366:                case EAI_AGAIN:
                    367:                        return "Host name lookup failure";
                    368: #ifdef EAI_BADFLAGS
                    369:                case EAI_BADFLAGS:
                    370:                        return "Invalid argument";
                    371: #endif
                    372: #ifdef EAI_FAMILY
                    373:                case EAI_FAMILY:
                    374:                        return "Address family not supported";
                    375: #endif
                    376: #ifdef EAI_MEMORY
                    377:                case EAI_MEMORY:
                    378:                        return "Not enough memory";
                    379: #endif
                    380: #ifdef EAI_NODATA
                    381:                case EAI_NODATA:
                    382:                        return "No host data of that type was found";
                    383: #endif
                    384: #ifdef EAI_SERVICE
                    385:                case EAI_SERVICE:
                    386:                        return "Class type not found";
                    387: #endif
                    388: #ifdef EAI_SOCKTYPE
                    389:                case EAI_SOCKTYPE:
                    390:                        return "Socket type not supported";
                    391: #endif
                    392:                default:
                    393:                        return "Unknown server error";
                    394:        }
                    395: #endif   /* HAVE_HSTRERROR */
                    396: }
                    397: 
                    398: static int gethostnameinfo(const struct sockaddr *sa,
                    399:                        char *node,
                    400:                        size_t nodelen,
                    401:                        int flags)
                    402: {
                    403:        int ret = -1;
                    404:        char *p = NULL;
                    405: 
                    406:        if (!(flags & NI_NUMERICHOST)) {
                    407:                struct hostent *hp = gethostbyaddr(
                    408:                                (void *)&((struct sockaddr_in *)sa)->sin_addr,
                    409:                                sizeof (struct in_addr),
                    410:                                sa->sa_family);
                    411:                ret = check_hostent_err(hp);
                    412:                if (ret == 0) {
                    413:                        /* Name looked up successfully. */
                    414:                        ret = snprintf(node, nodelen, "%s", hp->h_name);
                    415:                        if (ret < 0 || (size_t)ret >= nodelen) {
                    416:                                return EAI_MEMORY;
                    417:                        }
                    418:                        if (flags & NI_NOFQDN) {
                    419:                                p = strchr(node,'.');
                    420:                                if (p) {
                    421:                                        *p = '\0';
                    422:                                }
                    423:                        }
                    424:                        return 0;
                    425:                }
                    426: 
                    427:                if (flags & NI_NAMEREQD) {
                    428:                        /* If we require a name and didn't get one,
                    429:                         * automatically fail. */
                    430:                        return ret;
                    431:                }
                    432:                /* Otherwise just fall into the numeric host code... */
                    433:        }
                    434:        p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
                    435:        ret = snprintf(node, nodelen, "%s", p);
                    436:        if (ret < 0 || (size_t)ret >= nodelen) {
                    437:                return EAI_MEMORY;
                    438:        }
                    439:        return 0;
                    440: }
                    441: 
                    442: static int getservicenameinfo(const struct sockaddr *sa,
                    443:                        char *service,
                    444:                        size_t servicelen,
                    445:                        int flags)
                    446: {
                    447:        int ret = -1;
                    448:        int port = ntohs(((struct sockaddr_in *)sa)->sin_port);
                    449: 
                    450:        if (!(flags & NI_NUMERICSERV)) {
                    451:                struct servent *se = getservbyport(
                    452:                                port,
                    453:                                (flags & NI_DGRAM) ? "udp" : "tcp");
                    454:                if (se && se->s_name) {
                    455:                        /* Service name looked up successfully. */
                    456:                        ret = snprintf(service, servicelen, "%s", se->s_name);
                    457:                        if (ret < 0 || (size_t)ret >= servicelen) {
                    458:                                return EAI_MEMORY;
                    459:                        }
                    460:                        return 0;
                    461:                }
                    462:                /* Otherwise just fall into the numeric service code... */
                    463:        }
                    464:        ret = snprintf(service, servicelen, "%d", port);
                    465:        if (ret < 0 || (size_t)ret >= servicelen) {
                    466:                return EAI_MEMORY;
                    467:        }
                    468:        return 0;
                    469: }
                    470: 
                    471: /*
                    472:  * Convert an ipv4 address to a hostname.
                    473:  *
                    474:  * Bugs:       - No IPv6 support.
                    475:  */
                    476: int getnameinfo(const struct sockaddr *sa, socklen_t salen,
                    477:                        char *node, size_t nodelen,
                    478:                        char *service, size_t servicelen, int flags)
                    479: {
                    480: 
                    481:        /* Invalid arguments. */
                    482:        if (sa == NULL || (node == NULL && service == NULL)) {
                    483:                return EAI_FAIL;
                    484:        }
                    485: 
                    486:        if (sa->sa_family != AF_INET) {
                    487:                return EAI_FAIL;
                    488:        }
                    489: 
                    490:        if (salen < (socklen_t)sizeof (struct sockaddr_in)) {
                    491:                return EAI_FAIL;
                    492:        }
                    493: 
                    494:        if (node) {
                    495:                int ret = gethostnameinfo(sa, node, nodelen, flags);
                    496:                if (ret)
                    497:                        return ret;
                    498:        }
                    499: 
                    500:        if (service) {
                    501:                return getservicenameinfo(sa, service, servicelen, flags);
                    502:        }
                    503:        return 0;
                    504: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>