Annotation of embedaddon/curl/lib/hostip4.c, revision 1.1

1.1     ! misho       1: /***************************************************************************
        !             2:  *                                  _   _ ____  _
        !             3:  *  Project                     ___| | | |  _ \| |
        !             4:  *                             / __| | | | |_) | |
        !             5:  *                            | (__| |_| |  _ <| |___
        !             6:  *                             \___|\___/|_| \_\_____|
        !             7:  *
        !             8:  * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
        !             9:  *
        !            10:  * This software is licensed as described in the file COPYING, which
        !            11:  * you should have received as part of this distribution. The terms
        !            12:  * are also available at https://curl.haxx.se/docs/copyright.html.
        !            13:  *
        !            14:  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
        !            15:  * copies of the Software, and permit persons to whom the Software is
        !            16:  * furnished to do so, under the terms of the COPYING file.
        !            17:  *
        !            18:  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
        !            19:  * KIND, either express or implied.
        !            20:  *
        !            21:  ***************************************************************************/
        !            22: 
        !            23: #include "curl_setup.h"
        !            24: 
        !            25: /***********************************************************************
        !            26:  * Only for plain IPv4 builds
        !            27:  **********************************************************************/
        !            28: #ifdef CURLRES_IPV4 /* plain IPv4 code coming up */
        !            29: 
        !            30: #ifdef HAVE_NETINET_IN_H
        !            31: #include <netinet/in.h>
        !            32: #endif
        !            33: #ifdef HAVE_NETDB_H
        !            34: #include <netdb.h>
        !            35: #endif
        !            36: #ifdef HAVE_ARPA_INET_H
        !            37: #include <arpa/inet.h>
        !            38: #endif
        !            39: #ifdef __VMS
        !            40: #include <in.h>
        !            41: #include <inet.h>
        !            42: #endif
        !            43: 
        !            44: #ifdef HAVE_PROCESS_H
        !            45: #include <process.h>
        !            46: #endif
        !            47: 
        !            48: #include "urldata.h"
        !            49: #include "sendf.h"
        !            50: #include "hostip.h"
        !            51: #include "hash.h"
        !            52: #include "share.h"
        !            53: #include "strerror.h"
        !            54: #include "url.h"
        !            55: /* The last 3 #include files should be in this order */
        !            56: #include "curl_printf.h"
        !            57: #include "curl_memory.h"
        !            58: #include "memdebug.h"
        !            59: 
        !            60: /*
        !            61:  * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
        !            62:  * been set and returns TRUE if they are OK.
        !            63:  */
        !            64: bool Curl_ipvalid(struct connectdata *conn)
        !            65: {
        !            66:   if(conn->ip_version == CURL_IPRESOLVE_V6)
        !            67:     /* An IPv6 address was requested and we can't get/use one */
        !            68:     return FALSE;
        !            69: 
        !            70:   return TRUE; /* OK, proceed */
        !            71: }
        !            72: 
        !            73: #ifdef CURLRES_SYNCH
        !            74: 
        !            75: /*
        !            76:  * Curl_getaddrinfo() - the IPv4 synchronous version.
        !            77:  *
        !            78:  * The original code to this function was from the Dancer source code, written
        !            79:  * by Bjorn Reese, it has since been patched and modified considerably.
        !            80:  *
        !            81:  * gethostbyname_r() is the thread-safe version of the gethostbyname()
        !            82:  * function. When we build for plain IPv4, we attempt to use this
        !            83:  * function. There are _three_ different gethostbyname_r() versions, and we
        !            84:  * detect which one this platform supports in the configure script and set up
        !            85:  * the HAVE_GETHOSTBYNAME_R_3, HAVE_GETHOSTBYNAME_R_5 or
        !            86:  * HAVE_GETHOSTBYNAME_R_6 defines accordingly. Note that HAVE_GETADDRBYNAME
        !            87:  * has the corresponding rules. This is primarily on *nix. Note that some unix
        !            88:  * flavours have thread-safe versions of the plain gethostbyname() etc.
        !            89:  *
        !            90:  */
        !            91: Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
        !            92:                                 const char *hostname,
        !            93:                                 int port,
        !            94:                                 int *waitp)
        !            95: {
        !            96:   Curl_addrinfo *ai = NULL;
        !            97: 
        !            98: #ifdef CURL_DISABLE_VERBOSE_STRINGS
        !            99:   (void)conn;
        !           100: #endif
        !           101: 
        !           102:   *waitp = 0; /* synchronous response only */
        !           103: 
        !           104:   ai = Curl_ipv4_resolve_r(hostname, port);
        !           105:   if(!ai)
        !           106:     infof(conn->data, "Curl_ipv4_resolve_r failed for %s\n", hostname);
        !           107: 
        !           108:   return ai;
        !           109: }
        !           110: #endif /* CURLRES_SYNCH */
        !           111: #endif /* CURLRES_IPV4 */
        !           112: 
        !           113: #if defined(CURLRES_IPV4) && !defined(CURLRES_ARES)
        !           114: 
        !           115: /*
        !           116:  * Curl_ipv4_resolve_r() - ipv4 threadsafe resolver function.
        !           117:  *
        !           118:  * This is used for both synchronous and asynchronous resolver builds,
        !           119:  * implying that only threadsafe code and function calls may be used.
        !           120:  *
        !           121:  */
        !           122: Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
        !           123:                                    int port)
        !           124: {
        !           125: #if !defined(HAVE_GETADDRINFO_THREADSAFE) && defined(HAVE_GETHOSTBYNAME_R_3)
        !           126:   int res;
        !           127: #endif
        !           128:   Curl_addrinfo *ai = NULL;
        !           129:   struct hostent *h = NULL;
        !           130:   struct hostent *buf = NULL;
        !           131: 
        !           132: #if defined(HAVE_GETADDRINFO_THREADSAFE)
        !           133:   struct addrinfo hints;
        !           134:   char sbuf[12];
        !           135:   char *sbufptr = NULL;
        !           136: 
        !           137:   memset(&hints, 0, sizeof(hints));
        !           138:   hints.ai_family = PF_INET;
        !           139:   hints.ai_socktype = SOCK_STREAM;
        !           140:   if(port) {
        !           141:     msnprintf(sbuf, sizeof(sbuf), "%d", port);
        !           142:     sbufptr = sbuf;
        !           143:   }
        !           144: 
        !           145:   (void)Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &ai);
        !           146: 
        !           147: #elif defined(HAVE_GETHOSTBYNAME_R)
        !           148:   /*
        !           149:    * gethostbyname_r() is the preferred resolve function for many platforms.
        !           150:    * Since there are three different versions of it, the following code is
        !           151:    * somewhat #ifdef-ridden.
        !           152:    */
        !           153:   int h_errnop;
        !           154: 
        !           155:   buf = calloc(1, CURL_HOSTENT_SIZE);
        !           156:   if(!buf)
        !           157:     return NULL; /* major failure */
        !           158:   /*
        !           159:    * The clearing of the buffer is a workaround for a gethostbyname_r bug in
        !           160:    * qnx nto and it is also _required_ for some of these functions on some
        !           161:    * platforms.
        !           162:    */
        !           163: 
        !           164: #if defined(HAVE_GETHOSTBYNAME_R_5)
        !           165:   /* Solaris, IRIX and more */
        !           166:   h = gethostbyname_r(hostname,
        !           167:                       (struct hostent *)buf,
        !           168:                       (char *)buf + sizeof(struct hostent),
        !           169:                       CURL_HOSTENT_SIZE - sizeof(struct hostent),
        !           170:                       &h_errnop);
        !           171: 
        !           172:   /* If the buffer is too small, it returns NULL and sets errno to
        !           173:    * ERANGE. The errno is thread safe if this is compiled with
        !           174:    * -D_REENTRANT as then the 'errno' variable is a macro defined to get
        !           175:    * used properly for threads.
        !           176:    */
        !           177: 
        !           178:   if(h) {
        !           179:     ;
        !           180:   }
        !           181:   else
        !           182: #elif defined(HAVE_GETHOSTBYNAME_R_6)
        !           183:   /* Linux */
        !           184: 
        !           185:   (void)gethostbyname_r(hostname,
        !           186:                       (struct hostent *)buf,
        !           187:                       (char *)buf + sizeof(struct hostent),
        !           188:                       CURL_HOSTENT_SIZE - sizeof(struct hostent),
        !           189:                       &h, /* DIFFERENCE */
        !           190:                       &h_errnop);
        !           191:   /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a
        !           192:    * sudden this function returns EAGAIN if the given buffer size is too
        !           193:    * small. Previous versions are known to return ERANGE for the same
        !           194:    * problem.
        !           195:    *
        !           196:    * This wouldn't be such a big problem if older versions wouldn't
        !           197:    * sometimes return EAGAIN on a common failure case. Alas, we can't
        !           198:    * assume that EAGAIN *or* ERANGE means ERANGE for any given version of
        !           199:    * glibc.
        !           200:    *
        !           201:    * For now, we do that and thus we may call the function repeatedly and
        !           202:    * fail for older glibc versions that return EAGAIN, until we run out of
        !           203:    * buffer size (step_size grows beyond CURL_HOSTENT_SIZE).
        !           204:    *
        !           205:    * If anyone has a better fix, please tell us!
        !           206:    *
        !           207:    * -------------------------------------------------------------------
        !           208:    *
        !           209:    * On October 23rd 2003, Dan C dug up more details on the mysteries of
        !           210:    * gethostbyname_r() in glibc:
        !           211:    *
        !           212:    * In glibc 2.2.5 the interface is different (this has also been
        !           213:    * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't
        !           214:    * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32
        !           215:    * (shipped/upgraded by Redhat 7.2) don't show this behavior!
        !           216:    *
        !           217:    * In this "buggy" version, the return code is -1 on error and 'errno'
        !           218:    * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a
        !           219:    * thread-safe variable.
        !           220:    */
        !           221: 
        !           222:   if(!h) /* failure */
        !           223: #elif defined(HAVE_GETHOSTBYNAME_R_3)
        !           224:   /* AIX, Digital Unix/Tru64, HPUX 10, more? */
        !           225: 
        !           226:   /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
        !           227:    * the plain fact that it does not return unique full buffers on each
        !           228:    * call, but instead several of the pointers in the hostent structs will
        !           229:    * point to the same actual data! This have the unfortunate down-side that
        !           230:    * our caching system breaks down horribly. Luckily for us though, AIX 4.3
        !           231:    * and more recent versions have a "completely thread-safe"[*] libc where
        !           232:    * all the data is stored in thread-specific memory areas making calls to
        !           233:    * the plain old gethostbyname() work fine even for multi-threaded
        !           234:    * programs.
        !           235:    *
        !           236:    * This AIX 4.3 or later detection is all made in the configure script.
        !           237:    *
        !           238:    * Troels Walsted Hansen helped us work this out on March 3rd, 2003.
        !           239:    *
        !           240:    * [*] = much later we've found out that it isn't at all "completely
        !           241:    * thread-safe", but at least the gethostbyname() function is.
        !           242:    */
        !           243: 
        !           244:   if(CURL_HOSTENT_SIZE >=
        !           245:      (sizeof(struct hostent) + sizeof(struct hostent_data))) {
        !           246: 
        !           247:     /* August 22nd, 2000: Albert Chin-A-Young brought an updated version
        !           248:      * that should work! September 20: Richard Prescott worked on the buffer
        !           249:      * size dilemma.
        !           250:      */
        !           251: 
        !           252:     res = gethostbyname_r(hostname,
        !           253:                           (struct hostent *)buf,
        !           254:                           (struct hostent_data *)((char *)buf +
        !           255:                                                   sizeof(struct hostent)));
        !           256:     h_errnop = SOCKERRNO; /* we don't deal with this, but set it anyway */
        !           257:   }
        !           258:   else
        !           259:     res = -1; /* failure, too smallish buffer size */
        !           260: 
        !           261:   if(!res) { /* success */
        !           262: 
        !           263:     h = buf; /* result expected in h */
        !           264: 
        !           265:     /* This is the worst kind of the different gethostbyname_r() interfaces.
        !           266:      * Since we don't know how big buffer this particular lookup required,
        !           267:      * we can't realloc down the huge alloc without doing closer analysis of
        !           268:      * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every
        !           269:      * name lookup. Fixing this would require an extra malloc() and then
        !           270:      * calling Curl_addrinfo_copy() that subsequent realloc()s down the new
        !           271:      * memory area to the actually used amount.
        !           272:      */
        !           273:   }
        !           274:   else
        !           275: #endif /* HAVE_...BYNAME_R_5 || HAVE_...BYNAME_R_6 || HAVE_...BYNAME_R_3 */
        !           276:   {
        !           277:     h = NULL; /* set return code to NULL */
        !           278:     free(buf);
        !           279:   }
        !           280: #else /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
        !           281:   /*
        !           282:    * Here is code for platforms that don't have a thread safe
        !           283:    * getaddrinfo() nor gethostbyname_r() function or for which
        !           284:    * gethostbyname() is the preferred one.
        !           285:    */
        !           286:   h = gethostbyname((void *)hostname);
        !           287: #endif /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
        !           288: 
        !           289:   if(h) {
        !           290:     ai = Curl_he2ai(h, port);
        !           291: 
        !           292:     if(buf) /* used a *_r() function */
        !           293:       free(buf);
        !           294:   }
        !           295: 
        !           296:   return ai;
        !           297: }
        !           298: #endif /* defined(CURLRES_IPV4) && !defined(CURLRES_ARES) */

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