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 }