Annotation of embedaddon/curl/lib/asyn-thread.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: #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>