Annotation of embedaddon/curl/lib/hostip4.c, revision 1.1.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>