Annotation of embedaddon/rsync/lib/getaddrinfo.c, revision 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>