31 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
34 #ifdef HAVE_SYS_TYPES_H
35 #include <sys/types.h>
37 #ifdef HAVE_SYS_SOCKET_H
38 #include <sys/socket.h>
40 #ifdef HAVE_NETINET_IN_H
41 #include <netinet/in.h>
46 #ifdef HAVE_ARPA_INET_H
47 #include <arpa/inet.h>
63 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
65 #define in_addr_t unsigned long
75 #define _MPRINTF_REPLACE
78 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
88 #define ARES_SUCCESS CURLE_OK
92 static int host_cache_initialized;
99 #if !defined(HAVE_GETHOSTBYNAME_R) || defined(USE_ARES) || \
100 defined(USE_THREADING_GETHOSTBYNAME)
101 static struct hostent* pack_hostent(
char** buf,
struct hostent* orig);
105 #ifdef USE_THREADING_GETHOSTBYNAME
106 #ifdef DEBUG_THREADING_GETHOSTBYNAME
108 #define TRACE(args) \
109 do { trace_it("%u: ", __LINE__); trace_it args; } while (0)
111 static void trace_it (
const char *fmt, ...);
116 static struct hostent* pack_hostent (
char** buf,
struct hostent* orig);
117 static bool init_gethostbyname_thread (
struct connectdata *conn,
118 const char *hostname,
int port);
128 if (!host_cache_initialized) {
130 host_cache_initialized = 1;
136 return &hostname_cache;
141 if (host_cache_initialized) {
143 host_cache_initialized = 0;
148 static int _num_chars(
int i)
170 create_hostcache_id(
char *server,
int port,
size_t *entry_len)
175 *entry_len = strlen(server) +
180 id = malloc(*entry_len + 1);
185 sprintf(
id,
"%s:%d", server, port);
196 hostcache_timestamp_remove(
void *datap,
void *hc)
213 hostcache_prune(
curl_hash *hostcache,
int cache_timeout, time_t now)
222 hostcache_timestamp_remove);
247 #ifdef HAVE_SIGSETJMP
249 sigjmp_buf curl_jmpenv;
269 entry_id = create_hostcache_id(hostname, port, &entry_len);
320 char *entry_id =
NULL;
331 #ifdef HAVE_SIGSETJMP
336 failf(data,
"name lookup timed out");
342 entry_id = create_hostcache_id(hostname, port, &entry_len);
365 Curl_addrinfo *addr = my_getaddrinfo(conn, hostname, port, &wait);
386 dns = cache_resolv_response(data, addr, hostname, port);
417 infof(data,
"Interal host cache screw-up!");
459 #define CURL_NAMELOOKUP_SIZE 9000
465 fd_set *write_fd_set,
470 read_fd_set, write_fd_set);
480 fd_set read_fds, write_fds;
481 static const struct timeval tv={0,0};
488 nfds = ares_fds(data->
state.areschannel, &read_fds, &write_fds);
490 count =
select(nfds, &read_fds, &write_fds,
NULL,
494 ares_process(data->
state.areschannel, &read_fds, &write_fds);
498 if(conn->async.done) {
502 *dns = conn->async.dns;
522 bool timedout =
FALSE;
536 fd_set read_fds, write_fds;
537 struct timeval *tvp, tv, store;
545 nfds = ares_fds(data->
state.areschannel, &read_fds, &write_fds);
548 tvp = ares_timeout(data->
state.areschannel,
550 count =
select(nfds, &read_fds, &write_fds,
NULL, tvp);
551 if (count < 0 && errno != EINVAL)
558 ares_process(data->
state.areschannel, &read_fds, &write_fds);
567 *entry = conn->async.dns;
569 if(!conn->async.dns) {
571 if(timedout || (conn->async.status == ARES_ETIMEOUT)) {
572 failf(data,
"Resolving host timed out: %s", conn->
name);
575 else if(conn->async.done) {
576 failf(data,
"Could not resolve host: %s (%s)", conn->
name,
577 ares_strerror(conn->async.status));
592 #if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME)
596 static void host_callback(
void *arg,
598 struct hostent *hostent)
603 conn->async.done =
TRUE;
604 conn->async.status = status;
612 struct hostent *he = pack_hostent(&bufp, hostent);
619 dns = cache_resolv_response(data, he,
627 conn->async.dns = dns;
656 conn->async.
port = port;
657 conn->async.done =
FALSE;
658 conn->async.status = 0;
659 conn->async.dns =
NULL;
662 ares_gethostbyname(data->
state.areschannel, hostname, PF_INET,
663 host_callback, conn);
671 #if !defined(USE_ARES) && !defined(USE_THREADING_GETHOSTBYNAME)
694 #if !defined(USE_ARES)
697 fd_set *write_fd_set,
708 #if defined(ENABLE_IPV6) && !defined(USE_ARES)
716 int curl_getaddrinfo(
char *hostname,
char *service,
717 struct addrinfo *hints,
719 int line,
const char *
source)
721 int res=(getaddrinfo)(hostname, service, hints, result);
725 fprintf(logfile,
"ADDR %s:%d getaddrinfo() = %p\n",
726 source, line, (
void *)*result);
730 fprintf(logfile,
"ADDR %s:%d getaddrinfo() failed\n",
736 void curl_freeaddrinfo(
struct addrinfo *freethis,
737 int line,
const char *source)
739 (freeaddrinfo)(freethis);
741 fprintf(logfile,
"ADDR %s:%d freeaddrinfo(%p)\n",
742 source, line, (
void *)freethis);
758 struct addrinfo hints, *
res;
760 char sbuf[NI_MAXSERV];
767 s = socket(PF_INET6, SOCK_DGRAM, 0);
795 memset(&hints, 0,
sizeof(hints));
796 hints.ai_family = pf;
797 hints.ai_socktype = SOCK_STREAM;
798 hints.ai_flags = AI_CANONNAME;
799 snprintf(sbuf,
sizeof(sbuf),
"%d", port);
800 error = getaddrinfo(hostname, sbuf, &hints, &res);
802 infof(data,
"getaddrinfo(3) failed for %s:%d\n", hostname, port);
810 #if !defined(HAVE_GETHOSTBYNAME_R) || defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME)
811 static void hostcache_fixoffset(
struct hostent *h,
long offset);
816 static struct hostent* pack_hostent(
char** buf,
struct hostent* orig)
820 struct hostent* copy;
827 copy = (
struct hostent*)bufptr;
829 bufptr +=
sizeof(
struct hostent);
830 copy->h_name = bufptr;
831 len = strlen(orig->h_name) + 1;
832 strncpy(bufptr, orig->h_name, len);
836 #define MEMALIGN(x) ((x)+(8-(((unsigned long)(x))&0x7)))
841 copy->h_aliases = (
char**)bufptr;
844 for (i = 0; orig->h_aliases && orig->h_aliases[
i]; ++
i);
847 bufptr += (i + 1) *
sizeof(
char*);
850 if(orig->h_aliases) {
851 for(i = 0; (str = orig->h_aliases[
i]); i++) {
852 len = strlen(str) + 1;
853 strncpy(bufptr, str, len);
854 copy->h_aliases[
i] = bufptr;
861 copy->h_aliases[
i] =
NULL;
863 copy->h_addrtype = orig->h_addrtype;
864 copy->h_length = orig->h_length;
869 copy->h_addr_list = (
char**)bufptr;
872 for (i = 0; orig->h_addr_list[
i] !=
NULL; ++
i);
875 bufptr += (i + 1) *
sizeof(
char*);
878 len = orig->h_length;
879 str = orig->h_addr_list[
i];
880 while (str !=
NULL) {
881 memcpy(bufptr, str, len);
882 copy->h_addr_list[
i] = bufptr;
884 str = orig->h_addr_list[++
i];
886 copy->h_addr_list[
i] =
NULL;
890 newbuf=(
char *)realloc(*buf, (
long)bufptr-(long)(*buf));
894 hostcache_fixoffset((
struct hostent*)newbuf, (
long)newbuf-(
long)*buf);
898 copy = (
struct hostent*)newbuf;
904 static void hostcache_fixoffset(
struct hostent *h,
long offset)
908 h->h_name=(
char *)((
long)h->h_name+
offset);
911 h->h_aliases=(
char **)((
long)h->h_aliases+
offset);
912 while(h->h_aliases[i]) {
913 h->h_aliases[
i]=(
char *)((
long)h->h_aliases[
i]+
offset);
918 h->h_addr_list=(
char **)((
long)h->h_addr_list+
offset);
920 while(h->h_addr_list[i]) {
921 h->h_addr_list[
i]=(
char *)((
long)h->h_addr_list[
i]+
offset);
928 static char *MakeIP(
unsigned long num,
char *addr,
int addr_len)
930 #if defined(HAVE_INET_NTOA) || defined(HAVE_INET_NTOA_R)
932 in.s_addr = htonl(num);
934 #if defined(HAVE_INET_NTOA_R)
940 unsigned char *paddr;
943 paddr = (
unsigned char *)#
944 sprintf(addr,
"%u.%u.%u.%u", paddr[0], paddr[1], paddr[2], paddr[3]);
957 struct hostent *h =
NULL;
964 in=inet_addr(hostname);
966 struct in_addr *addrentry;
968 struct hostent hostentry;
969 char *h_addr_list[2];
970 struct in_addr addrentry;
972 } *buf = (
struct namebuf *)malloc(
sizeof(
struct namebuf));
977 h->h_addr_list = &buf->h_addr_list[0];
978 addrentry = &buf->addrentry;
979 addrentry->s_addr =
in;
980 h->h_addr_list[0] = (
char*)addrentry;
981 h->h_addr_list[1] =
NULL;
982 h->h_addrtype = AF_INET;
983 h->h_length =
sizeof(*addrentry);
984 h->h_name = &buf->h_name[0];
985 MakeIP(ntohl(in), (
char *)h->h_name,
sizeof(buf->h_name));
987 #if defined(HAVE_GETHOSTBYNAME_R)
999 #ifdef HAVE_GETHOSTBYNAME_R_5
1003 h = gethostbyname_r(hostname,
1004 (
struct hostent *)buf,
1005 (
char *)buf +
sizeof(
struct hostent),
1006 step_size -
sizeof(
struct hostent),
1014 if(h || (errno != ERANGE))
1021 infof(data,
"gethostbyname_r() uses %d bytes\n", step_size);
1026 h=(
struct hostent *)realloc(buf, step_size);
1027 offset=(long)h-(
long)buf;
1028 hostcache_fixoffset(h, offset);
1033 #ifdef HAVE_GETHOSTBYNAME_R_6
1036 res=gethostbyname_r(hostname,
1037 (
struct hostent *)buf,
1038 (
char *)buf +
sizeof(
struct hostent),
1039 step_size -
sizeof(
struct hostent),
1074 if(((ERANGE == res) || (EAGAIN == res)) ||
1075 ((res<0) && ((ERANGE == errno) || (EAGAIN == errno))))
1085 infof(data,
"gethostbyname_r() uses %d bytes\n", step_size);
1089 h=(
struct hostent *)realloc(buf, step_size);
1090 offset=(long)h-(
long)buf;
1091 hostcache_fixoffset(h, offset);
1096 #ifdef HAVE_GETHOSTBYNAME_R_3
1113 (
sizeof(
struct hostent)+
sizeof(
struct hostent_data))) {
1119 res = gethostbyname_r(hostname,
1120 (
struct hostent *)buf,
1121 (
struct hostent_data *)((
char *)buf +
1122 sizeof(
struct hostent)));
1130 h = (
struct hostent*)buf;
1143 infof(data,
"gethostbyname_r(2) failed for %s\n", hostname);
1150 #ifdef USE_THREADING_GETHOSTBYNAME
1151 if (init_gethostbyname_thread(conn,hostname,port)) {
1155 infof(data,
"init_gethostbyname_thread() failed for %s; code %lu\n",
1156 hostname, GetLastError());
1158 h = gethostbyname(hostname);
1160 infof(data,
"gethostbyname(2) failed for %s\n", hostname);
1166 h = pack_hostent(&buf, h);
1179 #if defined(USE_THREADING_GETHOSTBYNAME)
1180 #ifdef DEBUG_THREADING_GETHOSTBYNAME
1181 static void trace_it (
const char *fmt, ...)
1183 static int do_trace = -1;
1187 do_trace = getenv(
"CURL_TRACE") ? 1 : 0;
1190 va_start (args, fmt);
1191 vfprintf (stderr, fmt, args);
1199 static DWORD WINAPI gethostbyname_thread (
void *arg)
1205 WSASetLastError (conn->async.status = NO_DATA);
1206 he = gethostbyname (conn->async.
hostname);
1212 host_callback(conn, (
int)WSAGetLastError(),
NULL);
1215 TRACE((
"Winsock-error %d, addr %s\n", conn->async.status,
1216 he ?
inet_ntoa(*(
struct in_addr*)he->h_addr) :
"unknown"));
1223 static void destroy_thread_data (
struct connectdata *conn)
1227 if (conn->async.os_specific)
1228 free(conn->async.os_specific);
1230 conn->async.os_specific =
NULL;
1233 static bool init_gethostbyname_thread (
struct connectdata *conn,
1234 const char *hostname,
int port)
1236 struct thread_data *td = malloc(
sizeof(*td));
1239 SetLastError(ENOMEM);
1243 memset (td, 0,
sizeof(*td));
1248 SetLastError(ENOMEM);
1252 conn->async.
port = port;
1253 conn->async.done =
FALSE;
1254 conn->async.status = 0;
1255 conn->async.dns =
NULL;
1256 conn->async.os_specific = (
void*) td;
1258 td->thread_hnd = CreateThread(
NULL, 0, gethostbyname_thread,
1259 conn, 0, &td->thread_id);
1260 if (!td->thread_hnd) {
1261 TRACE((
"CreateThread() failed; %lu\n", GetLastError()));
1262 destroy_thread_data(conn);
1272 struct thread_data *td = (
struct thread_data*) conn->async.os_specific;
1275 DWORD status, ticks;
1285 ticks = GetTickCount();
1287 status = WaitForSingleObject(td->thread_hnd, 1000UL*timeout);
1288 if (status == WAIT_OBJECT_0 || status == WAIT_ABANDONED) {
1290 WSASetLastError(conn->async.status);
1291 GetExitCodeThread(td->thread_hnd, &td->thread_status);
1292 TRACE((
"status %lu, thread-status %08lX\n", status, td->thread_status));
1295 conn->async.done =
TRUE;
1296 TerminateThread(td->thread_hnd, (
DWORD)-1);
1297 td->thread_status = (
DWORD)-1;
1300 TRACE((
"gethostbyname_thread() retval %08lX, elapsed %lu ms\n",
1301 td->thread_status, GetTickCount()-ticks));
1304 *entry = conn->async.dns;
1308 if (!conn->async.dns) {
1310 if (td->thread_status == (
DWORD)-1 || conn->async.status == NO_DATA) {
1311 failf(data,
"Resolving host timed out: %s", conn->
name);
1314 else if(conn->async.done) {
1315 failf(data,
"Could not resolve host: %s (code %lu)", conn->
name, conn->async.status);
1321 destroy_thread_data(conn);
1334 if (conn->async.done) {
1336 destroy_thread_data(conn);
1337 if (!conn->async.dns) {
1338 TRACE((
"Curl_is_resolved(): CURLE_COULDNT_RESOLVE_HOST\n"));
1341 *entry = conn->async.dns;
1342 TRACE((
"resolved okay, dns %p\n", *entry));
1345 TRACE((
"not yet\n"));
#define CURL_IPRESOLVE_V6
void * Curl_hash_pick(curl_hash *h, char *key, size_t key_len)
int Curl_resolv(struct connectdata *conn, char *hostname, int port, struct Curl_dns_entry **entry)
typedef HANDLE(WINAPI *PFNWGLCREATEBUFFERREGIONARBPROC)(HDC hDC
#define CURL_IPRESOLVE_V4
#define CURL_NAMELOOKUP_SIZE
void Curl_global_host_cache_init(void)
GLsizei GLsizei GLcharARB * source
char * inet_ntoa_r(const struct in_addr in, char *buffer, int buflen)
GLuint GLuint GLsizei count
CURLcode Curl_multi_ares_fdset(struct connectdata *conn, fd_set *read_fd_set, fd_set *write_fd_set, int *max_fdp)
void Curl_global_host_cache_dtor(void)
void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
void Curl_hash_clean(curl_hash *h)
curl_hash * Curl_global_host_cache_get(void)
void Curl_freeaddrinfo(Curl_addrinfo *p)
void Curl_hash_clean_with_criterium(curl_hash *h, void *user, int(*comp)(void *, void *))
GLsizei GLsizei GLenum GLenum const GLvoid * data
void Curl_freednsinfo(void *freethis)
int Curl_hash_init(curl_hash *h, int slots, curl_hash_dtor dtor)
struct Curl_share * share
long Curl_tvdiff(struct timeval newer, struct timeval older)
GLenum const GLvoid * addr
struct SessionHandle * data
CURLcode Curl_disconnect(struct connectdata *conn)
CURLcode Curl_wait_for_resolv(struct connectdata *conn, struct Curl_dns_entry **entry)
void Curl_hostcache_prune(struct SessionHandle *data)
void Curl_safefree(void *ptr)
CURLcode Curl_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dns)
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
struct timeval Curl_tvnow(void)
CURLSHcode Curl_share_lock(struct SessionHandle *data, curl_lock_data type, curl_lock_access accesstype)
struct hostent Curl_addrinfo
void * Curl_hash_add(curl_hash *h, char *key, size_t key_len, void *p)
CURLSHcode Curl_share_unlock(struct SessionHandle *data, curl_lock_data type)
int sprintf(idStr &string, const char *fmt,...)
#define CURLE_OPERATION_TIMEDOUT