3
A brief file description
5
@section license License
7
Licensed to the Apache Software Foundation (ASF) under one
8
or more contributor license agreements. See the NOTICE file
9
distributed with this work for additional information
10
regarding copyright ownership. The ASF licenses this file
11
to you under the Apache License, Version 2.0 (the
12
"License"); you may not use this file except in compliance
13
with the License. You may obtain a copy of the License at
15
http://www.apache.org/licenses/LICENSE-2.0
17
Unless required by applicable law or agreed to in writing, software
18
distributed under the License is distributed on an "AS IS" BASIS,
19
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
See the License for the specific language governing permissions and
21
limitations under the License.
30
//char system_config_directory[512] = "etc/trafficserver";
35
// dxu: turn off all Diags.h 's function.
41
// Compilation Options
45
#include "ink_apidefs.h"
47
HostDBProcessor hostDBProcessor;
48
int HostDBProcessor::hostdb_strict_round_robin = 0;
49
int hostdb_enable = true;
50
int hostdb_migrate_on_demand = true;
51
int hostdb_cluster = false;
52
int hostdb_cluster_round_robin = false;
53
int hostdb_lookup_timeout = 120;
54
int hostdb_insert_timeout = 160;
55
int hostdb_re_dns_on_reload = false;
56
int hostdb_ttl_mode = TTL_OBEY;
57
unsigned int hostdb_current_interval = 0;
58
unsigned int hostdb_ip_stale_interval = HOST_DB_IP_STALE;
59
unsigned int hostdb_ip_timeout_interval = HOST_DB_IP_TIMEOUT;
60
unsigned int hostdb_ip_fail_timeout_interval = HOST_DB_IP_FAIL_TIMEOUT;
61
unsigned int hostdb_serve_stale_but_revalidate = 0;
62
char hostdb_filename[PATH_NAME_MAX + 1] = DEFAULT_HOST_DB_FILENAME;
63
int hostdb_size = DEFAULT_HOST_DB_SIZE;
64
//int hostdb_timestamp = 0;
65
int hostdb_sync_frequency = 60;
66
int hostdb_disable_reverse_lookup = 0;
68
ClassAllocator<HostDBContinuation> hostDBContAllocator("hostDBContAllocator");
70
// Static configuration information
76
static Queue <HostDBContinuation > remoteHostDBQueue[MULTI_CACHE_PARTITIONS];
80
corrupt_debugging_callout(HostDBInfo * e, RebuildMC & r)
82
Debug("hostdb", "corrupt %d part %d", (char *) &e->app.rr.offset - r.data, r.partition);
88
hostdb_cont_free(HostDBContinuation * cont)
90
if (cont->pending_action)
91
cont->pending_action->cancel();
93
cont->action.mutex = 0;
94
hostDBContAllocator.free(cont);
99
// Function Prototypes
103
register_ShowHostDB(Continuation * c, HTTPHdr * h);
110
HostDBProcessor::HostDBProcessor()
115
HostDBCache::HostDBCache()
117
tag_bits = HOST_DB_TAG_BITS;
118
max_hits = (1 << HOST_DB_HITS_BITS) - 1;
119
version.ink_major = HOST_DB_CACHE_MAJOR_VERSION;
120
version.ink_minor = HOST_DB_CACHE_MINOR_VERSION;
125
HostDBCache::rebuild_callout(HostDBInfo * e, RebuildMC & r)
127
if (e->round_robin && e->reverse_dns)
128
return corrupt_debugging_callout(e, r);
129
if (e->reverse_dns) {
130
if (e->data.hostname_offset < 0)
132
if (e->data.hostname_offset > 0) {
133
if (!valid_offset(e->data.hostname_offset - 1))
134
return corrupt_debugging_callout(e, r);
135
char *p = (char *) ptr(&e->data.hostname_offset, r.partition);
137
return corrupt_debugging_callout(e, r);
139
while (*p && p - s < MAXDNAME) {
140
if (!valid_heap_pointer(p))
141
return corrupt_debugging_callout(e, r);
144
if (p - s >= MAXDNAME)
145
return corrupt_debugging_callout(e, r);
148
if (e->round_robin) {
149
if (e->app.rr.offset < 0)
151
if (!valid_offset(e->app.rr.offset - 1))
152
return corrupt_debugging_callout(e, r);
153
HostDBRoundRobin *rr = (HostDBRoundRobin *) ptr(&e->app.rr.offset, r.partition);
155
return corrupt_debugging_callout(e, r);
156
if (rr->n > HOST_DB_MAX_ROUND_ROBIN_INFO || rr->n <= 0 ||
157
rr->good > HOST_DB_MAX_ROUND_ROBIN_INFO || rr->good <= 0 || rr->good > rr->n)
158
return corrupt_debugging_callout(e, r);
159
for (int i = 0; i < rr->good; i++) {
160
if (!valid_heap_pointer(((char *) &rr->info[i + 1]) - 1))
162
if (!rr->info[i].ip())
163
return corrupt_debugging_callout(e, r);
164
if (rr->info[i].md5_high != e->md5_high ||
165
rr->info[i].md5_low != e->md5_low || rr->info[i].md5_low_low != e->md5_low_low)
166
return corrupt_debugging_callout(e, r);
169
if (e->is_ip_timeout())
176
HostDBProcessor::cache()
182
struct HostDBTestRR: public Continuation
187
int outstanding, success, failure;
190
int mainEvent(int event, Event * e)
192
if (event == EVENT_INTERVAL) {
193
printf("HostDBTestRR: %d outstanding %d succcess %d failure\n", outstanding, success, failure);
195
if (event == EVENT_HOST_DB_LOOKUP) {
205
while (outstanding < 40) {
208
char *end = (char *) ink_memchr(b, '\n', nb);
211
end = (char *) ink_memchr(b, '\n', nb);
217
hostDBProcessor.getbyname_re(this, b);
218
nb -= ((end + 1) - b);
219
memcpy(b, end + 1, nb);
232
nb = read(fd, b + nb, 512 - nb);
233
ink_release_assert(nb >= 0);
237
HostDBTestRR():Continuation(new_ProxyMutex()), nb(0), outstanding(0), success(0), failure(0), in(0) {
238
printf("starting HostDBTestRR....\n");
239
fd = open("hostdb_test.config", O_RDONLY, 0);
240
ink_release_assert(fd >= 0);
242
SET_HANDLER(&HostDBTestRR::mainEvent);
247
struct HostDBSyncer: public Continuation
250
ink_hrtime start_time;
252
int sync_event(int event, void *edata);
253
int wait_event(int event, void *edata);
259
HostDBSyncer::HostDBSyncer():
260
Continuation(new_ProxyMutex()), frequency(0), start_time(0)
262
SET_HANDLER(&HostDBSyncer::sync_event);
263
IOCORE_EstablishStaticConfigInt32(hostdb_sync_frequency, "proxy.config.cache.hostdb.sync_frequency");
268
HostDBSyncer::sync_event(int, void *)
270
SET_HANDLER(&HostDBSyncer::wait_event);
271
start_time = ink_get_hrtime();
272
hostDBProcessor.cache()->sync_partitions(this);
278
HostDBSyncer::wait_event(int, void *)
280
SET_HANDLER(&HostDBSyncer::sync_event);
281
mutex->thread_holding->schedule_in_local(this, HRTIME_SECONDS(hostdb_sync_frequency));
287
HostDBCache::start(int flags)
291
char storage_path[PATH_NAME_MAX + 1];
292
int storage_size = 0;
294
bool reconfigure = ((flags & PROCESSOR_RECONFIGURE) ? true : false);
295
bool fix = ((flags & PROCESSOR_FIX) ? true : false);
297
// Read configuration
298
// Command line overrides manager configuration.
300
IOCORE_ReadConfigInt32(hostdb_enable, "proxy.config.hostdb");
301
IOCORE_ReadConfigString(hostdb_filename, "proxy.config.hostdb.filename", PATH_NAME_MAX);
302
IOCORE_ReadConfigInt32(hostdb_size, "proxy.config.hostdb.size");
304
#if defined (_IOCORE_WIN32)
305
// since the config directory is always based of TSBase, we make sure
306
// all the internal paths correctly get set.
307
char szPath[PATH_NAME_MAX + 1];
308
IOCORE_ReadConfigString(szPath, "proxy.config.hostdb.storage_path", PATH_NAME_MAX);
310
while (szPath[i] != 0) {
311
if (szPath[i] == '/')
315
ink_strncpy(storage_path, system_root_dir, sizeof(storage_path));
316
strcat(storage_path, DIR_SEP);
317
strcat(storage_path, szPath);
319
IOCORE_ReadConfigString(storage_path, "proxy.config.hostdb.storage_path", PATH_NAME_MAX);
321
IOCORE_ReadConfigInt32(storage_size, "proxy.config.hostdb.storage_size");
323
if (storage_path[0] != '/') {
324
Layout::relative_to(storage_path, PATH_NAME_MAX,
325
system_root_dir, storage_path);
328
Debug("hostdb", "Storage path is %s", storage_path);
330
// XXX: Should this be W_OK?
331
if (access(storage_path, R_OK) == -1) {
332
ink_strncpy(storage_path, system_runtime_dir, sizeof(storage_path));
333
if (access(storage_path, R_OK) == -1) {
334
Warning("Unable to access() directory '%s': %d, %s", storage_path, errno, strerror(errno));
335
Warning(" Please set 'proxy.config.hostdb.storage_path' or 'proxy.config.local_state_dir' ");
338
hostDBStore = NEW(new Store);
339
hostDBSpan = NEW(new Span);
340
hostDBSpan->init(storage_path, storage_size);
341
hostDBStore->add(hostDBSpan);
343
Debug("hostdb", "Opening %s, size=%d", hostdb_filename, hostdb_size);
344
if (open(hostDBStore, "hostdb.config", hostdb_filename, hostdb_size, reconfigure, fix, false /* slient */ ) < 0) {
345
Note("reconfiguring host database");
347
char p[PATH_NAME_MAX + 1];
348
Layout::relative_to(p, PATH_NAME_MAX,
349
system_config_directory, "internal/hostdb.config");
351
Debug("hostdb", "unable to unlink %s", p);
354
hostDBStore = NEW(new Store);
355
hostDBSpan = NEW(new Span);
356
hostDBSpan->init(storage_path, storage_size);
357
hostDBStore->add(hostDBSpan);
359
if (open(hostDBStore, "hostdb.config", hostdb_filename, hostdb_size, true, fix) < 0) {
360
Warning("could not initialize host database. Host database will be disabled");
366
HOSTDB_SET_DYN_COUNT(hostdb_bytes_stat, totalsize);
367
// XXX I don't see this being reference in the previous function calls, so I am going to delete it -bcall
373
// Start up the Host Database processor.
374
// Load configuration, register configuration and statistics and
378
HostDBProcessor::start(int)
380
//bool found = false;
381
hostDB.alloc_mutexes();
383
if (hostDB.start(0) < 0)
387
if (auto_clear_hostdb_flag)
391
HOSTDB_SET_DYN_COUNT(hostdb_total_entries_stat, hostDB.totalelements);
394
statPagesManager.register_http("hostdb", register_ShowHostDB);
398
// Register configuration callback, and establish configuation links
400
IOCORE_EstablishStaticConfigInt32(hostdb_ttl_mode, "proxy.config.hostdb.ttl_mode");
401
IOCORE_EstablishStaticConfigInt32(hostdb_disable_reverse_lookup, "proxy.config.hostdb.disable_reverse_lookup");
402
IOCORE_EstablishStaticConfigInt32(hostdb_re_dns_on_reload, "proxy.config.hostdb.re_dns_on_reload");
403
IOCORE_EstablishStaticConfigInt32(hostdb_migrate_on_demand, "proxy.config.hostdb.migrate_on_demand");
404
IOCORE_EstablishStaticConfigInt32(hostdb_strict_round_robin, "proxy.config.hostdb.strict_round_robin");
405
IOCORE_EstablishStaticConfigInt32(hostdb_cluster, "proxy.config.hostdb.cluster");
406
IOCORE_EstablishStaticConfigInt32(hostdb_cluster_round_robin, "proxy.config.hostdb.cluster.round_robin");
407
IOCORE_EstablishStaticConfigInt32(hostdb_lookup_timeout, "proxy.config.hostdb.lookup_timeout");
408
IOCORE_EstablishStaticConfigInt32U(hostdb_ip_timeout_interval, "proxy.config.hostdb.timeout");
409
IOCORE_EstablishStaticConfigInt32U(hostdb_ip_stale_interval, "proxy.config.hostdb.verify_after");
410
IOCORE_EstablishStaticConfigInt32U(hostdb_ip_fail_timeout_interval, "proxy.config.hostdb.fail.timeout");
411
IOCORE_EstablishStaticConfigInt32U(hostdb_serve_stale_but_revalidate, "proxy.config.hostdb.serve_stale_for");
414
// Set up hostdb_current_interval
416
hostdb_current_interval = (unsigned int)
417
(ink_get_based_hrtime() / HOST_DB_TIMEOUT_INTERVAL);
418
//hostdb_timestamp = time(NULL);
420
HostDBContinuation *b = hostDBContAllocator.alloc();
421
SET_CONTINUATION_HANDLER(b, (HostDBContHandler) & HostDBContinuation::backgroundEvent);
422
b->mutex = new_ProxyMutex();
423
eventProcessor.schedule_every(b, HOST_DB_TIMEOUT_INTERVAL, ET_DNS);
428
eventProcessor.schedule_imm(NEW(new HostDBSyncer));
434
HostDBContinuation::init(char *hostname, int len,
435
int aip, int aport, INK_MD5 & amd5, Continuation * cont, void *pDS, bool is_srv, int timeout)
438
memcpy(name, hostname, len);
442
dns_lookup_timeout = timeout;
444
is_srv_lookup = is_srv;
448
mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets));
453
//ink_assert(!"this sucks");
454
action.mutex = mutex;
460
make_md5(INK_MD5 & md5, char *hostname, int len, int port, char *pDNSServers, int srv)
464
ink_code_incr_MMH_init(&ctx);
465
ink_code_incr_MMH_update(&ctx, hostname, len);
466
unsigned short p = port;
468
ink_code_incr_MMH_update(&ctx, (char *) &p, 2);
469
ink_code_incr_MMH_update(&ctx, (char *) &srv, 4); /* FIXME: check this */
471
ink_code_incr_MMH_update(&ctx, pDNSServers, strlen(pDNSServers));
472
ink_code_incr_MMH_final((char *) &md5, &ctx);
475
ink_code_incr_md5_init(&ctx);
476
ink_code_incr_md5_update(&ctx, hostname, len);
477
unsigned short p = port;
479
ink_code_incr_md5_update(&ctx, (char *) &p, 2);
480
ink_code_incr_MMH_update(&ctx, (char *) &srv, 4); /* FIXME: check this */
482
ink_code_incr_md5_update(&ctx, pDNSServers, strlen(pDNSServers));
483
ink_code_incr_md5_final((char *) &md5, &ctx);
489
reply_to_cont(Continuation * cont, HostDBInfo * ar)
491
const char *reason = "none";
495
cont->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
500
if (r->is_srv && r->srv_count) {
501
cont->handleEvent(EVENT_SRV_LOOKUP, NULL);
504
cont->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
507
if (r->reverse_dns) {
508
if (!r->hostname()) {
509
reason = "missing hostname";
510
ink_assert(!"missing hostname");
513
Debug("hostdb", "hostname = %s", r->hostname());
515
if (r->round_robin) {
517
reason = "missing round-robin";
518
ink_assert(!"missing round-robin");
521
Debug("hostdb", "RR of %d with %d good, 1st IP = %X", r->rr()->n, r->rr()->good, r->ip());
523
if (r->is_srv && r->srv_count) {
524
cont->handleEvent(EVENT_SRV_LOOKUP, r);
528
} else if (r->is_srv) {
529
/* failure case where this is an SRV lookup, but we got no records back -- this is handled properly in process_srv_info */
530
cont->handleEvent(EVENT_SRV_LOOKUP, r);
533
cont->handleEvent(EVENT_HOST_DB_LOOKUP, r);
539
if (r->is_srv && r->srv_count) {
540
cont->handleEvent(EVENT_SRV_LOOKUP, r);
542
cont->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
544
Warning("bogus entry deleted from HostDB: %s", reason);
545
hostDB.delete_block(ar);
551
probe(ProxyMutex *mutex, INK_MD5 & md5, char *hostname, int len, int ip, int port, void *pDS, bool ignore_timeout,
554
ink_debug_assert(this_ethread() == hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets))->thread_holding);
556
uint64_t folded_md5 = fold_md5(md5);
557
HostDBInfo *r = hostDB.lookup_block(folded_md5, hostDB.levels);
558
Debug("hostdb", "probe %s %llX %d [ignore_timeout = %d]", hostname, folded_md5, !!r, ignore_timeout);
559
if (r && md5[1] == r->md5_high) {
561
// Check for timeout (fail probe)
563
if (r->is_deleted()) {
564
Debug("hostdb", "HostDB entry was set as deleted");
566
} else if (r->failed()) {
567
Debug("hostdb", "%s failed", hostname);
568
if (r->is_ip_fail_timeout()) {
569
Debug("hostdb", "fail timeout %u", r->ip_interval());
572
} else if (!ignore_timeout && r->is_ip_timeout() && !r->serve_stale_but_revalidate()) {
573
Debug("hostdb", "timeout %u %u %u", r->ip_interval(), r->ip_timestamp, r->ip_timeout_interval);
574
HOSTDB_INCREMENT_DYN_STAT(hostdb_ttl_expires_stat);
578
if (r->reverse_dns && !r->hostname()) {
579
Debug("hostdb", "missing reverse dns");
580
hostDB.delete_block(r);
583
if (r->round_robin && !r->rr()) {
584
Debug("hostdb", "missing round-robin");
585
hostDB.delete_block(r);
588
// Check for stale (revalidate offline if we are the owner)
590
// we are beyond our TTL but we choose to serve for another N seconds [hostdb_serve_stale_but_revalidate seconds]
591
if ((!ignore_timeout && r->is_ip_stale()
593
&& !cluster_machine_at_depth(master_hash(md5))
595
&& !r->reverse_dns) || (r->is_ip_timeout() && r->serve_stale_but_revalidate())) {
596
Debug("hostdb", "stale %u %u %u, using it and refreshing it", r->ip_interval(),
597
r->ip_timestamp, r->ip_timeout_interval);
599
if (!is_dotted_form_hostname(hostname)) {
600
HostDBContinuation *c = hostDBContAllocator.alloc();
601
c->init(hostname, len, ip, port, md5, NULL, pDS, is_srv_lookup, 0);
617
// Insert a HostDBInfo into the database
618
// A null value indicates that the block is empty.
621
HostDBContinuation::insert(unsigned int attl)
623
ink_debug_assert(this_ethread() == hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets))->thread_holding);
624
uint64_t folded_md5 = fold_md5(md5);
625
// remove the old one to prevent buildup
626
HostDBInfo *old_r = hostDB.lookup_block(folded_md5, 3);
628
hostDB.delete_block(old_r);
629
HostDBInfo *r = hostDB.insert_block(folded_md5, NULL, 0);
630
Debug("hostdb_insert", "inserting in bucket %d", (int) (folded_md5 % hostDB.buckets));
631
r->md5_high = md5[1];
632
if (attl > HOST_DB_MAX_TTL)
633
attl = HOST_DB_MAX_TTL;
634
r->ip_timeout_interval = attl;
635
r->ip_timestamp = hostdb_current_interval;
636
Debug("hostdb", "inserting for: %s: (md5: %llX) now: %u timeout: %u ttl: %u", name, folded_md5, r->ip_timestamp,
637
r->ip_timeout_interval, attl);
643
// Get an entry by either name or IP
646
HostDBProcessor::getby(Continuation * cont,
647
char *hostname, int len, int port, unsigned int ip, bool aforce_dns, int dns_lookup_timeout)
650
char *pServerLine = 0;
652
EThread *thread = this_ethread();
653
ProxyMutex *mutex = thread->mutex;
655
HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat);
657
if ((!hostdb_enable || (hostname && !*hostname)) || (hostdb_disable_reverse_lookup && ip)) {
658
MUTEX_TRY_LOCK(lock, cont->mutex, thread);
661
cont->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
662
return ACTION_RESULT_DONE;
665
if (hostname && SplitDNSConfig::isSplitDNSEnabled()) {
666
char *scan = hostname;
667
for (; *scan != '\0' && (ParseRules::is_digit(*scan) || '.' == *scan); scan++);
669
void *pSD = (void *) SplitDNSConfig::acquire();
671
pDS = ((SplitDNS *) pSD)->getDNSRecord(hostname);
674
pServerLine = ((DNSServer *) pDS)->x_dns_ip_line;
677
SplitDNSConfig::release((SplitDNS *) pSD);
682
// if it is by name, INK_MD5 the name
686
len = strlen(hostname);
687
make_md5(md5, hostname, len, port, pServerLine);
690
// INK_MD5 the ip, pad on both sizes with 0's
691
// so that it does not intersect the string space
693
// suvasv: Changed from this
694
// uint64_t dummy = ip << 16;
695
// to uint64_t dummy = ip*64*1024 for bug INKqa10029.
696
// Problem was that ip << 16 would not work for architectures with
697
// a different byte order. This takes cares of all byte orders.
698
uint64_t dummy = ((uint64_t) ip) * 64 * 1024;
699
md5.encodeBuffer((char *) &dummy, 8);
702
// Attempt to find the result in-line, for level 1 hits
705
// find the partition lock
707
// TODO: Could we reuse the "mutex" above safely? I think so, but not sure.
708
ProxyMutex *bmutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets));
709
MUTEX_TRY_LOCK(lock, bmutex, thread);
710
MUTEX_TRY_LOCK(lock2, cont->mutex, thread);
712
// If we can get the lock and a level 1 probe succeeds, return
715
HostDBInfo *r = probe(bmutex, md5, hostname, len, ip, port, pDS);
717
Debug("hostdb", "immediate answer for %s", hostname ? hostname : "<addr>");
718
HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
719
reply_to_cont(cont, r);
720
return ACTION_RESULT_DONE;
724
Debug("hostdb", "delaying force %d answer for %s", aforce_dns, hostname);
727
// Otherwise, create a continuation to do a deeper probe in the background
729
HostDBContinuation *c = hostDBContAllocator.alloc();
730
c->init(hostname, len, ip, port, md5, cont, pDS, false, dns_lookup_timeout);
732
c->force_dns = aforce_dns;
733
SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent);
735
// Since ProxyMutexPtr has a cast operator, gcc-3.x get upset
736
// about ambiguity when doing this comparison, so by reversing
737
// the operands, I force it to pick the cast operation /leif.
738
if (thread->mutex == cont->mutex) {
739
thread->schedule_in(c, MUTEX_RETRY_DELAY);
741
dnsProcessor.thread->schedule_imm(c);
748
// Wrapper from getbyname to getby
751
HostDBProcessor::getbyname_re(Continuation * cont, char *ahostname, int len, int port, int flags)
753
bool force_dns = false;
754
EThread *thread = this_ethread();
755
ProxyMutex *mutex = thread->mutex;
757
if (flags & HOSTDB_FORCE_DNS_ALWAYS)
759
else if (flags & HOSTDB_FORCE_DNS_RELOAD) {
760
force_dns = (hostdb_re_dns_on_reload ? true : false);
762
HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat);
764
return getby(cont, ahostname, len, port, 0, force_dns);
768
/* Support SRV records */
770
HostDBProcessor::getSRVbyname_imm(Continuation * cont, process_srv_info_pfn process_srv_info,
771
char *hostname, int len, int port, int flags, int dns_lookup_timeout)
773
ink_debug_assert(cont->mutex->thread_holding == this_ethread());
774
bool force_dns = false;
775
EThread *thread = cont->mutex->thread_holding;
776
ProxyMutex *mutex = thread->mutex;
778
if (flags & HOSTDB_FORCE_DNS_ALWAYS)
780
else if (flags & HOSTDB_FORCE_DNS_RELOAD) {
781
force_dns = (hostdb_re_dns_on_reload ? true : false);
783
HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat);
789
HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat);
791
if (!hostdb_enable || !*hostname) {
792
(cont->*process_srv_info) (NULL);
793
return ACTION_RESULT_DONE;
797
len = strlen(hostname);
799
make_md5(md5, hostname, len, port, 0, 1);
801
// Attempt to find the result in-line, for level 1 hits
803
// find the partition lock
804
ProxyMutex *bucket_mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets));
805
MUTEX_TRY_LOCK(lock, bucket_mutex, thread);
807
// If we can get the lock and a level 1 probe succeeds, return
809
HostDBInfo *r = probe(bucket_mutex, md5, hostname, len, 1, port, pDS, false, true);
811
Debug("hostdb", "immediate SRV answer for %s from hostdb", hostname);
812
Debug("dns_srv", "immediate SRV answer for %s from hostdb", hostname);
813
HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
814
(cont->*process_srv_info) (r);
815
return ACTION_RESULT_DONE;
820
Debug("dns_srv", "delaying (force=%d) SRV answer for %s [timeout = %d]", force_dns, hostname, dns_lookup_timeout);
822
// Otherwise, create a continuation to do a deeper probe in the background
823
HostDBContinuation *c = hostDBContAllocator.alloc();
824
c->init(hostname, len, 0, port, md5, cont, pDS, true, dns_lookup_timeout);
825
c->force_dns = force_dns;
826
SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent);
828
if (thread->mutex == cont->mutex) {
829
thread->schedule_in(c, MUTEX_RETRY_DELAY);
831
dnsProcessor.thread->schedule_imm(c);
838
// Wrapper from getbyname to getby
841
HostDBProcessor::getbyname_imm(Continuation * cont, process_hostdb_info_pfn process_hostdb_info,
842
char *hostname, int len, int port, int flags, int dns_lookup_timeout)
844
ink_debug_assert(cont->mutex->thread_holding == this_ethread());
845
bool force_dns = false;
846
EThread *thread = cont->mutex->thread_holding;
847
ProxyMutex *mutex = thread->mutex;
849
if (flags & HOSTDB_FORCE_DNS_ALWAYS)
851
else if (flags & HOSTDB_FORCE_DNS_RELOAD) {
852
force_dns = (hostdb_re_dns_on_reload ? true : false);
854
HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat);
859
HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat);
861
if (!hostdb_enable || !*hostname) {
862
(cont->*process_hostdb_info) (NULL);
863
return ACTION_RESULT_DONE;
867
len = strlen(hostname);
870
if (SplitDNSConfig::isSplitDNSEnabled()) {
871
char *scan = hostname;
872
char *pServerLine = 0;
873
for (; *scan != '\0' && (ParseRules::is_digit(*scan) || '.' == *scan); scan++);
875
void *pSD = (void *) SplitDNSConfig::acquire();
877
pDS = ((SplitDNS *) pSD)->getDNSRecord(hostname);
880
pServerLine = ((DNSServer *) pDS)->x_dns_ip_line;
883
SplitDNSConfig::release((SplitDNS *) pSD);
885
make_md5(md5, hostname, len, port, pServerLine);
888
make_md5(md5, hostname, len, port, 0);
890
// Attempt to find the result in-line, for level 1 hits
892
// find the partition lock
893
ProxyMutex *bucket_mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets));
894
MUTEX_TRY_LOCK(lock, bucket_mutex, thread);
896
// If we can get the lock and a level 1 probe succeeds, return
898
HostDBInfo *r = probe(bucket_mutex, md5, hostname, len, 0, port, pDS);
900
Debug("hostdb", "immediate answer for %s", hostname ? hostname : "<addr>");
901
HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
902
(cont->*process_hostdb_info) (r);
903
return ACTION_RESULT_DONE;
908
Debug("hostdb", "delaying force %d answer for %s [timeout %d]", force_dns, hostname, dns_lookup_timeout);
910
// Otherwise, create a continuation to do a deeper probe in the background
911
HostDBContinuation *c = hostDBContAllocator.alloc();
912
c->init(hostname, len, 0, port, md5, cont, pDS, false, dns_lookup_timeout);
913
c->force_dns = force_dns;
914
SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent);
916
thread->schedule_in(c, MUTEX_RETRY_DELAY);
923
do_setby(HostDBInfo * r, HostDBApplicationInfo * app, char *hostname, unsigned int ip)
925
HostDBRoundRobin *rr = r->rr();
928
ink_assert(hostname);
929
for (int i = 0; i < rr->n; i++) {
930
if (rr->info[i].ip() == ip) {
931
Debug("hostdb", "immediate setby for %s", hostname ? hostname : "<addr>");
932
rr->info[i].app.allotment.application1 = app->allotment.application1;
933
rr->info[i].app.allotment.application2 = app->allotment.application2;
938
if (r->reverse_dns || (!r->round_robin && r->ip() == ip)) {
939
Debug("hostdb", "immediate setby for %s", hostname ? hostname : "<addr>");
940
r->app.allotment.application1 = app->allotment.application1;
941
r->app.allotment.application2 = app->allotment.application2;
948
HostDBProcessor::setby(char *hostname, int len, int port, unsigned int ip, HostDBApplicationInfo * app)
955
// if it is by name, INK_MD5 the name
959
len = strlen(hostname);
960
make_md5(md5, hostname, len, port);
963
// INK_MD5 the ip, pad on both sizes with 0's
964
// so that it does not intersect the string space
967
// suvasv: Changed from this
968
// uint64_t dummy = ip << 16;
969
// to uint64_t dummy = ip*64*1024 for bug INKqa10029.
970
// Problem was that ip << 16 would not work for architectures with
971
// a different byte order. This takes cares of all byte orders.
972
uint64_t dummy = ((uint64_t) ip) * 64 * 1024;
973
md5.encodeBuffer((char *) &dummy, 8);
976
// Attempt to find the result in-line, for level 1 hits
978
ProxyMutex *mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets));
979
EThread *thread = this_ethread();
980
MUTEX_TRY_LOCK(lock, mutex, thread);
983
HostDBInfo *r = probe(mutex, md5, hostname, len, ip, port, 0);
985
do_setby(r, app, hostname, ip);
988
// Create a continuation to do a deaper probe in the background
990
HostDBContinuation *c = hostDBContAllocator.alloc();
991
c->init(hostname, len, ip, port, md5, NULL);
992
c->app.allotment.application1 = app->allotment.application1;
993
c->app.allotment.application2 = app->allotment.application2;
994
SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::setbyEvent);
995
thread->schedule_in(c, MUTEX_RETRY_DELAY);
1000
HostDBContinuation::setbyEvent(int event, Event * e)
1002
NOWARN_UNUSED(event);
1004
HostDBInfo *r = probe(mutex, md5, name, namelen, ip, port, 0);
1007
do_setby(r, &app, name, ip);
1008
hostdb_cont_free(this);
1014
remove_round_robin(HostDBInfo * r, char *hostname, unsigned int ip)
1017
if (!r->round_robin)
1019
HostDBRoundRobin *rr = r->rr();
1022
for (int i = 0; i < rr->good; i++) {
1023
if (rr->info[i].ip() == ip) {
1024
Debug("hostdb", "Deleting %u.%u.%u.%u from '%s' round robin DNS entry",
1025
((unsigned char *) &ip)[0], ((unsigned char *) &ip)[1],
1026
((unsigned char *) &ip)[2], ((unsigned char *) &ip)[3], hostname);
1027
HostDBInfo tmp = rr->info[i];
1028
rr->info[i] = rr->info[rr->good - 1];
1029
rr->info[rr->good - 1] = tmp;
1031
if (rr->good <= 0) {
1032
hostDB.delete_block(r);
1035
if (diags->on("hostdb")) {
1036
int bufsize = (HOST_DB_MAX_ROUND_ROBIN_INFO * 16) * 2;
1037
char *rr_ip_list = (char *) alloca(bufsize);
1038
char *p = rr_ip_list;
1039
for (int n = 0; n < rr->good; n++) {
1040
unsigned int rr_ip = rr->info[n].ip();
1041
unsigned char *pip = (unsigned char *) &rr_ip;
1042
int nbytes = snprintf(p, bufsize, "%hhu.%hhu.%hhu.%hhu ", pip[0], pip[1], pip[2], pip[3]);
1046
Note("'%s' round robin DNS entry updated, entries=%d, IP list: %s", hostname, rr->good, rr_ip_list);
1058
HostDBProcessor::failed_connect_on_ip_for_name(Continuation * cont, unsigned int ip, char *hostname, int len, int port)
1061
char *pServerLine = 0;
1066
if (hostname && SplitDNSConfig::isSplitDNSEnabled()) {
1067
pSD = SplitDNSConfig::acquire();
1070
pDS = pSD->getDNSRecord(hostname);
1071
pServerLine = ((DNSServer *) pDS)->x_dns_ip_line;
1073
SplitDNSConfig::release(pSD);
1077
make_md5(md5, hostname, len, port, pServerLine);
1078
ProxyMutex *mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets));
1079
EThread *thread = this_ethread();
1080
MUTEX_TRY_LOCK(lock, mutex, thread);
1082
if (!hostdb_enable || NULL == pDS) {
1084
cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, (void *) NULL);
1085
return ACTION_RESULT_DONE;
1088
HostDBInfo *r = probe(mutex, md5, hostname, len, ip, port, pDS);
1090
HostDBInfo *r = probe(mutex, md5, hostname, len, ip, port, 0);
1092
bool res = (remove_round_robin(r, hostname, ip) ? true : false);
1094
cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, res ? (void *) &ip : (void *) NULL);
1095
return ACTION_RESULT_DONE;
1097
HostDBContinuation *c = hostDBContAllocator.alloc();
1098
c->init(hostname, len, ip, port, md5, cont, pDS);
1099
SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::removeEvent);
1100
thread->schedule_in(c, MUTEX_RETRY_DELAY);
1106
HostDBContinuation::removeEvent(int event, Event * e)
1108
NOWARN_UNUSED(event);
1109
Continuation *cont = action.continuation;
1111
MUTEX_TRY_LOCK(lock, cont ? (ProxyMutex *) cont->mutex : (ProxyMutex *) NULL, e->ethread);
1113
e->schedule_in(HOST_DB_RETRY_PERIOD);
1116
if (!action.cancelled) {
1117
if (!hostdb_enable) {
1119
cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, (void *) NULL);
1121
HostDBInfo *r = probe(mutex, md5, name, namelen, ip, port, m_pDS);
1122
bool res = (remove_round_robin(r, name, ip) ? true : false);
1124
cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, res ? (void *) &ip : (void *) NULL);
1127
hostdb_cont_free(this);
1132
// Lookup done, insert into the local table, return data to the
1133
// calling continuation or to the calling cluster node.
1136
HostDBContinuation::lookup_done(int aip, char *aname, bool around_robin, unsigned int ttl_seconds, SRVHosts * srv)
1138
HostDBInfo *i = NULL;
1140
ink_debug_assert(this_ethread() == hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets))->thread_holding);
1141
if (!aip || !aname || !aname[0]) {
1143
Debug("hostdb", "lookup_done() failed for '%s'", name);
1144
} else if (is_srv()) {
1145
Debug("dns_srv", "SRV failed for '%s'", name);
1147
Debug("hostdb", "failed for %u.%u.%u.%u",
1148
((unsigned char *) &ip)[0], ((unsigned char *) &ip)[1],
1149
((unsigned char *) &ip)[2], ((unsigned char *) &ip)[3]);
1151
i = insert(hostdb_ip_fail_timeout_interval); // currently ... 0
1152
i->round_robin = false;
1153
i->reverse_dns = !is_byname() && !is_srv();
1155
switch (hostdb_ttl_mode) {
1157
ink_assert(!"bad TTL mode");
1161
ttl_seconds = hostdb_ip_timeout_interval * 60;
1164
if (hostdb_ip_timeout_interval * 60 < ttl_seconds)
1165
ttl_seconds = hostdb_ip_timeout_interval * 60;
1168
if (hostdb_ip_timeout_interval * 60 > ttl_seconds)
1169
ttl_seconds = hostdb_ip_timeout_interval * 60;
1172
HOSTDB_SUM_DYN_STAT(hostdb_ttl_stat, ttl_seconds);
1174
ttl_seconds = 1; // www.barnsandnobel.com is lame
1175
i = insert(ttl_seconds);
1177
Debug("hostdb", "done %u.%u.%u.%u TTL %d",
1178
((unsigned char *) &aip)[0], ((unsigned char *) &aip)[1],
1179
((unsigned char *) &aip)[2], ((unsigned char *) &aip)[3], ttl_seconds);
1181
i->round_robin = around_robin;
1182
i->reverse_dns = false;
1183
if (name != aname) {
1184
ink_strncpy(name, aname, MAXDNAME);
1187
} else if (is_srv()) {
1189
i->ip() = aip; /* this doesnt matter w. srv records -- setting to 1 so Md5 works */
1191
i->reverse_dns = false;
1193
if (srv) { //failed case: srv == NULL
1194
i->srv_count = srv->getCount();
1199
if (i->srv_count <= 0) {
1200
i->round_robin = false;
1202
i->round_robin = true;
1207
if (name != aname) {
1208
ink_strncpy(name, aname, MAXDNAME);
1212
Debug("hostdb", "done '%s' TTL %d", aname, ttl_seconds);
1213
const size_t s_size = strlen(aname) + 1;
1214
void *s = hostDB.alloc(&i->data.hostname_offset, s_size);
1216
ink_strncpy((char *) s, aname, s_size);
1217
i->round_robin = false;
1218
i->reverse_dns = true;
1221
ink_assert(!"out of room in hostdb data area");
1222
Warning("out of room in hostdb for reverse DNS data");
1223
hostDB.delete_block(i);
1230
do_put_response(from, i, from_cont);
1232
ink_assert(!i->round_robin || !i->reverse_dns);
1238
HostDBContinuation::dnsPendingEvent(int event, Event * e)
1240
ink_debug_assert(this_ethread() == hostDB.lock_for_bucket(fold_md5(md5) % hostDB.buckets)->thread_holding);
1242
timeout->cancel(this);
1245
if (event == EVENT_INTERVAL) {
1246
// we timed out, return a failure to the user
1247
MUTEX_TRY_LOCK_FOR(lock, action.mutex, ((Event *) e)->ethread, action.continuation);
1249
((Event *) e)->schedule_in(HOST_DB_RETRY_PERIOD);
1252
if (!action.cancelled && action.continuation)
1253
action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
1254
hostDB.pending_dns_for_hash(md5).remove(this);
1255
hostdb_cont_free(this);
1258
SET_HANDLER((HostDBContHandler) & HostDBContinuation::probeEvent);
1259
return probeEvent(EVENT_INTERVAL, NULL);
1264
restore_info(HostDBInfo * r, HostDBInfo * old_r, HostDBInfo & old_info, HostDBRoundRobin * old_rr_data)
1267
for (int j = 0; j < old_rr_data->n; j++)
1268
if (old_rr_data->info[j].ip() == r->ip()) {
1269
r->app = old_rr_data->info[j].app;
1273
if (old_info.ip() == r->ip()) {
1274
r->app = old_info.app;
1281
// DNS lookup result state
1284
HostDBContinuation::dnsEvent(int event, HostEnt * e)
1286
ink_debug_assert(this_ethread() == hostDB.lock_for_bucket(fold_md5(md5) % hostDB.buckets)->thread_holding);
1288
timeout->cancel(this);
1291
EThread *thread = mutex->thread_holding;
1292
if (event == EVENT_INTERVAL) {
1293
if (!action.continuation) {
1294
// give up on insert, it has been too long
1295
remove_trigger_pending_dns();
1296
hostdb_cont_free(this);
1299
MUTEX_TRY_LOCK_FOR(lock, action.mutex, thread, action.continuation);
1301
timeout = thread->schedule_in(this, HOST_DB_RETRY_PERIOD);
1304
if (!action.cancelled && action.continuation)
1305
action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
1307
// do not exit yet, wait to see if we can insert into DB
1308
timeout = thread->schedule_in(this, HRTIME_SECONDS(hostdb_insert_timeout));
1315
rr = !failed && (e->srv_hosts.getCount() > 0);
1317
rr = !failed && e->ent.h_addr_list[1];
1319
pending_action = NULL;
1321
ttl = failed ? 0 : e->ttl / 60;
1322
int ttl_seconds = failed ? 0 : e->ttl; //ebalsa: moving to second accuracy
1324
HostDBInfo *old_r = probe(mutex, md5, name, namelen, ip, port, m_pDS, true);
1325
HostDBInfo old_info;
1328
HostDBRoundRobin *old_rr_data = old_r ? old_r->rr() : NULL;
1330
int n = 0, nn = 0, first = -1;
1332
if (is_srv() && !failed) {
1333
n = e->srv_hosts.getCount();
1335
for (; nn < HOST_DB_MAX_ROUND_ROBIN_INFO && e->ent.h_addr_list[nn]; nn++)
1336
if (*(unsigned int *) e->ent.h_addr_list[nn]) {
1341
Warning("0.0.0.0 removed from round-robin list for '%s'", name);
1351
HostDBInfo *r = NULL;
1354
lookup_done(failed ? 0 : *(unsigned int *) e->ent.h_addr_list[first], name, rr, ttl_seconds,
1355
failed ? 0 : &e->srv_hosts);
1357
r = lookup_done(1, /* junk: FIXME: is the code in lookup_done() wrong to NEED this? */
1358
name, /* hostname */
1359
rr, /* is round robin, doesnt matter for SRV since we recheck getCount() inside lookup_done() */
1360
ttl_seconds, /* ttl in seconds */
1361
failed ? 0 : &e->srv_hosts);
1363
r = lookup_done(failed ? 0 : ip, failed ? name : e->ent.h_name, false, ttl_seconds, failed ? 0 : &e->srv_hosts);
1366
int s = HostDBRoundRobin::size(n, is_srv());
1367
HostDBRoundRobin *rr_data = (HostDBRoundRobin *) hostDB.alloc(&r->app.rr.offset, s);
1368
Debug("hostdb", "allocating %d bytes for %d RR at %lX %d", s, n, rr_data, r->app.rr.offset);
1372
SortableQueue<SRV> *q = e->srv_hosts.getHosts();
1374
for (i = 0; i < n; i++) {
1376
SRV *t = q->dequeue();
1378
rr_data->info[i].ip() = 1;
1379
rr_data->info[i].round_robin = 0;
1380
rr_data->info[i].reverse_dns = 0;
1382
rr_data->info[i].srv_weight = t->getWeight();
1383
rr_data->info[i].srv_priority = t->getPriority();
1384
rr_data->info[i].srv_port = t->getPort();
1386
ink_strncpy(rr_data->rr_srv_hosts[i], t->getHost(), MAXDNAME);
1387
rr_data->rr_srv_hosts[i][MAXDNAME - 1] = '\0';
1388
rr_data->info[i].is_srv = true;
1390
rr_data->info[i].full = 1;
1391
rr_data->info[i].md5_high = r->md5_high;
1392
rr_data->info[i].md5_low = r->md5_low;
1393
rr_data->info[i].md5_low_low = r->md5_low_low;
1394
SRVAllocator.free(t);
1395
Debug("dns_srv", "inserted SRV RR record into HostDB with TTL: %d seconds", ttl_seconds);
1399
for (; ii < nn; ii++) {
1400
if (*(unsigned int *) e->ent.h_addr_list[ii]) {
1401
rr_data->info[i].ip() = *(unsigned int *) e->ent.h_addr_list[ii];
1402
rr_data->info[i].full = 1;
1403
rr_data->info[i].round_robin = 0;
1404
rr_data->info[i].reverse_dns = 0;
1405
rr_data->info[i].md5_high = r->md5_high;
1406
rr_data->info[i].md5_low = r->md5_low;
1407
rr_data->info[i].md5_low_low = r->md5_low_low;
1408
if (!restore_info(&rr_data->info[i], old_r, old_info, old_rr_data)) {
1409
rr_data->info[i].app.allotment.application1 = 0;
1410
rr_data->info[i].app.allotment.application2 = 0;
1416
rr_data->good = rr_data->n = n;
1417
rr_data->current = 0;
1419
ink_assert(!"out of room in hostdb data area");
1420
Warning("out of room in hostdb for round-robin DNS data");
1425
restore_info(r, old_r, old_info, old_rr_data);
1426
ink_assert(!r || !r->round_robin || !r->reverse_dns);
1427
ink_assert(failed || !r->round_robin || r->app.rr.offset);
1430
// if we are not the owner, put on the owner
1432
ClusterMachine *m = cluster_machine_at_depth(master_hash(md5));
1434
do_put_response(m, r, NULL);
1437
// try to callback the user
1439
if (action.continuation) {
1440
MUTEX_TRY_LOCK_FOR(lock, action.mutex, thread, action.continuation);
1442
remove_trigger_pending_dns();
1443
SET_HANDLER((HostDBContHandler) & HostDBContinuation::probeEvent);
1444
thread->schedule_in(this, HOST_DB_RETRY_PERIOD);
1447
if (!action.cancelled)
1448
reply_to_cont(action.continuation, r);
1450
// wake up everyone else who is waiting
1451
remove_trigger_pending_dns();
1455
hostdb_cont_free(this);
1463
// HostDB Get Message
1464
// Used to lookup host information on a remote node in the cluster
1466
struct HostDB_get_message
1473
char name[MAXDNAME];
1478
// Make a get message
1481
HostDBContinuation::make_get_message(char *buf, int size)
1483
ink_assert(size >= (int) sizeof(HostDB_get_message));
1485
HostDB_get_message *msg = (HostDB_get_message *) buf;
1487
msg->port = htonl(port);
1488
msg->ip = htonl(ip);
1492
ink_strncpy(msg->name, name, sizeof(msg->name));
1495
int len = sizeof(HostDB_get_message) - MAXDNAME + strlen(name) + 1;
1502
// Make and send a get message
1504
bool HostDBContinuation::do_get_response(Event * e)
1507
if (!hostdb_cluster)
1510
// find an appropriate Machine
1515
if (hostdb_migrate_on_demand)
1516
m = cluster_machine_at_depth(master_hash(md5), &probe_depth, past_probes);
1520
m = cluster_machine_at_depth(master_hash(md5));
1531
memset(&msg, 0, sizeof(msg));
1533
len = make_get_message((char *) &msg, sizeof(HostDB_get_message));
1535
// Setup this continuation, with a timeout
1537
remoteHostDBQueue[key_partition()].enqueue(this);
1538
SET_HANDLER((HostDBContHandler) & HostDBContinuation::clusterEvent);
1539
timeout = mutex->thread_holding->schedule_in(this, HOST_DB_CLUSTER_TIMEOUT);
1543
clusterProcessor.invoke_remote(m, GET_HOSTINFO_CLUSTER_FUNCTION, (char *) &msg, len);
1550
// HostDB Put Message
1551
// This message is used in a response to a cluster node for
1552
// Host inforamation.
1554
struct HostDB_put_message
1584
// Build the put message
1587
HostDBContinuation::make_put_message(HostDBInfo * r, Continuation * c, char *buf, int size)
1589
ink_assert(size >= (int) sizeof(HostDB_put_message));
1591
HostDB_put_message *msg = (HostDB_put_message *) buf;
1592
memset(msg, 0, sizeof(HostDB_put_message));
1597
msg->ip = htonl(r->ip());
1598
msg->application1 = r->app.allotment.application1;
1599
msg->application2 = r->app.allotment.application2;
1600
msg->missing = false;
1601
msg->round_robin = r->round_robin;
1602
msg->ttl = r->ip_time_remaining();
1604
msg->missing = true;
1608
ink_strncpy(msg->name, name, sizeof(msg->name));
1612
int len = sizeof(HostDB_put_message) - MAXDNAME + strlen(name) + 1;
1619
// Build the put message and send it
1622
HostDBContinuation::do_put_response(ClusterMachine * m, HostDBInfo * r, Continuation * c)
1624
// don't remote fill round-robin DNS entries
1625
// if configured not to cluster them
1626
if (!c && r->round_robin && !hostdb_cluster_round_robin)
1629
HostDB_put_message msg;
1630
int len = make_put_message(r, c, (char *) &msg, sizeof(HostDB_put_message));
1632
clusterProcessor.invoke_remote(m, PUT_HOSTINFO_CLUSTER_FUNCTION, (char *) &msg, len);
1635
#endif // NON_MODULAR
1642
HostDBContinuation::probeEvent(int event, Event * e)
1644
NOWARN_UNUSED(event);
1645
ink_assert(!link.prev && !link.next);
1646
EThread *t = e ? e->ethread : this_ethread();
1648
MUTEX_TRY_LOCK_FOR(lock, action.mutex, t, action.continuation);
1650
mutex->thread_holding->schedule_in(this, HOST_DB_RETRY_PERIOD);
1654
if (action.cancelled) {
1655
hostdb_cont_free(this);
1659
if (!hostdb_enable || (!*name && !ip)) {
1660
if (action.continuation)
1661
action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
1664
do_put_response(from, 0, from_cont);
1666
hostdb_cont_free(this);
1674
HostDBInfo *r = probe(mutex, md5, name, namelen, ip, port, m_pDS);
1677
HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
1680
if (action.continuation && r)
1681
reply_to_cont(action.continuation, r);
1683
// Respond to any remote node
1686
do_put_response(from, r, from_cont);
1689
// If it suceeds or it was a remote probe, we are done
1692
hostdb_cont_free(this);
1696
// If it failed, do a remote probe
1698
if (do_get_response(e))
1702
// If there are no remote nodes to probe, do a DNS lookup
1710
HostDBContinuation::set_check_pending_dns()
1712
Queue<HostDBContinuation> &q = hostDB.pending_dns_for_hash(md5);
1713
HostDBContinuation *c = q.head;
1714
for (; c; c = (HostDBContinuation *) c->link.next) {
1715
if (md5 == c->md5) {
1716
Debug("hostdb", "enqueuing additional request");
1727
HostDBContinuation::remove_trigger_pending_dns()
1729
Queue<HostDBContinuation> &q = hostDB.pending_dns_for_hash(md5);
1731
HostDBContinuation *c = q.head;
1732
Queue<HostDBContinuation> qq;
1734
HostDBContinuation *n = (HostDBContinuation *) c->link.next;
1735
if (md5 == c->md5) {
1736
Debug("hostdb", "dequeuing additional request");
1742
while ((c = qq.dequeue()))
1743
c->handleEvent(EVENT_IMMEDIATE, NULL);
1748
// Query the DNS processor
1751
HostDBContinuation::do_dns()
1753
ink_assert(!action.cancelled);
1755
Debug("hostdb", "DNS %s", name);
1756
unsigned int tip = ink_inet_addr(name);
1757
// check 127.0.0.1 format
1758
if ((int) tip != -1) {
1759
if (action.continuation) {
1760
HostDBInfo *r = lookup_done(tip, name, false, HOST_DB_MAX_TTL, NULL);
1761
reply_to_cont(action.continuation, r);
1763
hostdb_cont_free(this);
1767
if (hostdb_lookup_timeout)
1768
timeout = mutex->thread_holding->schedule_in(this, HRTIME_SECONDS(hostdb_lookup_timeout));
1771
if (set_check_pending_dns()) {
1772
SET_HANDLER((HostDBContHandler) & HostDBContinuation::dnsEvent);
1774
DNSHandler *dnsH = 0;
1777
dnsH = (DNSHandler *) (((DNSServer *) (m_pDS))->x_dnsH);
1779
pending_action = dnsProcessor.gethostbyname(this, name, dnsH, dns_lookup_timeout);
1780
} else if (is_srv()) {
1781
DNSHandler *dnsH = 0;
1782
Debug("dns_srv", "SRV lookup of %s", name);
1783
pending_action = dnsProcessor.getSRVbyname(this, name, dnsH, dns_lookup_timeout);
1785
Debug("hostdb", "DNS IP %u.%u.%u.%u",
1786
((unsigned char *) &ip)[0], ((unsigned char *) &ip)[1],
1787
((unsigned char *) &ip)[2], ((unsigned char *) &ip)[3]);
1788
pending_action = dnsProcessor.gethostbyaddr(this, ip, dns_lookup_timeout);
1791
SET_HANDLER((HostDBContHandler) & HostDBContinuation::dnsPendingEvent);
1799
// Handle the response (put message)
1802
HostDBContinuation::clusterResponseEvent(int event, Event * e)
1804
NOWARN_UNUSED(event);
1806
HostDBContinuation *c;
1807
for (c = (HostDBContinuation *) remoteHostDBQueue[key_partition()].head; c; c = (HostDBContinuation *) c->link.next)
1811
// Check to see that we have not already timed out
1816
MUTEX_TRY_LOCK(lock, c->mutex, e->ethread);
1817
MUTEX_TRY_LOCK(lock2, c->action.mutex, e->ethread);
1818
if (!lock || !lock2) {
1819
e->schedule_in(HOST_DB_RETRY_PERIOD);
1822
bool failed = missing || (round_robin && !hostdb_cluster_round_robin);
1823
action.continuation->handleEvent(EVENT_HOST_DB_GET_RESPONSE, failed ? 0 : this);
1827
// just a remote fill
1828
ink_assert(!missing);
1829
lookup_done(ip, name, false, ttl, NULL);
1831
hostdb_cont_free(this);
1837
// Wait for the response (put message)
1840
HostDBContinuation::clusterEvent(int event, Event * e)
1842
// remove ourselves from the queue
1844
remoteHostDBQueue[key_partition()].remove(this);
1848
ink_assert(!"bad case");
1849
hostdb_cont_free(this);
1852
// handle the put response, e is really a HostDBContinuation *
1854
case EVENT_HOST_DB_GET_RESPONSE:
1856
timeout->cancel(this);
1860
HostDBContinuation *c = (HostDBContinuation *) e;
1861
HostDBInfo *r = lookup_done(c->ip, c->name, false, c->ttl, NULL);
1862
r->app.allotment.application1 = c->app.allotment.application1;
1863
r->app.allotment.application2 = c->app.allotment.application2;
1865
HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
1867
if (!action.cancelled) {
1868
if (reply_to_cont(action.continuation, r)) {
1869
// if we are not the owner and neither was the sender,
1872
if (hostdb_migrate_on_demand) {
1873
ClusterMachine *m = cluster_machine_at_depth(master_hash(md5));
1874
if (m && m != c->from)
1875
do_put_response(m, r, NULL);
1879
hostdb_cont_free(this);
1882
return failed_cluster_request(e);
1884
// did not get the put message in time
1886
case EVENT_INTERVAL:{
1887
MUTEX_TRY_LOCK_FOR(lock, action.mutex, e->ethread, action.continuation);
1889
e->schedule_in(HOST_DB_RETRY_PERIOD);
1892
return failed_cluster_request(e);
1899
HostDBContinuation::failed_cluster_request(Event * e)
1901
if (action.cancelled) {
1902
hostdb_cont_free(this);
1905
// Attempt another remote probe
1907
if (do_get_response(e))
1910
// Otherwise, do a DNS lookup
1918
get_hostinfo_ClusterFunction(ClusterMachine * from, void *data, int len)
1922
HostDB_get_message *msg = (HostDB_get_message *) data;
1926
char *hostname = msg->name;
1927
if (hostname && SplitDNSConfig::isSplitDNSEnabled()) {
1928
pSD = SplitDNSConfig::acquire();
1931
pDS = pSD->getDNSRecord(hostname);
1933
SplitDNSConfig::release(pSD);
1937
HostDBContinuation *c = hostDBContAllocator.alloc();
1938
SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent);
1940
c->from_cont = msg->cont;
1942
/* -----------------------------------------
1943
we make a big assumption here! we presume
1944
that all the machines in the cluster are
1945
set to use the same configuration for
1947
----------------------------------------- */
1950
c->init(msg->name, msg->namelen, ntohl(msg->ip), ntohl(msg->port), msg->md5, NULL, pDS);
1951
TEST(printf("get_hostinfo_ClusterFunction %s %d\n", msg->name, msg->ip));
1952
c->mutex = hostDB.lock_for_bucket(fold_md5(msg->md5) % hostDB.buckets);
1953
c->action.mutex = c->mutex;
1954
dnsProcessor.thread->schedule_imm(c);
1959
put_hostinfo_ClusterFunction(ClusterMachine * from, void *data, int len)
1962
HostDB_put_message *msg = (HostDB_put_message *) data;
1963
HostDBContinuation *c = hostDBContAllocator.alloc();
1965
SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::clusterResponseEvent);
1966
c->init(msg->name, msg->namelen, ntohl(msg->ip), ntohl(msg->port), msg->md5, NULL);
1967
TEST(printf("put_hostinfo_ClusterFunction %s %d\n", msg->name, msg->ip));
1968
c->mutex = hostDB.lock_for_bucket(fold_md5(msg->md5) % hostDB.buckets);
1969
c->from_cont = msg->cont; // cannot use action if cont freed due to timeout
1970
c->missing = msg->missing;
1971
c->round_robin = msg->round_robin;
1974
dnsProcessor.thread->schedule_imm(c);
1976
#endif // NON_MODULAR
1981
// Just increment the current_interval. Might do other stuff
1982
// here, like move records to the current position in the cluster.
1985
HostDBContinuation::backgroundEvent(int event, Event * e)
1987
NOWARN_UNUSED(event);
1989
hostdb_current_interval++;
1994
bool HostDBInfo::match(INK_MD5 & md5, int bucket, int buckets)
1996
NOWARN_UNUSED(bucket);
1997
if (md5[1] != md5_high)
2001
folded_md5 = fold_md5(md5);
2003
ttag = folded_md5 / buckets;
2015
tmp.md5_low_low = (unsigned int) ttag;
2016
tmp.md5_low = (unsigned int) (ttag >> 24);
2017
return tmp.md5_low_low == md5_low_low && tmp.md5_low == md5_low;
2022
HostDBInfo::hostname()
2027
return (char *) hostDB.ptr(&data.hostname_offset, hostDB.ptr_to_partition((char *) this));
2037
HostDBRoundRobin *r = (HostDBRoundRobin *) hostDB.ptr(&app.rr.offset, hostDB.ptr_to_partition((char *) this));
2039
if (r && (r->n > HOST_DB_MAX_ROUND_ROBIN_INFO || r->n <= 0 || r->good > HOST_DB_MAX_ROUND_ROBIN_INFO || r->good <= 0)) {
2040
ink_assert(!"bad round-robin");
2048
HostDBInfo::heap_size()
2051
char *h = hostname();
2054
return strlen(h) + 1;
2055
} else if (round_robin) {
2056
HostDBRoundRobin *r = rr();
2059
// this is a bit conservative, we might want to resurect them later
2060
return HostDBRoundRobin::size(r->n, this->is_srv);
2067
HostDBInfo::heap_offset_ptr()
2070
return &data.hostname_offset;
2073
return &app.rr.offset;
2081
HostDBContinuation::master_machine(ClusterConfiguration * cc)
2083
return cc->machine_hash((int) (md5[1] >> 32));
2085
#endif // NON_MODULAR
2090
typedef int (ShowHostDB::*ShowHostDBEventHandler) (int event, Event * data);
2091
struct ShowHostDB: public ShowCont
2097
int showMain(int event, Event * e)
2099
CHECK_SHOW(begin("HostDB"));
2100
CHECK_SHOW(show("<form method = GET action = \"./name\">\n"
2101
"Lookup by name (e.g. www.inktomi.com):<br>\n"
2102
"<input type=text name=name size=64 maxlength=256>\n"
2104
"<form method = GET action = \"./ip\">\n"
2105
"Lookup by IP (e.g. 127.0.0.1):<br>\n"
2106
"<input type=text name=ip size=64 maxlength=256>\n"
2108
"<form method = GET action = \"./nameforce\">\n"
2109
"Force DNS by name (e.g. www.inktomi.com):<br>\n"
2110
"<input type=text name=name size=64 maxlength=256>\n" "</form>\n"));
2111
return complete(event, e);
2115
int showLookup(int event, Event * e)
2117
NOWARN_UNUSED(event);
2119
SET_HANDLER(&ShowHostDB::showLookupDone);
2121
hostDBProcessor.getbyname_re(this, name, 0, force ? HostDBProcessor::HOSTDB_FORCE_DNS_ALWAYS : 0);
2123
hostDBProcessor.getbyaddr_re(this, ip);
2128
int showOne(HostDBInfo * r, bool rr, int event, Event * e)
2130
CHECK_SHOW(show("<table border=1>\n"));
2131
CHECK_SHOW(show("<tr><td>%s</td><td>%s%s</td></tr>\n",
2132
"Type", r->round_robin ? "Round-Robin" : "", r->reverse_dns ? "Reverse DNS" : "DNS"));
2133
CHECK_SHOW(show("<tr><td>%s</td><td>%u</td></tr>\n", "App1", r->app.allotment.application1));
2134
CHECK_SHOW(show("<tr><td>%s</td><td>%u</td></tr>\n", "App2", r->app.allotment.application2));
2136
CHECK_SHOW(show("<tr><td>%s</td><td>%s</td></tr>\n", "Stale", r->is_ip_stale()? "Yes" : "No"));
2137
CHECK_SHOW(show("<tr><td>%s</td><td>%s</td></tr>\n", "Timed-Out", r->is_ip_timeout()? "Yes" : "No"));
2138
CHECK_SHOW(show("<tr><td>%s</td><td>%d</td></tr>\n", "TTL", r->ip_time_remaining()));
2140
if (r->reverse_dns) {
2141
CHECK_SHOW(show("<tr><td>%s</td><td>%s</td></tr>\n", "Hostname", r->hostname()? r->hostname() : "<none>"));
2143
CHECK_SHOW(show("<tr><td>%s</td><td>%u.%u.%u.%u</td></tr>\n", "IP", PRINT_IP(r->ip())));
2145
CHECK_SHOW(show("</table>\n"));
2150
int showLookupDone(int event, Event * e)
2152
HostDBInfo *r = (HostDBInfo *) e;
2154
CHECK_SHOW(begin("HostDB Lookup"));
2156
CHECK_SHOW(show("<H2>%s</H2>\n", name));
2158
CHECK_SHOW(show("<H2>%u.%u.%u.%u</H2>\n", PRINT_IP(ip)));
2161
showOne(r, false, event, e);
2162
if (r->round_robin) {
2163
HostDBRoundRobin *rr_data = r->rr();
2165
CHECK_SHOW(show("<table border=1>\n"));
2166
CHECK_SHOW(show("<tr><td>%s</td><td>%d</td></tr>\n", "Total", rr_data->n));
2167
CHECK_SHOW(show("<tr><td>%s</td><td>%d</td></tr>\n", "Good", rr_data->good));
2168
CHECK_SHOW(show("<tr><td>%s</td><td>%d</td></tr>\n", "Current", rr_data->current));
2169
CHECK_SHOW(show("</table>\n"));
2171
for (int i = 0; i < rr_data->n; i++)
2172
showOne(&rr_data->info[i], true, event, e);
2177
CHECK_SHOW(show("<H2>%u.%u.%u.%u Not Found</H2>\n", PRINT_IP(ip)));
2179
CHECK_SHOW(show("<H2>%s Not Found</H2>\n", name));
2182
return complete(event, e);
2186
ShowHostDB(Continuation * c, HTTPHdr * h):
2187
ShowCont(c, h), name(0), ip(0), force(0) {
2188
SET_HANDLER(&ShowHostDB::showMain);
2192
#define STR_LEN_EQ_PREFIX(_x,_l,_s) (!ptr_len_ncasecmp(_x,_l,_s,sizeof(_s)-1))
2196
register_ShowHostDB(Continuation * c, HTTPHdr * h)
2198
ShowHostDB *s = new ShowHostDB(c, h);
2200
const char *path = h->url_get()->path_get(&path_len);
2202
SET_CONTINUATION_HANDLER(s, &ShowHostDB::showMain);
2203
if (STR_LEN_EQ_PREFIX(path, path_len, "ip")) {
2204
s->force = !ptr_len_ncasecmp(path + 3, path_len - 3, "force", 5);
2206
const char *query = h->url_get()->query_get(&query_len);
2207
s->sarg = xstrndup(query, query_len);
2210
gn = (char *) ink_memchr(s->sarg, '=', strlen(s->sarg));
2212
s->ip = ink_inet_addr(gn + 1);
2213
SET_CONTINUATION_HANDLER(s, &ShowHostDB::showLookup);
2214
} else if (STR_LEN_EQ_PREFIX(path, path_len, "name")) {
2215
s->force = !ptr_len_ncasecmp(path + 5, path_len - 5, "force", 5);
2217
const char *query = h->url_get()->query_get(&query_len);
2218
s->sarg = xstrndup(query, query_len);
2221
gn = (char *) ink_memchr(s->sarg, '=', strlen(s->sarg));
2224
SET_CONTINUATION_HANDLER(s, &ShowHostDB::showLookup);
2226
this_ethread()->schedule_imm(s);
2229
#endif // NON_MODULAR
2232
#define HOSTDB_TEST_MAX_OUTSTANDING 100
2233
#define HOSTDB_TEST_LENGTH 100000
2235
struct HostDBTestReverse;
2236
typedef int (HostDBTestReverse::*HostDBTestReverseHandler) (int, void *);
2237
struct HostDBTestReverse: public Continuation
2241
#if TS_HAS_LRAND48_R
2242
struct drand48_data dr;
2245
int mainEvent(int event, Event * e)
2247
if (event == EVENT_HOST_DB_LOOKUP) {
2248
HostDBInfo *i = (HostDBInfo *) e;
2250
printf("HostDBTestReverse: reversed %s\n", i->hostname());
2253
while (outstanding < HOSTDB_TEST_MAX_OUTSTANDING && total < HOSTDB_TEST_LENGTH)
2256
#if TS_HAS_LRAND48_R
2261
unsigned int ip = (unsigned int) l;
2264
if (!(outstanding % 1000))
2265
printf("HostDBTestReverse: %d\n", total);
2266
hostDBProcessor.getbyaddr_re(this, ip);
2269
printf("HostDBTestReverse: done\n");
2274
HostDBTestReverse():Continuation(new_ProxyMutex()), outstanding(0), total(0) {
2275
SET_HANDLER((HostDBTestReverseHandler) & HostDBTestReverse::mainEvent);
2276
#if TS_HAS_SRAND48_R
2277
srand48_r(time(NULL), &dr);
2279
srand48(time(NULL));
2289
if (is_action_tag_set("hostdb_test_rr"))
2290
eventProcessor.schedule_every(new HostDBTestRR, HRTIME_SECONDS(1), ET_NET);
2291
if (is_action_tag_set("hostdb_test_reverse")) {
2292
eventProcessor.schedule_imm(new HostDBTestReverse, ET_CACHE);
2298
RecRawStatBlock *hostdb_rsb;
2301
ink_hostdb_init(ModuleVersion v)
2303
static int init_called = 0;
2305
ink_release_assert(!checkModuleVersion(v, HOSTDB_MODULE_VERSION));
2310
// do one time stuff
2311
// create a stat block for HostDBStats
2312
hostdb_rsb = RecAllocateRawStatBlock((int) HostDB_Stat_Count);
2318
RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
2319
"proxy.process.hostdb.total_entries",
2320
RECD_INT, RECP_NULL, (int) hostdb_total_entries_stat, RecRawStatSyncCount);
2322
RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
2323
"proxy.process.hostdb.total_lookups",
2324
RECD_INT, RECP_NULL, (int) hostdb_total_lookups_stat, RecRawStatSyncSum);
2326
RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
2327
"proxy.process.hostdb.total_hits",
2328
RECD_INT, RECP_NON_PERSISTENT, (int) hostdb_total_hits_stat, RecRawStatSyncSum);
2330
RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
2331
"proxy.process.hostdb.ttl", RECD_FLOAT, RECP_NULL, (int) hostdb_ttl_stat, RecRawStatSyncAvg);
2333
RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
2334
"proxy.process.hostdb.ttl_expires",
2335
RECD_INT, RECP_NULL, (int) hostdb_ttl_expires_stat, RecRawStatSyncSum);
2337
RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
2338
"proxy.process.hostdb.re_dns_on_reload",
2339
RECD_INT, RECP_NULL, (int) hostdb_re_dns_on_reload_stat, RecRawStatSyncSum);
2341
RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
2342
"proxy.process.hostdb.bytes", RECD_INT, RECP_NULL, (int) hostdb_bytes_stat, RecRawStatSyncCount);