Annotation of embedaddon/curl/lib/asyn-thread.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: #include "socketpair.h"
                     25: 
                     26: /***********************************************************************
                     27:  * Only for threaded name resolves builds
                     28:  **********************************************************************/
                     29: #ifdef CURLRES_THREADED
                     30: 
                     31: #ifdef HAVE_NETINET_IN_H
                     32: #include <netinet/in.h>
                     33: #endif
                     34: #ifdef HAVE_NETDB_H
                     35: #include <netdb.h>
                     36: #endif
                     37: #ifdef HAVE_ARPA_INET_H
                     38: #include <arpa/inet.h>
                     39: #endif
                     40: #ifdef __VMS
                     41: #include <in.h>
                     42: #include <inet.h>
                     43: #endif
                     44: 
                     45: #if defined(USE_THREADS_POSIX)
                     46: #  ifdef HAVE_PTHREAD_H
                     47: #    include <pthread.h>
                     48: #  endif
                     49: #elif defined(USE_THREADS_WIN32)
                     50: #  ifdef HAVE_PROCESS_H
                     51: #    include <process.h>
                     52: #  endif
                     53: #endif
                     54: 
                     55: #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
                     56: #undef in_addr_t
                     57: #define in_addr_t unsigned long
                     58: #endif
                     59: 
                     60: #ifdef HAVE_GETADDRINFO
                     61: #  define RESOLVER_ENOMEM  EAI_MEMORY
                     62: #else
                     63: #  define RESOLVER_ENOMEM  ENOMEM
                     64: #endif
                     65: 
                     66: #include "urldata.h"
                     67: #include "sendf.h"
                     68: #include "hostip.h"
                     69: #include "hash.h"
                     70: #include "share.h"
                     71: #include "strerror.h"
                     72: #include "url.h"
                     73: #include "multiif.h"
                     74: #include "inet_ntop.h"
                     75: #include "curl_threads.h"
                     76: #include "connect.h"
                     77: #include "socketpair.h"
                     78: /* The last 3 #include files should be in this order */
                     79: #include "curl_printf.h"
                     80: #include "curl_memory.h"
                     81: #include "memdebug.h"
                     82: 
                     83: struct resdata {
                     84:   struct curltime start;
                     85: };
                     86: 
                     87: /*
                     88:  * Curl_resolver_global_init()
                     89:  * Called from curl_global_init() to initialize global resolver environment.
                     90:  * Does nothing here.
                     91:  */
                     92: int Curl_resolver_global_init(void)
                     93: {
                     94:   return CURLE_OK;
                     95: }
                     96: 
                     97: /*
                     98:  * Curl_resolver_global_cleanup()
                     99:  * Called from curl_global_cleanup() to destroy global resolver environment.
                    100:  * Does nothing here.
                    101:  */
                    102: void Curl_resolver_global_cleanup(void)
                    103: {
                    104: }
                    105: 
                    106: /*
                    107:  * Curl_resolver_init()
                    108:  * Called from curl_easy_init() -> Curl_open() to initialize resolver
                    109:  * URL-state specific environment ('resolver' member of the UrlState
                    110:  * structure).
                    111:  */
                    112: CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
                    113: {
                    114:   (void)easy;
                    115:   *resolver = calloc(1, sizeof(struct resdata));
                    116:   if(!*resolver)
                    117:     return CURLE_OUT_OF_MEMORY;
                    118:   return CURLE_OK;
                    119: }
                    120: 
                    121: /*
                    122:  * Curl_resolver_cleanup()
                    123:  * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
                    124:  * URL-state specific environment ('resolver' member of the UrlState
                    125:  * structure).
                    126:  */
                    127: void Curl_resolver_cleanup(void *resolver)
                    128: {
                    129:   free(resolver);
                    130: }
                    131: 
                    132: /*
                    133:  * Curl_resolver_duphandle()
                    134:  * Called from curl_easy_duphandle() to duplicate resolver URL state-specific
                    135:  * environment ('resolver' member of the UrlState structure).
                    136:  */
                    137: CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
                    138: {
                    139:   (void)from;
                    140:   return Curl_resolver_init(easy, to);
                    141: }
                    142: 
                    143: static void destroy_async_data(struct Curl_async *);
                    144: 
                    145: /*
                    146:  * Cancel all possibly still on-going resolves for this connection.
                    147:  */
                    148: void Curl_resolver_cancel(struct connectdata *conn)
                    149: {
                    150:   destroy_async_data(&conn->async);
                    151: }
                    152: 
                    153: /* This function is used to init a threaded resolve */
                    154: static bool init_resolve_thread(struct connectdata *conn,
                    155:                                 const char *hostname, int port,
                    156:                                 const struct addrinfo *hints);
                    157: 
                    158: 
                    159: /* Data for synchronization between resolver thread and its parent */
                    160: struct thread_sync_data {
                    161:   curl_mutex_t * mtx;
                    162:   int done;
                    163: 
                    164:   char *hostname;        /* hostname to resolve, Curl_async.hostname
                    165:                             duplicate */
                    166:   int port;
                    167: #ifdef USE_SOCKETPAIR
                    168:   struct connectdata *conn;
                    169:   curl_socket_t sock_pair[2]; /* socket pair */
                    170: #endif
                    171:   int sock_error;
                    172:   Curl_addrinfo *res;
                    173: #ifdef HAVE_GETADDRINFO
                    174:   struct addrinfo hints;
                    175: #endif
                    176:   struct thread_data *td; /* for thread-self cleanup */
                    177: };
                    178: 
                    179: struct thread_data {
                    180:   curl_thread_t thread_hnd;
                    181:   unsigned int poll_interval;
                    182:   time_t interval_end;
                    183:   struct thread_sync_data tsd;
                    184: };
                    185: 
                    186: static struct thread_sync_data *conn_thread_sync_data(struct connectdata *conn)
                    187: {
                    188:   return &(((struct thread_data *)conn->async.os_specific)->tsd);
                    189: }
                    190: 
                    191: /* Destroy resolver thread synchronization data */
                    192: static
                    193: void destroy_thread_sync_data(struct thread_sync_data * tsd)
                    194: {
                    195:   if(tsd->mtx) {
                    196:     Curl_mutex_destroy(tsd->mtx);
                    197:     free(tsd->mtx);
                    198:   }
                    199: 
                    200:   free(tsd->hostname);
                    201: 
                    202:   if(tsd->res)
                    203:     Curl_freeaddrinfo(tsd->res);
                    204: 
                    205: #ifdef USE_SOCKETPAIR
                    206:   /*
                    207:    * close one end of the socket pair (may be done in resolver thread);
                    208:    * the other end (for reading) is always closed in the parent thread.
                    209:    */
                    210:   if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
                    211:     sclose(tsd->sock_pair[1]);
                    212:   }
                    213: #endif
                    214:   memset(tsd, 0, sizeof(*tsd));
                    215: }
                    216: 
                    217: /* Initialize resolver thread synchronization data */
                    218: static
                    219: int init_thread_sync_data(struct thread_data * td,
                    220:                            const char *hostname,
                    221:                            int port,
                    222:                            const struct addrinfo *hints)
                    223: {
                    224:   struct thread_sync_data *tsd = &td->tsd;
                    225: 
                    226:   memset(tsd, 0, sizeof(*tsd));
                    227: 
                    228:   tsd->td = td;
                    229:   tsd->port = port;
                    230:   /* Treat the request as done until the thread actually starts so any early
                    231:    * cleanup gets done properly.
                    232:    */
                    233:   tsd->done = 1;
                    234: #ifdef HAVE_GETADDRINFO
                    235:   DEBUGASSERT(hints);
                    236:   tsd->hints = *hints;
                    237: #else
                    238:   (void) hints;
                    239: #endif
                    240: 
                    241:   tsd->mtx = malloc(sizeof(curl_mutex_t));
                    242:   if(tsd->mtx == NULL)
                    243:     goto err_exit;
                    244: 
                    245:   Curl_mutex_init(tsd->mtx);
                    246: 
                    247: #ifdef USE_SOCKETPAIR
                    248:   /* create socket pair, avoid AF_LOCAL since it doesn't build on Solaris */
                    249:   if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &tsd->sock_pair[0]) < 0) {
                    250:     tsd->sock_pair[0] = CURL_SOCKET_BAD;
                    251:     tsd->sock_pair[1] = CURL_SOCKET_BAD;
                    252:     goto err_exit;
                    253:   }
                    254: #endif
                    255:   tsd->sock_error = CURL_ASYNC_SUCCESS;
                    256: 
                    257:   /* Copying hostname string because original can be destroyed by parent
                    258:    * thread during gethostbyname execution.
                    259:    */
                    260:   tsd->hostname = strdup(hostname);
                    261:   if(!tsd->hostname)
                    262:     goto err_exit;
                    263: 
                    264:   return 1;
                    265: 
                    266:  err_exit:
                    267:   /* Memory allocation failed */
                    268:   destroy_thread_sync_data(tsd);
                    269:   return 0;
                    270: }
                    271: 
                    272: static int getaddrinfo_complete(struct connectdata *conn)
                    273: {
                    274:   struct thread_sync_data *tsd = conn_thread_sync_data(conn);
                    275:   int rc;
                    276: 
                    277:   rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res);
                    278:   /* The tsd->res structure has been copied to async.dns and perhaps the DNS
                    279:      cache.  Set our copy to NULL so destroy_thread_sync_data doesn't free it.
                    280:   */
                    281:   tsd->res = NULL;
                    282: 
                    283:   return rc;
                    284: }
                    285: 
                    286: 
                    287: #ifdef HAVE_GETADDRINFO
                    288: 
                    289: /*
                    290:  * getaddrinfo_thread() resolves a name and then exits.
                    291:  *
                    292:  * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
                    293:  * and wait on it.
                    294:  */
                    295: static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
                    296: {
                    297:   struct thread_sync_data *tsd = (struct thread_sync_data*)arg;
                    298:   struct thread_data *td = tsd->td;
                    299:   char service[12];
                    300:   int rc;
                    301: #ifdef USE_SOCKETPAIR
                    302:   char buf[1];
                    303: #endif
                    304: 
                    305:   msnprintf(service, sizeof(service), "%d", tsd->port);
                    306: 
                    307:   rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
                    308: 
                    309:   if(rc != 0) {
                    310:     tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
                    311:     if(tsd->sock_error == 0)
                    312:       tsd->sock_error = RESOLVER_ENOMEM;
                    313:   }
                    314:   else {
                    315:     Curl_addrinfo_set_port(tsd->res, tsd->port);
                    316:   }
                    317: 
                    318:   Curl_mutex_acquire(tsd->mtx);
                    319:   if(tsd->done) {
                    320:     /* too late, gotta clean up the mess */
                    321:     Curl_mutex_release(tsd->mtx);
                    322:     destroy_thread_sync_data(tsd);
                    323:     free(td);
                    324:   }
                    325:   else {
                    326: #ifdef USE_SOCKETPAIR
                    327:     if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
                    328:       /* DNS has been resolved, signal client task */
                    329:       buf[0] = 1;
                    330:       if(swrite(tsd->sock_pair[1],  buf, sizeof(buf)) < 0) {
                    331:         /* update sock_erro to errno */
                    332:         tsd->sock_error = SOCKERRNO;
                    333:       }
                    334:     }
                    335: #endif
                    336:     tsd->done = 1;
                    337:     Curl_mutex_release(tsd->mtx);
                    338:   }
                    339: 
                    340:   return 0;
                    341: }
                    342: 
                    343: #else /* HAVE_GETADDRINFO */
                    344: 
                    345: /*
                    346:  * gethostbyname_thread() resolves a name and then exits.
                    347:  */
                    348: static unsigned int CURL_STDCALL gethostbyname_thread(void *arg)
                    349: {
                    350:   struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
                    351:   struct thread_data *td = tsd->td;
                    352: 
                    353:   tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
                    354: 
                    355:   if(!tsd->res) {
                    356:     tsd->sock_error = SOCKERRNO;
                    357:     if(tsd->sock_error == 0)
                    358:       tsd->sock_error = RESOLVER_ENOMEM;
                    359:   }
                    360: 
                    361:   Curl_mutex_acquire(tsd->mtx);
                    362:   if(tsd->done) {
                    363:     /* too late, gotta clean up the mess */
                    364:     Curl_mutex_release(tsd->mtx);
                    365:     destroy_thread_sync_data(tsd);
                    366:     free(td);
                    367:   }
                    368:   else {
                    369:     tsd->done = 1;
                    370:     Curl_mutex_release(tsd->mtx);
                    371:   }
                    372: 
                    373:   return 0;
                    374: }
                    375: 
                    376: #endif /* HAVE_GETADDRINFO */
                    377: 
                    378: /*
                    379:  * destroy_async_data() cleans up async resolver data and thread handle.
                    380:  */
                    381: static void destroy_async_data(struct Curl_async *async)
                    382: {
                    383:   if(async->os_specific) {
                    384:     struct thread_data *td = (struct thread_data*) async->os_specific;
                    385:     int done;
                    386: #ifdef USE_SOCKETPAIR
                    387:     curl_socket_t sock_rd = td->tsd.sock_pair[0];
                    388:     struct connectdata *conn = td->tsd.conn;
                    389: #endif
                    390: 
                    391:     /*
                    392:      * if the thread is still blocking in the resolve syscall, detach it and
                    393:      * let the thread do the cleanup...
                    394:      */
                    395:     Curl_mutex_acquire(td->tsd.mtx);
                    396:     done = td->tsd.done;
                    397:     td->tsd.done = 1;
                    398:     Curl_mutex_release(td->tsd.mtx);
                    399: 
                    400:     if(!done) {
                    401:       Curl_thread_destroy(td->thread_hnd);
                    402:     }
                    403:     else {
                    404:       if(td->thread_hnd != curl_thread_t_null)
                    405:         Curl_thread_join(&td->thread_hnd);
                    406: 
                    407:       destroy_thread_sync_data(&td->tsd);
                    408: 
                    409:       free(async->os_specific);
                    410:     }
                    411: #ifdef USE_SOCKETPAIR
                    412:     /*
                    413:      * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
                    414:      * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
                    415:      */
                    416:     if(conn)
                    417:       Curl_multi_closed(conn->data, sock_rd);
                    418:     sclose(sock_rd);
                    419: #endif
                    420:   }
                    421:   async->os_specific = NULL;
                    422: 
                    423:   free(async->hostname);
                    424:   async->hostname = NULL;
                    425: }
                    426: 
                    427: /*
                    428:  * init_resolve_thread() starts a new thread that performs the actual
                    429:  * resolve. This function returns before the resolve is done.
                    430:  *
                    431:  * Returns FALSE in case of failure, otherwise TRUE.
                    432:  */
                    433: static bool init_resolve_thread(struct connectdata *conn,
                    434:                                 const char *hostname, int port,
                    435:                                 const struct addrinfo *hints)
                    436: {
                    437:   struct thread_data *td = calloc(1, sizeof(struct thread_data));
                    438:   int err = ENOMEM;
                    439: 
                    440:   conn->async.os_specific = (void *)td;
                    441:   if(!td)
                    442:     goto errno_exit;
                    443: 
                    444:   conn->async.port = port;
                    445:   conn->async.done = FALSE;
                    446:   conn->async.status = 0;
                    447:   conn->async.dns = NULL;
                    448:   td->thread_hnd = curl_thread_t_null;
                    449: 
                    450:   if(!init_thread_sync_data(td, hostname, port, hints)) {
                    451:     conn->async.os_specific = NULL;
                    452:     free(td);
                    453:     goto errno_exit;
                    454:   }
                    455: 
                    456:   free(conn->async.hostname);
                    457:   conn->async.hostname = strdup(hostname);
                    458:   if(!conn->async.hostname)
                    459:     goto err_exit;
                    460: 
                    461:   /* The thread will set this to 1 when complete. */
                    462:   td->tsd.done = 0;
                    463: 
                    464: #ifdef HAVE_GETADDRINFO
                    465:   td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
                    466: #else
                    467:   td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
                    468: #endif
                    469: 
                    470:   if(!td->thread_hnd) {
                    471:     /* The thread never started, so mark it as done here for proper cleanup. */
                    472:     td->tsd.done = 1;
                    473:     err = errno;
                    474:     goto err_exit;
                    475:   }
                    476: 
                    477:   return TRUE;
                    478: 
                    479:  err_exit:
                    480:   destroy_async_data(&conn->async);
                    481: 
                    482:  errno_exit:
                    483:   errno = err;
                    484:   return FALSE;
                    485: }
                    486: 
                    487: /*
                    488:  * resolver_error() calls failf() with the appropriate message after a resolve
                    489:  * error
                    490:  */
                    491: 
                    492: static CURLcode resolver_error(struct connectdata *conn)
                    493: {
                    494:   const char *host_or_proxy;
                    495:   CURLcode result;
                    496: 
                    497:   if(conn->bits.httpproxy) {
                    498:     host_or_proxy = "proxy";
                    499:     result = CURLE_COULDNT_RESOLVE_PROXY;
                    500:   }
                    501:   else {
                    502:     host_or_proxy = "host";
                    503:     result = CURLE_COULDNT_RESOLVE_HOST;
                    504:   }
                    505: 
                    506:   failf(conn->data, "Could not resolve %s: %s", host_or_proxy,
                    507:         conn->async.hostname);
                    508: 
                    509:   return result;
                    510: }
                    511: 
                    512: static CURLcode thread_wait_resolv(struct connectdata *conn,
                    513:                                    struct Curl_dns_entry **entry,
                    514:                                    bool report)
                    515: {
                    516:   struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
                    517:   CURLcode result = CURLE_OK;
                    518: 
                    519:   DEBUGASSERT(conn && td);
                    520:   DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
                    521: 
                    522:   /* wait for the thread to resolve the name */
                    523:   if(Curl_thread_join(&td->thread_hnd)) {
                    524:     if(entry)
                    525:       result = getaddrinfo_complete(conn);
                    526:   }
                    527:   else
                    528:     DEBUGASSERT(0);
                    529: 
                    530:   conn->async.done = TRUE;
                    531: 
                    532:   if(entry)
                    533:     *entry = conn->async.dns;
                    534: 
                    535:   if(!conn->async.dns && report)
                    536:     /* a name was not resolved, report error */
                    537:     result = resolver_error(conn);
                    538: 
                    539:   destroy_async_data(&conn->async);
                    540: 
                    541:   if(!conn->async.dns && report)
                    542:     connclose(conn, "asynch resolve failed");
                    543: 
                    544:   return result;
                    545: }
                    546: 
                    547: 
                    548: /*
                    549:  * Until we gain a way to signal the resolver threads to stop early, we must
                    550:  * simply wait for them and ignore their results.
                    551:  */
                    552: void Curl_resolver_kill(struct connectdata *conn)
                    553: {
                    554:   struct thread_data *td = (struct thread_data*) conn->async.os_specific;
                    555: 
                    556:   /* If we're still resolving, we must wait for the threads to fully clean up,
                    557:      unfortunately.  Otherwise, we can simply cancel to clean up any resolver
                    558:      data. */
                    559:   if(td && td->thread_hnd != curl_thread_t_null)
                    560:     (void)thread_wait_resolv(conn, NULL, FALSE);
                    561:   else
                    562:     Curl_resolver_cancel(conn);
                    563: }
                    564: 
                    565: /*
                    566:  * Curl_resolver_wait_resolv()
                    567:  *
                    568:  * Waits for a resolve to finish. This function should be avoided since using
                    569:  * this risk getting the multi interface to "hang".
                    570:  *
                    571:  * If 'entry' is non-NULL, make it point to the resolved dns entry
                    572:  *
                    573:  * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
                    574:  * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
                    575:  *
                    576:  * This is the version for resolves-in-a-thread.
                    577:  */
                    578: CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
                    579:                                    struct Curl_dns_entry **entry)
                    580: {
                    581:   return thread_wait_resolv(conn, entry, TRUE);
                    582: }
                    583: 
                    584: /*
                    585:  * Curl_resolver_is_resolved() is called repeatedly to check if a previous
                    586:  * name resolve request has completed. It should also make sure to time-out if
                    587:  * the operation seems to take too long.
                    588:  */
                    589: CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
                    590:                                    struct Curl_dns_entry **entry)
                    591: {
                    592:   struct Curl_easy *data = conn->data;
                    593:   struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
                    594:   int done = 0;
                    595: 
                    596:   *entry = NULL;
                    597: 
                    598:   if(!td) {
                    599:     DEBUGASSERT(td);
                    600:     return CURLE_COULDNT_RESOLVE_HOST;
                    601:   }
                    602: 
                    603:   Curl_mutex_acquire(td->tsd.mtx);
                    604:   done = td->tsd.done;
                    605:   Curl_mutex_release(td->tsd.mtx);
                    606: 
                    607:   if(done) {
                    608:     getaddrinfo_complete(conn);
                    609: 
                    610:     if(!conn->async.dns) {
                    611:       CURLcode result = resolver_error(conn);
                    612:       destroy_async_data(&conn->async);
                    613:       return result;
                    614:     }
                    615:     destroy_async_data(&conn->async);
                    616:     *entry = conn->async.dns;
                    617:   }
                    618:   else {
                    619:     /* poll for name lookup done with exponential backoff up to 250ms */
                    620:     /* should be fine even if this converts to 32 bit */
                    621:     time_t elapsed = (time_t)Curl_timediff(Curl_now(),
                    622:                                            data->progress.t_startsingle);
                    623:     if(elapsed < 0)
                    624:       elapsed = 0;
                    625: 
                    626:     if(td->poll_interval == 0)
                    627:       /* Start at 1ms poll interval */
                    628:       td->poll_interval = 1;
                    629:     else if(elapsed >= td->interval_end)
                    630:       /* Back-off exponentially if last interval expired  */
                    631:       td->poll_interval *= 2;
                    632: 
                    633:     if(td->poll_interval > 250)
                    634:       td->poll_interval = 250;
                    635: 
                    636:     td->interval_end = elapsed + td->poll_interval;
                    637:     Curl_expire(conn->data, td->poll_interval, EXPIRE_ASYNC_NAME);
                    638:   }
                    639: 
                    640:   return CURLE_OK;
                    641: }
                    642: 
                    643: int Curl_resolver_getsock(struct connectdata *conn,
                    644:                           curl_socket_t *socks)
                    645: {
                    646:   int ret_val = 0;
                    647:   time_t milli;
                    648:   timediff_t ms;
                    649:   struct Curl_easy *data = conn->data;
                    650:   struct resdata *reslv = (struct resdata *)data->state.resolver;
                    651: #ifdef USE_SOCKETPAIR
                    652:   struct thread_data *td = (struct thread_data*)conn->async.os_specific;
                    653: #else
                    654:   (void)socks;
                    655: #endif
                    656: 
                    657: #ifdef USE_SOCKETPAIR
                    658:   if(td) {
                    659:     /* return read fd to client for polling the DNS resolution status */
                    660:     socks[0] = td->tsd.sock_pair[0];
                    661:     DEBUGASSERT(td->tsd.conn == conn || !td->tsd.conn);
                    662:     td->tsd.conn = conn;
                    663:     ret_val = GETSOCK_READSOCK(0);
                    664:   }
                    665:   else {
                    666: #endif
                    667:     ms = Curl_timediff(Curl_now(), reslv->start);
                    668:     if(ms < 3)
                    669:       milli = 0;
                    670:     else if(ms <= 50)
                    671:       milli = (time_t)ms/3;
                    672:     else if(ms <= 250)
                    673:       milli = 50;
                    674:     else
                    675:       milli = 200;
                    676:     Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
                    677: #ifdef USE_SOCKETPAIR
                    678:   }
                    679: #endif
                    680: 
                    681: 
                    682:   return ret_val;
                    683: }
                    684: 
                    685: #ifndef HAVE_GETADDRINFO
                    686: /*
                    687:  * Curl_getaddrinfo() - for platforms without getaddrinfo
                    688:  */
                    689: Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
                    690:                                          const char *hostname,
                    691:                                          int port,
                    692:                                          int *waitp)
                    693: {
                    694:   struct Curl_easy *data = conn->data;
                    695:   struct resdata *reslv = (struct resdata *)data->state.resolver;
                    696: 
                    697:   *waitp = 0; /* default to synchronous response */
                    698: 
                    699:   reslv->start = Curl_now();
                    700: 
                    701:   /* fire up a new resolver thread! */
                    702:   if(init_resolve_thread(conn, hostname, port, NULL)) {
                    703:     *waitp = 1; /* expect asynchronous response */
                    704:     return NULL;
                    705:   }
                    706: 
                    707:   failf(conn->data, "getaddrinfo() thread failed\n");
                    708: 
                    709:   return NULL;
                    710: }
                    711: 
                    712: #else /* !HAVE_GETADDRINFO */
                    713: 
                    714: /*
                    715:  * Curl_resolver_getaddrinfo() - for getaddrinfo
                    716:  */
                    717: Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
                    718:                                          const char *hostname,
                    719:                                          int port,
                    720:                                          int *waitp)
                    721: {
                    722:   struct addrinfo hints;
                    723:   int pf = PF_INET;
                    724:   struct Curl_easy *data = conn->data;
                    725:   struct resdata *reslv = (struct resdata *)data->state.resolver;
                    726: 
                    727:   *waitp = 0; /* default to synchronous response */
                    728: 
                    729: #ifdef CURLRES_IPV6
                    730:   /*
                    731:    * Check if a limited name resolve has been requested.
                    732:    */
                    733:   switch(conn->ip_version) {
                    734:   case CURL_IPRESOLVE_V4:
                    735:     pf = PF_INET;
                    736:     break;
                    737:   case CURL_IPRESOLVE_V6:
                    738:     pf = PF_INET6;
                    739:     break;
                    740:   default:
                    741:     pf = PF_UNSPEC;
                    742:     break;
                    743:   }
                    744: 
                    745:   if((pf != PF_INET) && !Curl_ipv6works(conn))
                    746:     /* The stack seems to be a non-IPv6 one */
                    747:     pf = PF_INET;
                    748: #endif /* CURLRES_IPV6 */
                    749: 
                    750:   memset(&hints, 0, sizeof(hints));
                    751:   hints.ai_family = pf;
                    752:   hints.ai_socktype = (conn->transport == TRNSPRT_TCP)?
                    753:     SOCK_STREAM : SOCK_DGRAM;
                    754: 
                    755:   reslv->start = Curl_now();
                    756:   /* fire up a new resolver thread! */
                    757:   if(init_resolve_thread(conn, hostname, port, &hints)) {
                    758:     *waitp = 1; /* expect asynchronous response */
                    759:     return NULL;
                    760:   }
                    761: 
                    762:   failf(data, "getaddrinfo() thread failed to start\n");
                    763:   return NULL;
                    764: 
                    765: }
                    766: 
                    767: #endif /* !HAVE_GETADDRINFO */
                    768: 
                    769: CURLcode Curl_set_dns_servers(struct Curl_easy *data,
                    770:                               char *servers)
                    771: {
                    772:   (void)data;
                    773:   (void)servers;
                    774:   return CURLE_NOT_BUILT_IN;
                    775: 
                    776: }
                    777: 
                    778: CURLcode Curl_set_dns_interface(struct Curl_easy *data,
                    779:                                 const char *interf)
                    780: {
                    781:   (void)data;
                    782:   (void)interf;
                    783:   return CURLE_NOT_BUILT_IN;
                    784: }
                    785: 
                    786: CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
                    787:                                 const char *local_ip4)
                    788: {
                    789:   (void)data;
                    790:   (void)local_ip4;
                    791:   return CURLE_NOT_BUILT_IN;
                    792: }
                    793: 
                    794: CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
                    795:                                 const char *local_ip6)
                    796: {
                    797:   (void)data;
                    798:   (void)local_ip6;
                    799:   return CURLE_NOT_BUILT_IN;
                    800: }
                    801: 
                    802: #endif /* CURLRES_THREADED */

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