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