00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 #ifndef _I_HostDBProcessor_h_
00025 #define _I_HostDBProcessor_h_
00026 
00027 #include "I_EventSystem.h"
00028 #include "SRV.h"
00029 
00030 
00031 #define EVENT_HOST_DB_LOOKUP                 (HOSTDB_EVENT_EVENTS_START+0)
00032 #define EVENT_HOST_DB_IP_REMOVED             (HOSTDB_EVENT_EVENTS_START+1)
00033 #define EVENT_HOST_DB_GET_RESPONSE           (HOSTDB_EVENT_EVENTS_START+2)
00034 
00035 #define EVENT_SRV_LOOKUP                 (SRV_EVENT_EVENTS_START+0)
00036 #define EVENT_SRV_IP_REMOVED             (SRV_EVENT_EVENTS_START+1)
00037 #define EVENT_SRV_GET_RESPONSE           (SRV_EVENT_EVENTS_START+2)
00038 
00039 #define HOST_DB_MAX_ROUND_ROBIN_INFO         16
00040 
00041 #define HOST_DB_SRV_PREFIX "_http._tcp."
00042 
00043 
00044 
00045 struct HostDBContinuation;
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 extern int hostdb_enable;
00056 extern unsigned int hostdb_current_interval;
00057 extern unsigned int hostdb_ip_stale_interval;
00058 extern unsigned int hostdb_ip_timeout_interval;
00059 extern unsigned int hostdb_ip_fail_timeout_interval;
00060 extern unsigned int hostdb_serve_stale_but_revalidate;
00061 
00062 
00063 static inline unsigned int
00064 makeHostHash(const char *string)
00065 {
00066   ink_assert(string && *string);
00067   if (!string || *string == 0)
00068     return 0;
00069 
00070   const uint32_t InitialFNV = 2166136261U;
00071   const int32_t FNVMultiple = 16777619;
00072 
00073   uint64_t hash = InitialFNV;
00074   uint32_t *p = (uint32_t *) &hash;
00075   while(*string)  {
00076     p[0] = p[0] ^ (toupper(*string));
00077     hash = (p[1] ^ p[0]) * FNVMultiple;
00078     ++string;
00079   }
00080   return (p[1] ^ p[0]);
00081 }
00082 
00083 
00084 
00085 
00086 
00087 
00088 
00089 
00090 
00091 
00092 
00093 union HostDBApplicationInfo
00094 {
00095   struct application_data_allotment
00096   {
00097     unsigned int application1;
00098     unsigned int application2;
00099   } allotment;
00100 
00101 
00102   
00103   
00104   
00105   
00106   
00107   
00108   
00109   
00110   
00111   
00112   
00113 
00114   struct http_server_attr
00115   {
00116     unsigned int http_version:3;
00117     unsigned int pipeline_max:7;
00118     unsigned int keepalive_timeout:6;
00119     unsigned int fail_count:8;
00120     unsigned int unused1:8;
00121     unsigned int last_failure:32;
00122   } http_data;
00123 
00124   enum HttpVersion_t
00125   {
00126     HTTP_VERSION_UNDEFINED = 0,
00127     HTTP_VERSION_09 = 1,
00128     HTTP_VERSION_10 = 2,
00129     HTTP_VERSION_11 = 3
00130   };
00131 
00132   struct application_data_rr
00133   {
00134     int offset;
00135   } rr;
00136 };
00137 
00138 struct HostDBRoundRobin;
00139 
00140 struct SRVInfo
00141 {
00142   unsigned int srv_offset:16;
00143   unsigned int srv_weight:16;
00144   unsigned int srv_priority:16;
00145   unsigned int srv_port:16;
00146   unsigned int key;
00147 };
00148 
00149 struct HostDBInfo
00150 {
00151 
00152 
00153 
00154   sockaddr* ip()  { return &data.ip.sa; }
00155   sockaddr const* ip() const { return &data.ip.sa; }
00156 
00157   char *hostname();
00158   char *srvname(HostDBRoundRobin *rr);
00159   HostDBRoundRobin *rr();
00160 
00161 
00162   void bad() { full = 0; }
00163 
00164 
00165 
00166 
00167 
00168 
00169 
00170   HostDBApplicationInfo app;
00171 
00172   unsigned int ip_interval()
00173   {
00174     return (hostdb_current_interval - ip_timestamp) & 0x7FFFFFFF;
00175   }
00176 
00177   int ip_time_remaining()
00178   {
00179     return (int) ip_timeout_interval - (int) ((hostdb_current_interval - ip_timestamp) & 0x7FFFFFFF);
00180   }
00181 
00182   bool is_ip_stale() {
00183     if (ip_timeout_interval >= 2 * hostdb_ip_stale_interval)
00184       return ip_interval() >= hostdb_ip_stale_interval;
00185     else
00186       return false;
00187   }
00188 
00189   bool is_ip_timeout() {
00190     return ip_interval() >= ip_timeout_interval;
00191   }
00192 
00193   bool is_ip_fail_timeout() {
00194     return ip_interval() >= hostdb_ip_fail_timeout_interval;
00195   }
00196 
00197   void refresh_ip()
00198   {
00199     ip_timestamp = hostdb_current_interval;
00200   }
00201 
00202   bool serve_stale_but_revalidate() {
00203     
00204     if (hostdb_serve_stale_but_revalidate <= 0)
00205       return false;
00206 
00207     
00208     
00209     
00210     if ((ip_timeout_interval + hostdb_serve_stale_but_revalidate) > ip_interval()) {
00211       Debug("hostdb", "serving stale entry %d | %d | %d as requested by config",
00212             ip_timeout_interval, hostdb_serve_stale_but_revalidate, ip_interval());
00213       return true;
00214     }
00215     
00216     return false;
00217   }
00218 
00219 
00220   
00221   
00222   
00223 
00224   union {
00225     IpEndpoint ip; 
00226     int hostname_offset; 
00227     SRVInfo srv;
00228   } data;
00229 
00230   unsigned int ip_timestamp;
00231   
00232   unsigned int ip_timeout_interval:31;
00233 
00234   unsigned int full:1;
00235   unsigned int backed:1;        
00236   unsigned int deleted:1;
00237   unsigned int hits:3;
00238 
00239   unsigned int is_srv:1; 
00240   unsigned int round_robin:1;
00241   unsigned int reverse_dns:1;
00242 
00243   unsigned int md5_low_low:24;
00244   unsigned int md5_low;
00245 
00246   uint64_t md5_high;
00247 
00248   bool failed() {
00249     return !((is_srv && data.srv.srv_offset) || (reverse_dns && data.hostname_offset) || ats_is_ip(ip()));
00250   }
00251   void set_failed() {
00252     if (is_srv)
00253       data.srv.srv_offset = 0;
00254     else if (reverse_dns)
00255       data.hostname_offset = 0;
00256     else
00257       ats_ip_invalidate(ip());
00258   }
00259 
00260   void set_deleted() { deleted = 1; }
00261   bool is_deleted() const { return deleted; }
00262 
00263   bool is_empty() const { return !full; }
00264 
00265   void set_empty()
00266   {
00267     full = 0;
00268     md5_high = 0;
00269     md5_low = 0;
00270     md5_low_low = 0;
00271   }
00272 
00273   void set_full(uint64_t folded_md5, int buckets)
00274   {
00275     uint64_t ttag = folded_md5 / buckets;
00276 
00277     if (!ttag)
00278       ttag = 1;
00279     md5_low_low = (unsigned int) ttag;
00280     md5_low = (unsigned int) (ttag >> 24);
00281     full = 1;
00282   }
00283 
00284   void reset()
00285   {
00286     ats_ip_invalidate(ip());
00287     app.allotment.application1 = 0;
00288     app.allotment.application2 = 0;
00289     backed = 0;
00290     deleted = 0;
00291     hits = 0;
00292     round_robin = 0;
00293     reverse_dns = 0;
00294     is_srv = 0;
00295   }
00296 
00297   uint64_t tag() {
00298     uint64_t f = md5_low;
00299     return (f << 24) + md5_low_low;
00300   }
00301 
00302   bool match(INK_MD5 &, int, int);
00303   int heap_size();
00304   int *heap_offset_ptr();
00305 };
00306 
00307 
00308 struct HostDBRoundRobin
00309 {
00310 
00311   short rrcount;
00312 
00313 
00314   short good;
00315 
00316   unsigned short current;
00317   unsigned short length;
00318   ink_time_t timed_rr_ctime;
00319 
00320   HostDBInfo info[];
00321 
00322   
00323   
00324   static unsigned size(unsigned count, unsigned srv_len = 0)
00325   {
00326     ink_assert(count > 0);
00327     return INK_ALIGN((sizeof(HostDBRoundRobin) + (count * sizeof(HostDBInfo)) + srv_len), 8);
00328   }
00329 
00330 
00331 
00332 
00333   int index_of(sockaddr const* addr);
00334   HostDBInfo *find_ip(sockaddr const* addr);
00335   
00336   HostDBInfo *find_target(const char *target);
00337 
00338 
00339 
00340 
00341   HostDBInfo* select_next(sockaddr const* addr);
00342   HostDBInfo *select_best_http(sockaddr const* client_ip, ink_time_t now, int32_t fail_window);
00343   HostDBInfo *select_best_srv(char *target, InkRand *rand, ink_time_t now, int32_t fail_window);
00344   HostDBRoundRobin()
00345     : rrcount(0), good(0), current(0), length(0), timed_rr_ctime(0)
00346   { }
00347 
00348 };
00349 
00350 struct HostDBCache;
00351 
00352 
00353 
00354 typedef void (Continuation::*process_hostdb_info_pfn) (HostDBInfo * r);
00355 typedef void (Continuation::*process_srv_info_pfn) (HostDBInfo * r);
00356 
00357 
00358 
00359 struct HostDBProcessor: public Processor
00360 {
00361   friend struct HostDBSyncer;
00362   
00363 
00364   
00365   
00366   
00367   
00368   
00369   
00370   
00371 
00372   enum
00373   { HOSTDB_DO_NOT_FORCE_DNS = 0,
00374     HOSTDB_ROUND_ROBIN = 0,
00375     HOSTDB_FORCE_DNS_RELOAD = 1,
00376     HOSTDB_FORCE_DNS_ALWAYS = 2,
00377     HOSTDB_DO_NOT_ROUND_ROBIN = 4
00378   };
00379 
00380 
00381   struct Options {
00382     typedef Options self; 
00383     int port; 
00384     int flags; 
00385     int timeout; 
00386     HostResStyle host_res_style; 
00387 
00388     Options() : port(0), flags(HOSTDB_DO_NOT_FORCE_DNS), timeout(0), host_res_style(HOST_RES_IPV4)
00389     { }
00390 
00391 
00392     self& setFlags(int f) { flags = f; return *this; }
00393   };
00394 
00395 
00396   static Options const DEFAULT_OPTIONS;
00397 
00398   HostDBProcessor()
00399   { }
00400 
00401   inkcoreapi Action *getbyname_re(Continuation * cont, const char *hostname, int len, Options const& opt = DEFAULT_OPTIONS);
00402 
00403   Action *getSRVbyname_imm(Continuation * cont, process_srv_info_pfn process_srv_info, const char *hostname, int len, Options const& opt = DEFAULT_OPTIONS);
00404 
00405   Action *getbyname_imm(
00406     Continuation * cont,
00407     process_hostdb_info_pfn process_hostdb_info,
00408     const char *hostname,
00409     int len,
00410     Options const& opt = DEFAULT_OPTIONS
00411   );
00412 
00413 
00414 
00415   Action *getbyaddr_re(Continuation * cont, sockaddr const* aip)
00416   {
00417     return getby(cont, NULL, 0, aip, false, HOST_RES_NONE, 0);
00418   }
00419 
00420 #if 0
00421 
00422 
00423 
00424 
00425 
00426 
00427 
00428   Action *failed_connect_on_ip_for_name(
00429     Continuation * cont,
00430     sockaddr const* aip,
00431     const char *hostname, int len = 0
00432   );
00433 #endif
00434 
00435 
00436   void setbyname_appinfo(char *hostname, int len, int port, HostDBApplicationInfo * app)
00437   {
00438     sockaddr_in addr;
00439     ats_ip4_set(&addr, INADDR_ANY, port);
00440     setby(hostname, len, ats_ip_sa_cast(&addr), app);
00441   }
00442 
00443   void setbyaddr_appinfo(sockaddr const* addr, HostDBApplicationInfo * app) {
00444     this->setby(0, 0, addr, app);
00445   }
00446 
00447   void setbyaddr_appinfo(in_addr_t ip, HostDBApplicationInfo * app)
00448   {
00449     sockaddr_in addr;
00450     ats_ip4_set(&addr, ip);
00451     this->setby(0, 0, ats_ip_sa_cast(&addr), app);
00452   }
00453 
00454 
00455   static int hostdb_strict_round_robin;
00456   static int hostdb_timed_round_robin;
00457 
00458   
00459   
00460 
00461 
00462   int start(int no_of_additional_event_threads = 0, size_t stacksize = DEFAULT_STACKSIZE);
00463 
00464   
00465   HostDBCache *cache();
00466 private:
00467   Action *getby(
00468     Continuation * cont,
00469     const char *hostname, int len,
00470     sockaddr const* ip,
00471     bool aforce_dns, HostResStyle host_res_style, int timeout
00472   );
00473 public:
00474 
00475 
00476 
00477 
00478 
00479   void setby(
00480     const char *hostname, 
00481     int len, 
00482     sockaddr const* aip, 
00483     HostDBApplicationInfo * app 
00484   );
00485 
00486   void setby_srv(const char *hostname, int len, const char *target,
00487       HostDBApplicationInfo * app);
00488 
00489 };
00490 
00491 void run_HostDBTest();
00492 
00493 extern inkcoreapi HostDBProcessor hostDBProcessor;
00494 
00495 void ink_hostdb_init(ModuleVersion version);
00496 
00497 #endif