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_LIMITS_H
00026 #include <limits.h>
00027 #endif
00028 #ifdef HAVE_NETINET_IN_H
00029 #include <netinet/in.h>
00030 #endif
00031 #ifdef HAVE_NETDB_H
00032 #include <netdb.h>
00033 #endif
00034 #ifdef HAVE_ARPA_INET_H
00035 #include <arpa/inet.h>
00036 #endif
00037 #ifdef __VMS
00038 #include <in.h>
00039 #include <inet.h>
00040 #endif
00041
00042 #ifdef HAVE_PROCESS_H
00043 #include <process.h>
00044 #endif
00045
00046 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
00047 #undef in_addr_t
00048 #define in_addr_t unsigned long
00049 #endif
00050
00051
00052
00053
00054
00055
00056
00057 #ifdef CURLRES_ARES
00058
00059 #include "urldata.h"
00060 #include "sendf.h"
00061 #include "hostip.h"
00062 #include "hash.h"
00063 #include "share.h"
00064 #include "strerror.h"
00065 #include "url.h"
00066 #include "multiif.h"
00067 #include "inet_pton.h"
00068 #include "connect.h"
00069 #include "select.h"
00070 #include "progress.h"
00071
00072 # if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
00073 (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
00074 # define CARES_STATICLIB
00075 # endif
00076 # include <ares.h>
00077 # include <ares_version.h>
00078
00079
00080 #if ARES_VERSION >= 0x010500
00081
00082 #define HAVE_CARES_CALLBACK_TIMEOUTS 1
00083 #endif
00084
00085
00086 #include "curl_printf.h"
00087 #include "curl_memory.h"
00088 #include "memdebug.h"
00089
00090 struct ResolverResults {
00091 int num_pending;
00092 Curl_addrinfo *temp_ai;
00093 int last_status;
00094 };
00095
00096
00097
00098
00099
00100
00101 int Curl_resolver_global_init(void)
00102 {
00103 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
00104 if(ares_library_init(ARES_LIB_INIT_ALL)) {
00105 return CURLE_FAILED_INIT;
00106 }
00107 #endif
00108 return CURLE_OK;
00109 }
00110
00111
00112
00113
00114
00115
00116
00117 void Curl_resolver_global_cleanup(void)
00118 {
00119 #ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
00120 ares_library_cleanup();
00121 #endif
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131 CURLcode Curl_resolver_init(void **resolver)
00132 {
00133 int status = ares_init((ares_channel*)resolver);
00134 if(status != ARES_SUCCESS) {
00135 if(status == ARES_ENOMEM)
00136 return CURLE_OUT_OF_MEMORY;
00137 else
00138 return CURLE_FAILED_INIT;
00139 }
00140 return CURLE_OK;
00141
00142
00143 }
00144
00145
00146
00147
00148
00149
00150
00151
00152 void Curl_resolver_cleanup(void *resolver)
00153 {
00154 ares_destroy((ares_channel)resolver);
00155 }
00156
00157
00158
00159
00160
00161
00162
00163
00164 int Curl_resolver_duphandle(void **to, void *from)
00165 {
00166
00167 if(ARES_SUCCESS != ares_dup((ares_channel*)to, (ares_channel)from))
00168 return CURLE_FAILED_INIT;
00169 return CURLE_OK;
00170 }
00171
00172 static void destroy_async_data(struct Curl_async *async);
00173
00174
00175
00176
00177 void Curl_resolver_cancel(struct connectdata *conn)
00178 {
00179 if(conn->data && conn->data->state.resolver)
00180 ares_cancel((ares_channel)conn->data->state.resolver);
00181 destroy_async_data(&conn->async);
00182 }
00183
00184
00185
00186
00187 static void destroy_async_data(struct Curl_async *async)
00188 {
00189 free(async->hostname);
00190
00191 if(async->os_specific) {
00192 struct ResolverResults *res = (struct ResolverResults *)async->os_specific;
00193 if(res) {
00194 if(res->temp_ai) {
00195 Curl_freeaddrinfo(res->temp_ai);
00196 res->temp_ai = NULL;
00197 }
00198 free(res);
00199 }
00200 async->os_specific = NULL;
00201 }
00202
00203 async->hostname = NULL;
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 int Curl_resolver_getsock(struct connectdata *conn,
00216 curl_socket_t *socks,
00217 int numsocks)
00218
00219 {
00220 struct timeval maxtime;
00221 struct timeval timebuf;
00222 struct timeval *timeout;
00223 long milli;
00224 int max = ares_getsock((ares_channel)conn->data->state.resolver,
00225 (ares_socket_t *)socks, numsocks);
00226
00227 maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
00228 maxtime.tv_usec = 0;
00229
00230 timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime,
00231 &timebuf);
00232 milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000);
00233 if(milli == 0)
00234 milli += 10;
00235 Curl_expire_latest(conn->data, milli);
00236
00237 return max;
00238 }
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250 static int waitperform(struct connectdata *conn, int timeout_ms)
00251 {
00252 struct Curl_easy *data = conn->data;
00253 int nfds;
00254 int bitmask;
00255 ares_socket_t socks[ARES_GETSOCK_MAXNUM];
00256 struct pollfd pfd[ARES_GETSOCK_MAXNUM];
00257 int i;
00258 int num = 0;
00259
00260 bitmask = ares_getsock((ares_channel)data->state.resolver, socks,
00261 ARES_GETSOCK_MAXNUM);
00262
00263 for(i=0; i < ARES_GETSOCK_MAXNUM; i++) {
00264 pfd[i].events = 0;
00265 pfd[i].revents = 0;
00266 if(ARES_GETSOCK_READABLE(bitmask, i)) {
00267 pfd[i].fd = socks[i];
00268 pfd[i].events |= POLLRDNORM|POLLIN;
00269 }
00270 if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
00271 pfd[i].fd = socks[i];
00272 pfd[i].events |= POLLWRNORM|POLLOUT;
00273 }
00274 if(pfd[i].events != 0)
00275 num++;
00276 else
00277 break;
00278 }
00279
00280 if(num)
00281 nfds = Curl_poll(pfd, num, timeout_ms);
00282 else
00283 nfds = 0;
00284
00285 if(!nfds)
00286
00287
00288 ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD,
00289 ARES_SOCKET_BAD);
00290 else {
00291
00292 for(i=0; i < num; i++)
00293 ares_process_fd((ares_channel)data->state.resolver,
00294 pfd[i].revents & (POLLRDNORM|POLLIN)?
00295 pfd[i].fd:ARES_SOCKET_BAD,
00296 pfd[i].revents & (POLLWRNORM|POLLOUT)?
00297 pfd[i].fd:ARES_SOCKET_BAD);
00298 }
00299 return nfds;
00300 }
00301
00302
00303
00304
00305
00306
00307
00308
00309 CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
00310 struct Curl_dns_entry **dns)
00311 {
00312 struct Curl_easy *data = conn->data;
00313 struct ResolverResults *res = (struct ResolverResults *)
00314 conn->async.os_specific;
00315 CURLcode result = CURLE_OK;
00316
00317 *dns = NULL;
00318
00319 waitperform(conn, 0);
00320
00321 if(res && !res->num_pending) {
00322 (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai);
00323
00324
00325 res->temp_ai = NULL;
00326 if(!conn->async.dns) {
00327 failf(data, "Could not resolve: %s (%s)",
00328 conn->async.hostname, ares_strerror(conn->async.status));
00329 result = conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
00330 CURLE_COULDNT_RESOLVE_HOST;
00331 }
00332 else
00333 *dns = conn->async.dns;
00334
00335 destroy_async_data(&conn->async);
00336 }
00337
00338 return result;
00339 }
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
00353 struct Curl_dns_entry **entry)
00354 {
00355 CURLcode result = CURLE_OK;
00356 struct Curl_easy *data = conn->data;
00357 long timeout;
00358 struct timeval now = Curl_tvnow();
00359 struct Curl_dns_entry *temp_entry;
00360
00361 timeout = Curl_timeleft(data, &now, TRUE);
00362 if(!timeout)
00363 timeout = CURL_TIMEOUT_RESOLVE * 1000;
00364
00365
00366 for(;;) {
00367 struct timeval *tvp, tv, store;
00368 long timediff;
00369 int itimeout;
00370 int timeout_ms;
00371
00372 itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout;
00373
00374 store.tv_sec = itimeout/1000;
00375 store.tv_usec = (itimeout%1000)*1000;
00376
00377 tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv);
00378
00379
00380
00381
00382 if(!tvp->tv_sec)
00383 timeout_ms = (int)(tvp->tv_usec/1000);
00384 else
00385 timeout_ms = 1000;
00386
00387 waitperform(conn, timeout_ms);
00388 Curl_resolver_is_resolved(conn, &temp_entry);
00389
00390 if(conn->async.done)
00391 break;
00392
00393 if(Curl_pgrsUpdate(conn)) {
00394 result = CURLE_ABORTED_BY_CALLBACK;
00395 timeout = -1;
00396 }
00397 else {
00398 struct timeval now2 = Curl_tvnow();
00399 timediff = Curl_tvdiff(now2, now);
00400 timeout -= timediff?timediff:1;
00401 now = now2;
00402 }
00403
00404 if(timeout < 0) {
00405
00406 ares_cancel((ares_channel)data->state.resolver);
00407 break;
00408 }
00409 }
00410
00411
00412
00413 if(entry)
00414 *entry = conn->async.dns;
00415
00416 if(result)
00417
00418
00419
00420
00421 connclose(conn, "c-ares resolve failed");
00422
00423 return result;
00424 }
00425
00426
00427 static void compound_results(struct ResolverResults *res,
00428 Curl_addrinfo *ai)
00429 {
00430 Curl_addrinfo *ai_tail;
00431 if(!ai)
00432 return;
00433 ai_tail = ai;
00434
00435 while(ai_tail->ai_next)
00436 ai_tail = ai_tail->ai_next;
00437
00438
00439 ai_tail->ai_next = res->temp_ai;
00440 res->temp_ai = ai;
00441 }
00442
00443
00444
00445
00446
00447
00448 static void query_completed_cb(void *arg,
00449 int status,
00450 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
00451 int timeouts,
00452 #endif
00453 struct hostent *hostent)
00454 {
00455 struct connectdata *conn = (struct connectdata *)arg;
00456 struct ResolverResults *res;
00457
00458 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
00459 (void)timeouts;
00460 #endif
00461
00462 if(ARES_EDESTRUCTION == status)
00463
00464
00465 return;
00466
00467 res = (struct ResolverResults *)conn->async.os_specific;
00468 res->num_pending--;
00469
00470 if(CURL_ASYNC_SUCCESS == status) {
00471 Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port);
00472 if(ai) {
00473 compound_results(res, ai);
00474 }
00475 }
00476
00477 if(res->last_status != ARES_SUCCESS)
00478 res->last_status = status;
00479 }
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489 Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
00490 const char *hostname,
00491 int port,
00492 int *waitp)
00493 {
00494 char *bufp;
00495 struct Curl_easy *data = conn->data;
00496 struct in_addr in;
00497 int family = PF_INET;
00498 #ifdef ENABLE_IPV6
00499 struct in6_addr in6;
00500 #endif
00501
00502 *waitp = 0;
00503
00504
00505 if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
00506
00507 return Curl_ip2addr(AF_INET, &in, hostname, port);
00508 }
00509
00510 #ifdef ENABLE_IPV6
00511
00512 if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0)
00513
00514 return Curl_ip2addr(AF_INET6, &in6, hostname, port);
00515
00516 switch(conn->ip_version) {
00517 default:
00518 #if ARES_VERSION >= 0x010601
00519 family = PF_UNSPEC;
00520
00521
00522 break;
00523 #endif
00524 case CURL_IPRESOLVE_V4:
00525 family = PF_INET;
00526 break;
00527 case CURL_IPRESOLVE_V6:
00528 family = PF_INET6;
00529 break;
00530 }
00531 #endif
00532
00533 bufp = strdup(hostname);
00534 if(bufp) {
00535 struct ResolverResults *res = NULL;
00536 free(conn->async.hostname);
00537 conn->async.hostname = bufp;
00538 conn->async.port = port;
00539 conn->async.done = FALSE;
00540 conn->async.status = 0;
00541 conn->async.dns = NULL;
00542 res = calloc(sizeof(struct ResolverResults), 1);
00543 if(!res) {
00544 free(conn->async.hostname);
00545 conn->async.hostname = NULL;
00546 return NULL;
00547 }
00548 conn->async.os_specific = res;
00549
00550
00551 res->last_status = ARES_ENOTFOUND;
00552 #ifdef ENABLE_IPV6
00553 if(family == PF_UNSPEC) {
00554 if(Curl_ipv6works()) {
00555 res->num_pending = 2;
00556
00557
00558 ares_gethostbyname((ares_channel)data->state.resolver, hostname,
00559 PF_INET, query_completed_cb, conn);
00560 ares_gethostbyname((ares_channel)data->state.resolver, hostname,
00561 PF_INET6, query_completed_cb, conn);
00562 }
00563 else {
00564 res->num_pending = 1;
00565
00566
00567 ares_gethostbyname((ares_channel)data->state.resolver, hostname,
00568 PF_INET, query_completed_cb, conn);
00569 }
00570 }
00571 else
00572 #endif
00573 {
00574 res->num_pending = 1;
00575
00576
00577 ares_gethostbyname((ares_channel)data->state.resolver, hostname, family,
00578 query_completed_cb, conn);
00579 }
00580
00581 *waitp = 1;
00582 }
00583 return NULL;
00584 }
00585
00586 CURLcode Curl_set_dns_servers(struct Curl_easy *data,
00587 char *servers)
00588 {
00589 CURLcode result = CURLE_NOT_BUILT_IN;
00590 int ares_result;
00591
00592
00593
00594
00595
00596
00597
00598 if(!(servers && servers[0]))
00599 return CURLE_OK;
00600
00601 #if (ARES_VERSION >= 0x010704)
00602 ares_result = ares_set_servers_csv(data->state.resolver, servers);
00603 switch(ares_result) {
00604 case ARES_SUCCESS:
00605 result = CURLE_OK;
00606 break;
00607 case ARES_ENOMEM:
00608 result = CURLE_OUT_OF_MEMORY;
00609 break;
00610 case ARES_ENOTINITIALIZED:
00611 case ARES_ENODATA:
00612 case ARES_EBADSTR:
00613 default:
00614 result = CURLE_BAD_FUNCTION_ARGUMENT;
00615 break;
00616 }
00617 #else
00618 (void)data;
00619 (void)(ares_result);
00620 #endif
00621 return result;
00622 }
00623
00624 CURLcode Curl_set_dns_interface(struct Curl_easy *data,
00625 const char *interf)
00626 {
00627 #if (ARES_VERSION >= 0x010704)
00628 if(!interf)
00629 interf = "";
00630
00631 ares_set_local_dev((ares_channel)data->state.resolver, interf);
00632
00633 return CURLE_OK;
00634 #else
00635 (void)data;
00636 (void)interf;
00637 return CURLE_NOT_BUILT_IN;
00638 #endif
00639 }
00640
00641 CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
00642 const char *local_ip4)
00643 {
00644 #if (ARES_VERSION >= 0x010704)
00645 struct in_addr a4;
00646
00647 if((!local_ip4) || (local_ip4[0] == 0)) {
00648 a4.s_addr = 0;
00649 }
00650 else {
00651 if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) {
00652 return CURLE_BAD_FUNCTION_ARGUMENT;
00653 }
00654 }
00655
00656 ares_set_local_ip4((ares_channel)data->state.resolver, ntohl(a4.s_addr));
00657
00658 return CURLE_OK;
00659 #else
00660 (void)data;
00661 (void)local_ip4;
00662 return CURLE_NOT_BUILT_IN;
00663 #endif
00664 }
00665
00666 CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
00667 const char *local_ip6)
00668 {
00669 #if (ARES_VERSION >= 0x010704) && defined(ENABLE_IPV6)
00670 unsigned char a6[INET6_ADDRSTRLEN];
00671
00672 if((!local_ip6) || (local_ip6[0] == 0)) {
00673
00674 memset(a6, 0, sizeof(a6));
00675 }
00676 else {
00677 if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) {
00678 return CURLE_BAD_FUNCTION_ARGUMENT;
00679 }
00680 }
00681
00682 ares_set_local_ip6((ares_channel)data->state.resolver, a6);
00683
00684 return CURLE_OK;
00685 #else
00686 (void)data;
00687 (void)local_ip6;
00688 return CURLE_NOT_BUILT_IN;
00689 #endif
00690 }
00691 #endif