~ps10gel/ubuntu/xenial/trafficserver/6.2.0

« back to all changes in this revision

Viewing changes to iocore/hostdb/HostDB.cc

  • Committer: Bazaar Package Importer
  • Author(s): Arno Toell
  • Date: 2011-01-13 11:49:18 UTC
  • Revision ID: james.westby@ubuntu.com-20110113114918-vu422h8dknrgkj15
Tags: upstream-2.1.5-unstable
ImportĀ upstreamĀ versionĀ 2.1.5-unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** @file
 
2
 
 
3
  A brief file description
 
4
 
 
5
  @section license License
 
6
 
 
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
 
14
 
 
15
      http://www.apache.org/licenses/LICENSE-2.0
 
16
 
 
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.
 
22
 */
 
23
 
 
24
#define _HOSTDB_CC_
 
25
 
 
26
#include "P_HostDB.h"
 
27
#include "I_Layout.h"
 
28
 
 
29
#ifndef NON_MODULAR
 
30
//char system_config_directory[512] = "etc/trafficserver";
 
31
#else
 
32
#include "Show.h"
 
33
#endif
 
34
 
 
35
// dxu: turn off all Diags.h 's function.
 
36
//#define Debug
 
37
//#define Warning
 
38
//#define Note
 
39
 
 
40
//
 
41
// Compilation Options
 
42
//
 
43
#define USE_MMH
 
44
 
 
45
#include "ink_apidefs.h"
 
46
 
 
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;
 
67
 
 
68
ClassAllocator<HostDBContinuation> hostDBContAllocator("hostDBContAllocator");
 
69
 
 
70
// Static configuration information
 
71
 
 
72
HostDBCache
 
73
  hostDB;
 
74
 
 
75
#ifdef NON_MODULAR
 
76
static  Queue <HostDBContinuation > remoteHostDBQueue[MULTI_CACHE_PARTITIONS];
 
77
#endif
 
78
 
 
79
static inline int
 
80
corrupt_debugging_callout(HostDBInfo * e, RebuildMC & r)
 
81
{
 
82
  Debug("hostdb", "corrupt %d part %d", (char *) &e->app.rr.offset - r.data, r.partition);
 
83
  return -1;
 
84
}
 
85
 
 
86
 
 
87
inline void
 
88
hostdb_cont_free(HostDBContinuation * cont)
 
89
{
 
90
  if (cont->pending_action)
 
91
    cont->pending_action->cancel();
 
92
  cont->mutex = 0;
 
93
  cont->action.mutex = 0;
 
94
  hostDBContAllocator.free(cont);
 
95
}
 
96
 
 
97
 
 
98
//
 
99
// Function Prototypes
 
100
//
 
101
#ifdef NON_MODULAR
 
102
static Action *
 
103
register_ShowHostDB(Continuation * c, HTTPHdr * h);
 
104
#endif
 
105
 
 
106
 
 
107
//
 
108
// Initialization
 
109
//
 
110
HostDBProcessor::HostDBProcessor()
 
111
{
 
112
}
 
113
 
 
114
 
 
115
HostDBCache::HostDBCache()
 
116
{
 
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;
 
121
}
 
122
 
 
123
 
 
124
int
 
125
HostDBCache::rebuild_callout(HostDBInfo * e, RebuildMC & r)
 
126
{
 
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)
 
131
      return 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);
 
136
      if (!p)
 
137
        return corrupt_debugging_callout(e, r);
 
138
      char *s = p;
 
139
      while (*p && p - s < MAXDNAME) {
 
140
        if (!valid_heap_pointer(p))
 
141
          return corrupt_debugging_callout(e, r);
 
142
        p++;
 
143
      }
 
144
      if (p - s >= MAXDNAME)
 
145
        return corrupt_debugging_callout(e, r);
 
146
    }
 
147
  }
 
148
  if (e->round_robin) {
 
149
    if (e->app.rr.offset < 0)
 
150
      return 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);
 
154
    if (!rr)
 
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))
 
161
        return -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);
 
167
    }
 
168
  }
 
169
  if (e->is_ip_timeout())
 
170
    return 0;
 
171
  return 1;
 
172
}
 
173
 
 
174
 
 
175
HostDBCache *
 
176
HostDBProcessor::cache()
 
177
{
 
178
  return &hostDB;
 
179
}
 
180
 
 
181
 
 
182
struct HostDBTestRR: public Continuation
 
183
{
 
184
  int fd;
 
185
  char b[512];
 
186
  int nb;
 
187
  int outstanding, success, failure;
 
188
  int in;
 
189
 
 
190
  int mainEvent(int event, Event * e)
 
191
  {
 
192
    if (event == EVENT_INTERVAL) {
 
193
      printf("HostDBTestRR: %d outstanding %d succcess %d failure\n", outstanding, success, failure);
 
194
    }
 
195
    if (event == EVENT_HOST_DB_LOOKUP) {
 
196
      outstanding--;
 
197
      if (e)
 
198
        success++;
 
199
      else
 
200
        failure++;
 
201
    }
 
202
    if (in)
 
203
      return EVENT_CONT;
 
204
    in = 1;
 
205
    while (outstanding < 40) {
 
206
      if (!nb)
 
207
        goto Lreturn;
 
208
      char *end = (char *) ink_memchr(b, '\n', nb);
 
209
      if (!end)
 
210
        read_some();
 
211
      end = (char *) ink_memchr(b, '\n', nb);
 
212
      if (!end)
 
213
        nb = 0;
 
214
      else {
 
215
        *end = 0;
 
216
        outstanding++;
 
217
        hostDBProcessor.getbyname_re(this, b);
 
218
        nb -= ((end + 1) - b);
 
219
        memcpy(b, end + 1, nb);
 
220
        if (!nb)
 
221
          read_some();
 
222
      }
 
223
    }
 
224
  Lreturn:
 
225
    in = 0;
 
226
    return EVENT_CONT;
 
227
  }
 
228
 
 
229
 
 
230
  void read_some()
 
231
  {
 
232
    nb = read(fd, b + nb, 512 - nb);
 
233
    ink_release_assert(nb >= 0);
 
234
  }
 
235
 
 
236
 
 
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);
 
241
    read_some();
 
242
    SET_HANDLER(&HostDBTestRR::mainEvent);
 
243
  }
 
244
};
 
245
 
 
246
 
 
247
struct HostDBSyncer: public Continuation
 
248
{
 
249
  int frequency;
 
250
  ink_hrtime start_time;
 
251
 
 
252
  int sync_event(int event, void *edata);
 
253
  int wait_event(int event, void *edata);
 
254
 
 
255
    HostDBSyncer();
 
256
};
 
257
 
 
258
 
 
259
HostDBSyncer::HostDBSyncer():
 
260
Continuation(new_ProxyMutex()), frequency(0), start_time(0)
 
261
{
 
262
  SET_HANDLER(&HostDBSyncer::sync_event);
 
263
  IOCORE_EstablishStaticConfigInt32(hostdb_sync_frequency, "proxy.config.cache.hostdb.sync_frequency");
 
264
}
 
265
 
 
266
 
 
267
int
 
268
HostDBSyncer::sync_event(int, void *)
 
269
{
 
270
  SET_HANDLER(&HostDBSyncer::wait_event);
 
271
  start_time = ink_get_hrtime();
 
272
  hostDBProcessor.cache()->sync_partitions(this);
 
273
  return EVENT_DONE;
 
274
}
 
275
 
 
276
 
 
277
int
 
278
HostDBSyncer::wait_event(int, void *)
 
279
{
 
280
  SET_HANDLER(&HostDBSyncer::sync_event);
 
281
  mutex->thread_holding->schedule_in_local(this, HRTIME_SECONDS(hostdb_sync_frequency));
 
282
  return EVENT_DONE;
 
283
}
 
284
 
 
285
 
 
286
int
 
287
HostDBCache::start(int flags)
 
288
{
 
289
  Store *hostDBStore;
 
290
  Span *hostDBSpan;
 
291
  char storage_path[PATH_NAME_MAX + 1];
 
292
  int storage_size = 0;
 
293
 
 
294
  bool reconfigure = ((flags & PROCESSOR_RECONFIGURE) ? true : false);
 
295
  bool fix = ((flags & PROCESSOR_FIX) ? true : false);
 
296
 
 
297
  // Read configuration
 
298
  // Command line overrides manager configuration.
 
299
  //
 
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");
 
303
 
 
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);
 
309
  int i = 0;
 
310
  while (szPath[i] != 0) {
 
311
    if (szPath[i] == '/')
 
312
      szPath[i] = '\\';
 
313
    i++;
 
314
  }
 
315
  ink_strncpy(storage_path, system_root_dir, sizeof(storage_path));
 
316
  strcat(storage_path, DIR_SEP);
 
317
  strcat(storage_path, szPath);
 
318
#else
 
319
  IOCORE_ReadConfigString(storage_path, "proxy.config.hostdb.storage_path", PATH_NAME_MAX);
 
320
#endif
 
321
  IOCORE_ReadConfigInt32(storage_size, "proxy.config.hostdb.storage_size");
 
322
 
 
323
  if (storage_path[0] != '/') {
 
324
    Layout::relative_to(storage_path, PATH_NAME_MAX,
 
325
                        system_root_dir, storage_path);
 
326
  }
 
327
 
 
328
  Debug("hostdb", "Storage path is %s", storage_path);
 
329
 
 
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' ");
 
336
    }
 
337
  }
 
338
  hostDBStore = NEW(new Store);
 
339
  hostDBSpan = NEW(new Span);
 
340
  hostDBSpan->init(storage_path, storage_size);
 
341
  hostDBStore->add(hostDBSpan);
 
342
 
 
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");
 
346
 
 
347
    char p[PATH_NAME_MAX + 1];
 
348
    Layout::relative_to(p, PATH_NAME_MAX,
 
349
                        system_config_directory, "internal/hostdb.config");
 
350
    if (unlink(p) < 0)
 
351
      Debug("hostdb", "unable to unlink %s", p);
 
352
 
 
353
    delete hostDBStore;
 
354
    hostDBStore = NEW(new Store);
 
355
    hostDBSpan = NEW(new Span);
 
356
    hostDBSpan->init(storage_path, storage_size);
 
357
    hostDBStore->add(hostDBSpan);
 
358
 
 
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");
 
361
      hostdb_enable = 0;
 
362
      delete hostDBStore;
 
363
      return -1;
 
364
    }
 
365
  }
 
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
 
368
  delete hostDBStore;
 
369
  return 0;
 
370
}
 
371
 
 
372
 
 
373
// Start up the Host Database processor.
 
374
// Load configuration, register configuration and statistics and
 
375
// open the cache.
 
376
//
 
377
int
 
378
HostDBProcessor::start(int)
 
379
{
 
380
  //bool found = false;
 
381
  hostDB.alloc_mutexes();
 
382
 
 
383
  if (hostDB.start(0) < 0)
 
384
    return -1;
 
385
 
 
386
#ifdef NON_MODULAR
 
387
  if (auto_clear_hostdb_flag)
 
388
    hostDB.clear();
 
389
#endif
 
390
 
 
391
  HOSTDB_SET_DYN_COUNT(hostdb_total_entries_stat, hostDB.totalelements);
 
392
 
 
393
#ifdef NON_MODULAR
 
394
  statPagesManager.register_http("hostdb", register_ShowHostDB);
 
395
#endif
 
396
 
 
397
  //
 
398
  // Register configuration callback, and establish configuation links
 
399
  //
 
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");
 
412
 
 
413
  //
 
414
  // Set up hostdb_current_interval
 
415
  //
 
416
  hostdb_current_interval = (unsigned int)
 
417
    (ink_get_based_hrtime() / HOST_DB_TIMEOUT_INTERVAL);
 
418
  //hostdb_timestamp = time(NULL);
 
419
 
 
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);
 
424
 
 
425
  //
 
426
  // Sync HostDB
 
427
  //
 
428
  eventProcessor.schedule_imm(NEW(new HostDBSyncer));
 
429
  return 0;
 
430
}
 
431
 
 
432
 
 
433
void
 
434
HostDBContinuation::init(char *hostname, int len,
 
435
                         int aip, int aport, INK_MD5 & amd5, Continuation * cont, void *pDS, bool is_srv, int timeout)
 
436
{
 
437
  if (hostname) {
 
438
    memcpy(name, hostname, len);
 
439
    name[len] = 0;
 
440
  } else
 
441
    name[0] = 0;
 
442
  dns_lookup_timeout = timeout;
 
443
  namelen = len;
 
444
  is_srv_lookup = is_srv;
 
445
  ip = aip;
 
446
  port = aport;
 
447
  md5 = amd5;
 
448
  mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets));
 
449
  m_pDS = pDS;
 
450
  if (cont) {
 
451
    action = cont;
 
452
  } else {
 
453
    //ink_assert(!"this sucks");
 
454
    action.mutex = mutex;
 
455
  }
 
456
}
 
457
 
 
458
 
 
459
void
 
460
make_md5(INK_MD5 & md5, char *hostname, int len, int port, char *pDNSServers, int srv)
 
461
{
 
462
#ifdef USE_MMH
 
463
  MMH_CTX ctx;
 
464
  ink_code_incr_MMH_init(&ctx);
 
465
  ink_code_incr_MMH_update(&ctx, hostname, len);
 
466
  unsigned short p = port;
 
467
  p = htons(p);
 
468
  ink_code_incr_MMH_update(&ctx, (char *) &p, 2);
 
469
  ink_code_incr_MMH_update(&ctx, (char *) &srv, 4);     /* FIXME: check this */
 
470
  if (pDNSServers)
 
471
    ink_code_incr_MMH_update(&ctx, pDNSServers, strlen(pDNSServers));
 
472
  ink_code_incr_MMH_final((char *) &md5, &ctx);
 
473
#else
 
474
  INK_DIGEST_CTX ctx;
 
475
  ink_code_incr_md5_init(&ctx);
 
476
  ink_code_incr_md5_update(&ctx, hostname, len);
 
477
  unsigned short p = port;
 
478
  p = htons(p);
 
479
  ink_code_incr_md5_update(&ctx, (char *) &p, 2);
 
480
  ink_code_incr_MMH_update(&ctx, (char *) &srv, 4);     /* FIXME: check this */
 
481
  if (pDNSServers)
 
482
    ink_code_incr_md5_update(&ctx, pDNSServers, strlen(pDNSServers));
 
483
  ink_code_incr_md5_final((char *) &md5, &ctx);
 
484
#endif
 
485
}
 
486
 
 
487
 
 
488
static bool
 
489
reply_to_cont(Continuation * cont, HostDBInfo * ar)
 
490
{
 
491
  const char *reason = "none";
 
492
  HostDBInfo *r = ar;
 
493
 
 
494
  if (r == NULL) {
 
495
    cont->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
 
496
    return false;
 
497
  }
 
498
 
 
499
  if (r->failed()) {
 
500
    if (r->is_srv && r->srv_count) {
 
501
      cont->handleEvent(EVENT_SRV_LOOKUP, NULL);
 
502
      return false;
 
503
    }
 
504
    cont->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
 
505
    return false;
 
506
  } else {
 
507
    if (r->reverse_dns) {
 
508
      if (!r->hostname()) {
 
509
        reason = "missing hostname";
 
510
        ink_assert(!"missing hostname");
 
511
        goto Lerror;
 
512
      }
 
513
      Debug("hostdb", "hostname = %s", r->hostname());
 
514
    }
 
515
    if (r->round_robin) {
 
516
      if (!r->rr()) {
 
517
        reason = "missing round-robin";
 
518
        ink_assert(!"missing round-robin");
 
519
        goto Lerror;
 
520
      }
 
521
      Debug("hostdb", "RR of %d with %d good, 1st IP = %X", r->rr()->n, r->rr()->good, r->ip());
 
522
    }
 
523
    if (r->is_srv && r->srv_count) {
 
524
      cont->handleEvent(EVENT_SRV_LOOKUP, r);
 
525
      if (!r->full)
 
526
        goto Ldelete;
 
527
      return true;
 
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);
 
531
      return true;
 
532
    }
 
533
    cont->handleEvent(EVENT_HOST_DB_LOOKUP, r);
 
534
    if (!r->full)
 
535
      goto Ldelete;
 
536
    return true;
 
537
  }
 
538
Lerror:
 
539
  if (r->is_srv && r->srv_count) {
 
540
    cont->handleEvent(EVENT_SRV_LOOKUP, r);
 
541
  }
 
542
  cont->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
 
543
Ldelete:
 
544
  Warning("bogus entry deleted from HostDB: %s", reason);
 
545
  hostDB.delete_block(ar);
 
546
  return false;
 
547
}
 
548
 
 
549
 
 
550
HostDBInfo *
 
551
probe(ProxyMutex *mutex, INK_MD5 & md5, char *hostname, int len, int ip, int port, void *pDS, bool ignore_timeout,
 
552
      bool is_srv_lookup)
 
553
{
 
554
  ink_debug_assert(this_ethread() == hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets))->thread_holding);
 
555
  if (hostdb_enable) {
 
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) {
 
560
 
 
561
      // Check for timeout (fail probe)
 
562
      //
 
563
      if (r->is_deleted()) {
 
564
        Debug("hostdb", "HostDB entry was set as deleted");
 
565
        return NULL;
 
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());
 
570
          return NULL;
 
571
        }
 
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);
 
575
        return NULL;
 
576
      }
 
577
//error conditions
 
578
      if (r->reverse_dns && !r->hostname()) {
 
579
        Debug("hostdb", "missing reverse dns");
 
580
        hostDB.delete_block(r);
 
581
        return NULL;
 
582
      }
 
583
      if (r->round_robin && !r->rr()) {
 
584
        Debug("hostdb", "missing round-robin");
 
585
        hostDB.delete_block(r);
 
586
        return NULL;
 
587
      }
 
588
      // Check for stale (revalidate offline if we are the owner)
 
589
      // -or-
 
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()
 
592
#ifdef NON_MODULAR
 
593
           && !cluster_machine_at_depth(master_hash(md5))
 
594
#endif
 
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);
 
598
        r->refresh_ip();
 
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);
 
602
          c->do_dns();
 
603
        }
 
604
      }
 
605
 
 
606
      r->hits++;
 
607
      if (!r->hits)
 
608
        r->hits--;
 
609
      return r;
 
610
    }
 
611
  }
 
612
  return NULL;
 
613
}
 
614
 
 
615
 
 
616
//
 
617
// Insert a HostDBInfo into the database
 
618
// A null value indicates that the block is empty.
 
619
//
 
620
HostDBInfo *
 
621
HostDBContinuation::insert(unsigned int attl)
 
622
{
 
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);
 
627
  if (old_r)
 
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);
 
638
  return r;
 
639
}
 
640
 
 
641
 
 
642
//
 
643
// Get an entry by either name or IP
 
644
//
 
645
Action *
 
646
HostDBProcessor::getby(Continuation * cont,
 
647
                       char *hostname, int len, int port, unsigned int ip, bool aforce_dns, int dns_lookup_timeout)
 
648
{
 
649
  INK_MD5 md5;
 
650
  char *pServerLine = 0;
 
651
  void *pDS = 0;
 
652
  EThread *thread = this_ethread();
 
653
  ProxyMutex *mutex = thread->mutex;
 
654
 
 
655
  HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat);
 
656
 
 
657
  if ((!hostdb_enable || (hostname && !*hostname)) || (hostdb_disable_reverse_lookup && ip)) {
 
658
    MUTEX_TRY_LOCK(lock, cont->mutex, thread);
 
659
    if (!lock)
 
660
      goto Lretry;
 
661
    cont->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
 
662
    return ACTION_RESULT_DONE;
 
663
  }
 
664
#ifdef SPLIT_DNS
 
665
  if (hostname && SplitDNSConfig::isSplitDNSEnabled()) {
 
666
    char *scan = hostname;
 
667
    for (; *scan != '\0' && (ParseRules::is_digit(*scan) || '.' == *scan); scan++);
 
668
    if ('\0' != *scan) {
 
669
      void *pSD = (void *) SplitDNSConfig::acquire();
 
670
      if (0 != pSD) {
 
671
        pDS = ((SplitDNS *) pSD)->getDNSRecord(hostname);
 
672
 
 
673
        if (0 != pDS) {
 
674
          pServerLine = ((DNSServer *) pDS)->x_dns_ip_line;
 
675
        }
 
676
      }
 
677
      SplitDNSConfig::release((SplitDNS *) pSD);
 
678
    }
 
679
  }
 
680
#endif // SPLIT_DNS
 
681
 
 
682
  // if it is by name, INK_MD5 the name
 
683
  //
 
684
  if (hostname) {
 
685
    if (!len)
 
686
      len = strlen(hostname);
 
687
    make_md5(md5, hostname, len, port, pServerLine);
 
688
  } else {
 
689
 
 
690
    // INK_MD5 the ip, pad on both sizes with 0's
 
691
    // so that it does not intersect the string space
 
692
    //
 
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);
 
700
  }
 
701
 
 
702
  // Attempt to find the result in-line, for level 1 hits
 
703
  //
 
704
  if (!aforce_dns) {
 
705
    // find the partition lock
 
706
    //
 
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);
 
711
 
 
712
    // If we can get the lock and a level 1 probe succeeds, return
 
713
    //
 
714
    if (lock && lock2) {
 
715
      HostDBInfo *r = probe(bmutex, md5, hostname, len, ip, port, pDS);
 
716
      if (r) {
 
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;
 
721
      }
 
722
    }
 
723
  }
 
724
  Debug("hostdb", "delaying force %d answer for %s", aforce_dns, hostname);
 
725
 
 
726
Lretry:
 
727
  // Otherwise, create a continuation to do a deeper probe in the background
 
728
  //
 
729
  HostDBContinuation *c = hostDBContAllocator.alloc();
 
730
  c->init(hostname, len, ip, port, md5, cont, pDS, false, dns_lookup_timeout);
 
731
  c->action = cont;
 
732
  c->force_dns = aforce_dns;
 
733
  SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent);
 
734
 
 
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);
 
740
  } else {
 
741
    dnsProcessor.thread->schedule_imm(c);
 
742
  }
 
743
 
 
744
  return &c->action;
 
745
}
 
746
 
 
747
 
 
748
// Wrapper from getbyname to getby
 
749
//
 
750
Action *
 
751
HostDBProcessor::getbyname_re(Continuation * cont, char *ahostname, int len, int port, int flags)
 
752
{
 
753
  bool force_dns = false;
 
754
  EThread *thread = this_ethread();
 
755
  ProxyMutex *mutex = thread->mutex;
 
756
 
 
757
  if (flags & HOSTDB_FORCE_DNS_ALWAYS)
 
758
    force_dns = true;
 
759
  else if (flags & HOSTDB_FORCE_DNS_RELOAD) {
 
760
    force_dns = (hostdb_re_dns_on_reload ? true : false);
 
761
    if (force_dns)
 
762
      HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat);
 
763
  }
 
764
  return getby(cont, ahostname, len, port, 0, force_dns);
 
765
}
 
766
 
 
767
 
 
768
/* Support SRV records */
 
769
Action *
 
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)
 
772
{
 
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;
 
777
 
 
778
  if (flags & HOSTDB_FORCE_DNS_ALWAYS)
 
779
    force_dns = true;
 
780
  else if (flags & HOSTDB_FORCE_DNS_RELOAD) {
 
781
    force_dns = (hostdb_re_dns_on_reload ? true : false);
 
782
    if (force_dns)
 
783
      HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat);
 
784
  }
 
785
 
 
786
  INK_MD5 md5;
 
787
  void *pDS = 0;
 
788
 
 
789
  HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat);
 
790
 
 
791
  if (!hostdb_enable || !*hostname) {
 
792
    (cont->*process_srv_info) (NULL);
 
793
    return ACTION_RESULT_DONE;
 
794
  }
 
795
 
 
796
  if (!len)
 
797
    len = strlen(hostname);
 
798
 
 
799
  make_md5(md5, hostname, len, port, 0, 1);
 
800
 
 
801
  // Attempt to find the result in-line, for level 1 hits
 
802
  if (!force_dns) {
 
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);
 
806
 
 
807
    // If we can get the lock and a level 1 probe succeeds, return
 
808
    if (lock) {
 
809
      HostDBInfo *r = probe(bucket_mutex, md5, hostname, len, 1, port, pDS, false, true);
 
810
      if (r) {
 
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;
 
816
      }
 
817
    }
 
818
  }
 
819
 
 
820
  Debug("dns_srv", "delaying (force=%d) SRV answer for %s [timeout = %d]", force_dns, hostname, dns_lookup_timeout);
 
821
 
 
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);
 
827
 
 
828
  if (thread->mutex == cont->mutex) {
 
829
    thread->schedule_in(c, MUTEX_RETRY_DELAY);
 
830
  } else {
 
831
    dnsProcessor.thread->schedule_imm(c);
 
832
  }
 
833
 
 
834
  return &c->action;
 
835
}
 
836
 
 
837
 
 
838
// Wrapper from getbyname to getby
 
839
//
 
840
Action *
 
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)
 
843
{
 
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;
 
848
 
 
849
  if (flags & HOSTDB_FORCE_DNS_ALWAYS)
 
850
    force_dns = true;
 
851
  else if (flags & HOSTDB_FORCE_DNS_RELOAD) {
 
852
    force_dns = (hostdb_re_dns_on_reload ? true : false);
 
853
    if (force_dns)
 
854
      HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat);
 
855
  }
 
856
 
 
857
  INK_MD5 md5;
 
858
  void *pDS = 0;
 
859
  HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat);
 
860
 
 
861
  if (!hostdb_enable || !*hostname) {
 
862
    (cont->*process_hostdb_info) (NULL);
 
863
    return ACTION_RESULT_DONE;
 
864
  }
 
865
 
 
866
  if (!len)
 
867
    len = strlen(hostname);
 
868
 
 
869
#ifdef SPLIT_DNS
 
870
  if (SplitDNSConfig::isSplitDNSEnabled()) {
 
871
    char *scan = hostname;
 
872
    char *pServerLine = 0;
 
873
    for (; *scan != '\0' && (ParseRules::is_digit(*scan) || '.' == *scan); scan++);
 
874
    if ('\0' != *scan) {
 
875
      void *pSD = (void *) SplitDNSConfig::acquire();
 
876
      if (0 != pSD) {
 
877
        pDS = ((SplitDNS *) pSD)->getDNSRecord(hostname);
 
878
 
 
879
        if (0 != pDS) {
 
880
          pServerLine = ((DNSServer *) pDS)->x_dns_ip_line;
 
881
        }
 
882
      }
 
883
      SplitDNSConfig::release((SplitDNS *) pSD);
 
884
    }
 
885
    make_md5(md5, hostname, len, port, pServerLine);
 
886
  } else
 
887
#endif // SPLIT_DNS
 
888
    make_md5(md5, hostname, len, port, 0);
 
889
 
 
890
  // Attempt to find the result in-line, for level 1 hits
 
891
  if (!force_dns) {
 
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);
 
895
 
 
896
    // If we can get the lock and a level 1 probe succeeds, return
 
897
    if (lock) {
 
898
      HostDBInfo *r = probe(bucket_mutex, md5, hostname, len, 0, port, pDS);
 
899
      if (r) {
 
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;
 
904
      }
 
905
    }
 
906
  }
 
907
 
 
908
  Debug("hostdb", "delaying force %d answer for %s [timeout %d]", force_dns, hostname, dns_lookup_timeout);
 
909
 
 
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);
 
915
 
 
916
  thread->schedule_in(c, MUTEX_RETRY_DELAY);
 
917
 
 
918
  return &c->action;
 
919
}
 
920
 
 
921
 
 
922
static void
 
923
do_setby(HostDBInfo * r, HostDBApplicationInfo * app, char *hostname, unsigned int ip)
 
924
{
 
925
  HostDBRoundRobin *rr = r->rr();
 
926
 
 
927
  if (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;
 
934
        return;
 
935
      }
 
936
    }
 
937
  } else {
 
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;
 
942
    }
 
943
  }
 
944
}
 
945
 
 
946
 
 
947
void
 
948
HostDBProcessor::setby(char *hostname, int len, int port, unsigned int ip, HostDBApplicationInfo * app)
 
949
{
 
950
  if (!hostdb_enable)
 
951
    return;
 
952
 
 
953
  INK_MD5 md5;
 
954
 
 
955
  // if it is by name, INK_MD5 the name
 
956
  //
 
957
  if (hostname) {
 
958
    if (!len)
 
959
      len = strlen(hostname);
 
960
    make_md5(md5, hostname, len, port);
 
961
  } else {
 
962
 
 
963
    // INK_MD5 the ip, pad on both sizes with 0's
 
964
    // so that it does not intersect the string space
 
965
    //
 
966
 
 
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);
 
974
  }
 
975
 
 
976
  // Attempt to find the result in-line, for level 1 hits
 
977
 
 
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);
 
981
 
 
982
  if (lock) {
 
983
    HostDBInfo *r = probe(mutex, md5, hostname, len, ip, port, 0);
 
984
    if (r)
 
985
      do_setby(r, app, hostname, ip);
 
986
    return;
 
987
  }
 
988
  // Create a continuation to do a deaper probe in the background
 
989
 
 
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);
 
996
}
 
997
 
 
998
 
 
999
int
 
1000
HostDBContinuation::setbyEvent(int event, Event * e)
 
1001
{
 
1002
  NOWARN_UNUSED(event);
 
1003
  NOWARN_UNUSED(e);
 
1004
  HostDBInfo *r = probe(mutex, md5, name, namelen, ip, port, 0);
 
1005
 
 
1006
  if (r)
 
1007
    do_setby(r, &app, name, ip);
 
1008
  hostdb_cont_free(this);
 
1009
  return EVENT_DONE;
 
1010
}
 
1011
 
 
1012
 
 
1013
static int
 
1014
remove_round_robin(HostDBInfo * r, char *hostname, unsigned int ip)
 
1015
{
 
1016
  if (r) {
 
1017
    if (!r->round_robin)
 
1018
      return false;
 
1019
    HostDBRoundRobin *rr = r->rr();
 
1020
    if (!rr)
 
1021
      return false;
 
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;
 
1030
        rr->good--;
 
1031
        if (rr->good <= 0) {
 
1032
          hostDB.delete_block(r);
 
1033
          return false;
 
1034
        } else {
 
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]);
 
1043
              p += nbytes;
 
1044
              bufsize -= nbytes;
 
1045
            }
 
1046
            Note("'%s' round robin DNS entry updated, entries=%d, IP list: %s", hostname, rr->good, rr_ip_list);
 
1047
          }
 
1048
        }
 
1049
        return true;
 
1050
      }
 
1051
    }
 
1052
  }
 
1053
  return false;
 
1054
}
 
1055
 
 
1056
 
 
1057
Action *
 
1058
HostDBProcessor::failed_connect_on_ip_for_name(Continuation * cont, unsigned int ip, char *hostname, int len, int port)
 
1059
{
 
1060
  INK_MD5 md5;
 
1061
  char *pServerLine = 0;
 
1062
  void *pDS = 0;
 
1063
 
 
1064
#ifdef SPLIT_DNS
 
1065
  SplitDNS *pSD = 0;
 
1066
  if (hostname && SplitDNSConfig::isSplitDNSEnabled()) {
 
1067
    pSD = SplitDNSConfig::acquire();
 
1068
 
 
1069
    if (0 != pSD) {
 
1070
      pDS = pSD->getDNSRecord(hostname);
 
1071
      pServerLine = ((DNSServer *) pDS)->x_dns_ip_line;
 
1072
    }
 
1073
    SplitDNSConfig::release(pSD);
 
1074
  }
 
1075
#endif // SPLIT_DNS
 
1076
 
 
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);
 
1081
  if (lock) {
 
1082
    if (!hostdb_enable || NULL == pDS) {
 
1083
      if (cont)
 
1084
        cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, (void *) NULL);
 
1085
      return ACTION_RESULT_DONE;
 
1086
    }
 
1087
#ifdef SPLIT_DNS
 
1088
    HostDBInfo *r = probe(mutex, md5, hostname, len, ip, port, pDS);
 
1089
#else
 
1090
    HostDBInfo *r = probe(mutex, md5, hostname, len, ip, port, 0);
 
1091
#endif
 
1092
    bool res = (remove_round_robin(r, hostname, ip) ? true : false);
 
1093
    if (cont)
 
1094
      cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, res ? (void *) &ip : (void *) NULL);
 
1095
    return ACTION_RESULT_DONE;
 
1096
  }
 
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);
 
1101
  return &c->action;
 
1102
}
 
1103
 
 
1104
 
 
1105
int
 
1106
HostDBContinuation::removeEvent(int event, Event * e)
 
1107
{
 
1108
  NOWARN_UNUSED(event);
 
1109
  Continuation *cont = action.continuation;
 
1110
 
 
1111
  MUTEX_TRY_LOCK(lock, cont ? (ProxyMutex *) cont->mutex : (ProxyMutex *) NULL, e->ethread);
 
1112
  if (!lock) {
 
1113
    e->schedule_in(HOST_DB_RETRY_PERIOD);
 
1114
    return EVENT_CONT;
 
1115
  }
 
1116
  if (!action.cancelled) {
 
1117
    if (!hostdb_enable) {
 
1118
      if (cont)
 
1119
        cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, (void *) NULL);
 
1120
    } else {
 
1121
      HostDBInfo *r = probe(mutex, md5, name, namelen, ip, port, m_pDS);
 
1122
      bool res = (remove_round_robin(r, name, ip) ? true : false);
 
1123
      if (cont)
 
1124
        cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, res ? (void *) &ip : (void *) NULL);
 
1125
    }
 
1126
  }
 
1127
  hostdb_cont_free(this);
 
1128
  return EVENT_DONE;
 
1129
}
 
1130
 
 
1131
 
 
1132
// Lookup done, insert into the local table, return data to the
 
1133
// calling continuation or to the calling cluster node.
 
1134
//
 
1135
HostDBInfo *
 
1136
HostDBContinuation::lookup_done(int aip, char *aname, bool around_robin, unsigned int ttl_seconds, SRVHosts * srv)
 
1137
{
 
1138
  HostDBInfo *i = NULL;
 
1139
 
 
1140
  ink_debug_assert(this_ethread() == hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets))->thread_holding);
 
1141
  if (!aip || !aname || !aname[0]) {
 
1142
    if (is_byname()) {
 
1143
      Debug("hostdb", "lookup_done() failed for '%s'", name);
 
1144
    } else if (is_srv()) {
 
1145
      Debug("dns_srv", "SRV failed for '%s'", name);
 
1146
    } else {
 
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]);
 
1150
    }
 
1151
    i = insert(hostdb_ip_fail_timeout_interval);        // currently ... 0
 
1152
    i->round_robin = false;
 
1153
    i->reverse_dns = !is_byname() && !is_srv();
 
1154
  } else {
 
1155
    switch (hostdb_ttl_mode) {
 
1156
    default:
 
1157
      ink_assert(!"bad TTL mode");
 
1158
    case TTL_OBEY:
 
1159
      break;
 
1160
    case TTL_IGNORE:
 
1161
      ttl_seconds = hostdb_ip_timeout_interval * 60;
 
1162
      break;
 
1163
    case TTL_MIN:
 
1164
      if (hostdb_ip_timeout_interval * 60 < ttl_seconds)
 
1165
        ttl_seconds = hostdb_ip_timeout_interval * 60;
 
1166
      break;
 
1167
    case TTL_MAX:
 
1168
      if (hostdb_ip_timeout_interval * 60 > ttl_seconds)
 
1169
        ttl_seconds = hostdb_ip_timeout_interval * 60;
 
1170
      break;
 
1171
    }
 
1172
    HOSTDB_SUM_DYN_STAT(hostdb_ttl_stat, ttl_seconds);
 
1173
    if (!ttl_seconds)
 
1174
      ttl_seconds = 1;          // www.barnsandnobel.com is lame
 
1175
    i = insert(ttl_seconds);
 
1176
    if (is_byname()) {
 
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);
 
1180
      i->ip() = aip;
 
1181
      i->round_robin = around_robin;
 
1182
      i->reverse_dns = false;
 
1183
      if (name != aname) {
 
1184
        ink_strncpy(name, aname, MAXDNAME);
 
1185
      }
 
1186
      i->is_srv = false;
 
1187
    } else if (is_srv()) {
 
1188
 
 
1189
      i->ip() = aip;            /* this doesnt matter w. srv records -- setting to 1 so Md5 works */
 
1190
 
 
1191
      i->reverse_dns = false;
 
1192
 
 
1193
      if (srv) {                //failed case: srv == NULL
 
1194
        i->srv_count = srv->getCount();
 
1195
      } else {
 
1196
        i->srv_count = 0;
 
1197
      }
 
1198
 
 
1199
      if (i->srv_count <= 0) {
 
1200
        i->round_robin = false;
 
1201
      } else {
 
1202
        i->round_robin = true;
 
1203
      }
 
1204
 
 
1205
      i->is_srv = true;
 
1206
 
 
1207
      if (name != aname) {
 
1208
        ink_strncpy(name, aname, MAXDNAME);
 
1209
      }
 
1210
 
 
1211
    } else {
 
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);
 
1215
      if (s) {
 
1216
        ink_strncpy((char *) s, aname, s_size);
 
1217
        i->round_robin = false;
 
1218
        i->reverse_dns = true;
 
1219
        i->is_srv = false;
 
1220
      } else {
 
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);
 
1224
        return NULL;
 
1225
      }
 
1226
    }
 
1227
  }
 
1228
#ifdef NON_MODULAR
 
1229
  if (from_cont)
 
1230
    do_put_response(from, i, from_cont);
 
1231
#endif
 
1232
  ink_assert(!i->round_robin || !i->reverse_dns);
 
1233
  return i;
 
1234
}
 
1235
 
 
1236
 
 
1237
int
 
1238
HostDBContinuation::dnsPendingEvent(int event, Event * e)
 
1239
{
 
1240
  ink_debug_assert(this_ethread() == hostDB.lock_for_bucket(fold_md5(md5) % hostDB.buckets)->thread_holding);
 
1241
  if (timeout) {
 
1242
    timeout->cancel(this);
 
1243
    timeout = NULL;
 
1244
  }
 
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);
 
1248
    if (!lock) {
 
1249
      ((Event *) e)->schedule_in(HOST_DB_RETRY_PERIOD);
 
1250
      return EVENT_CONT;
 
1251
    }
 
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);
 
1256
    return EVENT_DONE;
 
1257
  } else {
 
1258
    SET_HANDLER((HostDBContHandler) & HostDBContinuation::probeEvent);
 
1259
    return probeEvent(EVENT_INTERVAL, NULL);
 
1260
  }
 
1261
}
 
1262
 
 
1263
static int
 
1264
restore_info(HostDBInfo * r, HostDBInfo * old_r, HostDBInfo & old_info, HostDBRoundRobin * old_rr_data)
 
1265
{
 
1266
  if (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;
 
1270
        return true;
 
1271
      }
 
1272
  } else if (old_r)
 
1273
    if (old_info.ip() == r->ip()) {
 
1274
      r->app = old_info.app;
 
1275
      return true;
 
1276
    }
 
1277
  return false;
 
1278
}
 
1279
 
 
1280
 
 
1281
// DNS lookup result state
 
1282
//
 
1283
int
 
1284
HostDBContinuation::dnsEvent(int event, HostEnt * e)
 
1285
{
 
1286
  ink_debug_assert(this_ethread() == hostDB.lock_for_bucket(fold_md5(md5) % hostDB.buckets)->thread_holding);
 
1287
  if (timeout) {
 
1288
    timeout->cancel(this);
 
1289
    timeout = NULL;
 
1290
  }
 
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);
 
1297
      return EVENT_DONE;
 
1298
    }
 
1299
    MUTEX_TRY_LOCK_FOR(lock, action.mutex, thread, action.continuation);
 
1300
    if (!lock) {
 
1301
      timeout = thread->schedule_in(this, HOST_DB_RETRY_PERIOD);
 
1302
      return EVENT_CONT;
 
1303
    }
 
1304
    if (!action.cancelled && action.continuation)
 
1305
      action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
 
1306
    action = 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));
 
1309
    return EVENT_DONE;
 
1310
  } else {
 
1311
    bool failed = !e;
 
1312
 
 
1313
    bool rr;
 
1314
    if (is_srv()) {
 
1315
      rr = !failed && (e->srv_hosts.getCount() > 0);
 
1316
    } else
 
1317
      rr = !failed && e->ent.h_addr_list[1];
 
1318
 
 
1319
    pending_action = NULL;
 
1320
 
 
1321
    ttl = failed ? 0 : e->ttl / 60;
 
1322
    int ttl_seconds = failed ? 0 : e->ttl;      //ebalsa: moving to second accuracy
 
1323
 
 
1324
    HostDBInfo *old_r = probe(mutex, md5, name, namelen, ip, port, m_pDS, true);
 
1325
    HostDBInfo old_info;
 
1326
    if (old_r)
 
1327
      old_info = *old_r;
 
1328
    HostDBRoundRobin *old_rr_data = old_r ? old_r->rr() : NULL;
 
1329
 
 
1330
    int n = 0, nn = 0, first = -1;
 
1331
    if (rr) {
 
1332
      if (is_srv() && !failed) {
 
1333
        n = e->srv_hosts.getCount();
 
1334
      } else {
 
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]) {
 
1337
            if (first < 0)
 
1338
              first = nn;
 
1339
            n++;
 
1340
          } else
 
1341
            Warning("0.0.0.0 removed from round-robin list for '%s'", name);
 
1342
        if (first < 0) {
 
1343
          failed = true;
 
1344
          rr = false;
 
1345
        }
 
1346
      }
 
1347
    } else {
 
1348
      first = 0;
 
1349
    }
 
1350
 
 
1351
    HostDBInfo *r = NULL;
 
1352
    if (is_byname())
 
1353
      r =
 
1354
        lookup_done(failed ? 0 : *(unsigned int *) e->ent.h_addr_list[first], name, rr, ttl_seconds,
 
1355
                    failed ? 0 : &e->srv_hosts);
 
1356
    else if (is_srv())
 
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);
 
1362
    else
 
1363
      r = lookup_done(failed ? 0 : ip, failed ? name : e->ent.h_name, false, ttl_seconds, failed ? 0 : &e->srv_hosts);
 
1364
 
 
1365
    if (rr) {
 
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);
 
1369
      if (rr_data) {
 
1370
        int i = 0, ii = 0;
 
1371
        if (is_srv()) {
 
1372
          SortableQueue<SRV> *q = e->srv_hosts.getHosts();
 
1373
          if (q) {
 
1374
            for (i = 0; i < n; i++) {
 
1375
 
 
1376
              SRV *t = q->dequeue();
 
1377
 
 
1378
              rr_data->info[i].ip() = 1;
 
1379
              rr_data->info[i].round_robin = 0;
 
1380
              rr_data->info[i].reverse_dns = 0;
 
1381
 
 
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();
 
1385
 
 
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;
 
1389
 
 
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);
 
1396
            }
 
1397
          }
 
1398
        } else {
 
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;
 
1411
              }
 
1412
              i++;
 
1413
            }
 
1414
          }
 
1415
        }
 
1416
        rr_data->good = rr_data->n = n;
 
1417
        rr_data->current = 0;
 
1418
      } else {
 
1419
        ink_assert(!"out of room in hostdb data area");
 
1420
        Warning("out of room in hostdb for round-robin DNS data");
 
1421
        r->round_robin = 0;
 
1422
      }
 
1423
    }
 
1424
    if (!failed && !rr)
 
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);
 
1428
 
 
1429
#ifdef NON_MODULAR
 
1430
    // if we are not the owner, put on the owner
 
1431
    //
 
1432
    ClusterMachine *m = cluster_machine_at_depth(master_hash(md5));
 
1433
    if (m)
 
1434
      do_put_response(m, r, NULL);
 
1435
#endif
 
1436
 
 
1437
    // try to callback the user
 
1438
    //
 
1439
    if (action.continuation) {
 
1440
      MUTEX_TRY_LOCK_FOR(lock, action.mutex, thread, action.continuation);
 
1441
      if (!lock) {
 
1442
        remove_trigger_pending_dns();
 
1443
        SET_HANDLER((HostDBContHandler) & HostDBContinuation::probeEvent);
 
1444
        thread->schedule_in(this, HOST_DB_RETRY_PERIOD);
 
1445
        return EVENT_CONT;
 
1446
      }
 
1447
      if (!action.cancelled)
 
1448
        reply_to_cont(action.continuation, r);
 
1449
    }
 
1450
    // wake up everyone else who is waiting
 
1451
    remove_trigger_pending_dns();
 
1452
 
 
1453
    // all done
 
1454
    //
 
1455
    hostdb_cont_free(this);
 
1456
    return EVENT_DONE;
 
1457
  }
 
1458
}
 
1459
 
 
1460
 
 
1461
#ifdef NON_MODULAR
 
1462
//
 
1463
// HostDB Get Message
 
1464
// Used to lookup host information on a remote node in the cluster
 
1465
//
 
1466
struct HostDB_get_message
 
1467
{
 
1468
  INK_MD5 md5;
 
1469
  unsigned int ip;
 
1470
  int port;
 
1471
  Continuation *cont;
 
1472
  int namelen;
 
1473
  char name[MAXDNAME];
 
1474
};
 
1475
 
 
1476
 
 
1477
//
 
1478
// Make a get message
 
1479
//
 
1480
int
 
1481
HostDBContinuation::make_get_message(char *buf, int size)
 
1482
{
 
1483
  ink_assert(size >= (int) sizeof(HostDB_get_message));
 
1484
 
 
1485
  HostDB_get_message *msg = (HostDB_get_message *) buf;
 
1486
  msg->md5 = md5;
 
1487
  msg->port = htonl(port);
 
1488
  msg->ip = htonl(ip);
 
1489
  msg->cont = this;
 
1490
 
 
1491
  // name
 
1492
  ink_strncpy(msg->name, name, sizeof(msg->name));
 
1493
 
 
1494
  // length
 
1495
  int len = sizeof(HostDB_get_message) - MAXDNAME + strlen(name) + 1;
 
1496
 
 
1497
  return len;
 
1498
}
 
1499
 
 
1500
 
 
1501
//
 
1502
// Make and send a get message
 
1503
//
 
1504
bool HostDBContinuation::do_get_response(Event * e)
 
1505
{
 
1506
  NOWARN_UNUSED(e);
 
1507
  if (!hostdb_cluster)
 
1508
    return false;
 
1509
 
 
1510
  // find an appropriate Machine
 
1511
  //
 
1512
  ClusterMachine *
 
1513
    m = NULL;
 
1514
 
 
1515
  if (hostdb_migrate_on_demand)
 
1516
    m = cluster_machine_at_depth(master_hash(md5), &probe_depth, past_probes);
 
1517
  else {
 
1518
    if (probe_depth)
 
1519
      return false;
 
1520
    m = cluster_machine_at_depth(master_hash(md5));
 
1521
    probe_depth = 1;
 
1522
  }
 
1523
 
 
1524
  if (!m)
 
1525
    return false;
 
1526
 
 
1527
  // Make message
 
1528
  //
 
1529
  HostDB_get_message
 
1530
    msg;
 
1531
  memset(&msg, 0, sizeof(msg));
 
1532
  int
 
1533
    len = make_get_message((char *) &msg, sizeof(HostDB_get_message));
 
1534
 
 
1535
  // Setup this continuation, with a timeout
 
1536
  //
 
1537
  remoteHostDBQueue[key_partition()].enqueue(this);
 
1538
  SET_HANDLER((HostDBContHandler) & HostDBContinuation::clusterEvent);
 
1539
  timeout = mutex->thread_holding->schedule_in(this, HOST_DB_CLUSTER_TIMEOUT);
 
1540
 
 
1541
  // Send the message
 
1542
  //
 
1543
  clusterProcessor.invoke_remote(m, GET_HOSTINFO_CLUSTER_FUNCTION, (char *) &msg, len);
 
1544
 
 
1545
  return true;
 
1546
}
 
1547
 
 
1548
 
 
1549
//
 
1550
// HostDB Put Message
 
1551
// This message is used in a response to a cluster node for
 
1552
// Host inforamation.
 
1553
//
 
1554
struct HostDB_put_message
 
1555
{
 
1556
  INK_MD5
 
1557
    md5;
 
1558
  unsigned int
 
1559
    ip;
 
1560
  unsigned int
 
1561
    ttl;
 
1562
  int
 
1563
    port;
 
1564
  unsigned int
 
1565
    missing:
 
1566
    1;
 
1567
  unsigned int
 
1568
    round_robin:
 
1569
    1;
 
1570
  Continuation *
 
1571
    cont;
 
1572
  unsigned int
 
1573
    application1;
 
1574
  unsigned int
 
1575
    application2;
 
1576
  int
 
1577
    namelen;
 
1578
  char
 
1579
    name[MAXDNAME];
 
1580
};
 
1581
 
 
1582
 
 
1583
//
 
1584
// Build the put message
 
1585
//
 
1586
int
 
1587
HostDBContinuation::make_put_message(HostDBInfo * r, Continuation * c, char *buf, int size)
 
1588
{
 
1589
  ink_assert(size >= (int) sizeof(HostDB_put_message));
 
1590
 
 
1591
  HostDB_put_message *msg = (HostDB_put_message *) buf;
 
1592
  memset(msg, 0, sizeof(HostDB_put_message));
 
1593
 
 
1594
  msg->md5 = md5;
 
1595
  msg->cont = c;
 
1596
  if (r) {
 
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();
 
1603
  } else {
 
1604
    msg->missing = true;
 
1605
  }
 
1606
 
 
1607
  // name
 
1608
  ink_strncpy(msg->name, name, sizeof(msg->name));
 
1609
  msg->port = port;
 
1610
 
 
1611
  // length
 
1612
  int len = sizeof(HostDB_put_message) - MAXDNAME + strlen(name) + 1;
 
1613
 
 
1614
  return len;
 
1615
}
 
1616
 
 
1617
 
 
1618
//
 
1619
// Build the put message and send it
 
1620
//
 
1621
void
 
1622
HostDBContinuation::do_put_response(ClusterMachine * m, HostDBInfo * r, Continuation * c)
 
1623
{
 
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)
 
1627
    return;
 
1628
 
 
1629
  HostDB_put_message msg;
 
1630
  int len = make_put_message(r, c, (char *) &msg, sizeof(HostDB_put_message));
 
1631
 
 
1632
  clusterProcessor.invoke_remote(m, PUT_HOSTINFO_CLUSTER_FUNCTION, (char *) &msg, len);
 
1633
 
 
1634
}
 
1635
#endif // NON_MODULAR
 
1636
 
 
1637
 
 
1638
//
 
1639
// Probe state
 
1640
//
 
1641
int
 
1642
HostDBContinuation::probeEvent(int event, Event * e)
 
1643
{
 
1644
  NOWARN_UNUSED(event);
 
1645
  ink_assert(!link.prev && !link.next);
 
1646
  EThread *t = e ? e->ethread : this_ethread();
 
1647
 
 
1648
  MUTEX_TRY_LOCK_FOR(lock, action.mutex, t, action.continuation);
 
1649
  if (!lock) {
 
1650
    mutex->thread_holding->schedule_in(this, HOST_DB_RETRY_PERIOD);
 
1651
    return EVENT_CONT;
 
1652
  }
 
1653
 
 
1654
  if (action.cancelled) {
 
1655
    hostdb_cont_free(this);
 
1656
    return EVENT_DONE;
 
1657
  }
 
1658
 
 
1659
  if (!hostdb_enable || (!*name && !ip)) {
 
1660
    if (action.continuation)
 
1661
      action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
 
1662
#ifdef NON_MODULAR
 
1663
    if (from)
 
1664
      do_put_response(from, 0, from_cont);
 
1665
#endif
 
1666
    hostdb_cont_free(this);
 
1667
    return EVENT_DONE;
 
1668
  }
 
1669
 
 
1670
  if (!force_dns) {
 
1671
 
 
1672
    // Do the probe
 
1673
    //
 
1674
    HostDBInfo *r = probe(mutex, md5, name, namelen, ip, port, m_pDS);
 
1675
 
 
1676
    if (r)
 
1677
      HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
 
1678
 
 
1679
#ifdef NON_MODULAR
 
1680
    if (action.continuation && r)
 
1681
      reply_to_cont(action.continuation, r);
 
1682
 
 
1683
    // Respond to any remote node
 
1684
    //
 
1685
    if (from)
 
1686
      do_put_response(from, r, from_cont);
 
1687
#endif
 
1688
 
 
1689
    // If it suceeds or it was a remote probe, we are done
 
1690
    //
 
1691
    if (r || from) {
 
1692
      hostdb_cont_free(this);
 
1693
      return EVENT_DONE;
 
1694
    }
 
1695
#ifdef NON_MODULAR
 
1696
    // If it failed, do a remote probe
 
1697
    //
 
1698
    if (do_get_response(e))
 
1699
      return EVENT_CONT;
 
1700
#endif
 
1701
  }
 
1702
  // If there are no remote nodes to probe, do a DNS lookup
 
1703
  //
 
1704
  do_dns();
 
1705
  return EVENT_DONE;
 
1706
}
 
1707
 
 
1708
 
 
1709
int
 
1710
HostDBContinuation::set_check_pending_dns()
 
1711
{
 
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");
 
1717
      q.enqueue(this);
 
1718
      return false;
 
1719
    }
 
1720
  }
 
1721
  q.enqueue(this);
 
1722
  return true;
 
1723
}
 
1724
 
 
1725
 
 
1726
void
 
1727
HostDBContinuation::remove_trigger_pending_dns()
 
1728
{
 
1729
  Queue<HostDBContinuation> &q = hostDB.pending_dns_for_hash(md5);
 
1730
  q.remove(this);
 
1731
  HostDBContinuation *c = q.head;
 
1732
  Queue<HostDBContinuation> qq;
 
1733
  while (c) {
 
1734
    HostDBContinuation *n = (HostDBContinuation *) c->link.next;
 
1735
    if (md5 == c->md5) {
 
1736
      Debug("hostdb", "dequeuing additional request");
 
1737
      q.remove(c);
 
1738
      qq.enqueue(c);
 
1739
    }
 
1740
    c = n;
 
1741
  }
 
1742
  while ((c = qq.dequeue()))
 
1743
    c->handleEvent(EVENT_IMMEDIATE, NULL);
 
1744
}
 
1745
 
 
1746
 
 
1747
//
 
1748
// Query the DNS processor
 
1749
//
 
1750
void
 
1751
HostDBContinuation::do_dns()
 
1752
{
 
1753
  ink_assert(!action.cancelled);
 
1754
  if (is_byname()) {
 
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);
 
1762
      }
 
1763
      hostdb_cont_free(this);
 
1764
      return;
 
1765
    }
 
1766
  }
 
1767
  if (hostdb_lookup_timeout)
 
1768
    timeout = mutex->thread_holding->schedule_in(this, HRTIME_SECONDS(hostdb_lookup_timeout));
 
1769
  else
 
1770
    timeout = NULL;
 
1771
  if (set_check_pending_dns()) {
 
1772
    SET_HANDLER((HostDBContHandler) & HostDBContinuation::dnsEvent);
 
1773
    if (is_byname()) {
 
1774
      DNSHandler *dnsH = 0;
 
1775
#ifdef SPLIT_DNS
 
1776
      if (m_pDS)
 
1777
        dnsH = (DNSHandler *) (((DNSServer *) (m_pDS))->x_dnsH);
 
1778
#endif
 
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);
 
1784
    } else {
 
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);
 
1789
    }
 
1790
  } else {
 
1791
    SET_HANDLER((HostDBContHandler) & HostDBContinuation::dnsPendingEvent);
 
1792
  }
 
1793
}
 
1794
 
 
1795
#ifdef NON_MODULAR
 
1796
 
 
1797
 
 
1798
//
 
1799
// Handle the response (put message)
 
1800
//
 
1801
int
 
1802
HostDBContinuation::clusterResponseEvent(int event, Event * e)
 
1803
{
 
1804
  NOWARN_UNUSED(event);
 
1805
  if (from_cont) {
 
1806
    HostDBContinuation *c;
 
1807
    for (c = (HostDBContinuation *) remoteHostDBQueue[key_partition()].head; c; c = (HostDBContinuation *) c->link.next)
 
1808
      if (c == from_cont)
 
1809
        break;
 
1810
 
 
1811
    // Check to see that we have not already timed out
 
1812
    //
 
1813
    if (c) {
 
1814
      action = c;
 
1815
      from_cont = 0;
 
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);
 
1820
        return EVENT_CONT;
 
1821
      }
 
1822
      bool failed = missing || (round_robin && !hostdb_cluster_round_robin);
 
1823
      action.continuation->handleEvent(EVENT_HOST_DB_GET_RESPONSE, failed ? 0 : this);
 
1824
    }
 
1825
  } else {
 
1826
    action = 0;
 
1827
    // just a remote fill
 
1828
    ink_assert(!missing);
 
1829
    lookup_done(ip, name, false, ttl, NULL);
 
1830
  }
 
1831
  hostdb_cont_free(this);
 
1832
  return EVENT_DONE;
 
1833
}
 
1834
 
 
1835
 
 
1836
//
 
1837
// Wait for the response (put message)
 
1838
//
 
1839
int
 
1840
HostDBContinuation::clusterEvent(int event, Event * e)
 
1841
{
 
1842
  // remove ourselves from the queue
 
1843
  //
 
1844
  remoteHostDBQueue[key_partition()].remove(this);
 
1845
 
 
1846
  switch (event) {
 
1847
  default:
 
1848
    ink_assert(!"bad case");
 
1849
    hostdb_cont_free(this);
 
1850
    return EVENT_DONE;
 
1851
 
 
1852
    // handle the put response, e is really a HostDBContinuation *
 
1853
    //
 
1854
  case EVENT_HOST_DB_GET_RESPONSE:
 
1855
    if (timeout) {
 
1856
      timeout->cancel(this);
 
1857
      timeout = NULL;
 
1858
    }
 
1859
    if (e) {
 
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;
 
1864
 
 
1865
      HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
 
1866
 
 
1867
      if (!action.cancelled) {
 
1868
        if (reply_to_cont(action.continuation, r)) {
 
1869
          // if we are not the owner and neither was the sender,
 
1870
          // fill the owner
 
1871
          //
 
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);
 
1876
          }
 
1877
        }
 
1878
      }
 
1879
      hostdb_cont_free(this);
 
1880
      return EVENT_DONE;
 
1881
    }
 
1882
    return failed_cluster_request(e);
 
1883
 
 
1884
    // did not get the put message in time
 
1885
    //
 
1886
  case EVENT_INTERVAL:{
 
1887
      MUTEX_TRY_LOCK_FOR(lock, action.mutex, e->ethread, action.continuation);
 
1888
      if (!lock) {
 
1889
        e->schedule_in(HOST_DB_RETRY_PERIOD);
 
1890
        return EVENT_CONT;
 
1891
      }
 
1892
      return failed_cluster_request(e);
 
1893
    }
 
1894
  }
 
1895
}
 
1896
 
 
1897
 
 
1898
int
 
1899
HostDBContinuation::failed_cluster_request(Event * e)
 
1900
{
 
1901
  if (action.cancelled) {
 
1902
    hostdb_cont_free(this);
 
1903
    return EVENT_DONE;
 
1904
  }
 
1905
  // Attempt another remote probe
 
1906
  //
 
1907
  if (do_get_response(e))
 
1908
    return EVENT_CONT;
 
1909
 
 
1910
  // Otherwise, do a DNS lookup
 
1911
  //
 
1912
  do_dns();
 
1913
  return EVENT_DONE;
 
1914
}
 
1915
 
 
1916
 
 
1917
void
 
1918
get_hostinfo_ClusterFunction(ClusterMachine * from, void *data, int len)
 
1919
{
 
1920
  NOWARN_UNUSED(len);
 
1921
  void *pDS = 0;
 
1922
  HostDB_get_message *msg = (HostDB_get_message *) data;
 
1923
 
 
1924
#ifdef SPLIT_DNS
 
1925
  SplitDNS *pSD = 0;
 
1926
  char *hostname = msg->name;
 
1927
  if (hostname && SplitDNSConfig::isSplitDNSEnabled()) {
 
1928
    pSD = SplitDNSConfig::acquire();
 
1929
 
 
1930
    if (0 != pSD) {
 
1931
      pDS = pSD->getDNSRecord(hostname);
 
1932
    }
 
1933
    SplitDNSConfig::release(pSD);
 
1934
  }
 
1935
#endif // SPLIT_DNS
 
1936
 
 
1937
  HostDBContinuation *c = hostDBContAllocator.alloc();
 
1938
  SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent);
 
1939
  c->from = from;
 
1940
  c->from_cont = msg->cont;
 
1941
 
 
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
 
1946
     DNS servers
 
1947
     ----------------------------------------- */
 
1948
 
 
1949
 
 
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);
 
1955
}
 
1956
 
 
1957
 
 
1958
void
 
1959
put_hostinfo_ClusterFunction(ClusterMachine * from, void *data, int len)
 
1960
{
 
1961
  NOWARN_UNUSED(len);
 
1962
  HostDB_put_message *msg = (HostDB_put_message *) data;
 
1963
  HostDBContinuation *c = hostDBContAllocator.alloc();
 
1964
 
 
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;
 
1972
  c->ttl = msg->ttl;
 
1973
  c->from = from;
 
1974
  dnsProcessor.thread->schedule_imm(c);
 
1975
}
 
1976
#endif // NON_MODULAR
 
1977
 
 
1978
 
 
1979
//
 
1980
// Background event
 
1981
// Just increment the current_interval.  Might do other stuff
 
1982
// here, like move records to the current position in the cluster.
 
1983
//
 
1984
int
 
1985
HostDBContinuation::backgroundEvent(int event, Event * e)
 
1986
{
 
1987
  NOWARN_UNUSED(event);
 
1988
  NOWARN_UNUSED(e);
 
1989
  hostdb_current_interval++;
 
1990
 
 
1991
  return EVENT_CONT;
 
1992
}
 
1993
 
 
1994
bool HostDBInfo::match(INK_MD5 & md5, int bucket, int buckets)
 
1995
{
 
1996
  NOWARN_UNUSED(bucket);
 
1997
  if (md5[1] != md5_high)
 
1998
    return false;
 
1999
 
 
2000
  uint64_t
 
2001
    folded_md5 = fold_md5(md5);
 
2002
  uint64_t
 
2003
    ttag = folded_md5 / buckets;
 
2004
 
 
2005
  if (!ttag)
 
2006
    ttag = 1;
 
2007
  struct
 
2008
  {
 
2009
    unsigned int
 
2010
      md5_low_low:
 
2011
      24;
 
2012
    unsigned int
 
2013
      md5_low;
 
2014
  } tmp;
 
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;
 
2018
}
 
2019
 
 
2020
 
 
2021
char *
 
2022
HostDBInfo::hostname()
 
2023
{
 
2024
  if (!reverse_dns)
 
2025
    return NULL;
 
2026
 
 
2027
  return (char *) hostDB.ptr(&data.hostname_offset, hostDB.ptr_to_partition((char *) this));
 
2028
}
 
2029
 
 
2030
 
 
2031
HostDBRoundRobin *
 
2032
HostDBInfo::rr()
 
2033
{
 
2034
  if (!round_robin)
 
2035
    return NULL;
 
2036
 
 
2037
  HostDBRoundRobin *r = (HostDBRoundRobin *) hostDB.ptr(&app.rr.offset, hostDB.ptr_to_partition((char *) this));
 
2038
 
 
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");
 
2041
    return NULL;
 
2042
  }
 
2043
  return r;
 
2044
}
 
2045
 
 
2046
 
 
2047
int
 
2048
HostDBInfo::heap_size()
 
2049
{
 
2050
  if (reverse_dns) {
 
2051
    char *h = hostname();
 
2052
 
 
2053
    if (h)
 
2054
      return strlen(h) + 1;
 
2055
  } else if (round_robin) {
 
2056
    HostDBRoundRobin *r = rr();
 
2057
 
 
2058
    if (r)
 
2059
      // this is a bit conservative, we might want to resurect them later
 
2060
      return HostDBRoundRobin::size(r->n, this->is_srv);
 
2061
  }
 
2062
  return 0;
 
2063
}
 
2064
 
 
2065
 
 
2066
int *
 
2067
HostDBInfo::heap_offset_ptr()
 
2068
{
 
2069
  if (reverse_dns)
 
2070
    return &data.hostname_offset;
 
2071
 
 
2072
  if (round_robin)
 
2073
    return &app.rr.offset;
 
2074
 
 
2075
  return NULL;
 
2076
}
 
2077
 
 
2078
 
 
2079
#ifdef NON_MODULAR
 
2080
ClusterMachine *
 
2081
HostDBContinuation::master_machine(ClusterConfiguration * cc)
 
2082
{
 
2083
  return cc->machine_hash((int) (md5[1] >> 32));
 
2084
}
 
2085
#endif // NON_MODULAR
 
2086
 
 
2087
 
 
2088
#ifdef NON_MODULAR
 
2089
struct ShowHostDB;
 
2090
typedef int (ShowHostDB::*ShowHostDBEventHandler) (int event, Event * data);
 
2091
struct ShowHostDB: public ShowCont
 
2092
{
 
2093
  char *name;
 
2094
  unsigned int ip;
 
2095
  bool force;
 
2096
 
 
2097
  int showMain(int event, Event * e)
 
2098
  {
 
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"
 
2103
                    "</form>\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"
 
2107
                    "</form>\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);
 
2112
  }
 
2113
 
 
2114
 
 
2115
  int showLookup(int event, Event * e)
 
2116
  {
 
2117
    NOWARN_UNUSED(event);
 
2118
    NOWARN_UNUSED(e);
 
2119
    SET_HANDLER(&ShowHostDB::showLookupDone);
 
2120
    if (name)
 
2121
      hostDBProcessor.getbyname_re(this, name, 0, force ? HostDBProcessor::HOSTDB_FORCE_DNS_ALWAYS : 0);
 
2122
    else
 
2123
      hostDBProcessor.getbyaddr_re(this, ip);
 
2124
    return EVENT_CONT;
 
2125
  }
 
2126
 
 
2127
 
 
2128
  int showOne(HostDBInfo * r, bool rr, int event, Event * e)
 
2129
  {
 
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));
 
2135
    if (!rr) {
 
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()));
 
2139
    }
 
2140
    if (r->reverse_dns) {
 
2141
      CHECK_SHOW(show("<tr><td>%s</td><td>%s</td></tr>\n", "Hostname", r->hostname()? r->hostname() : "<none>"));
 
2142
    } else {
 
2143
      CHECK_SHOW(show("<tr><td>%s</td><td>%u.%u.%u.%u</td></tr>\n", "IP", PRINT_IP(r->ip())));
 
2144
    }
 
2145
    CHECK_SHOW(show("</table>\n"));
 
2146
    return EVENT_CONT;
 
2147
  }
 
2148
 
 
2149
 
 
2150
  int showLookupDone(int event, Event * e)
 
2151
  {
 
2152
    HostDBInfo *r = (HostDBInfo *) e;
 
2153
 
 
2154
    CHECK_SHOW(begin("HostDB Lookup"));
 
2155
    if (name) {
 
2156
      CHECK_SHOW(show("<H2>%s</H2>\n", name));
 
2157
    } else {
 
2158
      CHECK_SHOW(show("<H2>%u.%u.%u.%u</H2>\n", PRINT_IP(ip)));
 
2159
    }
 
2160
    if (r) {
 
2161
      showOne(r, false, event, e);
 
2162
      if (r->round_robin) {
 
2163
        HostDBRoundRobin *rr_data = r->rr();
 
2164
        if (rr_data) {
 
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"));
 
2170
 
 
2171
          for (int i = 0; i < rr_data->n; i++)
 
2172
            showOne(&rr_data->info[i], true, event, e);
 
2173
        }
 
2174
      }
 
2175
    } else {
 
2176
      if (name) {
 
2177
        CHECK_SHOW(show("<H2>%u.%u.%u.%u Not Found</H2>\n", PRINT_IP(ip)));
 
2178
      } else {
 
2179
        CHECK_SHOW(show("<H2>%s Not Found</H2>\n", name));
 
2180
      }
 
2181
    }
 
2182
    return complete(event, e);
 
2183
  }
 
2184
 
 
2185
 
 
2186
ShowHostDB(Continuation * c, HTTPHdr * h):
 
2187
  ShowCont(c, h), name(0), ip(0), force(0) {
 
2188
    SET_HANDLER(&ShowHostDB::showMain);
 
2189
  }
 
2190
};
 
2191
 
 
2192
#define STR_LEN_EQ_PREFIX(_x,_l,_s) (!ptr_len_ncasecmp(_x,_l,_s,sizeof(_s)-1))
 
2193
 
 
2194
 
 
2195
static Action *
 
2196
register_ShowHostDB(Continuation * c, HTTPHdr * h)
 
2197
{
 
2198
  ShowHostDB *s = new ShowHostDB(c, h);
 
2199
  int path_len;
 
2200
  const char *path = h->url_get()->path_get(&path_len);
 
2201
 
 
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);
 
2205
    int query_len;
 
2206
    const char *query = h->url_get()->query_get(&query_len);
 
2207
    s->sarg = xstrndup(query, query_len);
 
2208
    char *gn = NULL;
 
2209
    if (s->sarg)
 
2210
      gn = (char *) ink_memchr(s->sarg, '=', strlen(s->sarg));
 
2211
    if (gn)
 
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);
 
2216
    int query_len;
 
2217
    const char *query = h->url_get()->query_get(&query_len);
 
2218
    s->sarg = xstrndup(query, query_len);
 
2219
    char *gn = NULL;
 
2220
    if (s->sarg)
 
2221
      gn = (char *) ink_memchr(s->sarg, '=', strlen(s->sarg));
 
2222
    if (gn)
 
2223
      s->name = gn + 1;
 
2224
    SET_CONTINUATION_HANDLER(s, &ShowHostDB::showLookup);
 
2225
  }
 
2226
  this_ethread()->schedule_imm(s);
 
2227
  return &s->action;
 
2228
}
 
2229
#endif // NON_MODULAR
 
2230
 
 
2231
 
 
2232
#define HOSTDB_TEST_MAX_OUTSTANDING 100
 
2233
#define HOSTDB_TEST_LENGTH          100000
 
2234
 
 
2235
struct HostDBTestReverse;
 
2236
typedef int (HostDBTestReverse::*HostDBTestReverseHandler) (int, void *);
 
2237
struct HostDBTestReverse: public Continuation
 
2238
{
 
2239
  int outstanding;
 
2240
  int total;
 
2241
#if TS_HAS_LRAND48_R
 
2242
  struct drand48_data dr;
 
2243
#endif
 
2244
 
 
2245
  int mainEvent(int event, Event * e)
 
2246
  {
 
2247
    if (event == EVENT_HOST_DB_LOOKUP) {
 
2248
      HostDBInfo *i = (HostDBInfo *) e;
 
2249
      if (i)
 
2250
          printf("HostDBTestReverse: reversed %s\n", i->hostname());
 
2251
        outstanding--;
 
2252
    }
 
2253
    while (outstanding < HOSTDB_TEST_MAX_OUTSTANDING && total < HOSTDB_TEST_LENGTH)
 
2254
    {
 
2255
      long l = 0;
 
2256
#if TS_HAS_LRAND48_R
 
2257
      lrand48_r(&dr, &l);
 
2258
#else
 
2259
      l = lrand48();
 
2260
#endif
 
2261
      unsigned int ip = (unsigned int) l;
 
2262
      outstanding++;
 
2263
      total++;
 
2264
      if (!(outstanding % 1000))
 
2265
        printf("HostDBTestReverse: %d\n", total);
 
2266
      hostDBProcessor.getbyaddr_re(this, ip);
 
2267
    }
 
2268
    if (!outstanding) {
 
2269
      printf("HostDBTestReverse: done\n");
 
2270
      delete this;
 
2271
    }
 
2272
    return EVENT_CONT;
 
2273
  }
 
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);
 
2278
#else
 
2279
    srand48(time(NULL));
 
2280
#endif
 
2281
  }
 
2282
};
 
2283
 
 
2284
 
 
2285
#if TS_HAS_TESTS
 
2286
void
 
2287
run_HostDBTest()
 
2288
{
 
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);
 
2293
  }
 
2294
}
 
2295
#endif
 
2296
 
 
2297
 
 
2298
RecRawStatBlock *hostdb_rsb;
 
2299
 
 
2300
void
 
2301
ink_hostdb_init(ModuleVersion v)
 
2302
{
 
2303
  static int init_called = 0;
 
2304
 
 
2305
  ink_release_assert(!checkModuleVersion(v, HOSTDB_MODULE_VERSION));
 
2306
  if (init_called)
 
2307
    return;
 
2308
 
 
2309
  init_called = 1;
 
2310
  // do one time stuff
 
2311
  // create a stat block for HostDBStats
 
2312
  hostdb_rsb = RecAllocateRawStatBlock((int) HostDB_Stat_Count);
 
2313
 
 
2314
  //
 
2315
  // Register stats
 
2316
  //
 
2317
 
 
2318
  RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
 
2319
                     "proxy.process.hostdb.total_entries",
 
2320
                     RECD_INT, RECP_NULL, (int) hostdb_total_entries_stat, RecRawStatSyncCount);
 
2321
 
 
2322
  RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
 
2323
                     "proxy.process.hostdb.total_lookups",
 
2324
                     RECD_INT, RECP_NULL, (int) hostdb_total_lookups_stat, RecRawStatSyncSum);
 
2325
 
 
2326
  RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
 
2327
                     "proxy.process.hostdb.total_hits",
 
2328
                     RECD_INT, RECP_NON_PERSISTENT, (int) hostdb_total_hits_stat, RecRawStatSyncSum);
 
2329
 
 
2330
  RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
 
2331
                     "proxy.process.hostdb.ttl", RECD_FLOAT, RECP_NULL, (int) hostdb_ttl_stat, RecRawStatSyncAvg);
 
2332
 
 
2333
  RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
 
2334
                     "proxy.process.hostdb.ttl_expires",
 
2335
                     RECD_INT, RECP_NULL, (int) hostdb_ttl_expires_stat, RecRawStatSyncSum);
 
2336
 
 
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);
 
2340
 
 
2341
  RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
 
2342
                     "proxy.process.hostdb.bytes", RECD_INT, RECP_NULL, (int) hostdb_bytes_stat, RecRawStatSyncCount);
 
2343
}