00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "setup.h"
00025
00026 #include <string.h>
00027
00028 #ifdef NEED_MALLOC_H
00029 #include <malloc.h>
00030 #endif
00031 #ifdef HAVE_SYS_SOCKET_H
00032 #include <sys/socket.h>
00033 #endif
00034 #ifdef HAVE_NETINET_IN_H
00035 #include <netinet/in.h>
00036 #endif
00037 #ifdef HAVE_NETDB_H
00038 #include <netdb.h>
00039 #endif
00040 #ifdef HAVE_ARPA_INET_H
00041 #include <arpa/inet.h>
00042 #endif
00043 #ifdef HAVE_STDLIB_H
00044 #include <stdlib.h>
00045 #endif
00046 #ifdef HAVE_UNISTD_H
00047 #include <unistd.h>
00048 #endif
00049 #ifdef VMS
00050 #include <in.h>
00051 #include <inet.h>
00052 #include <stdlib.h>
00053 #endif
00054
00055 #ifdef HAVE_SETJMP_H
00056 #include <setjmp.h>
00057 #endif
00058
00059 #ifdef HAVE_PROCESS_H
00060 #include <process.h>
00061 #endif
00062
00063 #include "urldata.h"
00064 #include "sendf.h"
00065 #include "hostip.h"
00066 #include "hash.h"
00067 #include "share.h"
00068 #include "strerror.h"
00069 #include "url.h"
00070 #include "inet_ntop.h"
00071
00072 #define _MPRINTF_REPLACE
00073 #include <curl/mprintf.h>
00074
00075 #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
00076 #include "inet_ntoa_r.h"
00077 #endif
00078
00079 #include "memory.h"
00080
00081 #include "memdebug.h"
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 static struct curl_hash hostname_cache;
00122 static int host_cache_initialized;
00123
00124 static void freednsentry(void *freethis);
00125
00126
00127
00128
00129
00130
00131 void Curl_global_host_cache_init(void)
00132 {
00133 if (!host_cache_initialized) {
00134 Curl_hash_init(&hostname_cache, 7, Curl_hash_str, Curl_str_key_compare,
00135 freednsentry);
00136 host_cache_initialized = 1;
00137 }
00138 }
00139
00140
00141
00142
00143 struct curl_hash *Curl_global_host_cache_get(void)
00144 {
00145 return &hostname_cache;
00146 }
00147
00148
00149
00150
00151 void Curl_global_host_cache_dtor(void)
00152 {
00153 if (host_cache_initialized) {
00154 Curl_hash_clean(&hostname_cache);
00155 host_cache_initialized = 0;
00156 }
00157 }
00158
00159
00160
00161
00162 int Curl_num_addresses(const Curl_addrinfo *addr)
00163 {
00164 int i;
00165 for (i = 0; addr; addr = addr->ai_next, i++)
00166 ;
00167 return i;
00168 }
00169
00170
00171
00172
00173
00174
00175
00176
00177 const char *Curl_printable_address(const Curl_addrinfo *ip,
00178 char *buf, size_t bufsize)
00179 {
00180 const void *ip4 = &((const struct sockaddr_in*)ip->ai_addr)->sin_addr;
00181 int af = ip->ai_family;
00182 #ifdef CURLRES_IPV6
00183 const void *ip6 = &((const struct sockaddr_in6*)ip->ai_addr)->sin6_addr;
00184 #else
00185 const void *ip6 = NULL;
00186 #endif
00187
00188 return Curl_inet_ntop(af, af == AF_INET ? ip4 : ip6, buf, bufsize);
00189 }
00190
00191
00192
00193
00194
00195 static char *
00196 create_hostcache_id(const char *server, int port)
00197 {
00198
00199 return aprintf("%s:%d", server, port);
00200 }
00201
00202 struct hostcache_prune_data {
00203 int cache_timeout;
00204 time_t now;
00205 };
00206
00207
00208
00209
00210
00211
00212
00213
00214 static int
00215 hostcache_timestamp_remove(void *datap, void *hc)
00216 {
00217 struct hostcache_prune_data *data =
00218 (struct hostcache_prune_data *) datap;
00219 struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
00220
00221 if ((data->now - c->timestamp < data->cache_timeout) ||
00222 c->inuse) {
00223
00224 return 0;
00225 }
00226
00227
00228 return 1;
00229 }
00230
00231
00232
00233
00234 static void
00235 hostcache_prune(struct curl_hash *hostcache, int cache_timeout, time_t now)
00236 {
00237 struct hostcache_prune_data user;
00238
00239 user.cache_timeout = cache_timeout;
00240 user.now = now;
00241
00242 Curl_hash_clean_with_criterium(hostcache,
00243 (void *) &user,
00244 hostcache_timestamp_remove);
00245 }
00246
00247
00248
00249
00250
00251 void Curl_hostcache_prune(struct SessionHandle *data)
00252 {
00253 time_t now;
00254
00255 if((data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
00256
00257
00258 return;
00259
00260 if(data->share)
00261 Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
00262
00263 time(&now);
00264
00265
00266 hostcache_prune(data->dns.hostcache,
00267 data->set.dns_cache_timeout,
00268 now);
00269
00270 if(data->share)
00271 Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
00272 }
00273
00274 static int
00275 remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns)
00276 {
00277 struct hostcache_prune_data user;
00278
00279 if( !dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
00280
00281
00282 return 0;
00283
00284 time(&user.now);
00285 user.cache_timeout = data->set.dns_cache_timeout;
00286
00287 if ( !hostcache_timestamp_remove(&user,dns) )
00288 return 0;
00289
00290
00291
00292
00293 if(data->share)
00294 Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
00295
00296 Curl_hash_clean_with_criterium(data->dns.hostcache,
00297 (void *) &user,
00298 hostcache_timestamp_remove);
00299
00300 if(data->share)
00301 Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
00302
00303 return 1;
00304 }
00305
00306
00307 #ifdef HAVE_SIGSETJMP
00308
00309
00310
00311 sigjmp_buf curl_jmpenv;
00312 #endif
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324 struct Curl_dns_entry *
00325 Curl_cache_addr(struct SessionHandle *data,
00326 Curl_addrinfo *addr,
00327 const char *hostname,
00328 int port)
00329 {
00330 char *entry_id;
00331 size_t entry_len;
00332 struct Curl_dns_entry *dns;
00333 struct Curl_dns_entry *dns2;
00334 time_t now;
00335
00336
00337 entry_id = create_hostcache_id(hostname, port);
00338
00339 if (!entry_id)
00340 return NULL;
00341 entry_len = strlen(entry_id);
00342
00343
00344 dns = (struct Curl_dns_entry *) calloc(sizeof(struct Curl_dns_entry), 1);
00345 if (!dns) {
00346 free(entry_id);
00347 return NULL;
00348 }
00349
00350 dns->inuse = 0;
00351 dns->addr = addr;
00352
00353
00354
00355
00356 dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1,
00357 (void *)dns);
00358 if(!dns2) {
00359
00360 free(dns);
00361 free(entry_id);
00362 return NULL;
00363 }
00364 time(&now);
00365 dns = dns2;
00366
00367 dns->timestamp = now;
00368 dns->inuse++;
00369
00370
00371 free(entry_id);
00372
00373 return dns;
00374 }
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393 int Curl_resolv(struct connectdata *conn,
00394 const char *hostname,
00395 int port,
00396 struct Curl_dns_entry **entry)
00397 {
00398 char *entry_id = NULL;
00399 struct Curl_dns_entry *dns = NULL;
00400 size_t entry_len;
00401 int wait;
00402 struct SessionHandle *data = conn->data;
00403 CURLcode result;
00404 int rc;
00405 *entry = NULL;
00406
00407 #ifdef HAVE_SIGSETJMP
00408
00409
00410 if(!data->set.no_signal) {
00411 if (sigsetjmp(curl_jmpenv, 1)) {
00412
00413 failf(data, "name lookup timed out");
00414 return CURLRESOLV_ERROR;
00415 }
00416 }
00417 #endif
00418
00419
00420 entry_id = create_hostcache_id(hostname, port);
00421
00422 if (!entry_id)
00423 return CURLRESOLV_ERROR;
00424
00425 entry_len = strlen(entry_id);
00426
00427 if(data->share)
00428 Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
00429
00430
00431 dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
00432
00433 if(data->share)
00434 Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
00435
00436
00437 free(entry_id);
00438
00439
00440
00441 if ( remove_entry_if_stale(data,dns) )
00442 dns = NULL;
00443
00444 rc = CURLRESOLV_ERROR;
00445
00446 if (!dns) {
00447
00448
00449 Curl_addrinfo *addr;
00450
00451
00452
00453 if(!Curl_ipvalid(data))
00454 return CURLRESOLV_ERROR;
00455
00456
00457
00458
00459 addr = Curl_getaddrinfo(conn, hostname, port, &wait);
00460
00461 if (!addr) {
00462 if(wait) {
00463
00464
00465
00466 result = Curl_is_resolved(conn, &dns);
00467 if(result)
00468 return CURLRESOLV_ERROR;
00469 if(dns)
00470 rc = CURLRESOLV_RESOLVED;
00471 else
00472 rc = CURLRESOLV_PENDING;
00473 }
00474 }
00475 else {
00476 if(data->share)
00477 Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
00478
00479
00480 dns = Curl_cache_addr(data, addr, hostname, port);
00481
00482 if(data->share)
00483 Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
00484
00485 if(!dns)
00486
00487 Curl_freeaddrinfo(addr);
00488 else
00489 rc = CURLRESOLV_RESOLVED;
00490 }
00491 }
00492 else {
00493 if(data->share)
00494 Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
00495 dns->inuse++;
00496 if(data->share)
00497 Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
00498 rc = CURLRESOLV_RESOLVED;
00499 }
00500
00501 *entry = dns;
00502
00503 return rc;
00504 }
00505
00506
00507
00508
00509
00510
00511 void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
00512 {
00513 DEBUGASSERT(dns && (dns->inuse>0));
00514
00515 if(data->share)
00516 Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
00517
00518 dns->inuse--;
00519
00520 if(data->share)
00521 Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
00522 }
00523
00524
00525
00526
00527 static void freednsentry(void *freethis)
00528 {
00529 struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;
00530
00531 Curl_freeaddrinfo(p->addr);
00532
00533 free(p);
00534 }
00535
00536
00537
00538
00539 struct curl_hash *Curl_mk_dnscache(void)
00540 {
00541 return Curl_hash_alloc(7, Curl_hash_str, Curl_str_key_compare, freednsentry);
00542 }
00543
00544 #ifdef CURLRES_ADDRINFO_COPY
00545
00546
00547 #define MEMALIGN(x) ((x)+(8-(((unsigned long)(x))&0x7)))
00548
00549
00550
00551
00552
00553
00554 Curl_addrinfo *Curl_addrinfo_copy(const void *org, int port)
00555 {
00556 const struct hostent *orig = org;
00557
00558 return Curl_he2ai(orig, port);
00559 }
00560 #endif
00561
00562
00563
00564
00565
00566 #if defined(CURLRES_IPV4) || defined(CURLRES_ARES)
00567
00568
00569
00570
00571 void Curl_freeaddrinfo(Curl_addrinfo *ai)
00572 {
00573 Curl_addrinfo *next;
00574
00575
00576 while(ai) {
00577 next = ai->ai_next;
00578 if(ai->ai_canonname)
00579 free(ai->ai_canonname);
00580 free(ai);
00581 ai = next;
00582 }
00583 }
00584
00585 struct namebuf {
00586 struct hostent hostentry;
00587 char *h_addr_list[2];
00588 struct in_addr addrentry;
00589 char h_name[16];
00590 };
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601 Curl_addrinfo *Curl_ip2addr(in_addr_t num, const char *hostname, int port)
00602 {
00603 Curl_addrinfo *ai;
00604
00605 #if defined(VMS) && \
00606 defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
00607 #pragma pointer_size save
00608 #pragma pointer_size short
00609 #pragma message disable PTRMISMATCH
00610 #endif
00611
00612 struct hostent *h;
00613 struct in_addr *addrentry;
00614 struct namebuf buffer;
00615 struct namebuf *buf = &buffer;
00616
00617 h = &buf->hostentry;
00618 h->h_addr_list = &buf->h_addr_list[0];
00619 addrentry = &buf->addrentry;
00620 #ifdef _CRAYC
00621
00622
00623
00624 memcpy(addrentry, &num, SIZEOF_in_addr);
00625 #else
00626 addrentry->s_addr = num;
00627 #endif
00628 h->h_addr_list[0] = (char*)addrentry;
00629 h->h_addr_list[1] = NULL;
00630 h->h_addrtype = AF_INET;
00631 h->h_length = sizeof(*addrentry);
00632 h->h_name = &buf->h_name[0];
00633 h->h_aliases = NULL;
00634
00635
00636 snprintf((char *)h->h_name, 16, "%s", hostname);
00637
00638 #if defined(VMS) && \
00639 defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
00640 #pragma pointer_size restore
00641 #pragma message enable PTRMISMATCH
00642 #endif
00643
00644 ai = Curl_he2ai(h, port);
00645
00646 return ai;
00647 }
00648 #endif
00649
00650