File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / asyn-thread.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (4 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>