]> git.ipfire.org Git - thirdparty/squid.git/blame - src/fqdncache.cc
Cleanup: fix most 'unused parameter' warnings
[thirdparty/squid.git] / src / fqdncache.cc
CommitLineData
f88bb09c 1/*
bbc27441 2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
e25c139f 3 *
bbc27441
AJ
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
f88bb09c 7 */
8
bbc27441
AJ
9/* DEBUG: section 35 FQDN Cache */
10
582c2af2 11#include "squid.h"
aa839030 12#include "cbdata.h"
cfd66529 13#include "DnsLookupDetails.h"
a553a5a3 14#include "event.h"
3bca2b86 15#include "helper.h"
8822ebee 16#include "mgr/Registration.h"
4d5904f7 17#include "SquidConfig.h"
f64091a7 18#include "SquidDns.h"
985c86bc 19#include "SquidTime.h"
e4f1fdae 20#include "StatCounters.h"
e6ccf245 21#include "Store.h"
ed6e9fb9 22#include "util.h"
d295d770 23#include "wordlist.h"
f88bb09c 24
9c0a2256
FC
25#if SQUID_SNMP
26#include "snmp_core.h"
27#endif
28
63be0a78 29/**
30 \defgroup FQDNCacheAPI FQDN Cache API
31 \ingroup Components
32 \section Introduction Introduction
33 \par
34 * The FQDN cache is a built-in component of squid providing
35 * Hostname to IP-Number translation functionality and managing
36 * the involved data-structures. Efficiency concerns require
37 * mechanisms that allow non-blocking access to these mappings.
38 * The FQDN cache usually doesn't block on a request except for
39 * special cases where this is desired (see below).
40 *
41 \todo FQDN Cache should have its own API *.h file.
42 */
43
44/**
45 \defgroup FQDNCacheInternal FQDN Cache Internals
46 \ingroup FQDNCacheAPI
47 \par
48 * Internally, the execution flow is as follows:
49 * On a miss, fqdncache_nbgethostbyaddr() checks whether a request
50 * for this name is already pending, and if positive, it creates a
51 * new entry using fqdncacheAddEntry(). Then it calls
52 * fqdncacheAddPending() to add a request to the queue together
53 * with data and handler. Else, ifqdncache_dnsDispatch() is called
54 * to directly create a DNS query or to fqdncacheEnqueue() if all
55 * no DNS port is free.
56 *
57 \par
58 * fqdncacheCallback() is called regularly to walk down the pending
59 * list and call handlers.
60 *
61 \par
62 * LRU clean-up is performed through fqdncache_purgelru() according
63 * to the fqdncache_high threshold.
64 */
65
66/// \ingroup FQDNCacheInternal
f88bb09c 67#define FQDN_LOW_WATER 90
63be0a78 68
69/// \ingroup FQDNCacheInternal
f88bb09c 70#define FQDN_HIGH_WATER 95
f88bb09c 71
63be0a78 72/**
73 \ingroup FQDNCacheAPI
74 * The data structure used for storing name-address mappings
75 * is a small hashtable (static hash_table *fqdn_table),
76 * where structures of type fqdncache_entry whose most
77 * interesting members are:
78 */
e1381638
AJ
79class fqdncache_entry
80{
3ff65596 81public:
f53969cc 82 hash_link hash; /* must be first */
add5d21f 83 time_t lastref;
84 time_t expires;
85 unsigned char name_count;
86 char *names[FQDN_MAX_NAMES + 1];
87 FQDNH *handler;
88 void *handlerData;
89 char *error_message;
62e76326 90
add5d21f 91 struct timeval request_time;
92 dlink_node lru;
ac06f720 93 unsigned short locks;
62e76326 94
26ac0430 95 struct {
be4d35dc
FC
96 bool negcached;
97 bool fromhosts;
2fadd50d 98 } flags;
3ff65596
AR
99
100 int age() const; ///< time passed since request_time or -1 if unknown
add5d21f 101};
102
63be0a78 103/// \ingroup FQDNCacheInternal
26ac0430 104static struct _fqdn_cache_stats {
f88bb09c 105 int requests;
106 int replies;
107 int hits;
108 int misses;
f88bb09c 109 int negative_hits;
2fadd50d 110} FqdncacheStats;
f88bb09c 111
63be0a78 112/// \ingroup FQDNCacheInternal
4bc76d59 113static dlink_list lru_list;
114
59f34d62 115static IDNSCB fqdncacheHandleReply;
33ab4aaf 116static int fqdncacheParse(fqdncache_entry *, const rfc1035_rr *, int, const char *error_message);
add5d21f 117static void fqdncacheRelease(fqdncache_entry *);
118static fqdncache_entry *fqdncacheCreateEntry(const char *name);
3ff65596 119static void fqdncacheCallback(fqdncache_entry *, int wait);
f5b8bbc4 120static fqdncache_entry *fqdncache_get(const char *);
f5b8bbc4 121static int fqdncacheExpiredEntry(const fqdncache_entry *);
f5b8bbc4 122static void fqdncacheLockEntry(fqdncache_entry * f);
123static void fqdncacheUnlockEntry(fqdncache_entry * f);
ec878047 124static FREE fqdncacheFreeEntry;
add5d21f 125static void fqdncacheAddEntry(fqdncache_entry * f);
f88bb09c 126
63be0a78 127/// \ingroup FQDNCacheInternal
365e5b34 128static hash_table *fqdn_table = NULL;
f88bb09c 129
63be0a78 130/// \ingroup FQDNCacheInternal
24382924 131static long fqdncache_low = 180;
63be0a78 132
133/// \ingroup FQDNCacheInternal
24382924 134static long fqdncache_high = 200;
f88bb09c 135
ac49890a
CT
136/// \ingroup FQDNCacheInternal
137inline int fqdncacheCount() { return fqdn_table ? fqdn_table->count : 0; }
138
3ff65596
AR
139int
140fqdncache_entry::age() const
141{
142 return request_time.tv_sec ? tvSubMsec(request_time, current_time) : -1;
143}
144
63be0a78 145/**
146 \ingroup FQDNCacheInternal
147 * Removes the given fqdncache entry
148 */
b8d8561b 149static void
add5d21f 150fqdncacheRelease(fqdncache_entry * f)
f88bb09c 151{
f88bb09c 152 int k;
3fda0827 153 hash_remove_link(fqdn_table, (hash_link *) f);
62e76326 154
95dc7ff4 155 for (k = 0; k < (int) f->name_count; ++k)
62e76326 156 safe_free(f->names[k]);
157
bf8fe701 158 debugs(35, 5, "fqdncacheRelease: Released FQDN record for '" << hashKeyStr(&f->hash) << "'.");
62e76326 159
4bc76d59 160 dlinkDelete(&f->lru, &lru_list);
62e76326 161
186477c1 162 safe_free(f->hash.key);
62e76326 163
429fdbec 164 safe_free(f->error_message);
62e76326 165
db1cd23c 166 memFree(f, MEM_FQDNCACHE_ENTRY);
f88bb09c 167}
168
63be0a78 169/**
170 \ingroup FQDNCacheInternal
f53969cc 171 \param name FQDN hash string.
63be0a78 172 \retval Match for given name
173 */
b8d8561b 174static fqdncache_entry *
0ee4272b 175fqdncache_get(const char *name)
f88bb09c 176{
177 hash_link *e;
178 static fqdncache_entry *f;
f88bb09c 179 f = NULL;
62e76326 180
f88bb09c 181 if (fqdn_table) {
62e76326 182 if ((e = (hash_link *)hash_lookup(fqdn_table, name)) != NULL)
183 f = (fqdncache_entry *) e;
f88bb09c 184 }
62e76326 185
f88bb09c 186 return f;
187}
188
63be0a78 189/// \ingroup FQDNCacheInternal
b8d8561b 190static int
fe4e214f 191fqdncacheExpiredEntry(const fqdncache_entry * f)
f88bb09c 192{
0e70aa1e 193 /* all static entries are locked, so this takes care of them too */
62e76326 194
429fdbec 195 if (f->locks != 0)
62e76326 196 return 0;
197
e84703ad 198 if (f->expires > squid_curtime)
62e76326 199 return 0;
200
f88bb09c 201 return 1;
202}
203
63be0a78 204/// \ingroup FQDNCacheAPI
59c4d35b 205void
ced8def3 206fqdncache_purgelru(void *)
f88bb09c 207{
4bc76d59 208 dlink_node *m;
209 dlink_node *prev = NULL;
210 fqdncache_entry *f;
f88bb09c 211 int removed = 0;
52040193 212 eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 10.0, 1);
62e76326 213
4bc76d59 214 for (m = lru_list.tail; m; m = prev) {
ac49890a 215 if (fqdncacheCount() < fqdncache_low)
62e76326 216 break;
217
218 prev = m->prev;
219
220 f = (fqdncache_entry *)m->data;
221
222 if (f->locks != 0)
223 continue;
224
225 fqdncacheRelease(f);
226
95dc7ff4 227 ++removed;
f88bb09c 228 }
62e76326 229
bf8fe701 230 debugs(35, 9, "fqdncache_purgelru: removed " << removed << " entries");
f88bb09c 231}
232
63be0a78 233/// \ingroup FQDNCacheAPI
0e70aa1e 234static void
235purge_entries_fromhosts(void)
236{
237 dlink_node *m = lru_list.head;
238 fqdncache_entry *i = NULL;
239 fqdncache_entry *t;
62e76326 240
0e70aa1e 241 while (m) {
f53969cc
SM
242 if (i != NULL) { /* need to delay deletion */
243 fqdncacheRelease(i); /* we just override locks */
62e76326 244 i = NULL;
245 }
246
247 t = (fqdncache_entry *)m->data;
248
249 if (t->flags.fromhosts)
250 i = t;
251
252 m = m->next;
0e70aa1e 253 }
62e76326 254
0e70aa1e 255 if (i != NULL)
62e76326 256 fqdncacheRelease(i);
0e70aa1e 257}
258
63be0a78 259/**
260 \ingroup FQDNCacheInternal
261 *
262 * Create blank fqdncache_entry
263 */
b8d8561b 264static fqdncache_entry *
add5d21f 265fqdncacheCreateEntry(const char *name)
f88bb09c 266{
4bc76d59 267 static fqdncache_entry *f;
e6ccf245 268 f = (fqdncache_entry *)memAllocate(MEM_FQDNCACHE_ENTRY);
186477c1 269 f->hash.key = xstrdup(name);
4bc76d59 270 f->expires = squid_curtime + Config.negativeDnsTtl;
4bc76d59 271 return f;
f88bb09c 272}
273
63be0a78 274/// \ingroup FQDNCacheInternal
b8d8561b 275static void
add5d21f 276fqdncacheAddEntry(fqdncache_entry * f)
f88bb09c 277{
e6ccf245 278 hash_link *e = (hash_link *)hash_lookup(fqdn_table, f->hash.key);
62e76326 279
add5d21f 280 if (NULL != e) {
62e76326 281 /* avoid colission */
282 fqdncache_entry *q = (fqdncache_entry *) e;
283 fqdncacheRelease(q);
429fdbec 284 }
62e76326 285
186477c1 286 hash_join(fqdn_table, &f->hash);
add5d21f 287 dlinkAdd(f, &f->lru, &lru_list);
429fdbec 288 f->lastref = squid_curtime;
f88bb09c 289}
290
63be0a78 291/**
292 \ingroup FQDNCacheInternal
293 *
294 * Walks down the pending list, calling handlers
295 */
b8d8561b 296static void
3ff65596 297fqdncacheCallback(fqdncache_entry * f, int wait)
f88bb09c 298{
fa80a8ef 299 FQDNH *callback;
300 void *cbdata;
f88bb09c 301 f->lastref = squid_curtime;
62e76326 302
fa80a8ef 303 if (!f->handler)
62e76326 304 return;
305
5a2aa048 306 fqdncacheLockEntry(f);
62e76326 307
fa80a8ef 308 callback = f->handler;
62e76326 309
add5d21f 310 f->handler = NULL;
62e76326 311
fa80a8ef 312 if (cbdataReferenceValidDone(f->handlerData, &cbdata)) {
3ff65596
AR
313 const DnsLookupDetails details(f->error_message, wait);
314 callback(f->name_count ? f->names[0] : NULL, details, cbdata);
f88bb09c 315 }
62e76326 316
429fdbec 317 fqdncacheUnlockEntry(f);
f88bb09c 318}
319
63be0a78 320/// \ingroup FQDNCacheInternal
7ba8d0b8 321static int
33ab4aaf 322fqdncacheParse(fqdncache_entry *f, const rfc1035_rr * answers, int nr, const char *error_message)
59f34d62 323{
59f34d62 324 int k;
7ba8d0b8 325 int ttl = 0;
326 const char *name = (const char *)f->hash.key;
327 f->expires = squid_curtime + Config.negativeDnsTtl;
be4d35dc 328 f->flags.negcached = true;
62e76326 329
59f34d62 330 if (nr < 0) {
bf8fe701 331 debugs(35, 3, "fqdncacheParse: Lookup of '" << name << "' failed (" << error_message << ")");
7ba8d0b8 332 f->error_message = xstrdup(error_message);
333 return -1;
59f34d62 334 }
62e76326 335
59f34d62 336 if (nr == 0) {
bf8fe701 337 debugs(35, 3, "fqdncacheParse: No DNS records for '" << name << "'");
7ba8d0b8 338 f->error_message = xstrdup("No DNS records");
339 return 0;
59f34d62 340 }
62e76326 341
bf8fe701 342 debugs(35, 3, "fqdncacheParse: " << nr << " answers for '" << name << "'");
59f34d62 343 assert(answers);
62e76326 344
95dc7ff4 345 for (k = 0; k < nr; ++k) {
62e76326 346 if (answers[k]._class != RFC1035_CLASS_IN)
347 continue;
348
2d320a3a 349 if (answers[k].type == RFC1035_TYPE_PTR) {
350 if (!answers[k].rdata[0]) {
bf8fe701 351 debugs(35, 2, "fqdncacheParse: blank PTR record for '" << name << "'");
2d320a3a 352 continue;
353 }
470cd749 354
2d320a3a 355 if (strchr(answers[k].rdata, ' ')) {
bf8fe701 356 debugs(35, 2, "fqdncacheParse: invalid PTR record '" << answers[k].rdata << "' for '" << name << "'");
2d320a3a 357 continue;
358 }
359
a38ec4b1
FC
360 f->names[f->name_count] = xstrdup(answers[k].rdata);
361 ++ f->name_count;
2d320a3a 362 } else if (answers[k].type != RFC1035_TYPE_CNAME)
363 continue;
62e76326 364
7ba8d0b8 365 if (ttl == 0 || (int) answers[k].ttl < ttl)
366 ttl = answers[k].ttl;
62e76326 367
7ba8d0b8 368 if (f->name_count >= FQDN_MAX_NAMES)
369 break;
370 }
62e76326 371
7ba8d0b8 372 if (f->name_count == 0) {
e0236918 373 debugs(35, DBG_IMPORTANT, "fqdncacheParse: No PTR record for '" << name << "'");
7ba8d0b8 374 return 0;
375 }
62e76326 376
3e8c4107 377 if (ttl > Config.positiveDnsTtl)
7ba8d0b8 378 ttl = Config.positiveDnsTtl;
62e76326 379
7ba8d0b8 380 if (ttl < Config.negativeDnsTtl)
381 ttl = Config.negativeDnsTtl;
382
383 f->expires = squid_curtime + ttl;
62e76326 384
be4d35dc 385 f->flags.negcached = false;
7ba8d0b8 386
387 return f->name_count;
59f34d62 388}
62e76326 389
63be0a78 390/**
391 \ingroup FQDNCacheAPI
392 *
393 * Callback for handling DNS results.
394 */
429fdbec 395static void
33ab4aaf 396fqdncacheHandleReply(void *data, const rfc1035_rr * answers, int na, const char *error_message)
f88bb09c 397{
aa839030 398 fqdncache_entry *f;
399 static_cast<generic_cbdata *>(data)->unwrap(&f);
e91e2a72 400 ++FqdncacheStats.replies;
3ff65596 401 const int age = f->age();
e8baef82 402 statCounter.dns.svcTime.count(age);
7ba8d0b8 403 fqdncacheParse(f, answers, na, error_message);
add5d21f 404 fqdncacheAddEntry(f);
3ff65596 405 fqdncacheCallback(f, age);
f88bb09c 406}
407
63be0a78 408/**
409 \ingroup FQDNCacheAPI
410 *
f53969cc
SM
411 \param addr IP address of domain to resolve.
412 \param handler A pointer to the function to be called when
413 * the reply from the FQDN cache
414 * (or the DNS if the FQDN cache misses)
415 \param handlerData Information that is passed to the handler
416 * and does not affect the FQDN cache.
63be0a78 417 */
429fdbec 418void
b7ac5457 419fqdncache_nbgethostbyaddr(const Ip::Address &addr, FQDNH * handler, void *handlerData)
f88bb09c 420{
421 fqdncache_entry *f = NULL;
cc192b50 422 char name[MAX_IPSTRLEN];
74addf6c 423 generic_cbdata *c;
4dd643d5 424 addr.toStr(name,MAX_IPSTRLEN);
bf8fe701 425 debugs(35, 4, "fqdncache_nbgethostbyaddr: Name '" << name << "'.");
95dc7ff4 426 ++FqdncacheStats.requests;
62e76326 427
26ac0430 428 if (name[0] == '\0') {
bf8fe701 429 debugs(35, 4, "fqdncache_nbgethostbyaddr: Invalid name!");
3ff65596 430 const DnsLookupDetails details("Invalid hostname", -1); // error, no lookup
7fd65651
A
431 if (handler)
432 handler(NULL, details, handlerData);
62e76326 433 return;
f88bb09c 434 }
62e76326 435
add5d21f 436 f = fqdncache_get(name);
62e76326 437
26ac0430 438 if (NULL == f) {
62e76326 439 /* miss */
440 (void) 0;
26ac0430 441 } else if (fqdncacheExpiredEntry(f)) {
62e76326 442 /* hit, but expired -- bummer */
443 fqdncacheRelease(f);
444 f = NULL;
26ac0430 445 } else {
62e76326 446 /* hit */
bf8fe701 447 debugs(35, 4, "fqdncache_nbgethostbyaddr: HIT for '" << name << "'");
62e76326 448
449 if (f->flags.negcached)
95dc7ff4 450 ++ FqdncacheStats.negative_hits;
62e76326 451 else
95dc7ff4 452 ++ FqdncacheStats.hits;
62e76326 453
454 f->handler = handler;
455
456 f->handlerData = cbdataReference(handlerData);
457
3ff65596 458 fqdncacheCallback(f, -1); // no lookup
62e76326 459
460 return;
f88bb09c 461 }
add5d21f 462
bf8fe701 463 debugs(35, 5, "fqdncache_nbgethostbyaddr: MISS for '" << name << "'");
95dc7ff4 464 ++ FqdncacheStats.misses;
add5d21f 465 f = fqdncacheCreateEntry(name);
466 f->handler = handler;
fa80a8ef 467 f->handlerData = cbdataReference(handlerData);
add5d21f 468 f->request_time = current_time;
aa839030 469 c = new generic_cbdata(f);
59f34d62 470 idnsPTRLookup(addr, fqdncacheHandleReply, c);
f88bb09c 471}
472
63be0a78 473/**
474 \ingroup FQDNCacheAPI
475 *
476 * Is different in that it only checks if an entry exists in
477 * it's data-structures and does not by default contact the
478 * DNS, unless this is requested, by setting the flags
479 * to FQDN_LOOKUP_IF_MISS.
480 *
f53969cc
SM
481 \param addr address of the FQDN being resolved
482 \param flags values are NULL or FQDN_LOOKUP_IF_MISS. default is NULL.
63be0a78 483 *
484 */
0ee4272b 485const char *
b7ac5457 486fqdncache_gethostbyaddr(const Ip::Address &addr, int flags)
f88bb09c 487{
cc192b50 488 char name[MAX_IPSTRLEN];
f88bb09c 489 fqdncache_entry *f = NULL;
62e76326 490
4dd643d5 491 if (addr.isAnyAddr() || addr.isNoAddr()) {
5ad05949
AJ
492 return NULL;
493 }
494
4dd643d5 495 addr.toStr(name,MAX_IPSTRLEN);
95dc7ff4 496 ++ FqdncacheStats.requests;
add5d21f 497 f = fqdncache_get(name);
62e76326 498
26ac0430 499 if (NULL == f) {
62e76326 500 (void) 0;
26ac0430 501 } else if (fqdncacheExpiredEntry(f)) {
62e76326 502 fqdncacheRelease(f);
503 f = NULL;
26ac0430 504 } else if (f->flags.negcached) {
95dc7ff4 505 ++ FqdncacheStats.negative_hits;
3ff65596 506 // ignore f->error_message: the caller just checks FQDN cache presence
62e76326 507 return NULL;
26ac0430 508 } else {
95dc7ff4 509 ++ FqdncacheStats.hits;
62e76326 510 f->lastref = squid_curtime;
3ff65596 511 // ignore f->error_message: the caller just checks FQDN cache presence
62e76326 512 return f->names[0];
f88bb09c 513 }
62e76326 514
3ff65596 515 /* no entry [any more] */
2ffff82e 516
95dc7ff4 517 ++ FqdncacheStats.misses;
62e76326 518
26ac0430 519 if (flags & FQDN_LOOKUP_IF_MISS) {
d6990df9 520 fqdncache_nbgethostbyaddr(addr, NULL, NULL);
cc192b50 521 }
62e76326 522
f88bb09c 523 return NULL;
524}
525
63be0a78 526/**
527 \ingroup FQDNCacheInternal
528 *
529 * Process objects list
530 */
b8d8561b 531void
532fqdnStats(StoreEntry * sentry)
f88bb09c 533{
534 fqdncache_entry *f = NULL;
535 int k;
536 int ttl;
62e76326 537
4bc76d59 538 if (fqdn_table == NULL)
62e76326 539 return;
540
15576b6a 541 storeAppendPrintf(sentry, "FQDN Cache Statistics:\n");
62e76326 542
ac49890a 543 storeAppendPrintf(sentry, "FQDNcache Entries In Use: %d\n",
62e76326 544 memInUse(MEM_FQDNCACHE_ENTRY));
545
ac49890a
CT
546 storeAppendPrintf(sentry, "FQDNcache Entries Cached: %d\n",
547 fqdncacheCount());
548
15576b6a 549 storeAppendPrintf(sentry, "FQDNcache Requests: %d\n",
62e76326 550 FqdncacheStats.requests);
551
15576b6a 552 storeAppendPrintf(sentry, "FQDNcache Hits: %d\n",
62e76326 553 FqdncacheStats.hits);
554
15576b6a 555 storeAppendPrintf(sentry, "FQDNcache Negative Hits: %d\n",
62e76326 556 FqdncacheStats.negative_hits);
557
15576b6a 558 storeAppendPrintf(sentry, "FQDNcache Misses: %d\n",
62e76326 559 FqdncacheStats.misses);
560
15576b6a 561 storeAppendPrintf(sentry, "FQDN Cache Contents:\n\n");
62e76326 562
cc192b50 563 storeAppendPrintf(sentry, "%-45.45s %3s %3s %3s %s\n",
62e76326 564 "Address", "Flg", "TTL", "Cnt", "Hostnames");
565
0f6bebac 566 hash_first(fqdn_table);
62e76326 567
0f6bebac 568 while ((f = (fqdncache_entry *) hash_next(fqdn_table))) {
62e76326 569 ttl = (f->flags.fromhosts ? -1 : (f->expires - squid_curtime));
cc192b50 570 storeAppendPrintf(sentry, "%-45.45s %c%c %3.3d % 3d",
62e76326 571 hashKeyStr(&f->hash),
572 f->flags.negcached ? 'N' : ' ',
573 f->flags.fromhosts ? 'H' : ' ',
574 ttl,
575 (int) f->name_count);
576
95dc7ff4 577 for (k = 0; k < (int) f->name_count; ++k)
62e76326 578 storeAppendPrintf(sentry, " %s", f->names[k]);
579
580 storeAppendPrintf(sentry, "\n");
f88bb09c 581 }
f88bb09c 582}
583
63be0a78 584/// \ingroup FQDNCacheInternal
429fdbec 585static void
586fqdncacheLockEntry(fqdncache_entry * f)
587{
4bc76d59 588 if (f->locks++ == 0) {
62e76326 589 dlinkDelete(&f->lru, &lru_list);
590 dlinkAdd(f, &f->lru, &lru_list);
4bc76d59 591 }
429fdbec 592}
593
63be0a78 594/// \ingroup FQDNCacheInternal
429fdbec 595static void
596fqdncacheUnlockEntry(fqdncache_entry * f)
597{
ac06f720 598 assert(f->locks > 0);
5e263176 599 -- f->locks;
62e76326 600
429fdbec 601 if (fqdncacheExpiredEntry(f))
62e76326 602 fqdncacheRelease(f);
429fdbec 603}
604
63be0a78 605/// \ingroup FQDNCacheInternal
ec878047 606static void
607fqdncacheFreeEntry(void *data)
608{
e6ccf245 609 fqdncache_entry *f = (fqdncache_entry *)data;
ec878047 610 int k;
62e76326 611
95dc7ff4 612 for (k = 0; k < (int) f->name_count; ++k)
62e76326 613 safe_free(f->names[k]);
614
186477c1 615 safe_free(f->hash.key);
62e76326 616
ec878047 617 safe_free(f->error_message);
62e76326 618
db1cd23c 619 memFree(f, MEM_FQDNCACHE_ENTRY);
ec878047 620}
621
63be0a78 622/// \ingroup FQDNCacheAPI
56e15c50 623void
624fqdncacheFreeMemory(void)
625{
ec878047 626 hashFreeItems(fqdn_table, fqdncacheFreeEntry);
56e15c50 627 hashFreeMemory(fqdn_table);
afe95a7e 628 fqdn_table = NULL;
56e15c50 629}
429fdbec 630
63be0a78 631/**
632 \ingroup FQDNCacheAPI
633 *
634 * Recalculate FQDN cache size upon reconfigure.
635 * Is called to clear the FQDN cache's data structures,
636 * cancel all pending requests.
637 */
429fdbec 638void
639fqdncache_restart(void)
640{
e55650e3 641 fqdncache_high = (long) (((float) Config.fqdncache.size *
62e76326 642 (float) FQDN_HIGH_WATER) / (float) 100);
e55650e3 643 fqdncache_low = (long) (((float) Config.fqdncache.size *
62e76326 644 (float) FQDN_LOW_WATER) / (float) 100);
0e70aa1e 645 purge_entries_fromhosts();
646}
647
63be0a78 648/**
649 \ingroup FQDNCacheAPI
650 *
651 * Adds a "static" entry from /etc/hosts.
652 \par
653 * The worldist is to be managed by the caller,
654 * including pointed-to strings
655 *
f53969cc
SM
656 \param addr FQDN name to be added.
657 \param hostnames ??
0e70aa1e 658 */
659void
660fqdncacheAddEntryFromHosts(char *addr, wordlist * hostnames)
661{
662 fqdncache_entry *fce;
663 int j = 0;
62e76326 664
0e70aa1e 665 if ((fce = fqdncache_get(addr))) {
62e76326 666 if (1 == fce->flags.fromhosts) {
667 fqdncacheUnlockEntry(fce);
668 } else if (fce->locks > 0) {
e0236918 669 debugs(35, DBG_IMPORTANT, "fqdncacheAddEntryFromHosts: can't add static entry for locked address '" << addr << "'");
62e76326 670 return;
671 } else {
672 fqdncacheRelease(fce);
673 }
0e70aa1e 674 }
62e76326 675
0e70aa1e 676 fce = fqdncacheCreateEntry(addr);
62e76326 677
0e70aa1e 678 while (hostnames) {
62e76326 679 fce->names[j] = xstrdup(hostnames->key);
7176768b 680 Tolower(fce->names[j]);
95dc7ff4 681 ++j;
62e76326 682 hostnames = hostnames->next;
683
684 if (j >= FQDN_MAX_NAMES)
685 break;
0e70aa1e 686 }
62e76326 687
0e70aa1e 688 fce->name_count = j;
f53969cc 689 fce->names[j] = NULL; /* it's safe */
be4d35dc 690 fce->flags.fromhosts = true;
0e70aa1e 691 fqdncacheAddEntry(fce);
692 fqdncacheLockEntry(fce);
429fdbec 693}
ce75f381 694
fc54b8d2
FC
695/// \ingroup FQDNCacheInternal
696static void
697fqdncacheRegisterWithCacheManager(void)
698{
699 Mgr::RegisterAction("fqdncache", "FQDN Cache Stats and Contents",
700 fqdnStats, 0, 1);
701
702}
703
704/**
705 \ingroup FQDNCacheAPI
706 *
707 * Initialize the fqdncache.
708 * Called after IP cache initialization.
709 */
710void
711fqdncache_init(void)
712{
713 int n;
714
715 fqdncacheRegisterWithCacheManager();
716
717 if (fqdn_table)
718 return;
719
720 debugs(35, 3, "Initializing FQDN Cache...");
721
722 memset(&FqdncacheStats, '\0', sizeof(FqdncacheStats));
723
724 memset(&lru_list, '\0', sizeof(lru_list));
725
726 fqdncache_high = (long) (((float) Config.fqdncache.size *
727 (float) FQDN_HIGH_WATER) / (float) 100);
728
729 fqdncache_low = (long) (((float) Config.fqdncache.size *
730 (float) FQDN_LOW_WATER) / (float) 100);
731
732 n = hashPrime(fqdncache_high / 4);
733
734 fqdn_table = hash_create((HASHCMP *) strcmp, n, hash4);
735
736 memDataInit(MEM_FQDNCACHE_ENTRY, "fqdncache_entry",
737 sizeof(fqdncache_entry), 0);
738}
739
59ad6d31 740#if SQUID_SNMP
63be0a78 741/**
742 * \ingroup FQDNCacheAPI
743 * The function to return the FQDN statistics via SNMP
135171fe 744 */
86115da5 745variable_list *
e7ef99a7 746snmp_netFqdnFn(variable_list * Var, snint * ErrP)
d60c11be 747{
736eb6ad 748 variable_list *Answer = NULL;
6a644e75
AJ
749 MemBuf tmp;
750 debugs(49, 5, "snmp_netFqdnFn: Processing request:" << snmpDebugOid(Var->name, Var->name_length, tmp));
86115da5 751 *ErrP = SNMP_ERR_NOERROR;
62e76326 752
135171fe 753 switch (Var->name[LEN_SQ_NET + 1]) {
62e76326 754
e7ef99a7 755 case FQDN_ENT:
62e76326 756 Answer = snmp_var_new_integer(Var->name, Var->name_length,
ac49890a 757 fqdncacheCount(),
62e76326 758 SMI_GAUGE32);
759 break;
760
e7ef99a7 761 case FQDN_REQ:
62e76326 762 Answer = snmp_var_new_integer(Var->name, Var->name_length,
763 FqdncacheStats.requests,
764 SMI_COUNTER32);
765 break;
766
e7ef99a7 767 case FQDN_HITS:
62e76326 768 Answer = snmp_var_new_integer(Var->name, Var->name_length,
769 FqdncacheStats.hits,
770 SMI_COUNTER32);
771 break;
772
e7ef99a7 773 case FQDN_PENDHIT:
62e76326 774 /* this is now worthless */
775 Answer = snmp_var_new_integer(Var->name, Var->name_length,
776 0,
777 SMI_GAUGE32);
778 break;
779
e7ef99a7 780 case FQDN_NEGHIT:
62e76326 781 Answer = snmp_var_new_integer(Var->name, Var->name_length,
782 FqdncacheStats.negative_hits,
783 SMI_COUNTER32);
784 break;
785
e7ef99a7 786 case FQDN_MISS:
62e76326 787 Answer = snmp_var_new_integer(Var->name, Var->name_length,
788 FqdncacheStats.misses,
789 SMI_COUNTER32);
790 break;
791
e7ef99a7 792 case FQDN_GHBN:
62e76326 793 Answer = snmp_var_new_integer(Var->name, Var->name_length,
794 0, /* deprecated */
795 SMI_COUNTER32);
796 break;
797
ce75f381 798 default:
62e76326 799 *ErrP = SNMP_ERR_NOSUCHNAME;
800 break;
86115da5 801 }
62e76326 802
86115da5 803 return Answer;
ce75f381 804}
e7ef99a7 805
135171fe 806#endif /*SQUID_SNMP */
f53969cc 807