]> git.ipfire.org Git - thirdparty/squid.git/blame - src/fqdncache.cc
Use MEM_SNMP_SNINT type for allocating SNMP reply stuff
[thirdparty/squid.git] / src / fqdncache.cc
CommitLineData
f88bb09c 1
5999b776 2
f88bb09c 3/*
2094fc54 4 * $Id: fqdncache.cc,v 1.130 1999/06/17 20:23:11 wessels Exp $
f88bb09c 5 *
7cf620a9 6 * DEBUG: section 35 FQDN Cache
f88bb09c 7 * AUTHOR: Harvest Derived
8 *
42c04c16 9 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
e25c139f 10 * ----------------------------------------------------------
f88bb09c 11 *
12 * Squid is the result of efforts by numerous individuals from the
13 * Internet community. Development is led by Duane Wessels of the
e25c139f 14 * National Laboratory for Applied Network Research and funded by the
15 * National Science Foundation. Squid is Copyrighted (C) 1998 by
16 * Duane Wessels and the University of California San Diego. Please
17 * see the COPYRIGHT file for full details. Squid incorporates
18 * software developed and/or copyrighted by other sources. Please see
19 * the CREDITS file for full details.
f88bb09c 20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
cbdec147 33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 34 *
f88bb09c 35 */
36
37#include "squid.h"
38
f88bb09c 39#define FQDN_LOW_WATER 90
40#define FQDN_HIGH_WATER 95
f88bb09c 41
f88bb09c 42static struct {
43 int requests;
44 int replies;
45 int hits;
46 int misses;
47 int pending_hits;
48 int negative_hits;
49 int errors;
f88bb09c 50 int ghba_calls; /* # calls to blocking gethostbyaddr() */
51} FqdncacheStats;
52
4bc76d59 53static dlink_list lru_list;
54
59f34d62 55#if USE_DNSSERVERS
74addf6c 56static HLPCB fqdncacheHandleReply;
57static fqdncache_entry *fqdncacheParse(const char *buf);
59f34d62 58#else
59static IDNSCB fqdncacheHandleReply;
60static fqdncache_entry *fqdncacheParse(rfc1035_rr *, int);
61#endif
f5b8bbc4 62static void fqdncache_release(fqdncache_entry *);
f5b8bbc4 63static fqdncache_entry *fqdncache_create(const char *name);
f5b8bbc4 64static void fqdncache_call_pending(fqdncache_entry *);
65static void fqdncacheAddHostent(fqdncache_entry *, const struct hostent *);
f5b8bbc4 66static fqdncache_entry *fqdncache_get(const char *);
348b2031 67static FQDNH dummy_handler;
f5b8bbc4 68static int fqdncacheExpiredEntry(const fqdncache_entry *);
69static void fqdncacheAddPending(fqdncache_entry *, FQDNH *, void *);
f5b8bbc4 70static void fqdncacheChangeKey(fqdncache_entry * i);
71static void fqdncacheLockEntry(fqdncache_entry * f);
72static void fqdncacheUnlockEntry(fqdncache_entry * f);
ec878047 73static FREE fqdncacheFreeEntry;
f88bb09c 74
365e5b34 75static hash_table *fqdn_table = NULL;
f88bb09c 76
77static char fqdncache_status_char[] =
78{
79 'C',
80 'N',
81 'P',
82 'D'
83};
84
24382924 85static long fqdncache_low = 180;
86static long fqdncache_high = 200;
f88bb09c 87
f88bb09c 88/* removes the given fqdncache entry */
b8d8561b 89static void
90fqdncache_release(fqdncache_entry * f)
f88bb09c 91{
f88bb09c 92 int k;
e144eae4 93 assert(f->status != FQDN_PENDING);
94 assert(f->status != FQDN_DISPATCHED);
95 assert(f->pending_head == NULL);
3fda0827 96 hash_remove_link(fqdn_table, (hash_link *) f);
429fdbec 97 if (f->status == FQDN_CACHED) {
f88bb09c 98 for (k = 0; k < (int) f->name_count; k++)
99 safe_free(f->names[k]);
a3d5953d 100 debug(35, 5) ("fqdncache_release: Released FQDN record for '%s'.\n",
429fdbec 101 f->name);
f88bb09c 102 }
4bc76d59 103 dlinkDelete(&f->lru, &lru_list);
429fdbec 104 safe_free(f->name);
105 safe_free(f->error_message);
db1cd23c 106 memFree(f, MEM_FQDNCACHE_ENTRY);
f88bb09c 107}
108
109/* return match for given name */
b8d8561b 110static fqdncache_entry *
0ee4272b 111fqdncache_get(const char *name)
f88bb09c 112{
113 hash_link *e;
114 static fqdncache_entry *f;
f88bb09c 115 f = NULL;
116 if (fqdn_table) {
117 if ((e = hash_lookup(fqdn_table, name)) != NULL)
118 f = (fqdncache_entry *) e;
119 }
120 return f;
121}
122
b8d8561b 123static int
fe4e214f 124fqdncacheExpiredEntry(const fqdncache_entry * f)
f88bb09c 125{
126 if (f->status == FQDN_PENDING)
127 return 0;
128 if (f->status == FQDN_DISPATCHED)
129 return 0;
429fdbec 130 if (f->locks != 0)
131 return 0;
e84703ad 132 if (f->expires > squid_curtime)
f88bb09c 133 return 0;
134 return 1;
135}
136
59c4d35b 137void
138fqdncache_purgelru(void *notused)
f88bb09c 139{
4bc76d59 140 dlink_node *m;
141 dlink_node *prev = NULL;
142 fqdncache_entry *f;
f88bb09c 143 int removed = 0;
52040193 144 eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 10.0, 1);
4bc76d59 145 for (m = lru_list.tail; m; m = prev) {
59c4d35b 146 if (memInUse(MEM_FQDNCACHE_ENTRY) < fqdncache_low)
4bc76d59 147 break;
148 prev = m->prev;
149 f = m->data;
f88bb09c 150 if (f->status == FQDN_PENDING)
151 continue;
152 if (f->status == FQDN_DISPATCHED)
153 continue;
4bc76d59 154 if (f->locks != 0)
155 continue;
156 fqdncache_release(f);
f88bb09c 157 removed++;
158 }
ac750329 159 debug(35, 9) ("fqdncache_purgelru: removed %d entries\n", removed);
f88bb09c 160}
161
f88bb09c 162/* create blank fqdncache_entry */
b8d8561b 163static fqdncache_entry *
429fdbec 164fqdncache_create(const char *name)
f88bb09c 165{
4bc76d59 166 static fqdncache_entry *f;
59c4d35b 167 f = memAllocate(MEM_FQDNCACHE_ENTRY);
4bc76d59 168 f->name = xstrdup(name);
169 f->expires = squid_curtime + Config.negativeDnsTtl;
7db83ee8 170 hash_join(fqdn_table, (hash_link *) f);
4bc76d59 171 dlinkAdd(f, &f->lru, &lru_list);
172 return f;
f88bb09c 173}
174
b8d8561b 175static void
429fdbec 176fqdncacheAddHostent(fqdncache_entry * f, const struct hostent *hp)
f88bb09c 177{
178 int k;
429fdbec 179 f->name_count = 0;
180 f->names[f->name_count++] = xstrdup((char *) hp->h_name);
181 for (k = 0; hp->h_aliases[k]; k++) {
182 f->names[f->name_count++] = xstrdup(hp->h_aliases[k]);
183 if (f->name_count == FQDN_MAX_NAMES)
184 break;
185 }
186}
f88bb09c 187
429fdbec 188static fqdncache_entry *
189fqdncacheAddNew(const char *name, const struct hostent *hp, fqdncache_status_t status)
190{
191 fqdncache_entry *f;
e144eae4 192 assert(fqdncache_get(name) == NULL);
6a78c18e 193 debug(35, 10) ("fqdncacheAddNew: Adding '%s', status=%c\n",
429fdbec 194 name,
195 fqdncache_status_char[status]);
196 f = fqdncache_create(name);
197 if (hp)
198 fqdncacheAddHostent(f, hp);
199 f->status = status;
200 f->lastref = squid_curtime;
201 return f;
f88bb09c 202}
203
204/* walks down the pending list, calling handlers */
b8d8561b 205static void
206fqdncache_call_pending(fqdncache_entry * f)
f88bb09c 207{
59c4d35b 208 fqdn_pending *p = NULL;
f88bb09c 209 int nhandler = 0;
f88bb09c 210 f->lastref = squid_curtime;
429fdbec 211 fqdncacheLockEntry(f);
f88bb09c 212 while (f->pending_head != NULL) {
213 p = f->pending_head;
214 f->pending_head = p->next;
215 if (p->handler) {
216 nhandler++;
217 dns_error_message = f->error_message;
348b2031 218 p->handler((f->status == FQDN_CACHED) ? f->names[0] : NULL,
f88bb09c 219 p->handlerData);
220 }
db1cd23c 221 memFree(p, MEM_FQDNCACHE_PENDING);
f88bb09c 222 }
223 f->pending_head = NULL; /* nuke list */
a3d5953d 224 debug(35, 10) ("fqdncache_call_pending: Called %d handlers.\n", nhandler);
429fdbec 225 fqdncacheUnlockEntry(f);
f88bb09c 226}
227
b8d8561b 228static fqdncache_entry *
b18baa48 229#if USE_DNSSERVERS
74addf6c 230fqdncacheParse(const char *inbuf)
f88bb09c 231{
bd34f258 232 LOCAL_ARRAY(char, buf, DNS_INBUF_SZ);
e84703ad 233 char *token;
234 static fqdncache_entry f;
bd34f258 235 int ttl;
236 xstrncpy(buf, inbuf, DNS_INBUF_SZ);
778f4e28 237 debug(35, 5) ("fqdncacheParse: parsing: {%s}\n", buf);
bd34f258 238 memset(&f, '\0', sizeof(f));
239 f.expires = squid_curtime;
240 f.status = FQDN_NEGATIVE_CACHED;
c68e9c6b 241 if (inbuf == NULL) {
242 debug(35, 1) ("fqdncacheParse: Got <NULL> reply\n");
243 return &f;
244 }
bd34f258 245 token = strtok(buf, w_space);
246 if (NULL == token) {
6a78c18e 247 debug(35, 1) ("fqdncacheParse: Got <NULL>, expecting '$name'\n");
bd34f258 248 return &f;
249 }
250 if (0 == strcmp(token, "$fail")) {
251 f.expires = squid_curtime + Config.negativeDnsTtl;
252 token = strtok(NULL, "\n");
253 assert(NULL != token);
254 f.error_message = xstrdup(token);
255 return &f;
256 }
257 if (0 != strcmp(token, "$name")) {
6a78c18e 258 debug(35, 1) ("fqdncacheParse: Got '%s', expecting '$name'\n", token);
bd34f258 259 return &f;
260 }
261 token = strtok(NULL, w_space);
262 if (NULL == token) {
6a78c18e 263 debug(35, 1) ("fqdncacheParse: Got <NULL>, expecting TTL\n");
bd34f258 264 return &f;
265 }
266 f.status = FQDN_CACHED;
267 ttl = atoi(token);
268 if (ttl > 0)
269 f.expires = squid_curtime + ttl;
270 else
271 f.expires = squid_curtime + Config.positiveDnsTtl;
272 token = strtok(NULL, w_space);
273 if (NULL != token) {
274 f.names[0] = xstrdup(token);
275 f.name_count = 1;
f88bb09c 276 }
e84703ad 277 return &f;
f88bb09c 278}
59f34d62 279#else
59f34d62 280fqdncacheParse(rfc1035_rr * answers, int nr)
281{
282 static fqdncache_entry f;
283 int k;
284 int j;
285 int na = 0;
286 memset(&f, '\0', sizeof(f));
287 f.expires = squid_curtime;
288 f.status = FQDN_NEGATIVE_CACHED;
289 if (nr < 0) {
b18baa48 290 debug(35, 3) ("fqdncacheParse: Lookup failed (error %d)\n",
59f34d62 291 rfc1035_errno);
292 assert(rfc1035_error_message);
293 f.error_message = xstrdup(rfc1035_error_message);
294 return &f;
295 }
296 if (nr == 0) {
b18baa48 297 debug(35, 3) ("fqdncacheParse: No DNS records\n");
59f34d62 298 f.error_message = xstrdup("No DNS records");
299 return &f;
300 }
39d5df9b 301 debug(35, 3) ("fqdncacheParse: %d answers\n", nr);
59f34d62 302 assert(answers);
303 for (j = 0, k = 0; k < nr; k++) {
304 if (answers[k].type != RFC1035_TYPE_PTR)
305 continue;
306 if (answers[k].class != RFC1035_CLASS_IN)
307 continue;
308 na++;
309 f.status = FQDN_CACHED;
310 f.names[0] = xstrdup(answers[k].rdata);
311 f.name_count = 1;
312 f.expires = squid_curtime + answers[k].ttl;
313 return &f;
314 }
315 debug(35, 1) ("fqdncacheParse: No PTR record\n");
316 f.error_message = xstrdup("No PTR record");
317 return &f;
318}
319#endif
f88bb09c 320
429fdbec 321static void
59f34d62 322#if USE_DNSSERVERS
74addf6c 323fqdncacheHandleReply(void *data, char *reply)
59f34d62 324#else
325fqdncacheHandleReply(void *data, rfc1035_rr * answers, int na)
326#endif
f88bb09c 327{
f88bb09c 328 int n;
74addf6c 329 generic_cbdata *c = data;
330 fqdncache_entry *f = c->data;
e84703ad 331 fqdncache_entry *x = NULL;
698e6f16 332 assert(f->status == FQDN_DISPATCHED);
74addf6c 333 assert(f->locks);
334 cbdataFree(c);
335 c = NULL;
c68e9c6b 336 n = ++FqdncacheStats.replies;
74addf6c 337 statHistCount(&Counter.dns.svc_time,
338 tvSubMsec(f->request_time, current_time));
59f34d62 339#if USE_DNSSERVERS
c68e9c6b 340 x = fqdncacheParse(reply);
59f34d62 341#else
342 x = fqdncacheParse(answers, na);
343#endif
c68e9c6b 344 assert(x);
345 f->name_count = x->name_count;
346 for (n = 0; n < (int) f->name_count; n++)
347 f->names[n] = x->names[n];
348 f->error_message = x->error_message;
349 f->status = x->status;
350 f->expires = x->expires;
351 fqdncache_call_pending(f);
74addf6c 352 fqdncacheUnlockEntry(f); /* unlock from FQDN_DISPATCHED */
f88bb09c 353}
354
b8d8561b 355static void
348b2031 356fqdncacheAddPending(fqdncache_entry * f, FQDNH * handler, void *handlerData)
f88bb09c 357{
59c4d35b 358 fqdn_pending *pending = memAllocate(MEM_FQDNCACHE_PENDING);
359 fqdn_pending **I = NULL;
429fdbec 360 f->lastref = squid_curtime;
f88bb09c 361 pending->handler = handler;
362 pending->handlerData = handlerData;
f88bb09c 363 for (I = &(f->pending_head); *I; I = &((*I)->next));
364 *I = pending;
365}
366
429fdbec 367void
348b2031 368fqdncache_nbgethostbyaddr(struct in_addr addr, FQDNH * handler, void *handlerData)
f88bb09c 369{
370 fqdncache_entry *f = NULL;
f88bb09c 371 char *name = inet_ntoa(addr);
74addf6c 372 generic_cbdata *c;
698e6f16 373 assert(handler);
a3d5953d 374 debug(35, 4) ("fqdncache_nbgethostbyaddr: Name '%s'.\n", name);
f88bb09c 375 FqdncacheStats.requests++;
f88bb09c 376 if (name == NULL || name[0] == '\0') {
a3d5953d 377 debug(35, 4) ("fqdncache_nbgethostbyaddr: Invalid name!\n");
348b2031 378 handler(NULL, handlerData);
429fdbec 379 return;
f88bb09c 380 }
381 if ((f = fqdncache_get(name))) {
382 if (fqdncacheExpiredEntry(f)) {
383 fqdncache_release(f);
384 f = NULL;
385 }
386 }
387 if (f == NULL) {
388 /* MISS: No entry, create the new one */
a3d5953d 389 debug(35, 5) ("fqdncache_nbgethostbyaddr: MISS for '%s'\n", name);
f88bb09c 390 FqdncacheStats.misses++;
429fdbec 391 f = fqdncacheAddNew(name, NULL, FQDN_PENDING);
348b2031 392 fqdncacheAddPending(f, handler, handlerData);
74addf6c 393 f->request_time = current_time;
f88bb09c 394 } else if (f->status == FQDN_CACHED || f->status == FQDN_NEGATIVE_CACHED) {
395 /* HIT */
a3d5953d 396 debug(35, 4) ("fqdncache_nbgethostbyaddr: HIT for '%s'\n", name);
f88bb09c 397 if (f->status == FQDN_NEGATIVE_CACHED)
398 FqdncacheStats.negative_hits++;
399 else
400 FqdncacheStats.hits++;
348b2031 401 fqdncacheAddPending(f, handler, handlerData);
f88bb09c 402 fqdncache_call_pending(f);
429fdbec 403 return;
f88bb09c 404 } else if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED) {
a3d5953d 405 debug(35, 4) ("fqdncache_nbgethostbyaddr: PENDING for '%s'\n", name);
f88bb09c 406 FqdncacheStats.pending_hits++;
348b2031 407 fqdncacheAddPending(f, handler, handlerData);
429fdbec 408 if (squid_curtime - f->expires > 600) {
6a78c18e 409 debug(35, 0) ("fqdncache_nbgethostbyname: '%s' PENDING for %d seconds, aborting\n", name,
ec878047 410 (int) (squid_curtime + Config.negativeDnsTtl - f->expires));
429fdbec 411 fqdncacheChangeKey(f);
412 fqdncache_call_pending(f);
413 }
414 return;
f88bb09c 415 } else {
d46a87a8 416 debug(35, 1) ("fqdncache_nbgethostbyaddr: BAD status %d",
417 (int) f->status);
698e6f16 418 assert(0);
f88bb09c 419 }
74addf6c 420 /* for HIT, PENDING, DISPATCHED we've returned. For MISS we submit */
421 c = xcalloc(1, sizeof(*c));
422 c->data = f;
db1cd23c 423 cbdataAdd(c, cbdataXfree, 0);
429fdbec 424 f->status = FQDN_DISPATCHED;
4bc76d59 425 fqdncacheLockEntry(f); /* lock while FQDN_DISPATCHED */
59f34d62 426#if USE_DNSSERVERS
74addf6c 427 dnsSubmit(f->name, fqdncacheHandleReply, c);
59f34d62 428#else
429 idnsPTRLookup(addr, fqdncacheHandleReply, c);
430#endif
f88bb09c 431}
432
f88bb09c 433/* initialize the fqdncache */
b8d8561b 434void
0673c0ba 435fqdncache_init(void)
f88bb09c 436{
aa9e2cab 437 int n;
19054954 438 if (fqdn_table)
439 return;
a3d5953d 440 debug(35, 3) ("Initializing FQDN Cache...\n");
f88bb09c 441 memset(&FqdncacheStats, '\0', sizeof(FqdncacheStats));
3eb55834 442 memset(&lru_list, '\0', sizeof(lru_list));
e55650e3 443 fqdncache_high = (long) (((float) Config.fqdncache.size *
f88bb09c 444 (float) FQDN_HIGH_WATER) / (float) 100);
e55650e3 445 fqdncache_low = (long) (((float) Config.fqdncache.size *
f88bb09c 446 (float) FQDN_LOW_WATER) / (float) 100);
aa9e2cab 447 n = hashPrime(fqdncache_high / 4);
6a78c18e 448 fqdn_table = hash_create((HASHCMP *) strcmp, n, hash4);
22f3fd98 449 cachemgrRegister("fqdncache",
450 "FQDN Cache Stats and Contents",
1da3b90b 451 fqdnStats, 0, 1);
f88bb09c 452}
453
454/* clean up the pending entries in dnsserver */
455/* return 1 if we found the host, 0 otherwise */
b8d8561b 456int
b69f7771 457fqdncacheUnregister(struct in_addr addr, void *data)
f88bb09c 458{
03047798 459 char *name = inet_ntoa(addr);
f88bb09c 460 fqdncache_entry *f = NULL;
59c4d35b 461 fqdn_pending *p = NULL;
f88bb09c 462 int n = 0;
5a675d84 463 debug(35, 3) ("fqdncacheUnregister: name '%s'\n", name);
f88bb09c 464 if ((f = fqdncache_get(name)) == NULL)
465 return 0;
466 if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED) {
467 for (p = f->pending_head; p; p = p->next) {
b69f7771 468 if (p->handlerData != data)
469 continue;
470 p->handler = NULL;
b69f7771 471 n++;
f88bb09c 472 }
473 }
b69f7771 474 if (n == 0)
475 debug_trap("fqdncacheUnregister: callback data not found");
a3d5953d 476 debug(35, 3) ("fqdncacheUnregister: unregistered %d handlers\n", n);
f88bb09c 477 return n;
478}
479
0ee4272b 480const char *
b8d8561b 481fqdncache_gethostbyaddr(struct in_addr addr, int flags)
f88bb09c 482{
483 char *name = inet_ntoa(addr);
484 fqdncache_entry *f = NULL;
429fdbec 485 struct in_addr ip;
698e6f16 486 assert(name);
f88bb09c 487 FqdncacheStats.requests++;
488 if ((f = fqdncache_get(name))) {
429fdbec 489 if (fqdncacheExpiredEntry(f)) {
490 fqdncache_release(f);
491 f = NULL;
492 }
493 }
494 if (f) {
7c63efed 495 if (f->status == FQDN_NEGATIVE_CACHED) {
f88bb09c 496 FqdncacheStats.negative_hits++;
497 dns_error_message = f->error_message;
498 return NULL;
499 } else {
500 FqdncacheStats.hits++;
501 f->lastref = squid_curtime;
502 return f->names[0];
503 }
504 }
f88bb09c 505 /* check if it's already a FQDN address in text form. */
429fdbec 506 if (!safe_inet_addr(name, &ip))
f88bb09c 507 return name;
429fdbec 508 FqdncacheStats.misses++;
f88bb09c 509 if (flags & FQDN_LOOKUP_IF_MISS)
348b2031 510 fqdncache_nbgethostbyaddr(addr, dummy_handler, NULL);
f88bb09c 511 return NULL;
512}
513
514
515/* process objects list */
b8d8561b 516void
517fqdnStats(StoreEntry * sentry)
f88bb09c 518{
519 fqdncache_entry *f = NULL;
520 int k;
521 int ttl;
4bc76d59 522 if (fqdn_table == NULL)
f88bb09c 523 return;
15576b6a 524 storeAppendPrintf(sentry, "FQDN Cache Statistics:\n");
525 storeAppendPrintf(sentry, "FQDNcache Entries: %d\n",
59c4d35b 526 memInUse(MEM_FQDNCACHE_ENTRY));
15576b6a 527 storeAppendPrintf(sentry, "FQDNcache Requests: %d\n",
f88bb09c 528 FqdncacheStats.requests);
15576b6a 529 storeAppendPrintf(sentry, "FQDNcache Hits: %d\n",
f88bb09c 530 FqdncacheStats.hits);
15576b6a 531 storeAppendPrintf(sentry, "FQDNcache Pending Hits: %d\n",
f88bb09c 532 FqdncacheStats.pending_hits);
15576b6a 533 storeAppendPrintf(sentry, "FQDNcache Negative Hits: %d\n",
f88bb09c 534 FqdncacheStats.negative_hits);
15576b6a 535 storeAppendPrintf(sentry, "FQDNcache Misses: %d\n",
f88bb09c 536 FqdncacheStats.misses);
15576b6a 537 storeAppendPrintf(sentry, "Blocking calls to gethostbyaddr(): %d\n",
f88bb09c 538 FqdncacheStats.ghba_calls);
15576b6a 539 storeAppendPrintf(sentry, "FQDN Cache Contents:\n\n");
f88bb09c 540
0f6bebac 541 hash_first(fqdn_table);
542 while ((f = (fqdncache_entry *) hash_next(fqdn_table))) {
f88bb09c 543 if (f->status == FQDN_PENDING || f->status == FQDN_DISPATCHED)
544 ttl = 0;
545 else
e84703ad 546 ttl = (f->expires - squid_curtime);
15576b6a 547 storeAppendPrintf(sentry, " %-32.32s %c %6d %d",
f88bb09c 548 f->name,
549 fqdncache_status_char[f->status],
550 ttl,
551 (int) f->name_count);
552 for (k = 0; k < (int) f->name_count; k++)
553 storeAppendPrintf(sentry, " %s", f->names[k]);
22f3fd98 554 storeAppendPrintf(sentry, "\n");
f88bb09c 555 }
f88bb09c 556}
557
b8d8561b 558static void
79d39a72 559dummy_handler(const char *bufnotused, void *datanotused)
f88bb09c 560{
561 return;
562}
563
b8d8561b 564void
0ee4272b 565fqdncacheReleaseInvalid(const char *name)
f88bb09c 566{
567 fqdncache_entry *f;
568 if ((f = fqdncache_get(name)) == NULL)
569 return;
570 if (f->status != FQDN_NEGATIVE_CACHED)
571 return;
572 fqdncache_release(f);
573}
28ab0c0a 574
0ee4272b 575const char *
b8d8561b 576fqdnFromAddr(struct in_addr addr)
28ab0c0a 577{
0ee4272b 578 const char *n;
39de381a 579 static char buf[32];
17a0a4ee 580 if (Config.onoff.log_fqdn && (n = fqdncache_gethostbyaddr(addr, 0)))
28ab0c0a 581 return n;
f2052513 582 xstrncpy(buf, inet_ntoa(addr), 32);
39de381a 583 return buf;
28ab0c0a 584}
f201f309 585
429fdbec 586static void
587fqdncacheLockEntry(fqdncache_entry * f)
588{
4bc76d59 589 if (f->locks++ == 0) {
590 dlinkDelete(&f->lru, &lru_list);
591 dlinkAdd(f, &f->lru, &lru_list);
592 }
429fdbec 593}
594
595static void
596fqdncacheUnlockEntry(fqdncache_entry * f)
597{
598 if (f->locks == 0) {
599 debug_trap("fqdncacheUnlockEntry: Entry has no locks");
600 return;
601 }
602 f->locks--;
603 if (fqdncacheExpiredEntry(f))
604 fqdncache_release(f);
605}
606
ec878047 607static void
608fqdncacheFreeEntry(void *data)
609{
610 fqdncache_entry *f = data;
0e1a4726 611 fqdn_pending *p = NULL;
ec878047 612 int k;
0e1a4726 613 while ((p = f->pending_head)) {
614 f->pending_head = p->next;
db1cd23c 615 memFree(p, MEM_FQDNCACHE_PENDING);
0e1a4726 616 }
ec878047 617 for (k = 0; k < (int) f->name_count; k++)
618 safe_free(f->names[k]);
619 safe_free(f->name);
620 safe_free(f->error_message);
db1cd23c 621 memFree(f, MEM_FQDNCACHE_ENTRY);
ec878047 622}
623
56e15c50 624void
625fqdncacheFreeMemory(void)
626{
ec878047 627 hashFreeItems(fqdn_table, fqdncacheFreeEntry);
56e15c50 628 hashFreeMemory(fqdn_table);
afe95a7e 629 fqdn_table = NULL;
56e15c50 630}
429fdbec 631
632static void
633fqdncacheChangeKey(fqdncache_entry * f)
634{
635 static int index = 0;
636 LOCAL_ARRAY(char, new_key, 256);
637 hash_link *table_entry = hash_lookup(fqdn_table, f->name);
638 if (table_entry == NULL) {
6a78c18e 639 debug(35, 0) ("fqdncacheChangeKey: Could not find key '%s'\n", f->name);
429fdbec 640 return;
641 }
642 if (f != (fqdncache_entry *) table_entry) {
643 debug_trap("fqdncacheChangeKey: f != table_entry!");
644 return;
645 }
3fda0827 646 hash_remove_link(fqdn_table, table_entry);
042461c3 647 snprintf(new_key, 256, "%d/", ++index);
429fdbec 648 strncat(new_key, f->name, 128);
6a78c18e 649 debug(35, 1) ("fqdncacheChangeKey: from '%s' to '%s'\n", f->name, new_key);
429fdbec 650 safe_free(f->name);
651 f->name = xstrdup(new_key);
7db83ee8 652 hash_join(fqdn_table, (hash_link *) f);
429fdbec 653}
654
655/* call during reconfigure phase to clear out all the
656 * pending and dispatched reqeusts that got lost */
657void
658fqdncache_restart(void)
659{
660 fqdncache_entry *this;
698e6f16 661 assert(fqdn_table);
0f6bebac 662 hash_first(fqdn_table);
663 while ((this = (fqdncache_entry *) hash_next(fqdn_table))) {
429fdbec 664 if (this->status == FQDN_CACHED)
665 continue;
666 if (this->status == FQDN_NEGATIVE_CACHED)
667 continue;
429fdbec 668 }
e55650e3 669 fqdncache_high = (long) (((float) Config.fqdncache.size *
e144eae4 670 (float) FQDN_HIGH_WATER) / (float) 100);
e55650e3 671 fqdncache_low = (long) (((float) Config.fqdncache.size *
e144eae4 672 (float) FQDN_LOW_WATER) / (float) 100);
429fdbec 673}
ce75f381 674
675#ifdef SQUID_SNMP
e7ef99a7 676/*
135171fe 677 * The function to return the fqdn statistics via SNMP
678 */
d60c11be 679
86115da5 680variable_list *
e7ef99a7 681snmp_netFqdnFn(variable_list * Var, snint * ErrP)
d60c11be 682{
86115da5 683 variable_list *Answer;
d60c11be 684
e7ef99a7 685 debug(49, 5) ("snmp_netFqdnFn: Processing request:\n", Var->name[LEN_SQ_NET +
135171fe 686 1]);
e7ef99a7 687 snmpDebugOid(5, Var->name, Var->name_length);
ce75f381 688
86115da5 689 Answer = snmp_var_new(Var->name, Var->name_length);
690 *ErrP = SNMP_ERR_NOERROR;
e7ef99a7 691 Answer->val_len = sizeof(snint);
2094fc54 692 Answer->val.integer = memAllocate(MEM_SNMP_SNINT);
e7ef99a7 693 Answer->type = SMI_COUNTER32;
694
135171fe 695 switch (Var->name[LEN_SQ_NET + 1]) {
e7ef99a7 696 case FQDN_ENT:
135171fe 697 *(Answer->val.integer) = memInUse(MEM_FQDNCACHE_ENTRY);
698 Answer->type = SMI_GAUGE32;
699 break;
e7ef99a7 700 case FQDN_REQ:
135171fe 701 *(Answer->val.integer) = FqdncacheStats.requests;
702 break;
e7ef99a7 703 case FQDN_HITS:
135171fe 704 *(Answer->val.integer) = FqdncacheStats.hits;
705 break;
e7ef99a7 706 case FQDN_PENDHIT:
135171fe 707 *(Answer->val.integer) = FqdncacheStats.pending_hits;
708 Answer->type = SMI_GAUGE32;
709 break;
e7ef99a7 710 case FQDN_NEGHIT:
135171fe 711 *(Answer->val.integer) = FqdncacheStats.negative_hits;
712 break;
e7ef99a7 713 case FQDN_MISS:
135171fe 714 *(Answer->val.integer) = FqdncacheStats.misses;
715 break;
e7ef99a7 716 case FQDN_GHBN:
135171fe 717 *(Answer->val.integer) = FqdncacheStats.ghba_calls;
718 break;
ce75f381 719 default:
135171fe 720 *ErrP = SNMP_ERR_NOSUCHNAME;
721 snmp_var_free(Answer);
722 return (NULL);
86115da5 723 }
724 return Answer;
ce75f381 725}
e7ef99a7 726
135171fe 727#endif /*SQUID_SNMP */