* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
*
***************************************************************************/
-#include "setup.h"
+#include "curl_setup.h"
-#include <string.h>
-#include <errno.h>
-
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h> /* required for free() prototypes */
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* for the close() proto */
-#endif
#ifdef __VMS
#include <in.h>
#include <inet.h>
-#include <stdlib.h>
#endif
#if defined(USE_THREADS_POSIX)
#include "inet_pton.h"
#include "inet_ntop.h"
#include "curl_threads.h"
+#include "connect.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
* URL-state specific environment ('resolver' member of the UrlState
* structure). Does nothing here.
*/
-int Curl_resolver_init(void **resolver)
+CURLcode Curl_resolver_init(void **resolver)
{
(void)resolver;
return CURLE_OK;
#ifdef HAVE_GETADDRINFO
struct addrinfo hints;
#endif
+ struct thread_data *td; /* for thread-self cleanup */
};
struct thread_data {
curl_thread_t thread_hnd;
- curl_socket_t dummy_sock;
unsigned int poll_interval;
- int interval_end;
+ long interval_end;
struct thread_sync_data tsd;
};
/* Initialize resolver thread synchronization data */
static
-int init_thread_sync_data(struct thread_sync_data * tsd,
+int init_thread_sync_data(struct thread_data * td,
const char * hostname,
int port,
const struct addrinfo *hints)
{
+ struct thread_sync_data *tsd = &td->tsd;
+
memset(tsd, 0, sizeof(*tsd));
+ tsd->td = td;
tsd->port = port;
-#ifdef CURLRES_IPV6
+#ifdef HAVE_GETADDRINFO
DEBUGASSERT(hints);
tsd->hints = *hints;
#else
static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg)
{
struct thread_sync_data *tsd = (struct thread_sync_data*)arg;
- char service [NI_MAXSERV];
+ struct thread_data *td = tsd->td;
+ char service[12];
int rc;
snprintf(service, sizeof(service), "%d", tsd->port);
}
Curl_mutex_acquire(tsd->mtx);
- tsd->done = 1;
- Curl_mutex_release(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;
}
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);
}
Curl_mutex_acquire(tsd->mtx);
- tsd->done = 1;
- Curl_mutex_release(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;
}
*/
static void destroy_async_data (struct Curl_async *async)
{
- if(async->hostname)
- free(async->hostname);
-
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);
- if(td->dummy_sock != CURL_SOCKET_BAD)
- sclose(td->dummy_sock);
+ destroy_thread_sync_data(&td->tsd);
- if(td->thread_hnd != curl_thread_t_null)
- Curl_thread_join(&td->thread_hnd);
+ free(async->os_specific);
+ }
+ }
+ async->os_specific = NULL;
- destroy_thread_sync_data(&td->tsd);
+ if(async->hostname)
+ free(async->hostname);
- free(async->os_specific);
- }
async->hostname = NULL;
- async->os_specific = NULL;
}
/*
conn->async.done = FALSE;
conn->async.status = 0;
conn->async.dns = NULL;
- td->dummy_sock = CURL_SOCKET_BAD;
td->thread_hnd = curl_thread_t_null;
- if(!init_thread_sync_data(&td->tsd, hostname, port, hints))
+ if(!init_thread_sync_data(td, hostname, port, hints))
goto err_exit;
Curl_safefree(conn->async.hostname);
if(!conn->async.hostname)
goto err_exit;
-#ifdef WIN32
- /* This socket is only to keep Curl_resolver_fdset() and select() happy;
- * should never become signalled for read since it's unbound but
- * Windows needs at least 1 socket in select().
- */
- td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
- if(td->dummy_sock == CURL_SOCKET_BAD)
- goto err_exit;
-#endif
-
#ifdef HAVE_GETADDRINFO
td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
#else
return FALSE;
}
-#if defined(HAVE_GETADDRINFO) && !defined(HAVE_GAI_STRERROR) && !defined(WIN32)
-/* NetWare has getaddrinfo but lacks gai_strerror.
- Windows has a gai_strerror but it is bad (not thread-safe) and the generic
- socket error string function can be used for this pupose. */
-static const char *gai_strerror(int ecode)
-{
- switch (ecode){
- case EAI_AGAIN:
- return "The name could not be resolved at this time";
- case EAI_BADFLAGS:
- return "The flags parameter had an invalid value";
- case EAI_FAIL:
- return "A non-recoverable error occurred when attempting to "
- "resolve the name";
- case EAI_FAMILY:
- return "The address family was not recognized";
- case EAI_MEMORY:
- return "Out of memory";
- case EAI_NONAME:
- return "The name does not resolve for the supplied parameters";
- case EAI_SERVICE:
- return "The service passed was not recognized for the "
- "specified socket type"
- case EAI_SOCKTYPE:
- return "The intended socket type was not recognized"
- case EAI_SYSTEM:
- return "A system error occurred";
- case EAI_OVERFLOW:
- return "An argument buffer overflowed";
- default:
- return "Unknown error";
-
-/* define this now as this is a private implementation of said function */
-#define HAVE_GAI_STRERROR
-}
-#endif
-
-
/*
* resolver_error() calls failf() with the appropriate message after a resolve
* error
*/
-static void resolver_error(struct connectdata *conn, const char *host_or_proxy)
+static CURLcode resolver_error(struct connectdata *conn)
{
- failf(conn->data, "Could not resolve %s: %s; %s", host_or_proxy,
- conn->async.hostname,
-#ifdef HAVE_GAI_STRERROR
- /* NetWare doesn't have gai_strerror and on Windows it isn't deemed
- thread-safe */
- gai_strerror(conn->async.status)
-#else
- Curl_strerror(conn, conn->async.status);
-#endif
- );
+ const char *host_or_proxy;
+ CURLcode result;
+
+ if(conn->bits.httpproxy) {
+ host_or_proxy = "proxy";
+ result = CURLE_COULDNT_RESOLVE_PROXY;
+ }
+ else {
+ host_or_proxy = "host";
+ result = CURLE_COULDNT_RESOLVE_HOST;
+ }
+
+ failf(conn->data, "Could not resolve %s: %s", host_or_proxy,
+ conn->async.hostname);
+
+ return result;
}
/*
struct Curl_dns_entry **entry)
{
struct thread_data *td = (struct thread_data*) conn->async.os_specific;
- struct SessionHandle *data = conn->data;
- CURLcode rc = CURLE_OK;
+ CURLcode result = CURLE_OK;
DEBUGASSERT(conn && td);
/* wait for the thread to resolve the name */
if(Curl_thread_join(&td->thread_hnd))
- rc = getaddrinfo_complete(conn);
+ result = getaddrinfo_complete(conn);
else
DEBUGASSERT(0);
if(entry)
*entry = conn->async.dns;
- if(!conn->async.dns) {
- /* a name was not resolved */
- if(conn->bits.httpproxy) {
- resolver_error(conn, "proxy");
- rc = CURLE_COULDNT_RESOLVE_PROXY;
- }
- else {
- resolver_error(conn, "host");
- rc = CURLE_COULDNT_RESOLVE_HOST;
- }
- }
+ if(!conn->async.dns)
+ /* a name was not resolved, report error */
+ result = resolver_error(conn);
destroy_async_data(&conn->async);
if(!conn->async.dns)
- conn->bits.close = TRUE;
+ connclose(conn, "asynch resolve failed");
- return (rc);
+ return result;
}
/*
if(done) {
getaddrinfo_complete(conn);
- destroy_async_data(&conn->async);
if(!conn->async.dns) {
- resolver_error(conn, "host");
- return CURLE_COULDNT_RESOLVE_HOST;
+ 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 */
- int elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
+ long elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
if(elapsed < 0)
elapsed = 0;
curl_socket_t *socks,
int numsocks)
{
- const struct thread_data *td =
- (const struct thread_data *) conn->async.os_specific;
-
- if(td && td->dummy_sock != CURL_SOCKET_BAD) {
- if(numsocks) {
- /* return one socket waiting for readable, even though this is just
- a dummy */
- socks[0] = td->dummy_sock;
- return GETSOCK_READSOCK(0);
- }
- }
+ (void)conn;
+ (void)socks;
+ (void)numsocks;
return 0;
}
int *waitp)
{
struct addrinfo hints;
+ struct in_addr in;
Curl_addrinfo *res;
int error;
- char sbuf[NI_MAXSERV];
+ char sbuf[12];
int pf = PF_INET;
- struct SessionHandle *data = conn->data;
+#ifdef CURLRES_IPV6
+ struct in6_addr in6;
+#endif /* CURLRES_IPV6 */
*waitp = 0; /* default to synchronous response */
-#ifndef CURLRES_IPV4
+ /* First check if this is an IPv4 address string */
+ if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
+ /* This is a dotted IP address 123.123.123.123-style */
+ return Curl_ip2addr(AF_INET, &in, hostname, port);
+
+#ifdef CURLRES_IPV6
+ /* check if this is an IPv6 address string */
+ if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0)
+ /* This is an IPv6 address literal */
+ return Curl_ip2addr(AF_INET6, &in6, hostname, port);
+
/*
* Check if a limited name resolve has been requested.
*/
}
if((pf != PF_INET) && !Curl_ipv6works())
- /* the stack seems to be a non-ipv6 one */
+ /* The stack seems to be a non-IPv6 one */
pf = PF_INET;
-#endif /* !CURLRES_IPV4 */
+#endif /* CURLRES_IPV6 */
memset(&hints, 0, sizeof(hints));
hints.ai_family = pf;
}
/* fall-back to blocking version */
- infof(data, "init_resolve_thread() failed for %s; %s\n",
+ infof(conn->data, "init_resolve_thread() failed for %s; %s\n",
hostname, Curl_strerror(conn, ERRNO));
error = Curl_getaddrinfo_ex(hostname, sbuf, &hints, &res);
if(error) {
- infof(data, "getaddrinfo() failed for %s:%d; %s\n",
+ infof(conn->data, "getaddrinfo() failed for %s:%d; %s\n",
hostname, port, Curl_strerror(conn, SOCKERRNO));
return NULL;
}
#endif /* !HAVE_GETADDRINFO */
+CURLcode Curl_set_dns_servers(struct SessionHandle *data,
+ char *servers)
+{
+ (void)data;
+ (void)servers;
+ return CURLE_NOT_BUILT_IN;
+
+}
+
+CURLcode Curl_set_dns_interface(struct SessionHandle *data,
+ const char *interf)
+{
+ (void)data;
+ (void)interf;
+ return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data,
+ const char *local_ip4)
+{
+ (void)data;
+ (void)local_ip4;
+ return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data,
+ const char *local_ip6)
+{
+ (void)data;
+ (void)local_ip6;
+ return CURLE_NOT_BUILT_IN;
+}
+
#endif /* CURLRES_THREADED */