/* * gethostbyname_thread() resolves a name and then exits. */ static unsigned int CURL_STDCALL gethostbyname_thread (void *arg) { struct thread_sync_data *tsd = (struct thread_sync_data *)arg; struct thread_data *td = tsd->td; tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port); if(!tsd->res) { tsd->sock_error = SOCKERRNO; if(tsd->sock_error == 0) tsd->sock_error = RESOLVER_ENOMEM; } Curl_mutex_acquire(tsd->mtx); if(tsd->done) { /* too late, gotta clean up the mess */ Curl_mutex_release(tsd->mtx); destroy_thread_sync_data(tsd); free(td); } else { tsd->done = 1; Curl_mutex_release(tsd->mtx); } return 0; }
/* * getaddrinfo_thread() resolves a name and then exits. * * For builds without ARES, but with ENABLE_IPV6, create a resolver thread * and wait on it. */ static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg) { struct thread_sync_data *tsd = (struct thread_sync_data*)arg; struct thread_data *td = tsd->td; char service[12]; int rc; snprintf(service, sizeof(service), "%d", tsd->port); rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res); if(rc != 0) { tsd->sock_error = SOCKERRNO?SOCKERRNO:rc; if(tsd->sock_error == 0) tsd->sock_error = RESOLVER_ENOMEM; } else { Curl_addrinfo_set_port(tsd->res, tsd->port); } Curl_mutex_acquire(tsd->mtx); if(tsd->done) { /* too late, gotta clean up the mess */ Curl_mutex_release(tsd->mtx); destroy_thread_sync_data(tsd); free(td); } else { tsd->done = 1; Curl_mutex_release(tsd->mtx); } return 0; }
/* * destroy_async_data() cleans up async resolver data and thread handle. */ static void destroy_async_data (struct Curl_async *async) { if(async->os_specific) { struct thread_data *td = (struct thread_data*) async->os_specific; int done; /* * if the thread is still blocking in the resolve syscall, detach it and * let the thread do the cleanup... */ Curl_mutex_acquire(td->tsd.mtx); done = td->tsd.done; td->tsd.done = 1; Curl_mutex_release(td->tsd.mtx); if(!done) { Curl_thread_destroy(td->thread_hnd); } else { if(td->thread_hnd != curl_thread_t_null) Curl_thread_join(&td->thread_hnd); destroy_thread_sync_data(&td->tsd); free(async->os_specific); } } async->os_specific = NULL; free(async->hostname); async->hostname = NULL; }
/* * Curl_is_resolved() is called repeatedly to check if a previous name resolve * request has completed. It should also make sure to time-out if the * operation seems to take too long. */ CURLcode Curl_is_resolved(struct connectdata *conn, struct Curl_dns_entry **entry) { struct SessionHandle *data = conn->data; struct thread_data *td = (struct thread_data*) conn->async.os_specific; int done = 0; *entry = NULL; if (!td) { DEBUGASSERT(td); return CURLE_COULDNT_RESOLVE_HOST; } Curl_mutex_acquire(td->tsd.mtx); done = td->tsd.done; Curl_mutex_release(td->tsd.mtx); if (done) { getaddrinfo_complete(conn); if (td->poll_interval != 0) Curl_expire(conn->data, 0); Curl_destroy_thread_data(&conn->async); if(!conn->async.dns) { failf(data, "Could not resolve host: %s; %s", conn->host.name, Curl_strerror(conn, conn->async.status)); return CURLE_COULDNT_RESOLVE_HOST; } *entry = conn->async.dns; } else { /* poll for name lookup done with exponential backoff up to 250ms */ int elapsed; elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); if (elapsed < 0) { elapsed = 0; } if (td->poll_interval == 0) { /* Start at 1ms poll interval */ td->poll_interval = 1; } else if (elapsed >= td->interval_end) { /* Back-off exponentially if last interval expired */ td->poll_interval *= 2; } if (td->poll_interval > 250) td->poll_interval = 250; td->interval_end = elapsed + td->poll_interval; Curl_expire(conn->data, td->poll_interval); } return CURLE_OK; }
/* * Curl_resolver_is_resolved() is called repeatedly to check if a previous * name resolve request has completed. It should also make sure to time-out if * the operation seems to take too long. */ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, struct Curl_dns_entry **entry) { struct Curl_easy *data = conn->data; struct thread_data *td = (struct thread_data*) conn->async.os_specific; int done = 0; *entry = NULL; if(!td) { DEBUGASSERT(td); return CURLE_COULDNT_RESOLVE_HOST; } Curl_mutex_acquire(td->tsd.mtx); done = td->tsd.done; Curl_mutex_release(td->tsd.mtx); if(done) { getaddrinfo_complete(conn); if(!conn->async.dns) { CURLcode result = resolver_error(conn); destroy_async_data(&conn->async); return result; } destroy_async_data(&conn->async); *entry = conn->async.dns; } else { /* poll for name lookup done with exponential backoff up to 250ms */ timediff_t elapsed = Curl_timediff(Curl_now(), data->progress.t_startsingle); if(elapsed < 0) elapsed = 0; if(td->poll_interval == 0) /* Start at 1ms poll interval */ td->poll_interval = 1; else if(elapsed >= td->interval_end) /* Back-off exponentially if last interval expired */ td->poll_interval *= 2; if(td->poll_interval > 250) td->poll_interval = 250; td->interval_end = elapsed + td->poll_interval; Curl_expire(conn->data, td->poll_interval, EXPIRE_ASYNC_NAME); } return CURLE_OK; }
/* * gethostbyname_thread() resolves a name and then exits. */ static unsigned int CURL_STDCALL gethostbyname_thread (void *arg) { struct thread_sync_data *tsd = (struct thread_sync_data *)arg; tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port); if(!tsd->res) { tsd->sock_error = SOCKERRNO; if(tsd->sock_error == 0) tsd->sock_error = RESOLVER_ENOMEM; } Curl_mutex_acquire(tsd->mtx); tsd->done = 1; Curl_mutex_release(tsd->mtx); return 0; }
/* * getaddrinfo_thread() resolves a name and then exits. * * For builds without ARES, but with ENABLE_IPV6, create a resolver thread * and wait on it. */ static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg) { struct thread_sync_data *tsd = (struct thread_sync_data*)arg; char service [NI_MAXSERV]; int rc; snprintf(service, sizeof(service), "%d", tsd->port); rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res); if(rc != 0) { tsd->sock_error = SOCKERRNO?SOCKERRNO:rc; if(tsd->sock_error == 0) tsd->sock_error = RESOLVER_ENOMEM; } Curl_mutex_acquire(tsd->mtx); tsd->done = 1; Curl_mutex_release(tsd->mtx); return 0; }