00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #define _HOSTDB_CC_
00025
00026 #include "P_HostDB.h"
00027 #include "I_Layout.h"
00028 #include "Show.h"
00029
00030
00031
00032
00033
00034
00035 #include "ink_apidefs.h"
00036
00037 HostDBProcessor hostDBProcessor;
00038 int HostDBProcessor::hostdb_strict_round_robin = 0;
00039 int HostDBProcessor::hostdb_timed_round_robin = 0;
00040 HostDBProcessor::Options const HostDBProcessor::DEFAULT_OPTIONS;
00041 HostDBContinuation::Options const HostDBContinuation::DEFAULT_OPTIONS;
00042 int hostdb_enable = true;
00043 int hostdb_migrate_on_demand = true;
00044 int hostdb_cluster = false;
00045 int hostdb_cluster_round_robin = false;
00046 int hostdb_lookup_timeout = 120;
00047 int hostdb_insert_timeout = 160;
00048 int hostdb_re_dns_on_reload = false;
00049 int hostdb_ttl_mode = TTL_OBEY;
00050 unsigned int hostdb_current_interval = 0;
00051 unsigned int hostdb_ip_stale_interval = HOST_DB_IP_STALE;
00052 unsigned int hostdb_ip_timeout_interval = HOST_DB_IP_TIMEOUT;
00053 unsigned int hostdb_ip_fail_timeout_interval = HOST_DB_IP_FAIL_TIMEOUT;
00054 unsigned int hostdb_serve_stale_but_revalidate = 0;
00055 char hostdb_filename[PATH_NAME_MAX + 1] = DEFAULT_HOST_DB_FILENAME;
00056 int hostdb_size = DEFAULT_HOST_DB_SIZE;
00057 int hostdb_sync_frequency = 120;
00058 int hostdb_srv_enabled = 0;
00059 int hostdb_disable_reverse_lookup = 0;
00060
00061 ClassAllocator<HostDBContinuation> hostDBContAllocator("hostDBContAllocator");
00062
00063
00064
00065 HostDBCache hostDB;
00066
00067 static Queue <HostDBContinuation > remoteHostDBQueue[MULTI_CACHE_PARTITIONS];
00068
00069 char *
00070 HostDBInfo::srvname(HostDBRoundRobin *rr)
00071 {
00072 if (!is_srv || !data.srv.srv_offset)
00073 return NULL;
00074 ink_assert(this - rr->info >= 0 && this - rr->info < rr->rrcount && data.srv.srv_offset < rr->length);
00075 return (char *) rr + data.srv.srv_offset;
00076 }
00077
00078 static inline int
00079 corrupt_debugging_callout(HostDBInfo * e, RebuildMC & r)
00080 {
00081 Debug("hostdb", "corrupt %ld part %d",
00082 (long)((char *) &e->app.rr.offset - r.data), r.partition);
00083 return -1;
00084 }
00085
00086 static inline bool
00087 is_addr_valid(
00088 uint8_t af,
00089 void* ptr
00090 ) {
00091 return
00092 (AF_INET == af && INADDR_ANY != *(reinterpret_cast<in_addr_t*>(ptr)))
00093 || (AF_INET6 == af && !IN6_IS_ADDR_UNSPECIFIED(reinterpret_cast<in6_addr*>(ptr)))
00094 ;
00095 }
00096
00097 static inline void
00098 ip_addr_set(
00099 sockaddr* ip,
00100 uint8_t af,
00101 void* ptr
00102 ) {
00103 if (AF_INET6 == af)
00104 ats_ip6_set(ip, *static_cast<in6_addr*>(ptr));
00105 else if (AF_INET == af)
00106 ats_ip4_set(ip, *static_cast<in_addr_t*>(ptr));
00107 else ats_ip_invalidate(ip);
00108 }
00109
00110 static inline void
00111 ip_addr_set(
00112 IpAddr& ip,
00113 uint8_t af,
00114 void* ptr
00115 ) {
00116 if (AF_INET6 == af)
00117 ip = *static_cast<in6_addr*>(ptr);
00118 else if (AF_INET == af)
00119 ip = *static_cast<in_addr_t*>(ptr);
00120 else
00121 ip.invalidate();
00122 }
00123
00124 inline void
00125 hostdb_cont_free(HostDBContinuation * cont)
00126 {
00127 if (cont->pending_action)
00128 cont->pending_action->cancel();
00129 cont->mutex = 0;
00130 cont->action.mutex = 0;
00131 hostDBContAllocator.free(cont);
00132 }
00133
00134
00135
00136
00137
00138 static inline bool
00139 check_for_retry(HostDBMark& mark, HostResStyle style) {
00140 bool zret = true;
00141 if (HOSTDB_MARK_IPV4 == mark && HOST_RES_IPV4 == style)
00142 mark = HOSTDB_MARK_IPV6;
00143 else if (HOSTDB_MARK_IPV6 == mark && HOST_RES_IPV6 == style)
00144 mark = HOSTDB_MARK_IPV4;
00145 else
00146 zret = false;
00147 return zret;
00148 }
00149
00150 char const*
00151 string_for(HostDBMark mark) {
00152 static char const* STRING[] = {
00153 "Generic", "IPv4", "IPv6", "SRV"
00154 };
00155 return STRING[mark];
00156 }
00157
00158
00159
00160
00161 static Action *
00162 register_ShowHostDB(Continuation * c, HTTPHdr * h);
00163
00164 void
00165 HostDBMD5::refresh() {
00166 if (host_name) {
00167 char const* server_line = dns_server ? dns_server->x_dns_ip_line : 0;
00168 make_md5(hash, host_name, host_len, port, server_line, db_mark);
00169 } else {
00170
00171
00172
00173 uint8_t buff[TS_IP6_SIZE+4];
00174 int n = ip.isIp6() ? sizeof(in6_addr) : sizeof(in_addr_t);
00175 memset(buff, 0, 2);
00176 memcpy(buff+2, ip._addr._byte, n);
00177 memset(buff + 2 + n , 0, 2);
00178 MD5Context().hash_immediate(hash, buff, n+4);
00179
00180 }
00181 }
00182
00183 HostDBMD5::HostDBMD5()
00184 : host_name(0), host_len(0), port(0),
00185 dns_server(0), db_mark(HOSTDB_MARK_GENERIC)
00186 {
00187 }
00188
00189 HostDBCache::HostDBCache()
00190 {
00191 tag_bits = HOST_DB_TAG_BITS;
00192 max_hits = (1 << HOST_DB_HITS_BITS) - 1;
00193 version.ink_major = HOST_DB_CACHE_MAJOR_VERSION;
00194 version.ink_minor = HOST_DB_CACHE_MINOR_VERSION;
00195 }
00196
00197
00198 int
00199 HostDBCache::rebuild_callout(HostDBInfo * e, RebuildMC & r)
00200 {
00201 if (e->round_robin && e->reverse_dns)
00202 return corrupt_debugging_callout(e, r);
00203 if (e->reverse_dns) {
00204 if (e->data.hostname_offset < 0)
00205 return 0;
00206 if (e->data.hostname_offset > 0) {
00207 if (!valid_offset(e->data.hostname_offset - 1))
00208 return corrupt_debugging_callout(e, r);
00209 char *p = (char *) ptr(&e->data.hostname_offset, r.partition);
00210 if (!p)
00211 return corrupt_debugging_callout(e, r);
00212 char *s = p;
00213 while (*p && p - s < MAXDNAME) {
00214 if (!valid_heap_pointer(p))
00215 return corrupt_debugging_callout(e, r);
00216 p++;
00217 }
00218 if (p - s >= MAXDNAME)
00219 return corrupt_debugging_callout(e, r);
00220 }
00221 }
00222 if (e->round_robin) {
00223 if (e->app.rr.offset < 0)
00224 return 0;
00225 if (!valid_offset(e->app.rr.offset - 1))
00226 return corrupt_debugging_callout(e, r);
00227 HostDBRoundRobin *rr = (HostDBRoundRobin *) ptr(&e->app.rr.offset, r.partition);
00228 if (!rr)
00229 return corrupt_debugging_callout(e, r);
00230 if (rr->rrcount > HOST_DB_MAX_ROUND_ROBIN_INFO || rr->rrcount <= 0 ||
00231 rr->good > HOST_DB_MAX_ROUND_ROBIN_INFO || rr->good <= 0 || rr->good > rr->rrcount)
00232 return corrupt_debugging_callout(e, r);
00233 for (int i = 0; i < rr->good; i++) {
00234 if (!valid_heap_pointer(((char *) &rr->info[i + 1]) - 1))
00235 return -1;
00236 if (!ats_is_ip(rr->info[i].ip()))
00237 return corrupt_debugging_callout(e, r);
00238 if (rr->info[i].md5_high != e->md5_high ||
00239 rr->info[i].md5_low != e->md5_low || rr->info[i].md5_low_low != e->md5_low_low)
00240 return corrupt_debugging_callout(e, r);
00241 }
00242 }
00243 if (e->is_ip_timeout())
00244 return 0;
00245 return 1;
00246 }
00247
00248
00249 HostDBCache *
00250 HostDBProcessor::cache()
00251 {
00252 return &hostDB;
00253 }
00254
00255
00256 struct HostDBTestRR: public Continuation
00257 {
00258 int fd;
00259 char b[512];
00260 int nb;
00261 int outstanding, success, failure;
00262 int in;
00263
00264 int mainEvent(int event, Event * e)
00265 {
00266 if (event == EVENT_INTERVAL) {
00267 printf("HostDBTestRR: %d outstanding %d succcess %d failure\n", outstanding, success, failure);
00268 }
00269 if (event == EVENT_HOST_DB_LOOKUP) {
00270 --outstanding;
00271 if (e)
00272 ++success;
00273 else
00274 ++failure;
00275 }
00276 if (in)
00277 return EVENT_CONT;
00278 in = 1;
00279 while (outstanding < 40) {
00280 if (!nb)
00281 goto Lreturn;
00282 char *end = (char *)memchr(b, '\n', nb);
00283 if (!end)
00284 read_some();
00285 end = (char *)memchr(b, '\n', nb);
00286 if (!end)
00287 nb = 0;
00288 else {
00289 *end = 0;
00290 outstanding++;
00291 hostDBProcessor.getbyname_re(this, b, 0);
00292 nb -= ((end + 1) - b);
00293 memcpy(b, end + 1, nb);
00294 if (!nb)
00295 read_some();
00296 }
00297 }
00298 Lreturn:
00299 in = 0;
00300 return EVENT_CONT;
00301 }
00302
00303
00304 void read_some()
00305 {
00306 nb = read(fd, b + nb, 512 - nb);
00307 ink_release_assert(nb >= 0);
00308 }
00309
00310
00311 HostDBTestRR():Continuation(new_ProxyMutex()), nb(0), outstanding(0), success(0), failure(0), in(0) {
00312 printf("starting HostDBTestRR....\n");
00313 fd = open("hostdb_test.config", O_RDONLY, 0);
00314 ink_release_assert(fd >= 0);
00315 read_some();
00316 SET_HANDLER(&HostDBTestRR::mainEvent);
00317 }
00318 };
00319
00320
00321 struct HostDBSyncer: public Continuation
00322 {
00323 int frequency;
00324 ink_hrtime start_time;
00325
00326 int sync_event(int event, void *edata);
00327 int wait_event(int event, void *edata);
00328
00329 HostDBSyncer();
00330 };
00331
00332
00333 HostDBSyncer::HostDBSyncer():
00334 Continuation(new_ProxyMutex()), frequency(0), start_time(0)
00335 {
00336 SET_HANDLER(&HostDBSyncer::sync_event);
00337 }
00338
00339
00340 int
00341 HostDBSyncer::sync_event(int, void *)
00342 {
00343 SET_HANDLER(&HostDBSyncer::wait_event);
00344 start_time = ink_get_hrtime();
00345 hostDBProcessor.cache()->sync_partitions(this);
00346 return EVENT_DONE;
00347 }
00348
00349
00350 int
00351 HostDBSyncer::wait_event(int, void *)
00352 {
00353 ink_hrtime next_sync = HRTIME_SECONDS(hostdb_sync_frequency) - (ink_get_hrtime() - start_time);
00354
00355 SET_HANDLER(&HostDBSyncer::sync_event);
00356 if (next_sync > HRTIME_MSECONDS(100))
00357 mutex->thread_holding->schedule_in_local(this, next_sync);
00358 else
00359 mutex->thread_holding->schedule_imm_local(this);
00360 return EVENT_DONE;
00361 }
00362
00363
00364 int
00365 HostDBCache::start(int flags)
00366 {
00367 Store *hostDBStore;
00368 Span *hostDBSpan;
00369 char storage_path[PATH_NAME_MAX + 1];
00370 int storage_size = 33554432;
00371
00372 bool reconfigure = ((flags & PROCESSOR_RECONFIGURE) ? true : false);
00373 bool fix = ((flags & PROCESSOR_FIX) ? true : false);
00374
00375 storage_path[0] = '\0';
00376
00377
00378
00379
00380 REC_ReadConfigInt32(hostdb_enable, "proxy.config.hostdb");
00381 REC_ReadConfigString(hostdb_filename, "proxy.config.hostdb.filename", PATH_NAME_MAX);
00382 REC_ReadConfigInt32(hostdb_size, "proxy.config.hostdb.size");
00383 REC_ReadConfigInt32(hostdb_srv_enabled, "proxy.config.srv_enabled");
00384 REC_ReadConfigString(storage_path, "proxy.config.hostdb.storage_path", PATH_NAME_MAX);
00385 REC_ReadConfigInt32(storage_size, "proxy.config.hostdb.storage_size");
00386
00387
00388
00389 if (storage_path[0] == '\0') {
00390 ats_scoped_str rundir(RecConfigReadRuntimeDir());
00391 ink_strlcpy(storage_path, rundir, sizeof(storage_path));
00392 } else if (storage_path[0] != '/') {
00393 Layout::relative_to(storage_path, sizeof(storage_path), Layout::get()->prefix, storage_path);
00394 }
00395
00396 Debug("hostdb", "Storage path is %s", storage_path);
00397
00398 if (access(storage_path, W_OK | R_OK) == -1) {
00399 Warning("Unable to access() directory '%s': %d, %s", storage_path, errno, strerror(errno));
00400 Warning("Please set 'proxy.config.hostdb.storage_path' or 'proxy.config.local_state_dir'");
00401 }
00402
00403 hostDBStore = new Store;
00404 hostDBSpan = new Span;
00405 hostDBSpan->init(storage_path, storage_size);
00406 hostDBStore->add(hostDBSpan);
00407
00408 Debug("hostdb", "Opening %s, size=%d", hostdb_filename, hostdb_size);
00409 if (open(hostDBStore, "hostdb.config", hostdb_filename, hostdb_size, reconfigure, fix, false ) < 0) {
00410 ats_scoped_str rundir(RecConfigReadRuntimeDir());
00411 ats_scoped_str config(Layout::relative_to(rundir, "hostdb.config"));
00412
00413 Note("reconfiguring host database");
00414
00415 if (unlink(config) < 0)
00416 Debug("hostdb", "unable to unlink %s", (const char *)config);
00417
00418 delete hostDBStore;
00419 hostDBStore = new Store;
00420 hostDBSpan = new Span;
00421 hostDBSpan->init(storage_path, storage_size);
00422 hostDBStore->add(hostDBSpan);
00423
00424 if (open(hostDBStore, "hostdb.config", hostdb_filename, hostdb_size, true, fix) < 0) {
00425 Warning("could not initialize host database. Host database will be disabled");
00426 hostdb_enable = 0;
00427 delete hostDBStore;
00428 return -1;
00429 }
00430 }
00431 HOSTDB_SET_DYN_COUNT(hostdb_bytes_stat, totalsize);
00432
00433 delete hostDBStore;
00434 return 0;
00435 }
00436
00437
00438
00439
00440
00441
00442
00443 int
00444 HostDBProcessor::start(int, size_t)
00445 {
00446 hostDB.alloc_mutexes();
00447
00448 if (hostDB.start(0) < 0)
00449 return -1;
00450
00451 if (auto_clear_hostdb_flag)
00452 hostDB.clear();
00453
00454 HOSTDB_SET_DYN_COUNT(hostdb_total_entries_stat, hostDB.totalelements);
00455
00456 statPagesManager.register_http("hostdb", register_ShowHostDB);
00457
00458
00459
00460
00461 REC_EstablishStaticConfigInt32(hostdb_ttl_mode, "proxy.config.hostdb.ttl_mode");
00462 REC_EstablishStaticConfigInt32(hostdb_disable_reverse_lookup, "proxy.config.cache.hostdb.disable_reverse_lookup");
00463 REC_EstablishStaticConfigInt32(hostdb_re_dns_on_reload, "proxy.config.hostdb.re_dns_on_reload");
00464 REC_EstablishStaticConfigInt32(hostdb_migrate_on_demand, "proxy.config.hostdb.migrate_on_demand");
00465 REC_EstablishStaticConfigInt32(hostdb_strict_round_robin, "proxy.config.hostdb.strict_round_robin");
00466 REC_EstablishStaticConfigInt32(hostdb_timed_round_robin, "proxy.config.hostdb.timed_round_robin");
00467 REC_EstablishStaticConfigInt32(hostdb_cluster, "proxy.config.hostdb.cluster");
00468 REC_EstablishStaticConfigInt32(hostdb_cluster_round_robin, "proxy.config.hostdb.cluster.round_robin");
00469 REC_EstablishStaticConfigInt32(hostdb_lookup_timeout, "proxy.config.hostdb.lookup_timeout");
00470 REC_EstablishStaticConfigInt32U(hostdb_ip_timeout_interval, "proxy.config.hostdb.timeout");
00471 REC_EstablishStaticConfigInt32U(hostdb_ip_stale_interval, "proxy.config.hostdb.verify_after");
00472 REC_EstablishStaticConfigInt32U(hostdb_ip_fail_timeout_interval, "proxy.config.hostdb.fail.timeout");
00473 REC_EstablishStaticConfigInt32U(hostdb_serve_stale_but_revalidate, "proxy.config.hostdb.serve_stale_for");
00474 REC_EstablishStaticConfigInt32(hostdb_sync_frequency, "proxy.config.cache.hostdb.sync_frequency");
00475
00476
00477
00478
00479 hostdb_current_interval = (unsigned int)(ink_get_based_hrtime() / HOST_DB_TIMEOUT_INTERVAL);
00480
00481 HostDBContinuation *b = hostDBContAllocator.alloc();
00482 SET_CONTINUATION_HANDLER(b, (HostDBContHandler) & HostDBContinuation::backgroundEvent);
00483 b->mutex = new_ProxyMutex();
00484 eventProcessor.schedule_every(b, HOST_DB_TIMEOUT_INTERVAL, ET_DNS);
00485
00486
00487
00488
00489 if (hostdb_sync_frequency > 0)
00490 eventProcessor.schedule_imm(new HostDBSyncer);
00491 return 0;
00492 }
00493
00494
00495 void
00496 HostDBContinuation::init(HostDBMD5 const& the_md5, Options const& opt)
00497 {
00498 md5 = the_md5;
00499 if (md5.host_name) {
00500
00501 if (md5.host_len > static_cast<int>(sizeof(md5_host_name_store)-1))
00502 md5.host_len = sizeof(md5_host_name_store)-1;
00503 memcpy(md5_host_name_store, md5.host_name, md5.host_len);
00504 } else {
00505 md5.host_len = 0;
00506 }
00507 md5_host_name_store[md5.host_len] = 0;
00508 md5.host_name = md5_host_name_store;
00509
00510 host_res_style = opt.host_res_style;
00511 dns_lookup_timeout = opt.timeout;
00512 mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
00513 if (opt.cont) {
00514 action = opt.cont;
00515 } else {
00516
00517 action.mutex = mutex;
00518 }
00519 }
00520
00521 void
00522 HostDBContinuation::refresh_MD5() {
00523 ProxyMutex* old_bucket_mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
00524
00525 remove_trigger_pending_dns();
00526 md5.refresh();
00527
00528
00529 if (old_bucket_mutex == mutex)
00530 mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
00531 }
00532
00533 void
00534 make_md5(INK_MD5 & md5, const char *hostname, int len, int port, char const* pDNSServers, HostDBMark mark)
00535 {
00536 INK_DIGEST_CTX ctx;
00537 ink_code_incr_md5_init(&ctx);
00538 ink_code_incr_md5_update(&ctx, hostname, len);
00539 unsigned short p = port;
00540 p = htons(p);
00541 ink_code_incr_md5_update(&ctx, (char *) &p, 2);
00542 uint8_t m = static_cast<uint8_t>(mark);
00543 ink_code_incr_md5_update(&ctx, (char *) &m, sizeof(m));
00544 if (pDNSServers)
00545 ink_code_incr_md5_update(&ctx, pDNSServers, strlen(pDNSServers));
00546 ink_code_incr_md5_final((char *) &md5, &ctx);
00547 }
00548
00549 static bool
00550 reply_to_cont(Continuation * cont, HostDBInfo * r, bool is_srv = false)
00551 {
00552 if (r == NULL || r->is_srv != is_srv || r->failed()) {
00553 cont->handleEvent(is_srv ? EVENT_SRV_LOOKUP : EVENT_HOST_DB_LOOKUP, NULL);
00554 return false;
00555 }
00556
00557 if (r->reverse_dns) {
00558 if (!r->hostname()) {
00559 ink_assert(!"missing hostname");
00560 cont->handleEvent(is_srv ? EVENT_SRV_LOOKUP : EVENT_HOST_DB_LOOKUP, NULL);
00561 Warning("bogus entry deleted from HostDB: missing hostname");
00562 hostDB.delete_block(r);
00563 return false;
00564 }
00565 Debug("hostdb", "hostname = %s", r->hostname());
00566 }
00567
00568 if (!r->is_srv && r->round_robin) {
00569 if (!r->rr()) {
00570 ink_assert(!"missing round-robin");
00571 cont->handleEvent(is_srv ? EVENT_SRV_LOOKUP : EVENT_HOST_DB_LOOKUP, NULL);
00572 Warning("bogus entry deleted from HostDB: missing round-robin");
00573 hostDB.delete_block(r);
00574 return false;
00575 }
00576 ip_text_buffer ipb;
00577 Debug("hostdb", "RR of %d with %d good, 1st IP = %s", r->rr()->rrcount, r->rr()->good, ats_ip_ntop(r->ip(), ipb, sizeof ipb));
00578 }
00579
00580 cont->handleEvent(is_srv ? EVENT_SRV_LOOKUP : EVENT_HOST_DB_LOOKUP, r);
00581
00582 if (!r->full) {
00583 Warning("bogus entry deleted from HostDB: none");
00584 hostDB.delete_block(r);
00585 return false;
00586 }
00587
00588 return true;
00589 }
00590
00591 inline HostResStyle
00592 host_res_style_for(sockaddr const* ip) {
00593 return ats_is_ip6(ip) ? HOST_RES_IPV6_ONLY : HOST_RES_IPV4_ONLY;
00594 }
00595
00596 inline HostResStyle
00597 host_res_style_for(HostDBMark mark) {
00598 return HOSTDB_MARK_IPV4 == mark ? HOST_RES_IPV4_ONLY
00599 : HOSTDB_MARK_IPV6 == mark ? HOST_RES_IPV6_ONLY
00600 : HOST_RES_NONE
00601 ;
00602 }
00603
00604 inline HostDBMark
00605 db_mark_for(HostResStyle style) {
00606 HostDBMark zret = HOSTDB_MARK_GENERIC;
00607 if (HOST_RES_IPV4 == style || HOST_RES_IPV4_ONLY == style)
00608 zret = HOSTDB_MARK_IPV4;
00609 else if (HOST_RES_IPV6 == style || HOST_RES_IPV6_ONLY == style)
00610 zret = HOSTDB_MARK_IPV6;
00611 return zret;
00612 }
00613
00614 inline HostDBMark
00615 db_mark_for(sockaddr const* ip) {
00616 return ats_is_ip6(ip) ? HOSTDB_MARK_IPV6 : HOSTDB_MARK_IPV4;
00617 }
00618
00619 HostDBInfo *
00620 probe(ProxyMutex *mutex, HostDBMD5 const& md5, bool ignore_timeout)
00621 {
00622 ink_assert(this_ethread() == hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets))->thread_holding);
00623 if (hostdb_enable) {
00624 uint64_t folded_md5 = fold_md5(md5.hash);
00625 HostDBInfo *r = hostDB.lookup_block(folded_md5, hostDB.levels);
00626 Debug("hostdb", "probe %.*s %" PRIx64 " %d [ignore_timeout = %d]",
00627 md5.host_len, md5.host_name, folded_md5, !!r, ignore_timeout);
00628 if (r && md5.hash[1] == r->md5_high) {
00629
00630
00631
00632 if (r->is_deleted()) {
00633 Debug("hostdb", "HostDB entry was set as deleted");
00634 return NULL;
00635 } else if (r->failed()) {
00636 Debug("hostdb", "'%.*s' failed", md5.host_len, md5.host_name);
00637 if (r->is_ip_fail_timeout()) {
00638 Debug("hostdb", "fail timeout %u", r->ip_interval());
00639 return NULL;
00640 }
00641 } else if (!ignore_timeout && r->is_ip_timeout() && !r->serve_stale_but_revalidate()) {
00642 Debug("hostdb", "timeout %u %u %u", r->ip_interval(), r->ip_timestamp, r->ip_timeout_interval);
00643 HOSTDB_INCREMENT_DYN_STAT(hostdb_ttl_expires_stat);
00644 return NULL;
00645 }
00646
00647 if (r->reverse_dns && !r->hostname()) {
00648 Debug("hostdb", "missing reverse dns");
00649 hostDB.delete_block(r);
00650 return NULL;
00651 }
00652 if (r->round_robin && !r->rr()) {
00653 Debug("hostdb", "missing round-robin");
00654 hostDB.delete_block(r);
00655 return NULL;
00656 }
00657
00658
00659
00660 if ((!ignore_timeout && r->is_ip_stale()
00661 && !cluster_machine_at_depth(master_hash(md5.hash))
00662 && !r->reverse_dns) || (r->is_ip_timeout() && r->serve_stale_but_revalidate())) {
00663 Debug("hostdb", "stale %u %u %u, using it and refreshing it", r->ip_interval(),
00664 r->ip_timestamp, r->ip_timeout_interval);
00665 r->refresh_ip();
00666 if (!is_dotted_form_hostname(md5.host_name)) {
00667 HostDBContinuation *c = hostDBContAllocator.alloc();
00668 HostDBContinuation::Options copt;
00669 copt.host_res_style = host_res_style_for(r->ip());
00670 c->init(md5, copt);
00671 c->do_dns();
00672 }
00673 }
00674
00675 r->hits++;
00676 if (!r->hits)
00677 r->hits--;
00678 return r;
00679 }
00680 }
00681 return NULL;
00682 }
00683
00684
00685
00686
00687
00688
00689 HostDBInfo *
00690 HostDBContinuation::insert(unsigned int attl)
00691 {
00692 uint64_t folded_md5 = fold_md5(md5.hash);
00693 int bucket = folded_md5 % hostDB.buckets;
00694
00695 ink_assert(this_ethread() == hostDB.lock_for_bucket(bucket)->thread_holding);
00696
00697 HostDBInfo *old_r = hostDB.lookup_block(folded_md5, 3);
00698 if (old_r)
00699 hostDB.delete_block(old_r);
00700 HostDBInfo *r = hostDB.insert_block(folded_md5, NULL, 0);
00701 r->md5_high = md5.hash[1];
00702 if (attl > HOST_DB_MAX_TTL)
00703 attl = HOST_DB_MAX_TTL;
00704 r->ip_timeout_interval = attl;
00705 r->ip_timestamp = hostdb_current_interval;
00706 Debug("hostdb", "inserting for: %.*s: (md5: %" PRIx64 ") bucket: %d now: %u timeout: %u ttl: %u", md5.host_len, md5.host_name, folded_md5, bucket, r->ip_timestamp,
00707 r->ip_timeout_interval, attl);
00708 return r;
00709 }
00710
00711
00712
00713
00714
00715 Action *
00716 HostDBProcessor::getby(Continuation * cont,
00717 const char *hostname, int len, sockaddr const* ip, bool aforce_dns, HostResStyle host_res_style, int dns_lookup_timeout)
00718 {
00719 HostDBMD5 md5;
00720 EThread *thread = this_ethread();
00721 ProxyMutex *mutex = thread->mutex;
00722 ip_text_buffer ipb;
00723
00724 HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat);
00725
00726 if ((!hostdb_enable || (hostname && !*hostname)) || (hostdb_disable_reverse_lookup && ip)) {
00727 MUTEX_TRY_LOCK(lock, cont->mutex, thread);
00728 if (!lock)
00729 goto Lretry;
00730 cont->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
00731 return ACTION_RESULT_DONE;
00732 }
00733
00734
00735 md5.host_name = hostname;
00736 md5.host_len = hostname ? (len ? len : strlen(hostname)) : 0;
00737 md5.ip.assign(ip);
00738 md5.port = ip ? ats_ip_port_host_order(ip) : 0;
00739 md5.db_mark = db_mark_for(host_res_style);
00740 #ifdef SPLIT_DNS
00741 if (hostname && SplitDNSConfig::isSplitDNSEnabled()) {
00742 const char *scan = hostname;
00743
00744 for (; *scan != '\0' && (ParseRules::is_digit(*scan) || '.' == *scan); scan++);
00745 if ('\0' != *scan) {
00746 SplitDNS* pSD = SplitDNSConfig::acquire();
00747 if (0 != pSD)
00748 md5.dns_server = static_cast<DNSServer*>(pSD->getDNSRecord(hostname));
00749 SplitDNSConfig::release(pSD);
00750 }
00751 }
00752 #endif // SPLIT_DNS
00753 md5.refresh();
00754
00755
00756
00757 if (!aforce_dns) {
00758 bool loop;
00759 do {
00760 loop = false;
00761
00762
00763
00764 ProxyMutex *bmutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
00765 MUTEX_TRY_LOCK(lock, bmutex, thread);
00766 MUTEX_TRY_LOCK(lock2, cont->mutex, thread);
00767
00768 if (lock && lock2) {
00769
00770 HostDBInfo *r = probe(bmutex, md5, aforce_dns);
00771 if (r) {
00772 if (r->failed() && hostname)
00773 loop = check_for_retry(md5.db_mark, host_res_style);
00774 if (!loop) {
00775
00776 Debug("hostdb", "immediate answer for %s",
00777 hostname ? hostname
00778 : ats_is_ip(ip) ? ats_ip_ntop(ip, ipb, sizeof ipb)
00779 : "<null>"
00780 );
00781 HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
00782 reply_to_cont(cont, r);
00783 return ACTION_RESULT_DONE;
00784 }
00785 md5.refresh();
00786 }
00787 }
00788 } while (loop);
00789 }
00790 Debug("hostdb", "delaying force %d answer for %s", aforce_dns,
00791 hostname ? hostname
00792 : ats_is_ip(ip) ? ats_ip_ntop(ip, ipb, sizeof ipb)
00793 : "<null>"
00794 );
00795
00796 Lretry:
00797
00798
00799 HostDBContinuation *c = hostDBContAllocator.alloc();
00800 HostDBContinuation::Options opt;
00801 opt.timeout = dns_lookup_timeout;
00802 opt.force_dns = aforce_dns;
00803 opt.cont = cont;
00804 opt.host_res_style = host_res_style;
00805 c->init(md5, opt);
00806 SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent);
00807
00808
00809
00810
00811 if (thread->mutex == cont->mutex) {
00812 thread->schedule_in(c, MUTEX_RETRY_DELAY);
00813 } else {
00814 dnsProcessor.thread->schedule_imm(c);
00815 }
00816
00817 return &c->action;
00818 }
00819
00820
00821
00822
00823 Action *
00824 HostDBProcessor::getbyname_re(Continuation * cont, const char *ahostname, int len, Options const& opt)
00825 {
00826 bool force_dns = false;
00827 EThread *thread = this_ethread();
00828 ProxyMutex *mutex = thread->mutex;
00829
00830 if (opt.flags & HOSTDB_FORCE_DNS_ALWAYS)
00831 force_dns = true;
00832 else if (opt.flags & HOSTDB_FORCE_DNS_RELOAD) {
00833 force_dns = (hostdb_re_dns_on_reload ? true : false);
00834 if (force_dns)
00835 HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat);
00836 }
00837 return getby(cont, ahostname, len, 0, force_dns, opt.host_res_style, opt.timeout);
00838 }
00839
00840
00841
00842 Action *
00843 HostDBProcessor::getSRVbyname_imm(Continuation * cont, process_srv_info_pfn process_srv_info,
00844 const char *hostname, int len, Options const& opt)
00845 {
00846 ink_assert(cont->mutex->thread_holding == this_ethread());
00847 bool force_dns = false;
00848 EThread *thread = cont->mutex->thread_holding;
00849 ProxyMutex *mutex = thread->mutex;
00850
00851 if (opt.flags & HOSTDB_FORCE_DNS_ALWAYS)
00852 force_dns = true;
00853 else if (opt.flags & HOSTDB_FORCE_DNS_RELOAD) {
00854 force_dns = (hostdb_re_dns_on_reload ? true : false);
00855 if (force_dns)
00856 HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat);
00857 }
00858
00859 HostDBMD5 md5;
00860
00861 HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat);
00862
00863 if (!hostdb_enable || !*hostname) {
00864 (cont->*process_srv_info) (NULL);
00865 return ACTION_RESULT_DONE;
00866 }
00867
00868 md5.host_name = hostname;
00869 md5.host_len = hostname ? (len ? len : strlen(hostname)) : 0;
00870 md5.port = 0;
00871 md5.db_mark = HOSTDB_MARK_SRV;
00872 md5.refresh();
00873
00874
00875 if (!force_dns) {
00876
00877 ProxyMutex *bucket_mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
00878 MUTEX_TRY_LOCK(lock, bucket_mutex, thread);
00879
00880
00881 if (lock) {
00882 HostDBInfo *r = probe(bucket_mutex, md5, false);
00883 if (r) {
00884 Debug("hostdb", "immediate SRV answer for %s from hostdb", hostname);
00885 Debug("dns_srv", "immediate SRV answer for %s from hostdb", hostname);
00886 HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
00887 (cont->*process_srv_info) (r);
00888 return ACTION_RESULT_DONE;
00889 }
00890 }
00891 }
00892
00893 Debug("dns_srv", "delaying (force=%d) SRV answer for %.*s [timeout = %d]", force_dns, md5.host_len, md5.host_name, opt.timeout);
00894
00895
00896 HostDBContinuation *c = hostDBContAllocator.alloc();
00897 HostDBContinuation::Options copt;
00898 copt.timeout = opt.timeout;
00899 copt.cont = cont;
00900 copt.force_dns = force_dns;
00901 c->init(md5, copt);
00902 SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent);
00903
00904 if (thread->mutex == cont->mutex) {
00905 thread->schedule_in(c, MUTEX_RETRY_DELAY);
00906 } else {
00907 dnsProcessor.thread->schedule_imm(c);
00908 }
00909
00910 return &c->action;
00911 }
00912
00913
00914
00915
00916 Action *
00917 HostDBProcessor::getbyname_imm(Continuation * cont, process_hostdb_info_pfn process_hostdb_info,
00918 const char *hostname, int len, Options const& opt)
00919 {
00920 ink_assert(cont->mutex->thread_holding == this_ethread());
00921 bool force_dns = false;
00922 EThread *thread = cont->mutex->thread_holding;
00923 ProxyMutex *mutex = thread->mutex;
00924 HostDBMD5 md5;
00925
00926 if (opt.flags & HOSTDB_FORCE_DNS_ALWAYS)
00927 force_dns = true;
00928 else if (opt.flags & HOSTDB_FORCE_DNS_RELOAD) {
00929 force_dns = (hostdb_re_dns_on_reload ? true : false);
00930 if (force_dns)
00931 HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat);
00932 }
00933
00934 HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat);
00935
00936 if (!hostdb_enable || !*hostname) {
00937 (cont->*process_hostdb_info) (NULL);
00938 return ACTION_RESULT_DONE;
00939 }
00940
00941 md5.host_name = hostname;
00942 md5.host_len = hostname ? (len ? len : strlen(hostname)) : 0;
00943 md5.port = opt.port;
00944 md5.db_mark = db_mark_for(opt.host_res_style);
00945 #ifdef SPLIT_DNS
00946 if (SplitDNSConfig::isSplitDNSEnabled()) {
00947 const char *scan = hostname;
00948 for (; *scan != '\0' && (ParseRules::is_digit(*scan) || '.' == *scan); scan++);
00949 if ('\0' != *scan) {
00950 SplitDNS* pSD = SplitDNSConfig::acquire();
00951 if (0 != pSD)
00952 md5.dns_server = static_cast<DNSServer*>(pSD->getDNSRecord(md5.host_name));
00953 SplitDNSConfig::release(pSD);
00954 }
00955 }
00956 #endif // SPLIT_DNS
00957 md5.refresh();
00958
00959
00960 if (!force_dns) {
00961 bool loop;
00962 do {
00963 loop = false;
00964
00965 ProxyMutex *bucket_mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
00966 MUTEX_LOCK(lock, bucket_mutex, thread);
00967
00968 if (lock) {
00969
00970 HostDBInfo *r = probe(bucket_mutex, md5, false);
00971 if (r) {
00972 if (r->failed())
00973 loop = check_for_retry(md5.db_mark, opt.host_res_style);
00974 if (!loop) {
00975
00976 Debug("hostdb", "immediate answer for %.*s", md5.host_len, md5.host_name);
00977 HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
00978 (cont->*process_hostdb_info) (r);
00979 return ACTION_RESULT_DONE;
00980 }
00981 md5.refresh();
00982 }
00983 }
00984 } while (loop);
00985 }
00986
00987 Debug("hostdb", "delaying force %d answer for %.*s [timeout %d]", force_dns, md5.host_len, md5.host_name, opt.timeout);
00988
00989
00990 HostDBContinuation *c = hostDBContAllocator.alloc();
00991 HostDBContinuation::Options copt;
00992 copt.cont = cont;
00993 copt.force_dns = force_dns;
00994 copt.timeout = opt.timeout;
00995 copt.host_res_style = opt.host_res_style;
00996 c->init(md5, copt);
00997 SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent);
00998
00999 thread->schedule_in(c, HOST_DB_RETRY_PERIOD);
01000
01001 return &c->action;
01002 }
01003
01004
01005 static void
01006 do_setby(HostDBInfo * r, HostDBApplicationInfo * app, const char *hostname, IpAddr const& ip, bool is_srv = false)
01007 {
01008 HostDBRoundRobin *rr = r->rr();
01009
01010 if (is_srv && (!r->is_srv || !rr))
01011 return;
01012
01013 if (rr) {
01014 if (is_srv) {
01015 uint32_t key = makeHostHash(hostname);
01016 for (int i = 0; i < rr->rrcount; i++) {
01017 if (key == rr->info[i].data.srv.key && !strcmp(hostname, rr->info[i].srvname(rr))) {
01018 Debug("hostdb", "immediate setby for %s", hostname);
01019 rr->info[i].app.allotment.application1 = app->allotment.application1;
01020 rr->info[i].app.allotment.application2 = app->allotment.application2;
01021 return;
01022 }
01023 }
01024 } else
01025 for (int i = 0; i < rr->rrcount; i++) {
01026 if (rr->info[i].ip() == ip) {
01027 Debug("hostdb", "immediate setby for %s", hostname ? hostname : "<addr>");
01028 rr->info[i].app.allotment.application1 = app->allotment.application1;
01029 rr->info[i].app.allotment.application2 = app->allotment.application2;
01030 return;
01031 }
01032 }
01033 } else {
01034 if (r->reverse_dns || (!r->round_robin && ip == r->ip())) {
01035 Debug("hostdb", "immediate setby for %s", hostname ? hostname : "<addr>");
01036 r->app.allotment.application1 = app->allotment.application1;
01037 r->app.allotment.application2 = app->allotment.application2;
01038 }
01039 }
01040 }
01041
01042
01043 void
01044 HostDBProcessor::setby(const char *hostname, int len, sockaddr const* ip, HostDBApplicationInfo * app)
01045 {
01046 if (!hostdb_enable)
01047 return;
01048
01049 HostDBMD5 md5;
01050 md5.host_name = hostname;
01051 md5.host_len = hostname ? (len ? len : strlen(hostname)) : 0;
01052 md5.ip.assign(ip);
01053 md5.port = ip ? ats_ip_port_host_order(ip) : 0;
01054 md5.db_mark = db_mark_for(ip);
01055 md5.refresh();
01056
01057
01058
01059 ProxyMutex *mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
01060 EThread *thread = this_ethread();
01061 MUTEX_TRY_LOCK(lock, mutex, thread);
01062
01063 if (lock) {
01064 HostDBInfo *r = probe(mutex, md5, false);
01065 if (r)
01066 do_setby(r, app, hostname, md5.ip);
01067 return;
01068 }
01069
01070
01071 HostDBContinuation *c = hostDBContAllocator.alloc();
01072 c->init(md5);
01073 c->app.allotment.application1 = app->allotment.application1;
01074 c->app.allotment.application2 = app->allotment.application2;
01075 SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::setbyEvent);
01076 thread->schedule_in(c, MUTEX_RETRY_DELAY);
01077 }
01078
01079 void
01080 HostDBProcessor::setby_srv(const char *hostname, int len, const char *target, HostDBApplicationInfo * app)
01081 {
01082 if (!hostdb_enable || !hostname || !target)
01083 return;
01084
01085 HostDBMD5 md5;
01086 md5.host_name = hostname;
01087 md5.host_len = len ? len : strlen(hostname);
01088 md5.port = 0;
01089 md5.db_mark = HOSTDB_MARK_SRV;
01090 md5.refresh();
01091
01092
01093
01094 HostDBContinuation *c = hostDBContAllocator.alloc();
01095 c->init(md5);
01096 ink_strlcpy(c->srv_target_name, target, MAXDNAME);
01097 c->app.allotment.application1 = app->allotment.application1;
01098 c->app.allotment.application2 = app->allotment.application2;
01099 SET_CONTINUATION_HANDLER(c,
01100 (HostDBContHandler) & HostDBContinuation::setbyEvent);
01101 eventProcessor.schedule_imm(c);
01102 }
01103 int
01104 HostDBContinuation::setbyEvent(int , Event * )
01105 {
01106 HostDBInfo *r = probe(mutex, md5, false);
01107
01108 if (r)
01109 do_setby(r, &app, md5.host_name, md5.ip, is_srv());
01110
01111 hostdb_cont_free(this);
01112 return EVENT_DONE;
01113 }
01114
01115
01116 static int
01117 remove_round_robin(HostDBInfo * r, const char *hostname, IpAddr const& ip)
01118 {
01119 if (r) {
01120 if (!r->round_robin)
01121 return false;
01122 HostDBRoundRobin *rr = r->rr();
01123 if (!rr)
01124 return false;
01125 for (int i = 0; i < rr->good; i++) {
01126 if (ip == rr->info[i].ip()) {
01127 ip_text_buffer b;
01128 Debug("hostdb", "Deleting %s from '%s' round robin DNS entry", ip.toString(b, sizeof b), hostname);
01129 HostDBInfo tmp = rr->info[i];
01130 rr->info[i] = rr->info[rr->good - 1];
01131 rr->info[rr->good - 1] = tmp;
01132 rr->good--;
01133 if (rr->good <= 0) {
01134 hostDB.delete_block(r);
01135 return false;
01136 } else {
01137 if (diags->on("hostdb")) {
01138 int bufsize = rr->good * INET6_ADDRSTRLEN;
01139 char *rr_ip_list = (char *) alloca(bufsize);
01140 char *p = rr_ip_list;
01141 for (int n = 0; n < rr->good; ++n) {
01142 ats_ip_ntop(rr->info[n].ip(), p, bufsize);
01143 int nbytes = strlen(p);
01144 p += nbytes;
01145 bufsize -= nbytes;
01146 }
01147 Note("'%s' round robin DNS entry updated, entries=%d, IP list: %s", hostname, rr->good, rr_ip_list);
01148 }
01149 }
01150 return true;
01151 }
01152 }
01153 }
01154 return false;
01155 }
01156
01157 # if 0
01158 Action *
01159 HostDBProcessor::failed_connect_on_ip_for_name(Continuation * cont, sockaddr const* ip, const char *hostname, int len)
01160 {
01161 HostDBMD5 md5;
01162 md5.host_name = hostname;
01163 md5.host_len = hostname ? (len ? len : strlen(hostname)) : 0;
01164 md5.ip.assign(ip);
01165 md5.port = ip ? ats_ip_port_host_order(ip) : 0;
01166 md5.db_mark = db_mark_for(ip);
01167 #ifdef SPLIT_DNS
01168 SplitDNS *pSD = 0;
01169 if (hostname && SplitDNSConfig::isSplitDNSEnabled()) {
01170 pSD = SplitDNSConfig::acquire();
01171
01172 if (0 != pSD)
01173 md5.dns_server = static_cast<DNSServer*>(pSD->getDNSRecord(hostname));
01174 SplitDNSConfig::release(pSD);
01175 }
01176 #endif // SPLIT_DNS
01177 md5.refresh();
01178
01179 ProxyMutex *mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
01180 EThread *thread = this_ethread();
01181 MUTEX_TRY_LOCK(lock, mutex, thread);
01182 if (lock) {
01183 if (!hostdb_enable || NULL == md5.dns_server) {
01184 if (cont)
01185 cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, (void *) NULL);
01186 return ACTION_RESULT_DONE;
01187 }
01188 HostDBInfo *r = probe(mutex, md5, false);
01189 bool res = (remove_round_robin(r, hostname, ip) ? true : false);
01190 if (cont)
01191 cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, res ? (void *) ip : (void *) NULL);
01192 return ACTION_RESULT_DONE;
01193 }
01194 HostDBContinuation *c = hostDBContAllocator.alloc();
01195 HostDBContinuation::Options copt;
01196 copt.cont = cont;
01197 c->init(md5, copt);
01198 SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::removeEvent);
01199 thread->schedule_in(c, MUTEX_RETRY_DELAY);
01200 return &c->action;
01201 }
01202 #endif
01203
01204 int
01205 HostDBContinuation::removeEvent(int , Event * e)
01206 {
01207 Continuation *cont = action.continuation;
01208
01209 MUTEX_TRY_LOCK(lock, cont ? (ProxyMutex *) cont->mutex : (ProxyMutex *) NULL, e->ethread);
01210 if (!lock) {
01211 e->schedule_in(HOST_DB_RETRY_PERIOD);
01212 return EVENT_CONT;
01213 }
01214 if (!action.cancelled) {
01215 if (!hostdb_enable) {
01216 if (cont)
01217 cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, (void *) NULL);
01218 } else {
01219 HostDBInfo *r = probe(mutex, md5, false);
01220 bool res = (remove_round_robin(r, md5.host_name, md5.ip) ? true : false);
01221 if (cont)
01222 cont->handleEvent(
01223 EVENT_HOST_DB_IP_REMOVED,
01224 res ? static_cast<void *>(&md5.ip) : static_cast<void *>(NULL)
01225 );
01226 }
01227 }
01228 hostdb_cont_free(this);
01229 return EVENT_DONE;
01230 }
01231
01232
01233
01234
01235
01236 HostDBInfo *
01237 HostDBContinuation::lookup_done(IpAddr const& ip, char const* aname, bool around_robin, unsigned int ttl_seconds, SRVHosts * srv)
01238 {
01239 HostDBInfo *i = NULL;
01240
01241 ink_assert(this_ethread() == hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets))->thread_holding);
01242 if (!ip.isValid() || !aname || !aname[0]) {
01243 if (is_byname()) {
01244 Debug("hostdb", "lookup_done() failed for '%.*s'", md5.host_len, md5.host_name);
01245 } else if (is_srv()) {
01246 Debug("dns_srv", "SRV failed for '%.*s'", md5.host_len, md5.host_name);
01247 } else {
01248 ip_text_buffer b;
01249 Debug("hostdb", "failed for %s", md5.ip.toString(b, sizeof b));
01250 }
01251 i = insert(hostdb_ip_fail_timeout_interval);
01252 i->round_robin = false;
01253 i->is_srv = is_srv();
01254 i->reverse_dns = !is_byname() && !is_srv();
01255
01256 i->set_failed();
01257 } else {
01258 switch (hostdb_ttl_mode) {
01259 default:
01260 ink_assert(!"bad TTL mode");
01261 case TTL_OBEY:
01262 break;
01263 case TTL_IGNORE:
01264 ttl_seconds = hostdb_ip_timeout_interval * 60;
01265 break;
01266 case TTL_MIN:
01267 if (hostdb_ip_timeout_interval * 60 < ttl_seconds)
01268 ttl_seconds = hostdb_ip_timeout_interval * 60;
01269 break;
01270 case TTL_MAX:
01271 if (hostdb_ip_timeout_interval * 60 > ttl_seconds)
01272 ttl_seconds = hostdb_ip_timeout_interval * 60;
01273 break;
01274 }
01275 HOSTDB_SUM_DYN_STAT(hostdb_ttl_stat, ttl_seconds);
01276 if (!ttl_seconds)
01277 ttl_seconds = 1;
01278 i = insert(ttl_seconds);
01279 if (is_byname()) {
01280 ip_text_buffer b;
01281 Debug("hostdb", "done %s TTL %d", ip.toString(b, sizeof b), ttl_seconds);
01282 ats_ip_set(i->ip(), ip);
01283 i->round_robin = around_robin;
01284 i->reverse_dns = false;
01285 if (md5.host_name != aname) {
01286 ink_strlcpy(md5_host_name_store, aname, sizeof(md5_host_name_store));
01287 }
01288 i->is_srv = false;
01289 } else if (is_srv()) {
01290 ink_assert(srv && srv->srv_host_count > 0 && srv->srv_host_count <= 16 && around_robin);
01291
01292 i->data.srv.srv_offset = srv->srv_host_count;
01293 i->reverse_dns = false;
01294 i->is_srv = true;
01295 i->round_robin = around_robin;
01296
01297 if (md5.host_name != aname) {
01298 ink_strlcpy(md5_host_name_store, aname, sizeof(md5_host_name_store));
01299 }
01300
01301 } else {
01302 Debug("hostdb", "done '%s' TTL %d", aname, ttl_seconds);
01303 const size_t s_size = strlen(aname) + 1;
01304 void *s = hostDB.alloc(&i->data.hostname_offset, s_size);
01305 if (s) {
01306 ink_strlcpy((char *) s, aname, s_size);
01307 i->round_robin = false;
01308 i->reverse_dns = true;
01309 i->is_srv = false;
01310 } else {
01311 ink_assert(!"out of room in hostdb data area");
01312 Warning("out of room in hostdb for reverse DNS data");
01313 hostDB.delete_block(i);
01314 return NULL;
01315 }
01316 }
01317 }
01318 if (from_cont)
01319 do_put_response(from, i, from_cont);
01320 ink_assert(!i->round_robin || !i->reverse_dns);
01321 return i;
01322 }
01323
01324
01325 int
01326 HostDBContinuation::dnsPendingEvent(int event, Event * e)
01327 {
01328 ink_assert(this_ethread() == hostDB.lock_for_bucket(fold_md5(md5.hash) % hostDB.buckets)->thread_holding);
01329 if (timeout) {
01330 timeout->cancel(this);
01331 timeout = NULL;
01332 }
01333 if (event == EVENT_INTERVAL) {
01334
01335 MUTEX_TRY_LOCK_FOR(lock, action.mutex, ((Event *) e)->ethread, action.continuation);
01336 if (!lock) {
01337 timeout = eventProcessor.schedule_in(this, HOST_DB_RETRY_PERIOD);
01338 return EVENT_CONT;
01339 }
01340 if (!action.cancelled && action.continuation)
01341 action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
01342 hostDB.pending_dns_for_hash(md5.hash).remove(this);
01343 hostdb_cont_free(this);
01344 return EVENT_DONE;
01345 } else {
01346 SET_HANDLER((HostDBContHandler) & HostDBContinuation::probeEvent);
01347 return probeEvent(EVENT_INTERVAL, NULL);
01348 }
01349 }
01350
01351 static int
01352 restore_info(HostDBInfo * r, HostDBInfo * old_r, HostDBInfo & old_info, HostDBRoundRobin * old_rr_data)
01353 {
01354 if (old_rr_data) {
01355 for (int j = 0; j < old_rr_data->rrcount; j++)
01356 if (ats_ip_addr_eq(old_rr_data->info[j].ip(), r->ip())) {
01357 r->app = old_rr_data->info[j].app;
01358 return true;
01359 }
01360 } else if (old_r)
01361 if (ats_ip_addr_eq(old_info.ip(), r->ip())) {
01362 r->app = old_info.app;
01363 return true;
01364 }
01365 return false;
01366 }
01367
01368
01369
01370
01371 int
01372 HostDBContinuation::dnsEvent(int event, HostEnt * e)
01373 {
01374 ink_assert(this_ethread() == hostDB.lock_for_bucket(fold_md5(md5.hash) % hostDB.buckets)->thread_holding);
01375 if (timeout) {
01376 timeout->cancel(this);
01377 timeout = NULL;
01378 }
01379 EThread *thread = mutex->thread_holding;
01380 if (event == EVENT_INTERVAL) {
01381 if (!action.continuation) {
01382
01383 remove_trigger_pending_dns();
01384 hostdb_cont_free(this);
01385 return EVENT_DONE;
01386 }
01387 MUTEX_TRY_LOCK_FOR(lock, action.mutex, thread, action.continuation);
01388 if (!lock) {
01389 timeout = thread->schedule_in(this, HOST_DB_RETRY_PERIOD);
01390 return EVENT_CONT;
01391 }
01392
01393
01394
01395
01396 if (!action.cancelled && action.continuation)
01397 action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
01398 action = NULL;
01399
01400 timeout = thread->schedule_in(this, HRTIME_SECONDS(hostdb_insert_timeout));
01401 return EVENT_DONE;
01402 } else {
01403 bool failed = !e;
01404
01405 bool rr = false;
01406 pending_action = NULL;
01407
01408 if (is_srv()) {
01409 rr = !failed && (e->srv_hosts.srv_host_count > 0);
01410 } else if (!failed) {
01411 rr = 0 != e->ent.h_addr_list[1];
01412 } else {
01413 }
01414
01415 ttl = failed ? 0 : e->ttl / 60;
01416 int ttl_seconds = failed ? 0 : e->ttl;
01417
01418 HostDBInfo *old_r = probe(mutex, md5, true);
01419 HostDBInfo old_info;
01420 if (old_r)
01421 old_info = *old_r;
01422 HostDBRoundRobin *old_rr_data = old_r ? old_r->rr() : NULL;
01423 #ifdef DEBUG
01424 if (old_rr_data) {
01425 for (int i = 0; i < old_rr_data->rrcount; ++i) {
01426 if (old_r->md5_high != old_rr_data->info[i].md5_high ||
01427 old_r->md5_low != old_rr_data->info[i].md5_low ||
01428 old_r->md5_low_low != old_rr_data->info[i].md5_low_low)
01429 ink_assert(0);
01430 }
01431 }
01432 #endif
01433 int n = 0, nn = 0;
01434 void* first = 0;
01435 uint8_t af = e ? e->ent.h_addrtype : AF_UNSPEC;
01436 if (rr) {
01437 if (is_srv() && !failed) {
01438 n = e->srv_hosts.srv_host_count;
01439 } else {
01440 void* ptr;
01441 for (
01442 ; nn < HOST_DB_MAX_ROUND_ROBIN_INFO
01443 && 0 != (ptr = e->ent.h_addr_list[nn])
01444 ; ++nn
01445 ) {
01446 if (is_addr_valid(af, ptr)) {
01447 if (! first) first = ptr;
01448 ++n;
01449 } else {
01450 Warning("Zero address removed from round-robin list for '%s'", md5.host_name);
01451 }
01452
01453
01454
01455 }
01456 if (!first) {
01457 failed = true;
01458 rr = false;
01459 }
01460 }
01461 } else if (!failed) {
01462 first = e->ent.h_addr_list[0];
01463 }
01464
01465 HostDBInfo *r = NULL;
01466 IpAddr tip;
01467
01468 if (is_byname()) {
01469 if (first) ip_addr_set(tip, af, first);
01470 r = lookup_done(tip, md5.host_name, rr, ttl_seconds, failed ? 0 : &e->srv_hosts);
01471 } else if (is_srv()) {
01472 if (!failed)
01473 tip._family = AF_INET;
01474 r = lookup_done(tip,
01475 md5.host_name,
01476 rr,
01477 ttl_seconds,
01478 failed ? 0 : &e->srv_hosts);
01479 } else if (failed) {
01480 r = lookup_done(tip, md5.host_name, false, ttl_seconds, 0);
01481 } else {
01482 r = lookup_done(md5.ip, e->ent.h_name, false, ttl_seconds, &e->srv_hosts);
01483 }
01484
01485
01486 ink_assert(r && r->app.allotment.application1 == 0 && r->app.allotment.application2 == 0);
01487
01488 if (rr) {
01489 const int rrsize = HostDBRoundRobin::size(n, e->srv_hosts.srv_hosts_length);
01490 HostDBRoundRobin *rr_data = (HostDBRoundRobin *) hostDB.alloc(&r->app.rr.offset, rrsize);
01491
01492 Debug("hostdb", "allocating %d bytes for %d RR at %p %d", rrsize, n, rr_data, r->app.rr.offset);
01493
01494 if (rr_data) {
01495 rr_data->length = rrsize;
01496 int i = 0, ii = 0;
01497 if (is_srv()) {
01498 int skip = 0;
01499 char *pos = (char *) rr_data + sizeof(HostDBRoundRobin) + n * sizeof(HostDBInfo);
01500 SRV *q[HOST_DB_MAX_ROUND_ROBIN_INFO];
01501 ink_assert(n <= HOST_DB_MAX_ROUND_ROBIN_INFO);
01502
01503 for (i = 0; i < n; ++i) {
01504 q[i] = &e->srv_hosts.hosts[i];
01505 }
01506 for (i = 0; i < n; ++i) {
01507 for (ii = i + 1; ii < n; ++ii) {
01508 if (*q[ii] < *q[i]) {
01509 SRV *tmp = q[i];
01510 q[i] = q[ii];
01511 q[ii] = tmp;
01512 }
01513 }
01514 }
01515
01516 for (i = 0; i < n; ++i) {
01517 SRV *t = q[i];
01518 HostDBInfo& item = rr_data->info[i];
01519
01520 memset(&item, 0, sizeof(item));
01521 item.round_robin = 0;
01522 item.reverse_dns = 0;
01523 item.is_srv = 1;
01524 item.data.srv.srv_weight = t->weight;
01525 item.data.srv.srv_priority = t->priority;
01526 item.data.srv.srv_port = t->port;
01527 item.data.srv.key = t->key;
01528
01529 ink_assert((skip + t->host_len) <= e->srv_hosts.srv_hosts_length);
01530
01531 memcpy(pos + skip, t->host, t->host_len);
01532 item.data.srv.srv_offset = (pos - (char *) rr_data) + skip;
01533
01534 skip += t->host_len;
01535
01536 item.md5_high = r->md5_high;
01537 item.md5_low = r->md5_low;
01538 item.md5_low_low = r->md5_low_low;
01539 item.full = 1;
01540
01541 item.app.allotment.application1 = 0;
01542 item.app.allotment.application2 = 0;
01543 Debug("dns_srv", "inserted SRV RR record [%s] into HostDB with TTL: %d seconds", t->host, ttl_seconds);
01544 }
01545 rr_data->good = rr_data->rrcount = n;
01546 rr_data->current = 0;
01547
01548
01549 if (old_rr_data) {
01550 for (i = 0; i < rr_data->rrcount; ++i) {
01551 for (ii = 0; ii < old_rr_data->rrcount; ++ii) {
01552 if (rr_data->info[i].data.srv.key == old_rr_data->info[ii].data.srv.key) {
01553 char *new_host = rr_data->info[i].srvname(rr_data);
01554 char *old_host = old_rr_data->info[ii].srvname(old_rr_data);
01555 if (!strcmp(new_host, old_host))
01556 rr_data->info[i].app = old_rr_data->info[ii].app;
01557 }
01558 }
01559 }
01560 }
01561 } else {
01562 for (ii = 0; ii < nn; ++ii) {
01563 if (is_addr_valid(af, e->ent.h_addr_list[ii])) {
01564 HostDBInfo& item = rr_data->info[i];
01565 ip_addr_set(item.ip(), af, e->ent.h_addr_list[ii]);
01566
01567 item.full = 1;
01568 item.round_robin = 0;
01569 item.reverse_dns = 0;
01570 item.is_srv = 0;
01571 item.md5_high = r->md5_high;
01572 item.md5_low = r->md5_low;
01573 item.md5_low_low = r->md5_low_low;
01574 if (!restore_info(&item, old_r, old_info, old_rr_data)) {
01575 item.app.allotment.application1 = 0;
01576 item.app.allotment.application2 = 0;
01577 }
01578 ++i;
01579 }
01580 }
01581 rr_data->good = rr_data->rrcount = n;
01582 rr_data->current = 0;
01583 }
01584 } else {
01585 ink_assert(!"out of room in hostdb data area");
01586 Warning("out of room in hostdb for round-robin DNS data");
01587 r->round_robin = 0;
01588 }
01589 }
01590 if (!failed && !rr && !is_srv())
01591 restore_info(r, old_r, old_info, old_rr_data);
01592 ink_assert(!r || !r->round_robin || !r->reverse_dns);
01593 ink_assert(failed || !r->round_robin || r->app.rr.offset);
01594
01595
01596
01597 ClusterMachine *m = cluster_machine_at_depth(master_hash(md5.hash));
01598 if (m)
01599 do_put_response(m, r, NULL);
01600
01601
01602
01603 if (action.continuation) {
01604
01605 if (failed && check_for_retry(md5.db_mark, host_res_style)) {
01606 this->refresh_MD5();
01607 SET_CONTINUATION_HANDLER(this, (HostDBContHandler) & HostDBContinuation::probeEvent);
01608 thread->schedule_in(this, MUTEX_RETRY_DELAY);
01609 return EVENT_CONT;
01610 }
01611
01612 MUTEX_TRY_LOCK_FOR(lock, action.mutex, thread, action.continuation);
01613 if (!lock) {
01614 remove_trigger_pending_dns();
01615 SET_HANDLER((HostDBContHandler) & HostDBContinuation::probeEvent);
01616 thread->schedule_in(this, HOST_DB_RETRY_PERIOD);
01617 return EVENT_CONT;
01618 }
01619 if (!action.cancelled)
01620 reply_to_cont(action.continuation, r, is_srv());
01621 }
01622
01623 remove_trigger_pending_dns();
01624
01625
01626
01627 hostdb_cont_free(this);
01628 return EVENT_DONE;
01629 }
01630 }
01631
01632
01633
01634
01635
01636
01637 struct HostDB_get_message {
01638 INK_MD5 md5;
01639 IpEndpoint ip;
01640 Continuation *cont;
01641 int namelen;
01642 char name[MAXDNAME];
01643 };
01644
01645
01646
01647
01648
01649 int
01650 HostDBContinuation::make_get_message(char *buf, int size)
01651 {
01652 ink_assert(size >= (int) sizeof(HostDB_get_message));
01653
01654 HostDB_get_message *msg = reinterpret_cast<HostDB_get_message *>(buf);
01655 msg->md5 = md5.hash;
01656 ats_ip_set(&msg->ip.sa, md5.ip, htons(md5.port));
01657 msg->cont = this;
01658
01659
01660 ink_strlcpy(msg->name, md5.host_name, sizeof(msg->name));
01661
01662
01663 int len = sizeof(HostDB_get_message) - MAXDNAME + md5.host_len + 1;
01664
01665 return len;
01666 }
01667
01668
01669
01670
01671
01672 bool HostDBContinuation::do_get_response(Event * )
01673 {
01674 if (!hostdb_cluster)
01675 return false;
01676
01677
01678
01679 ClusterMachine *m = NULL;
01680
01681 if (hostdb_migrate_on_demand) {
01682 m = cluster_machine_at_depth(master_hash(md5.hash), &probe_depth, past_probes);
01683 } else {
01684 if (probe_depth)
01685 return false;
01686 m = cluster_machine_at_depth(master_hash(md5.hash));
01687 probe_depth = 1;
01688 }
01689
01690 if (!m)
01691 return false;
01692
01693
01694
01695 HostDB_get_message msg;
01696
01697 memset(&msg, 0, sizeof(msg));
01698 int len = make_get_message((char *) &msg, sizeof(HostDB_get_message));
01699
01700
01701
01702 remoteHostDBQueue[key_partition()].enqueue(this);
01703 SET_HANDLER((HostDBContHandler) & HostDBContinuation::clusterEvent);
01704 timeout = mutex->thread_holding->schedule_in(this, HOST_DB_CLUSTER_TIMEOUT);
01705
01706
01707
01708 clusterProcessor.invoke_remote(m->pop_ClusterHandler(), GET_HOSTINFO_CLUSTER_FUNCTION, (char *) &msg, len);
01709
01710 return true;
01711 }
01712
01713
01714
01715
01716
01717
01718
01719 struct HostDB_put_message {
01720 INK_MD5 md5;
01721 IpEndpoint ip;
01722 unsigned int ttl;
01723 unsigned int missing:1;
01724 unsigned int round_robin:1;
01725 Continuation* cont;
01726 unsigned int application1;
01727 unsigned int application2;
01728 int namelen;
01729 char name[MAXDNAME];
01730 };
01731
01732
01733
01734
01735
01736 int
01737 HostDBContinuation::make_put_message(HostDBInfo * r, Continuation * c, char *buf, int size)
01738 {
01739 ink_assert(size >= (int) sizeof(HostDB_put_message));
01740
01741 HostDB_put_message *msg = reinterpret_cast<HostDB_put_message *>(buf);
01742 memset(msg, 0, sizeof(HostDB_put_message));
01743
01744 msg->md5 = md5.hash;
01745 msg->cont = c;
01746 if (r) {
01747 ats_ip_copy(&msg->ip.sa, r->ip());
01748 msg->application1 = r->app.allotment.application1;
01749 msg->application2 = r->app.allotment.application2;
01750 msg->missing = false;
01751 msg->round_robin = r->round_robin;
01752 msg->ttl = r->ip_time_remaining();
01753 } else {
01754 msg->missing = true;
01755 }
01756
01757
01758 ink_strlcpy(msg->name, md5.host_name, sizeof(msg->name));
01759
01760
01761 int len = sizeof(HostDB_put_message) - MAXDNAME + md5.host_len + 1;
01762
01763 return len;
01764 }
01765
01766
01767
01768
01769
01770 void
01771 HostDBContinuation::do_put_response(ClusterMachine * m, HostDBInfo * r, Continuation * c)
01772 {
01773
01774
01775 if (!hostdb_cluster || (!c && r->round_robin && !hostdb_cluster_round_robin))
01776 return;
01777
01778 HostDB_put_message msg;
01779 int len = make_put_message(r, c, (char *) &msg, sizeof(HostDB_put_message));
01780
01781 clusterProcessor.invoke_remote(m->pop_ClusterHandler(), PUT_HOSTINFO_CLUSTER_FUNCTION, (char *) &msg, len);
01782
01783 }
01784
01785
01786
01787
01788
01789 int
01790 HostDBContinuation::probeEvent(int , Event * e)
01791 {
01792 ink_assert(!link.prev && !link.next);
01793 EThread *t = e ? e->ethread : this_ethread();
01794
01795 MUTEX_TRY_LOCK_FOR(lock, action.mutex, t, action.continuation);
01796 if (!lock) {
01797 mutex->thread_holding->schedule_in(this, HOST_DB_RETRY_PERIOD);
01798 return EVENT_CONT;
01799 }
01800
01801 if (action.cancelled) {
01802 hostdb_cont_free(this);
01803 return EVENT_DONE;
01804 }
01805
01806 if (!hostdb_enable || (!*md5.host_name && !md5.ip.isValid())) {
01807 if (action.continuation)
01808 action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
01809 if (from)
01810 do_put_response(from, 0, from_cont);
01811 hostdb_cont_free(this);
01812 return EVENT_DONE;
01813 }
01814
01815 if (!force_dns) {
01816
01817
01818
01819 HostDBInfo *r = probe(mutex, md5, false);
01820
01821 if (r)
01822 HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
01823
01824 if (action.continuation && r)
01825 reply_to_cont(action.continuation, r);
01826
01827
01828
01829 if (from)
01830 do_put_response(from, r, from_cont);
01831
01832
01833
01834 if (r || from) {
01835 hostdb_cont_free(this);
01836 return EVENT_DONE;
01837 }
01838
01839
01840 if (do_get_response(e))
01841 return EVENT_CONT;
01842 }
01843
01844
01845 do_dns();
01846 return EVENT_DONE;
01847 }
01848
01849
01850 int
01851 HostDBContinuation::set_check_pending_dns()
01852 {
01853 Queue<HostDBContinuation> &q = hostDB.pending_dns_for_hash(md5.hash);
01854 HostDBContinuation *c = q.head;
01855 for (; c; c = (HostDBContinuation *) c->link.next) {
01856 if (md5.hash == c->md5.hash) {
01857 Debug("hostdb", "enqueuing additional request");
01858 q.enqueue(this);
01859 return false;
01860 }
01861 }
01862 q.enqueue(this);
01863 return true;
01864 }
01865
01866
01867 void
01868 HostDBContinuation::remove_trigger_pending_dns()
01869 {
01870 Queue<HostDBContinuation> &q = hostDB.pending_dns_for_hash(md5.hash);
01871 q.remove(this);
01872 HostDBContinuation *c = q.head;
01873 Queue<HostDBContinuation> qq;
01874 while (c) {
01875 HostDBContinuation *n = (HostDBContinuation *) c->link.next;
01876 if (md5.hash == c->md5.hash) {
01877 Debug("hostdb", "dequeuing additional request");
01878 q.remove(c);
01879 qq.enqueue(c);
01880 }
01881 c = n;
01882 }
01883 while ((c = qq.dequeue()))
01884 c->handleEvent(EVENT_IMMEDIATE, NULL);
01885 }
01886
01887
01888
01889
01890
01891 void
01892 HostDBContinuation::do_dns()
01893 {
01894 ink_assert(!action.cancelled);
01895 if (is_byname()) {
01896 Debug("hostdb", "DNS %s", md5.host_name);
01897 IpAddr tip;
01898 if (0 == tip.load(md5.host_name)) {
01899
01900 if (action.continuation) {
01901 HostDBInfo *r = lookup_done(tip, md5.host_name, false, HOST_DB_MAX_TTL, NULL);
01902 reply_to_cont(action.continuation, r);
01903 }
01904 hostdb_cont_free(this);
01905 return;
01906 }
01907 }
01908 if (hostdb_lookup_timeout)
01909 timeout = mutex->thread_holding->schedule_in(this, HRTIME_SECONDS(hostdb_lookup_timeout));
01910 else
01911 timeout = NULL;
01912 if (set_check_pending_dns()) {
01913 DNSProcessor::Options opt;
01914 opt.timeout = dns_lookup_timeout;
01915 opt.host_res_style = host_res_style_for(md5.db_mark);
01916 SET_HANDLER((HostDBContHandler) & HostDBContinuation::dnsEvent);
01917 if (is_byname()) {
01918 if (md5.dns_server)
01919 opt.handler = md5.dns_server->x_dnsH;
01920 pending_action = dnsProcessor.gethostbyname(this, md5.host_name, opt);
01921 } else if (is_srv()) {
01922 Debug("dns_srv", "SRV lookup of %s", md5.host_name);
01923 pending_action = dnsProcessor.getSRVbyname(this, md5.host_name, opt);
01924 } else {
01925 ip_text_buffer ipb;
01926 Debug("hostdb", "DNS IP %s", md5.ip.toString(ipb, sizeof ipb));
01927 pending_action = dnsProcessor.gethostbyaddr(this, &md5.ip, opt);
01928 }
01929 } else {
01930 SET_HANDLER((HostDBContHandler) & HostDBContinuation::dnsPendingEvent);
01931 }
01932 }
01933
01934
01935
01936
01937
01938 int
01939 HostDBContinuation::clusterResponseEvent(int, Event * e)
01940 {
01941 if (from_cont) {
01942 HostDBContinuation *c;
01943 for (c = (HostDBContinuation *) remoteHostDBQueue[key_partition()].head; c; c = (HostDBContinuation *) c->link.next)
01944 if (c == from_cont)
01945 break;
01946
01947
01948
01949 if (c) {
01950 action = c;
01951 from_cont = 0;
01952 MUTEX_TRY_LOCK(lock, c->mutex, e->ethread);
01953 MUTEX_TRY_LOCK(lock2, c->action.mutex, e->ethread);
01954 if (!lock || !lock2) {
01955 e->schedule_in(HOST_DB_RETRY_PERIOD);
01956 return EVENT_CONT;
01957 }
01958 bool failed = missing || (round_robin && !hostdb_cluster_round_robin);
01959 action.continuation->handleEvent(EVENT_HOST_DB_GET_RESPONSE, failed ? 0 : this);
01960 }
01961 } else {
01962 action = 0;
01963
01964 ink_assert(!missing);
01965 lookup_done(md5.ip, md5.host_name, false, ttl, NULL);
01966 }
01967 hostdb_cont_free(this);
01968 return EVENT_DONE;
01969 }
01970
01971
01972
01973
01974
01975 int
01976 HostDBContinuation::clusterEvent(int event, Event * e)
01977 {
01978
01979
01980 remoteHostDBQueue[key_partition()].remove(this);
01981
01982 switch (event) {
01983 default:
01984 ink_assert(!"bad case");
01985 hostdb_cont_free(this);
01986 return EVENT_DONE;
01987
01988
01989
01990 case EVENT_HOST_DB_GET_RESPONSE:
01991 if (timeout) {
01992 timeout->cancel(this);
01993 timeout = NULL;
01994 }
01995 if (e) {
01996 HostDBContinuation *c = (HostDBContinuation *) e;
01997 HostDBInfo *r = lookup_done(md5.ip, c->md5.host_name, false, c->ttl, NULL);
01998 r->app.allotment.application1 = c->app.allotment.application1;
01999 r->app.allotment.application2 = c->app.allotment.application2;
02000
02001 HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
02002
02003 if (!action.cancelled) {
02004 if (reply_to_cont(action.continuation, r)) {
02005
02006
02007
02008 if (hostdb_migrate_on_demand) {
02009 ClusterMachine *m = cluster_machine_at_depth(master_hash(md5.hash));
02010 if (m && m != c->from)
02011 do_put_response(m, r, NULL);
02012 }
02013 }
02014 }
02015 hostdb_cont_free(this);
02016 return EVENT_DONE;
02017 }
02018 return failed_cluster_request(e);
02019
02020
02021
02022 case EVENT_INTERVAL:{
02023 MUTEX_TRY_LOCK_FOR(lock, action.mutex, e->ethread, action.continuation);
02024 if (!lock) {
02025 e->schedule_in(HOST_DB_RETRY_PERIOD);
02026 return EVENT_CONT;
02027 }
02028 return failed_cluster_request(e);
02029 }
02030 }
02031 }
02032
02033
02034 int
02035 HostDBContinuation::failed_cluster_request(Event * e)
02036 {
02037 if (action.cancelled) {
02038 hostdb_cont_free(this);
02039 return EVENT_DONE;
02040 }
02041
02042
02043 if (do_get_response(e))
02044 return EVENT_CONT;
02045
02046
02047
02048 do_dns();
02049 return EVENT_DONE;
02050 }
02051
02052
02053 void
02054 get_hostinfo_ClusterFunction(ClusterHandler *ch, void *data, int )
02055 {
02056 HostDBMD5 md5;
02057 HostDB_get_message *msg = (HostDB_get_message *) data;
02058
02059 md5.host_name = msg->name;
02060 md5.host_len = msg->namelen;
02061 md5.ip.assign(&msg->ip.sa);
02062 md5.port = ats_ip_port_host_order(&msg->ip.sa);
02063 md5.hash = msg->md5;
02064 md5.db_mark = db_mark_for(&msg->ip.sa);
02065 #ifdef SPLIT_DNS
02066 SplitDNS *pSD = 0;
02067 char *hostname = msg->name;
02068 if (hostname && SplitDNSConfig::isSplitDNSEnabled()) {
02069 pSD = SplitDNSConfig::acquire();
02070
02071 if (0 != pSD) {
02072 md5.dns_server = static_cast<DNSServer*>(pSD->getDNSRecord(hostname));
02073 }
02074 SplitDNSConfig::release(pSD);
02075 }
02076 #endif // SPLIT_DNS
02077
02078 HostDBContinuation *c = hostDBContAllocator.alloc();
02079 HostDBContinuation::Options copt;
02080 SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent);
02081 c->from = ch->machine;
02082 c->from_cont = msg->cont;
02083
02084
02085
02086
02087
02088
02089
02090
02091 copt.host_res_style = host_res_style_for(&msg->ip.sa);
02092 c->init(md5, copt);
02093 c->mutex = hostDB.lock_for_bucket(fold_md5(msg->md5) % hostDB.buckets);
02094 c->action.mutex = c->mutex;
02095 dnsProcessor.thread->schedule_imm(c);
02096 }
02097
02098
02099 void
02100 put_hostinfo_ClusterFunction(ClusterHandler *ch, void *data, int )
02101 {
02102 HostDB_put_message *msg = (HostDB_put_message *) data;
02103 HostDBContinuation *c = hostDBContAllocator.alloc();
02104 HostDBContinuation::Options copt;
02105 HostDBMD5 md5;
02106
02107 SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::clusterResponseEvent);
02108 md5.host_name = msg->name;
02109 md5.host_len = msg->namelen;
02110 md5.ip.assign(&msg->ip.sa);
02111 md5.port = ats_ip_port_host_order(&msg->ip.sa);
02112 md5.hash = msg->md5;
02113 md5.db_mark = db_mark_for(&msg->ip.sa);
02114 copt.host_res_style = host_res_style_for(&msg->ip.sa);
02115 c->init(md5, copt);
02116 c->mutex = hostDB.lock_for_bucket(fold_md5(msg->md5) % hostDB.buckets);
02117 c->from_cont = msg->cont;
02118 c->missing = msg->missing;
02119 c->round_robin = msg->round_robin;
02120 c->ttl = msg->ttl;
02121 c->from = ch->machine;
02122 dnsProcessor.thread->schedule_imm(c);
02123 }
02124
02125
02126
02127
02128
02129
02130
02131 int
02132 HostDBContinuation::backgroundEvent(int , Event * )
02133 {
02134 hostdb_current_interval++;
02135
02136 return EVENT_CONT;
02137 }
02138
02139 bool HostDBInfo::match(INK_MD5 & md5, int , int buckets)
02140 {
02141 if (md5[1] != md5_high)
02142 return false;
02143
02144 uint64_t folded_md5 = fold_md5(md5);
02145 uint64_t ttag = folded_md5 / buckets;
02146
02147 if (!ttag)
02148 ttag = 1;
02149
02150 struct
02151 {
02152 unsigned int md5_low_low:24;
02153 unsigned int md5_low;
02154 } tmp;
02155
02156 tmp.md5_low_low = (unsigned int) ttag;
02157 tmp.md5_low = (unsigned int) (ttag >> 24);
02158
02159 return tmp.md5_low_low == md5_low_low && tmp.md5_low == md5_low;
02160 }
02161
02162
02163 char *
02164 HostDBInfo::hostname()
02165 {
02166 if (!reverse_dns)
02167 return NULL;
02168
02169 return (char *) hostDB.ptr(&data.hostname_offset, hostDB.ptr_to_partition((char *) this));
02170 }
02171
02172
02173 HostDBRoundRobin *
02174 HostDBInfo::rr()
02175 {
02176 if (!round_robin)
02177 return NULL;
02178
02179 HostDBRoundRobin *r = (HostDBRoundRobin *) hostDB.ptr(&app.rr.offset, hostDB.ptr_to_partition((char *) this));
02180
02181 if (r && (r->rrcount > HOST_DB_MAX_ROUND_ROBIN_INFO || r->rrcount <= 0 || r->good > HOST_DB_MAX_ROUND_ROBIN_INFO || r->good <= 0)) {
02182 ink_assert(!"bad round-robin");
02183 return NULL;
02184 }
02185 return r;
02186 }
02187
02188
02189 int
02190 HostDBInfo::heap_size()
02191 {
02192 if (reverse_dns) {
02193 char *h = hostname();
02194
02195 if (h)
02196 return strlen(h) + 1;
02197 } else if (round_robin) {
02198 HostDBRoundRobin *r = rr();
02199
02200 if (r)
02201 return r->length;
02202 }
02203 return 0;
02204 }
02205
02206
02207 int *
02208 HostDBInfo::heap_offset_ptr()
02209 {
02210 if (reverse_dns)
02211 return &data.hostname_offset;
02212
02213 if (round_robin)
02214 return &app.rr.offset;
02215
02216 return NULL;
02217 }
02218
02219
02220 ClusterMachine *
02221 HostDBContinuation::master_machine(ClusterConfiguration * cc)
02222 {
02223 return cc->machine_hash((int) (md5.hash[1] >> 32));
02224 }
02225
02226 struct ShowHostDB;
02227 typedef int (ShowHostDB::*ShowHostDBEventHandler) (int event, Event * data);
02228 struct ShowHostDB: public ShowCont
02229 {
02230 char *name;
02231 IpEndpoint ip;
02232 bool force;
02233
02234 int showMain(int event, Event * e)
02235 {
02236 CHECK_SHOW(begin("HostDB"));
02237 CHECK_SHOW(show("<form method = GET action = \"./name\">\n"
02238 "Lookup by name (e.g. trafficserver.apache.org):<br>\n"
02239 "<input type=text name=name size=64 maxlength=256>\n"
02240 "</form>\n"
02241 "<form method = GET action = \"./ip\">\n"
02242 "Lookup by IP (e.g. 127.0.0.1):<br>\n"
02243 "<input type=text name=ip size=64 maxlength=256>\n"
02244 "</form>\n"
02245 "<form method = GET action = \"./nameforce\">\n"
02246 "Force DNS by name (e.g. trafficserver.apache.org):<br>\n"
02247 "<input type=text name=name size=64 maxlength=256>\n" "</form>\n"));
02248 return complete(event, e);
02249 }
02250
02251
02252 int showLookup(int , Event * )
02253 {
02254 SET_HANDLER(&ShowHostDB::showLookupDone);
02255 if (name)
02256 hostDBProcessor.getbyname_re(this, name, 0, HostDBProcessor::Options().setFlags(force ? HostDBProcessor::HOSTDB_FORCE_DNS_ALWAYS : 0));
02257 else
02258 hostDBProcessor.getbyaddr_re(this, &ip.sa);
02259 return EVENT_CONT;
02260 }
02261
02262
02263 int showOne(HostDBInfo * r, bool rr, int event, Event * e)
02264 {
02265 ip_text_buffer b;
02266 CHECK_SHOW(show("<table border=1>\n"));
02267 CHECK_SHOW(show("<tr><td>%s</td><td>%s%s</td></tr>\n",
02268 "Type", r->round_robin ? "Round-Robin" : "", r->reverse_dns ? "Reverse DNS" : "DNS"));
02269 CHECK_SHOW(show("<tr><td>%s</td><td>%u</td></tr>\n", "App1", r->app.allotment.application1));
02270 CHECK_SHOW(show("<tr><td>%s</td><td>%u</td></tr>\n", "App2", r->app.allotment.application2));
02271 if (!rr) {
02272 CHECK_SHOW(show("<tr><td>%s</td><td>%s</td></tr>\n", "Stale", r->is_ip_stale()? "Yes" : "No"));
02273 CHECK_SHOW(show("<tr><td>%s</td><td>%s</td></tr>\n", "Timed-Out", r->is_ip_timeout()? "Yes" : "No"));
02274 CHECK_SHOW(show("<tr><td>%s</td><td>%d</td></tr>\n", "TTL", r->ip_time_remaining()));
02275 }
02276 if (r->reverse_dns) {
02277 CHECK_SHOW(show("<tr><td>%s</td><td>%s</td></tr>\n", "Hostname", r->hostname()? r->hostname() : "<none>"));
02278 } else {
02279 CHECK_SHOW(show("<tr><td>%s</td><td>%s</td></tr>\n", "IP", ats_ip_ntop(r->ip(), b, sizeof b)));
02280 }
02281 CHECK_SHOW(show("</table>\n"));
02282 return EVENT_CONT;
02283 }
02284
02285
02286 int showLookupDone(int event, Event * e)
02287 {
02288 HostDBInfo *r = (HostDBInfo *) e;
02289
02290 CHECK_SHOW(begin("HostDB Lookup"));
02291 if (name) {
02292 CHECK_SHOW(show("<H2>%s</H2>\n", name));
02293 } else {
02294 CHECK_SHOW(show("<H2>%u.%u.%u.%u</H2>\n", PRINT_IP(ip)));
02295 }
02296 if (r) {
02297 showOne(r, false, event, e);
02298 if (r->round_robin) {
02299 HostDBRoundRobin *rr_data = r->rr();
02300 if (rr_data) {
02301 CHECK_SHOW(show("<table border=1>\n"));
02302 CHECK_SHOW(show("<tr><td>%s</td><td>%d</td></tr>\n", "Total", rr_data->rrcount));
02303 CHECK_SHOW(show("<tr><td>%s</td><td>%d</td></tr>\n", "Good", rr_data->good));
02304 CHECK_SHOW(show("<tr><td>%s</td><td>%d</td></tr>\n", "Current", rr_data->current));
02305 CHECK_SHOW(show("</table>\n"));
02306
02307 for (int i = 0; i < rr_data->rrcount; i++)
02308 showOne(&rr_data->info[i], true, event, e);
02309 }
02310 }
02311 } else {
02312 if (name) {
02313 ip_text_buffer b;
02314 CHECK_SHOW(show("<H2>%s Not Found</H2>\n", ats_ip_ntop(&ip.sa, b, sizeof b)));
02315 } else {
02316 CHECK_SHOW(show("<H2>%s Not Found</H2>\n", name));
02317 }
02318 }
02319 return complete(event, e);
02320 }
02321
02322
02323 ShowHostDB(Continuation * c, HTTPHdr * h)
02324 : ShowCont(c, h), name(0), force(0)
02325 {
02326 ats_ip_invalidate(&ip);
02327 SET_HANDLER(&ShowHostDB::showMain);
02328 }
02329
02330 };
02331
02332 #define STR_LEN_EQ_PREFIX(_x,_l,_s) (!ptr_len_ncasecmp(_x,_l,_s,sizeof(_s)-1))
02333
02334
02335 static Action *
02336 register_ShowHostDB(Continuation * c, HTTPHdr * h)
02337 {
02338 ShowHostDB *s = new ShowHostDB(c, h);
02339 int path_len;
02340 const char *path = h->url_get()->path_get(&path_len);
02341
02342 SET_CONTINUATION_HANDLER(s, &ShowHostDB::showMain);
02343 if (STR_LEN_EQ_PREFIX(path, path_len, "ip")) {
02344 s->force = !ptr_len_ncasecmp(path + 3, path_len - 3, "force", 5);
02345 int query_len;
02346 const char *query = h->url_get()->query_get(&query_len);
02347 s->sarg = ats_strndup(query, query_len);
02348 char *gn = NULL;
02349 if (s->sarg)
02350 gn = (char *)memchr(s->sarg, '=', strlen(s->sarg));
02351 if (gn) {
02352 ats_ip_pton(gn+1, &s->ip);
02353 }
02354 SET_CONTINUATION_HANDLER(s, &ShowHostDB::showLookup);
02355 } else if (STR_LEN_EQ_PREFIX(path, path_len, "name")) {
02356 s->force = !ptr_len_ncasecmp(path + 5, path_len - 5, "force", 5);
02357 int query_len;
02358 const char *query = h->url_get()->query_get(&query_len);
02359 s->sarg = ats_strndup(query, query_len);
02360 char *gn = NULL;
02361 if (s->sarg)
02362 gn = (char *)memchr(s->sarg, '=', strlen(s->sarg));
02363 if (gn)
02364 s->name = gn + 1;
02365 SET_CONTINUATION_HANDLER(s, &ShowHostDB::showLookup);
02366 }
02367 this_ethread()->schedule_imm(s);
02368 return &s->action;
02369 }
02370
02371
02372 #define HOSTDB_TEST_MAX_OUTSTANDING 100
02373 #define HOSTDB_TEST_LENGTH 100000
02374
02375 struct HostDBTestReverse;
02376 typedef int (HostDBTestReverse::*HostDBTestReverseHandler) (int, void *);
02377 struct HostDBTestReverse: public Continuation
02378 {
02379 int outstanding;
02380 int total;
02381 #if HAVE_LRAND48_R
02382 struct drand48_data dr;
02383 #endif
02384
02385 int mainEvent(int event, Event * e)
02386 {
02387 if (event == EVENT_HOST_DB_LOOKUP) {
02388 HostDBInfo *i = (HostDBInfo *) e;
02389 if (i)
02390 printf("HostDBTestReverse: reversed %s\n", i->hostname());
02391 outstanding--;
02392 }
02393 while (outstanding < HOSTDB_TEST_MAX_OUTSTANDING && total < HOSTDB_TEST_LENGTH)
02394 {
02395 long l = 0;
02396 #if HAVE_LRAND48_R
02397 lrand48_r(&dr, &l);
02398 #else
02399 l = lrand48();
02400 #endif
02401 IpEndpoint ip;
02402 ip.sin.sin_addr.s_addr = static_cast<in_addr_t>(l);
02403 outstanding++;
02404 total++;
02405 if (!(outstanding % 1000))
02406 printf("HostDBTestReverse: %d\n", total);
02407 hostDBProcessor.getbyaddr_re(this, &ip.sa);
02408 }
02409 if (!outstanding) {
02410 printf("HostDBTestReverse: done\n");
02411 delete this;
02412 }
02413 return EVENT_CONT;
02414 }
02415 HostDBTestReverse():Continuation(new_ProxyMutex()), outstanding(0), total(0) {
02416 SET_HANDLER((HostDBTestReverseHandler) & HostDBTestReverse::mainEvent);
02417 #if HAVE_SRAND48_R
02418 srand48_r(time(NULL), &dr);
02419 #else
02420 srand48(time(NULL));
02421 #endif
02422 }
02423 };
02424
02425
02426 #if TS_HAS_TESTS
02427 void
02428 run_HostDBTest()
02429 {
02430 if (is_action_tag_set("hostdb_test_rr"))
02431 eventProcessor.schedule_every(new HostDBTestRR, HRTIME_SECONDS(1), ET_NET);
02432 if (is_action_tag_set("hostdb_test_reverse")) {
02433 eventProcessor.schedule_imm(new HostDBTestReverse, ET_CACHE);
02434 }
02435 }
02436 #endif
02437
02438
02439 RecRawStatBlock *hostdb_rsb;
02440
02441 void
02442 ink_hostdb_init(ModuleVersion v)
02443 {
02444 static int init_called = 0;
02445
02446 ink_release_assert(!checkModuleVersion(v, HOSTDB_MODULE_VERSION));
02447 if (init_called)
02448 return;
02449
02450 init_called = 1;
02451
02452
02453 hostdb_rsb = RecAllocateRawStatBlock((int) HostDB_Stat_Count);
02454
02455
02456
02457
02458
02459 RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
02460 "proxy.process.hostdb.total_entries",
02461 RECD_INT, RECP_PERSISTENT, (int) hostdb_total_entries_stat, RecRawStatSyncCount);
02462
02463 RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
02464 "proxy.process.hostdb.total_lookups",
02465 RECD_INT, RECP_PERSISTENT, (int) hostdb_total_lookups_stat, RecRawStatSyncSum);
02466
02467 RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
02468 "proxy.process.hostdb.total_hits",
02469 RECD_INT, RECP_NON_PERSISTENT, (int) hostdb_total_hits_stat, RecRawStatSyncSum);
02470
02471 RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
02472 "proxy.process.hostdb.ttl", RECD_FLOAT, RECP_PERSISTENT, (int) hostdb_ttl_stat, RecRawStatSyncAvg);
02473
02474 RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
02475 "proxy.process.hostdb.ttl_expires",
02476 RECD_INT, RECP_PERSISTENT, (int) hostdb_ttl_expires_stat, RecRawStatSyncSum);
02477
02478 RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
02479 "proxy.process.hostdb.re_dns_on_reload",
02480 RECD_INT, RECP_PERSISTENT, (int) hostdb_re_dns_on_reload_stat, RecRawStatSyncSum);
02481
02482 RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
02483 "proxy.process.hostdb.bytes", RECD_INT, RECP_PERSISTENT, (int) hostdb_bytes_stat, RecRawStatSyncCount);
02484
02485 ts_host_res_global_init();
02486 }