00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "curl_setup.h"
00024
00025 #ifdef HAVE_NETINET_IN_H
00026 #include <netinet/in.h>
00027 #endif
00028 #ifdef HAVE_NETDB_H
00029 #include <netdb.h>
00030 #endif
00031 #ifdef HAVE_ARPA_INET_H
00032 #include <arpa/inet.h>
00033 #endif
00034 #ifdef __VMS
00035 #include <in.h>
00036 #include <inet.h>
00037 #endif
00038
00039 #if defined(USE_THREADS_POSIX)
00040 # ifdef HAVE_PTHREAD_H
00041 # include <pthread.h>
00042 # endif
00043 #elif defined(USE_THREADS_WIN32)
00044 # ifdef HAVE_PROCESS_H
00045 # include <process.h>
00046 # endif
00047 #endif
00048
00049 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
00050 #undef in_addr_t
00051 #define in_addr_t unsigned long
00052 #endif
00053
00054 #ifdef HAVE_GETADDRINFO
00055 # define RESOLVER_ENOMEM EAI_MEMORY
00056 #else
00057 # define RESOLVER_ENOMEM ENOMEM
00058 #endif
00059
00060 #include "urldata.h"
00061 #include "sendf.h"
00062 #include "hostip.h"
00063 #include "hash.h"
00064 #include "share.h"
00065 #include "strerror.h"
00066 #include "url.h"
00067 #include "multiif.h"
00068 #include "inet_pton.h"
00069 #include "inet_ntop.h"
00070 #include "curl_threads.h"
00071 #include "connect.h"
00072
00073 #include "curl_printf.h"
00074 #include "curl_memory.h"
00075 #include "memdebug.h"
00076
00077
00078
00079
00080 #ifdef CURLRES_THREADED
00081
00082
00083
00084
00085
00086
00087 int Curl_resolver_global_init(void)
00088 {
00089 return CURLE_OK;
00090 }
00091
00092
00093
00094
00095
00096
00097 void Curl_resolver_global_cleanup(void)
00098 {
00099 }
00100
00101
00102
00103
00104
00105
00106
00107 CURLcode Curl_resolver_init(void **resolver)
00108 {
00109 (void)resolver;
00110 return CURLE_OK;
00111 }
00112
00113
00114
00115
00116
00117
00118
00119 void Curl_resolver_cleanup(void *resolver)
00120 {
00121 (void)resolver;
00122 }
00123
00124
00125
00126
00127
00128
00129
00130 int Curl_resolver_duphandle(void **to, void *from)
00131 {
00132 (void)to;
00133 (void)from;
00134 return CURLE_OK;
00135 }
00136
00137 static void destroy_async_data(struct Curl_async *);
00138
00139
00140
00141
00142 void Curl_resolver_cancel(struct connectdata *conn)
00143 {
00144 destroy_async_data(&conn->async);
00145 }
00146
00147
00148 static bool init_resolve_thread(struct connectdata *conn,
00149 const char *hostname, int port,
00150 const struct addrinfo *hints);
00151
00152
00153
00154 struct thread_sync_data {
00155 curl_mutex_t * mtx;
00156 int done;
00157
00158 char *hostname;
00159
00160 int port;
00161 int sock_error;
00162 Curl_addrinfo *res;
00163 #ifdef HAVE_GETADDRINFO
00164 struct addrinfo hints;
00165 #endif
00166 struct thread_data *td;
00167 };
00168
00169 struct thread_data {
00170 curl_thread_t thread_hnd;
00171 unsigned int poll_interval;
00172 time_t interval_end;
00173 struct thread_sync_data tsd;
00174 };
00175
00176 static struct thread_sync_data *conn_thread_sync_data(struct connectdata *conn)
00177 {
00178 return &(((struct thread_data *)conn->async.os_specific)->tsd);
00179 }
00180
00181 #define CONN_THREAD_SYNC_DATA(conn) &(((conn)->async.os_specific)->tsd);
00182
00183
00184 static
00185 void destroy_thread_sync_data(struct thread_sync_data * tsd)
00186 {
00187 if(tsd->mtx) {
00188 Curl_mutex_destroy(tsd->mtx);
00189 free(tsd->mtx);
00190 }
00191
00192 free(tsd->hostname);
00193
00194 if(tsd->res)
00195 Curl_freeaddrinfo(tsd->res);
00196
00197 memset(tsd, 0, sizeof(*tsd));
00198 }
00199
00200
00201 static
00202 int init_thread_sync_data(struct thread_data * td,
00203 const char *hostname,
00204 int port,
00205 const struct addrinfo *hints)
00206 {
00207 struct thread_sync_data *tsd = &td->tsd;
00208
00209 memset(tsd, 0, sizeof(*tsd));
00210
00211 tsd->td = td;
00212 tsd->port = port;
00213 #ifdef HAVE_GETADDRINFO
00214 DEBUGASSERT(hints);
00215 tsd->hints = *hints;
00216 #else
00217 (void) hints;
00218 #endif
00219
00220 tsd->mtx = malloc(sizeof(curl_mutex_t));
00221 if(tsd->mtx == NULL)
00222 goto err_exit;
00223
00224 Curl_mutex_init(tsd->mtx);
00225
00226 tsd->sock_error = CURL_ASYNC_SUCCESS;
00227
00228
00229
00230
00231 tsd->hostname = strdup(hostname);
00232 if(!tsd->hostname)
00233 goto err_exit;
00234
00235 return 1;
00236
00237 err_exit:
00238
00239 destroy_thread_sync_data(tsd);
00240 return 0;
00241 }
00242
00243 static int getaddrinfo_complete(struct connectdata *conn)
00244 {
00245 struct thread_sync_data *tsd = conn_thread_sync_data(conn);
00246 int rc;
00247
00248 rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res);
00249
00250
00251
00252 tsd->res = NULL;
00253
00254 return rc;
00255 }
00256
00257
00258 #ifdef HAVE_GETADDRINFO
00259
00260
00261
00262
00263
00264
00265
00266 static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
00267 {
00268 struct thread_sync_data *tsd = (struct thread_sync_data*)arg;
00269 struct thread_data *td = tsd->td;
00270 char service[12];
00271 int rc;
00272
00273 snprintf(service, sizeof(service), "%d", tsd->port);
00274
00275 rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
00276
00277 if(rc != 0) {
00278 tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
00279 if(tsd->sock_error == 0)
00280 tsd->sock_error = RESOLVER_ENOMEM;
00281 }
00282 else {
00283 Curl_addrinfo_set_port(tsd->res, tsd->port);
00284 }
00285
00286 Curl_mutex_acquire(tsd->mtx);
00287 if(tsd->done) {
00288
00289 Curl_mutex_release(tsd->mtx);
00290 destroy_thread_sync_data(tsd);
00291 free(td);
00292 }
00293 else {
00294 tsd->done = 1;
00295 Curl_mutex_release(tsd->mtx);
00296 }
00297
00298 return 0;
00299 }
00300
00301 #else
00302
00303
00304
00305
00306 static unsigned int CURL_STDCALL gethostbyname_thread(void *arg)
00307 {
00308 struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
00309 struct thread_data *td = tsd->td;
00310
00311 tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
00312
00313 if(!tsd->res) {
00314 tsd->sock_error = SOCKERRNO;
00315 if(tsd->sock_error == 0)
00316 tsd->sock_error = RESOLVER_ENOMEM;
00317 }
00318
00319 Curl_mutex_acquire(tsd->mtx);
00320 if(tsd->done) {
00321
00322 Curl_mutex_release(tsd->mtx);
00323 destroy_thread_sync_data(tsd);
00324 free(td);
00325 }
00326 else {
00327 tsd->done = 1;
00328 Curl_mutex_release(tsd->mtx);
00329 }
00330
00331 return 0;
00332 }
00333
00334 #endif
00335
00336
00337
00338
00339 static void destroy_async_data(struct Curl_async *async)
00340 {
00341 if(async->os_specific) {
00342 struct thread_data *td = (struct thread_data*) async->os_specific;
00343 int done;
00344
00345
00346
00347
00348
00349 Curl_mutex_acquire(td->tsd.mtx);
00350 done = td->tsd.done;
00351 td->tsd.done = 1;
00352 Curl_mutex_release(td->tsd.mtx);
00353
00354 if(!done) {
00355 Curl_thread_destroy(td->thread_hnd);
00356 }
00357 else {
00358 if(td->thread_hnd != curl_thread_t_null)
00359 Curl_thread_join(&td->thread_hnd);
00360
00361 destroy_thread_sync_data(&td->tsd);
00362
00363 free(async->os_specific);
00364 }
00365 }
00366 async->os_specific = NULL;
00367
00368 free(async->hostname);
00369 async->hostname = NULL;
00370 }
00371
00372
00373
00374
00375
00376
00377
00378 static bool init_resolve_thread(struct connectdata *conn,
00379 const char *hostname, int port,
00380 const struct addrinfo *hints)
00381 {
00382 struct thread_data *td = calloc(1, sizeof(struct thread_data));
00383 int err = RESOLVER_ENOMEM;
00384
00385 conn->async.os_specific = (void *)td;
00386 if(!td)
00387 goto err_exit;
00388
00389 conn->async.port = port;
00390 conn->async.done = FALSE;
00391 conn->async.status = 0;
00392 conn->async.dns = NULL;
00393 td->thread_hnd = curl_thread_t_null;
00394
00395 if(!init_thread_sync_data(td, hostname, port, hints))
00396 goto err_exit;
00397
00398 free(conn->async.hostname);
00399 conn->async.hostname = strdup(hostname);
00400 if(!conn->async.hostname)
00401 goto err_exit;
00402
00403 #ifdef HAVE_GETADDRINFO
00404 td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
00405 #else
00406 td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
00407 #endif
00408
00409 if(!td->thread_hnd) {
00410 #ifndef _WIN32_WCE
00411 err = errno;
00412 #endif
00413 goto err_exit;
00414 }
00415
00416 return TRUE;
00417
00418 err_exit:
00419 destroy_async_data(&conn->async);
00420
00421 SET_ERRNO(err);
00422
00423 return FALSE;
00424 }
00425
00426
00427
00428
00429
00430
00431 static CURLcode resolver_error(struct connectdata *conn)
00432 {
00433 const char *host_or_proxy;
00434 CURLcode result;
00435
00436 if(conn->bits.httpproxy) {
00437 host_or_proxy = "proxy";
00438 result = CURLE_COULDNT_RESOLVE_PROXY;
00439 }
00440 else {
00441 host_or_proxy = "host";
00442 result = CURLE_COULDNT_RESOLVE_HOST;
00443 }
00444
00445 failf(conn->data, "Could not resolve %s: %s", host_or_proxy,
00446 conn->async.hostname);
00447
00448 return result;
00449 }
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461 CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
00462 struct Curl_dns_entry **entry)
00463 {
00464 struct thread_data *td = (struct thread_data*) conn->async.os_specific;
00465 CURLcode result = CURLE_OK;
00466
00467 DEBUGASSERT(conn && td);
00468
00469
00470 if(Curl_thread_join(&td->thread_hnd))
00471 result = getaddrinfo_complete(conn);
00472 else
00473 DEBUGASSERT(0);
00474
00475 conn->async.done = TRUE;
00476
00477 if(entry)
00478 *entry = conn->async.dns;
00479
00480 if(!conn->async.dns)
00481
00482 result = resolver_error(conn);
00483
00484 destroy_async_data(&conn->async);
00485
00486 if(!conn->async.dns)
00487 connclose(conn, "asynch resolve failed");
00488
00489 return result;
00490 }
00491
00492
00493
00494
00495
00496
00497 CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
00498 struct Curl_dns_entry **entry)
00499 {
00500 struct Curl_easy *data = conn->data;
00501 struct thread_data *td = (struct thread_data*) conn->async.os_specific;
00502 int done = 0;
00503
00504 *entry = NULL;
00505
00506 if(!td) {
00507 DEBUGASSERT(td);
00508 return CURLE_COULDNT_RESOLVE_HOST;
00509 }
00510
00511 Curl_mutex_acquire(td->tsd.mtx);
00512 done = td->tsd.done;
00513 Curl_mutex_release(td->tsd.mtx);
00514
00515 if(done) {
00516 getaddrinfo_complete(conn);
00517
00518 if(!conn->async.dns) {
00519 CURLcode result = resolver_error(conn);
00520 destroy_async_data(&conn->async);
00521 return result;
00522 }
00523 destroy_async_data(&conn->async);
00524 *entry = conn->async.dns;
00525 }
00526 else {
00527
00528 time_t elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
00529 if(elapsed < 0)
00530 elapsed = 0;
00531
00532 if(td->poll_interval == 0)
00533
00534 td->poll_interval = 1;
00535 else if(elapsed >= td->interval_end)
00536
00537 td->poll_interval *= 2;
00538
00539 if(td->poll_interval > 250)
00540 td->poll_interval = 250;
00541
00542 td->interval_end = elapsed + td->poll_interval;
00543 Curl_expire(conn->data, td->poll_interval);
00544 }
00545
00546 return CURLE_OK;
00547 }
00548
00549 int Curl_resolver_getsock(struct connectdata *conn,
00550 curl_socket_t *socks,
00551 int numsocks)
00552 {
00553 (void)conn;
00554 (void)socks;
00555 (void)numsocks;
00556 return 0;
00557 }
00558
00559 #ifndef HAVE_GETADDRINFO
00560
00561
00562
00563 Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
00564 const char *hostname,
00565 int port,
00566 int *waitp)
00567 {
00568 struct in_addr in;
00569
00570 *waitp = 0;
00571
00572 if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
00573
00574 return Curl_ip2addr(AF_INET, &in, hostname, port);
00575
00576
00577 if(init_resolve_thread(conn, hostname, port, NULL)) {
00578 *waitp = 1;
00579 return NULL;
00580 }
00581
00582
00583 return Curl_ipv4_resolve_r(hostname, port);
00584 }
00585
00586 #else
00587
00588
00589
00590
00591 Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
00592 const char *hostname,
00593 int port,
00594 int *waitp)
00595 {
00596 struct addrinfo hints;
00597 struct in_addr in;
00598 Curl_addrinfo *res;
00599 int error;
00600 char sbuf[12];
00601 int pf = PF_INET;
00602 #ifdef CURLRES_IPV6
00603 struct in6_addr in6;
00604 #endif
00605
00606 *waitp = 0;
00607
00608 #ifndef USE_RESOLVE_ON_IPS
00609
00610 if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
00611
00612 return Curl_ip2addr(AF_INET, &in, hostname, port);
00613
00614 #ifdef CURLRES_IPV6
00615
00616 if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0)
00617
00618 return Curl_ip2addr(AF_INET6, &in6, hostname, port);
00619 #endif
00620 #endif
00621
00622 #ifdef CURLRES_IPV6
00623
00624
00625
00626 switch(conn->ip_version) {
00627 case CURL_IPRESOLVE_V4:
00628 pf = PF_INET;
00629 break;
00630 case CURL_IPRESOLVE_V6:
00631 pf = PF_INET6;
00632 break;
00633 default:
00634 pf = PF_UNSPEC;
00635 break;
00636 }
00637
00638 if((pf != PF_INET) && !Curl_ipv6works())
00639
00640 pf = PF_INET;
00641 #endif
00642
00643 memset(&hints, 0, sizeof(hints));
00644 hints.ai_family = pf;
00645 hints.ai_socktype = conn->socktype;
00646
00647 snprintf(sbuf, sizeof(sbuf), "%d", port);
00648
00649
00650 if(init_resolve_thread(conn, hostname, port, &hints)) {
00651 *waitp = 1;
00652 return NULL;
00653 }
00654
00655
00656 infof(conn->data, "init_resolve_thread() failed for %s; %s\n",
00657 hostname, Curl_strerror(conn, ERRNO));
00658
00659 error = Curl_getaddrinfo_ex(hostname, sbuf, &hints, &res);
00660 if(error) {
00661 infof(conn->data, "getaddrinfo() failed for %s:%d; %s\n",
00662 hostname, port, Curl_strerror(conn, SOCKERRNO));
00663 return NULL;
00664 }
00665 else {
00666 Curl_addrinfo_set_port(res, port);
00667 }
00668
00669 return res;
00670 }
00671
00672 #endif
00673
00674 CURLcode Curl_set_dns_servers(struct Curl_easy *data,
00675 char *servers)
00676 {
00677 (void)data;
00678 (void)servers;
00679 return CURLE_NOT_BUILT_IN;
00680
00681 }
00682
00683 CURLcode Curl_set_dns_interface(struct Curl_easy *data,
00684 const char *interf)
00685 {
00686 (void)data;
00687 (void)interf;
00688 return CURLE_NOT_BUILT_IN;
00689 }
00690
00691 CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
00692 const char *local_ip4)
00693 {
00694 (void)data;
00695 (void)local_ip4;
00696 return CURLE_NOT_BUILT_IN;
00697 }
00698
00699 CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
00700 const char *local_ip6)
00701 {
00702 (void)data;
00703 (void)local_ip6;
00704 return CURLE_NOT_BUILT_IN;
00705 }
00706
00707 #endif