]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ipcache.cc
2.1 branch merge
[thirdparty/squid.git] / src / ipcache.cc
CommitLineData
7921dbc5 1
30a4f2a8 2/*
c68e9c6b 3 * $Id: ipcache.cc,v 1.206 1998/11/12 06:28:13 wessels Exp $
30a4f2a8 4 *
5 * DEBUG: section 14 IP Cache
6 * AUTHOR: Harvest Derived
7 *
42c04c16 8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
e25c139f 13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * Duane Wessels and the University of California San Diego. Please
16 * see the COPYRIGHT file for full details. Squid incorporates
17 * software developed and/or copyrighted by other sources. Please see
18 * the CREDITS file for full details.
30a4f2a8 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
019dd986 34 */
44a47c6e 35
36#include "squid.h"
37
30a4f2a8 38static struct {
39 int requests;
f88bb09c 40 int replies;
30a4f2a8 41 int hits;
42 int misses;
43 int pending_hits;
44 int negative_hits;
30a4f2a8 45 int errors;
30a4f2a8 46 int ghbn_calls; /* # calls to blocking gethostbyname() */
429fdbec 47 int release_locked;
30a4f2a8 48} IpcacheStats;
090089c4 49
ce75f381 50static dlink_list lru_list;
7b04dad5 51
74addf6c 52static FREE ipcacheFreeEntry;
53static HLPCB ipcacheHandleReply;
54static IPH dummy_handler;
55static int ipcacheExpiredEntry(ipcache_entry *);
f5b8bbc4 56static int ipcache_testname(void);
f5b8bbc4 57static ipcache_entry *ipcacheAddNew(const char *, const struct hostent *, ipcache_status_t);
74addf6c 58static ipcache_entry *ipcacheParse(const char *buf);
59static ipcache_entry *ipcache_create(const char *name);
f5b8bbc4 60static ipcache_entry *ipcache_get(const char *);
74addf6c 61static void ipcacheAddHostent(ipcache_entry *, const struct hostent *);
f5b8bbc4 62static void ipcacheAddPending(ipcache_entry *, IPH *, void *);
74addf6c 63static void ipcacheChangeKey(ipcache_entry * i);
64static void ipcacheLockEntry(ipcache_entry *);
f5b8bbc4 65static void ipcacheStatPrint(ipcache_entry *, StoreEntry *);
66static void ipcacheUnlockEntry(ipcache_entry *);
74addf6c 67static void ipcache_call_pending(ipcache_entry *);
68static void ipcache_release(ipcache_entry *);
30a4f2a8 69
e5f6c5c2 70static ipcache_addrs static_addrs;
365e5b34 71static hash_table *ip_table = NULL;
090089c4 72
30a4f2a8 73static char ipcache_status_char[] =
090089c4 74{
30a4f2a8 75 'C',
76 'N',
77 'P',
78 'D'
79};
090089c4 80
24382924 81static long ipcache_low = 180;
82static long ipcache_high = 200;
f88bb09c 83
c021888f 84#if LIBRESOLV_DNS_TTL_HACK
85extern int _dns_ttl_;
86#endif
87
b8d8561b 88static int
0673c0ba 89ipcache_testname(void)
090089c4 90{
b09ad9fd 91 wordlist *w = NULL;
a3d5953d 92 debug(14, 1) ("Performing DNS Tests...\n");
b6f794d6 93 if ((w = Config.dns_testname_list) == NULL)
b09ad9fd 94 return 1;
95 for (; w; w = w->next) {
30a4f2a8 96 IpcacheStats.ghbn_calls++;
b09ad9fd 97 if (gethostbyname(w->key) != NULL)
98 return 1;
090089c4 99 }
b09ad9fd 100 return 0;
090089c4 101}
102
090089c4 103/* removes the given ipcache entry */
b8d8561b 104static void
105ipcache_release(ipcache_entry * i)
090089c4 106{
30a4f2a8 107 hash_link *table_entry = NULL;
2b19063a 108 if ((table_entry = hash_lookup(ip_table, i->name)) == NULL) {
109 snprintf(tmp_error_buf, ERROR_BUF_SZ, "ipcache_release: key '%s' not found\n", i->name);
110 fatal_dump(tmp_error_buf);
111 }
365e5b34 112 assert(i == (ipcache_entry *) table_entry);
429fdbec 113 if (i->locks) {
114 i->expires = squid_curtime;
edeb28fd 115 ipcacheChangeKey(i);
429fdbec 116 IpcacheStats.release_locked++;
30a4f2a8 117 return;
090089c4 118 }
3fda0827 119 hash_remove_link(ip_table, table_entry);
7b04dad5 120 dlinkDelete(&i->lru, &lru_list);
f7a5493b 121 if (i->status == IP_CACHED) {
e5f6c5c2 122 safe_free(i->addrs.in_addrs);
22c653cd 123 safe_free(i->addrs.bad_mask);
a3d5953d 124 debug(14, 5) ("ipcache_release: Released IP cached record for '%s'.\n",
f7a5493b 125 i->name);
30a4f2a8 126 }
f7a5493b 127 safe_free(i->name);
128 safe_free(i->error_message);
59c4d35b 129 memFree(MEM_IPCACHE_ENTRY, i);
30a4f2a8 130 return;
090089c4 131}
132
b8d8561b 133static ipcache_entry *
0ee4272b 134ipcache_get(const char *name)
090089c4 135{
7b04dad5 136 assert(ip_table != NULL);
137 return (ipcache_entry *) hash_lookup(ip_table, name);
090089c4 138}
139
b8d8561b 140static int
141ipcacheExpiredEntry(ipcache_entry * i)
30a4f2a8 142{
30a4f2a8 143 if (i->status == IP_PENDING)
144 return 0;
145 if (i->status == IP_DISPATCHED)
146 return 0;
620da955 147 if (i->locks != 0)
148 return 0;
7c63efed 149 if (i->addrs.count == 0)
150 return 1;
af00901c 151 if (i->expires > squid_curtime)
30a4f2a8 152 return 0;
153 return 1;
154}
090089c4 155
7b04dad5 156void
157ipcache_purgelru(void *voidnotused)
158{
159 dlink_node *m;
160 dlink_node *prev = NULL;
161 ipcache_entry *i;
162 int removed = 0;
52040193 163 eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
7b04dad5 164 for (m = lru_list.tail; m; m = prev) {
59c4d35b 165 if (memInUse(MEM_IPCACHE_ENTRY) < ipcache_low)
7b04dad5 166 break;
167 prev = m->prev;
168 i = m->data;
169 if (i->status == IP_PENDING)
170 continue;
171 if (i->status == IP_DISPATCHED)
172 continue;
173 if (i->locks != 0)
174 continue;
175 ipcache_release(i);
176 removed++;
177 }
178 debug(14, 3) ("ipcache_purgelru: removed %d entries\n", removed);
179}
180
090089c4 181/* create blank ipcache_entry */
b8d8561b 182static ipcache_entry *
0ee4272b 183ipcache_create(const char *name)
090089c4 184{
7b04dad5 185 static ipcache_entry *i;
59c4d35b 186 i = memAllocate(MEM_IPCACHE_ENTRY);
7b04dad5 187 i->name = xstrdup(name);
188 i->expires = squid_curtime + Config.negativeDnsTtl;
189 hash_join(ip_table, (hash_link *) i);
190 dlinkAdd(i, &i->lru, &lru_list);
191 return i;
090089c4 192}
193
b8d8561b 194static void
0ee4272b 195ipcacheAddHostent(ipcache_entry * i, const struct hostent *hp)
090089c4 196{
f6c78bd2 197 int addr_count = 0;
198 int k;
199 safe_free(i->addrs.in_addrs);
22c653cd 200 safe_free(i->addrs.bad_mask);
f6c78bd2 201 while ((addr_count < 255) && *(hp->h_addr_list + addr_count))
202 ++addr_count;
203 i->addrs.count = (unsigned char) addr_count;
204 i->addrs.in_addrs = xcalloc(addr_count, sizeof(struct in_addr));
22c653cd 205 i->addrs.bad_mask = xcalloc(addr_count, sizeof(unsigned char));
206 i->addrs.badcount = 0;
f6c78bd2 207 for (k = 0; k < addr_count; k++)
3c0117c9 208 xmemcpy(&i->addrs.in_addrs[k].s_addr,
f6c78bd2 209 *(hp->h_addr_list + k),
210 hp->h_length);
dd7ad0a4 211}
090089c4 212
dd7ad0a4 213static ipcache_entry *
0ee4272b 214ipcacheAddNew(const char *name, const struct hostent *hp, ipcache_status_t status)
dd7ad0a4 215{
216 ipcache_entry *i;
30a4f2a8 217 if (ipcache_get(name))
c4170f1b 218 fatal_dump("ipcacheAddNew: somebody adding a duplicate!");
a3d5953d 219 debug(14, 10) ("ipcacheAddNew: Adding '%s', status=%c\n",
dd7ad0a4 220 name,
221 ipcache_status_char[status]);
222 i = ipcache_create(name);
223 if (hp)
224 ipcacheAddHostent(i, hp);
225 i->status = status;
226 i->lastref = squid_curtime;
227 return i;
090089c4 228}
229
090089c4 230/* walks down the pending list, calling handlers */
b8d8561b 231static void
232ipcache_call_pending(ipcache_entry * i)
090089c4 233{
59c4d35b 234 ip_pending *p = NULL;
090089c4 235 int nhandler = 0;
30a4f2a8 236 i->lastref = squid_curtime;
620da955 237 ipcacheLockEntry(i);
30a4f2a8 238 while (i->pending_head != NULL) {
365e5b34 239 p = i->pending_head;
240 i->pending_head = p->next;
241 if (p->handler) {
242 nhandler++;
243 dns_error_message = i->error_message;
244 if (cbdataValid(p->handlerData)) {
245 p->handler(i->status == IP_CACHED ? &i->addrs : NULL,
246 p->handlerData);
8407afee 247 }
365e5b34 248 cbdataUnlock(p->handlerData);
249 }
59c4d35b 250 memFree(MEM_IPCACHE_PENDING, p);
090089c4 251 }
365e5b34 252 i->pending_head = NULL; /* nuke list */
a3d5953d 253 debug(14, 10) ("ipcache_call_pending: Called %d handlers.\n", nhandler);
620da955 254 ipcacheUnlockEntry(i);
090089c4 255}
256
b8d8561b 257static ipcache_entry *
74addf6c 258ipcacheParse(const char *inbuf)
090089c4 259{
bd34f258 260 LOCAL_ARRAY(char, buf, DNS_INBUF_SZ);
d5a266cb 261 char *token;
262 static ipcache_entry i;
bd34f258 263 int j;
d5a266cb 264 int k;
bd34f258 265 int ipcount = 0;
266 int ttl;
267 char A[32][16];
bd34f258 268 memset(&i, '\0', sizeof(i));
269 i.expires = squid_curtime;
270 i.status = IP_NEGATIVE_CACHED;
c68e9c6b 271 if (inbuf == NULL) {
272 debug(14, 1) ("ipcacheParse: Got <NULL> reply\n");
273 return &i;
274 }
275 xstrncpy(buf, inbuf, DNS_INBUF_SZ);
276 debug(14, 5) ("ipcacheParse: parsing:%s\n", buf);
bd34f258 277 token = strtok(buf, w_space);
278 if (NULL == token) {
279 debug(14, 1) ("ipcacheParse: Got <NULL>, expecting '$addr'\n");
280 return &i;
281 }
282 if (0 == strcmp(token, "$fail")) {
283 i.expires = squid_curtime + Config.negativeDnsTtl;
284 token = strtok(NULL, "\n");
285 assert(NULL != token);
286 i.error_message = xstrdup(token);
287 return &i;
288 }
289 if (0 != strcmp(token, "$addr")) {
290 debug(14, 1) ("ipcacheParse: Got '%s', expecting '$addr'\n", token);
291 return &i;
292 }
293 token = strtok(NULL, w_space);
294 if (NULL == token) {
295 debug(14, 1) ("ipcacheParse: Got <NULL>, expecting TTL\n");
296 return &i;
297 }
298 i.status = IP_CACHED;
299 ttl = atoi(token);
300 if (ttl > 0)
301 i.expires = squid_curtime + ttl;
302 else
303 i.expires = squid_curtime + Config.positiveDnsTtl;
304 while (NULL != (token = strtok(NULL, w_space))) {
305 xstrncpy(A[ipcount], token, 16);
306 if (++ipcount == 32)
090089c4 307 break;
090089c4 308 }
bd34f258 309 if (0 == ipcount) {
310 i.addrs.in_addrs = NULL;
311 i.addrs.bad_mask = NULL;
312 } else {
313 i.addrs.in_addrs = xcalloc(ipcount, sizeof(struct in_addr));
314 i.addrs.bad_mask = xcalloc(ipcount, sizeof(unsigned char));
315 }
316 for (j = 0, k = 0; k < ipcount; k++) {
317 if (safe_inet_addr(A[k], &i.addrs.in_addrs[j]))
318 j++;
319 else
320 debug(14, 1) ("ipcacheParse: Invalid IP address '%s'\n", A[k]);
321 }
322 i.addrs.count = (unsigned char) j;
d5a266cb 323 return &i;
090089c4 324}
325
a7e59001 326static void
74addf6c 327ipcacheHandleReply(void *data, char *reply)
090089c4 328{
30a4f2a8 329 int n;
74addf6c 330 generic_cbdata *c = data;
331 ipcache_entry *i = c->data;
d5a266cb 332 ipcache_entry *x = NULL;
e144eae4 333 assert(i->status == IP_DISPATCHED);
74addf6c 334 assert(i->locks);
335 cbdataFree(c);
336 c = NULL;
337 n = ++IpcacheStats.replies;
338 statHistCount(&Counter.dns.svc_time, tvSubMsec(i->request_time, current_time));
c68e9c6b 339 x = ipcacheParse(reply);
340 assert(x);
341 i->status = x->status;
342 i->addrs = x->addrs;
343 i->error_message = x->error_message;
344 i->expires = x->expires;
345 ipcache_call_pending(i);
74addf6c 346 ipcacheUnlockEntry(i); /* unlock from IP_DISPATCHED */
090089c4 347}
348
b8d8561b 349static void
8407afee 350ipcacheAddPending(ipcache_entry * i, IPH * handler, void *handlerData)
30a4f2a8 351{
59c4d35b 352 ip_pending *pending = memAllocate(MEM_IPCACHE_PENDING);
353 ip_pending **I = NULL;
af00901c 354 i->lastref = squid_curtime;
30a4f2a8 355 pending->handler = handler;
8407afee 356 pending->handlerData = handlerData;
357 cbdataLock(handlerData);
30a4f2a8 358 for (I = &(i->pending_head); *I; I = &((*I)->next));
359 *I = pending;
360}
361
b8d8561b 362void
8407afee 363ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
090089c4 364{
30a4f2a8 365 ipcache_entry *i = NULL;
429fdbec 366 const ipcache_addrs *addrs = NULL;
74addf6c 367 generic_cbdata *c;
605bd345 368 assert(handler != NULL);
03a1ee42 369 debug(14, 4) ("ipcache_nbgethostbyname: Name '%s'.\n", name);
30a4f2a8 370 IpcacheStats.requests++;
090089c4 371 if (name == NULL || name[0] == '\0') {
a3d5953d 372 debug(14, 4) ("ipcache_nbgethostbyname: Invalid name!\n");
03a1ee42 373 handler(NULL, handlerData);
af00901c 374 return;
375 }
e5f6c5c2 376 if ((addrs = ipcacheCheckNumeric(name))) {
03a1ee42 377 handler(addrs, handlerData);
af00901c 378 return;
090089c4 379 }
30a4f2a8 380 if ((i = ipcache_get(name))) {
381 if (ipcacheExpiredEntry(i)) {
382 ipcache_release(i);
383 i = NULL;
090089c4 384 }
090089c4 385 }
30a4f2a8 386 if (i == NULL) {
387 /* MISS: No entry, create the new one */
a3d5953d 388 debug(14, 5) ("ipcache_nbgethostbyname: MISS for '%s'\n", name);
30a4f2a8 389 IpcacheStats.misses++;
dd7ad0a4 390 i = ipcacheAddNew(name, NULL, IP_PENDING);
8407afee 391 ipcacheAddPending(i, handler, handlerData);
b87b92fb 392 i->request_time = current_time;
30a4f2a8 393 } else if (i->status == IP_CACHED || i->status == IP_NEGATIVE_CACHED) {
394 /* HIT */
a3d5953d 395 debug(14, 4) ("ipcache_nbgethostbyname: HIT for '%s'\n", name);
30a4f2a8 396 if (i->status == IP_NEGATIVE_CACHED)
397 IpcacheStats.negative_hits++;
398 else
399 IpcacheStats.hits++;
8407afee 400 ipcacheAddPending(i, handler, handlerData);
30a4f2a8 401 ipcache_call_pending(i);
af00901c 402 return;
30a4f2a8 403 } else if (i->status == IP_PENDING || i->status == IP_DISPATCHED) {
a3d5953d 404 debug(14, 4) ("ipcache_nbgethostbyname: PENDING for '%s'\n", name);
30a4f2a8 405 IpcacheStats.pending_hits++;
8407afee 406 ipcacheAddPending(i, handler, handlerData);
7921dbc5 407 if (squid_curtime - i->expires > 600) {
5f6ac48b 408 debug(14, 0) ("ipcache_nbgethostbyname: '%s' PENDING for %d seconds, aborting\n", name, (int) (squid_curtime + Config.negativeDnsTtl - i->expires));
94af2e39 409 ipcacheChangeKey(i);
7921dbc5 410 ipcache_call_pending(i);
12001d13 411 }
af00901c 412 return;
30a4f2a8 413 } else {
414 fatal_dump("ipcache_nbgethostbyname: BAD ipcache_entry status");
090089c4 415 }
74addf6c 416 /* for HIT, PENDING, DISPATCHED we've returned. For MISS we submit */
417 c = xcalloc(1, sizeof(*c));
418 c->data = i;
419 cbdataAdd(c, MEM_NONE);
620da955 420 i->status = IP_DISPATCHED;
74addf6c 421 ipcacheLockEntry(i);
422 dnsSubmit(i->name, ipcacheHandleReply, c);
090089c4 423}
424
0ffd22bc 425/* initialize the ipcache */
b8d8561b 426void
0673c0ba 427ipcache_init(void)
0ffd22bc 428{
aa9e2cab 429 int n;
a3d5953d 430 debug(14, 3) ("Initializing IP Cache...\n");
30a4f2a8 431 memset(&IpcacheStats, '\0', sizeof(IpcacheStats));
3eb55834 432 memset(&lru_list, '\0', sizeof(lru_list));
0ffd22bc 433 /* test naming lookup */
30a4f2a8 434 if (!opt_dns_tests) {
a3d5953d 435 debug(14, 4) ("ipcache_init: Skipping DNS name lookup tests.\n");
b09ad9fd 436 } else if (!ipcache_testname()) {
1d73e33a 437 fatal("ipcache_init: DNS name lookup tests failed.");
0ffd22bc 438 } else {
a3d5953d 439 debug(14, 1) ("Successful DNS name lookup tests...\n");
0ffd22bc 440 }
e5f6c5c2 441 memset(&static_addrs, '\0', sizeof(ipcache_addrs));
442 static_addrs.in_addrs = xcalloc(1, sizeof(struct in_addr));
22c653cd 443 static_addrs.bad_mask = xcalloc(1, sizeof(unsigned char));
b15e6857 444 ipcache_high = (long) (((float) Config.ipcache.size *
445 (float) Config.ipcache.high) / (float) 100);
446 ipcache_low = (long) (((float) Config.ipcache.size *
447 (float) Config.ipcache.low) / (float) 100);
aa9e2cab 448 n = hashPrime(ipcache_high / 4);
6a78c18e 449 ip_table = hash_create((HASHCMP *) strcmp, n, hash4);
22f3fd98 450 cachemgrRegister("ipcache",
451 "IP Cache Stats and Contents",
1da3b90b 452 stat_ipcache_get, 0, 1);
090089c4 453}
454
8407afee 455int
456ipcacheUnregister(const char *name, void *data)
090089c4 457{
8407afee 458 ipcache_entry *i = NULL;
59c4d35b 459 ip_pending *p = NULL;
8407afee 460 int n = 0;
2302bc23 461 debug(14, 3) ("ipcacheUnregister: name '%s'\n", name);
8407afee 462 if ((i = ipcache_get(name)) == NULL)
365e5b34 463 return 0;
8407afee 464 if (i->status == IP_PENDING || i->status == IP_DISPATCHED) {
365e5b34 465 for (p = i->pending_head; p; p = p->next) {
466 if (p->handlerData != data)
467 continue;
468 p->handler = NULL;
469 n++;
470 }
8407afee 471 }
f889842a 472 assert(n > 0);
8407afee 473 debug(14, 3) ("ipcacheUnregister: unregistered %d handlers\n", n);
474 return n;
090089c4 475}
476
0ee4272b 477const ipcache_addrs *
478ipcache_gethostbyname(const char *name, int flags)
090089c4 479{
30a4f2a8 480 ipcache_entry *i = NULL;
e5f6c5c2 481 ipcache_addrs *addrs;
30a4f2a8 482 if (!name)
483 fatal_dump("ipcache_gethostbyname: NULL name");
a3d5953d 484 debug(14, 3) ("ipcache_gethostbyname: '%s', flags=%x\n", name, flags);
30a4f2a8 485 IpcacheStats.requests++;
486 if ((i = ipcache_get(name))) {
af00901c 487 if (ipcacheExpiredEntry(i)) {
488 ipcache_release(i);
489 i = NULL;
490 }
491 }
492 if (i) {
7c63efed 493 if (i->status == IP_NEGATIVE_CACHED) {
30a4f2a8 494 IpcacheStats.negative_hits++;
495 dns_error_message = i->error_message;
496 return NULL;
8a8d4042 497 } else if (i->addrs.count == 0) {
498 (void) 0;
090089c4 499 } else {
30a4f2a8 500 IpcacheStats.hits++;
501 i->lastref = squid_curtime;
e5f6c5c2 502 return &i->addrs;
090089c4 503 }
30a4f2a8 504 }
e5f6c5c2 505 if ((addrs = ipcacheCheckNumeric(name)))
506 return addrs;
e61d864a 507 IpcacheStats.misses++;
30a4f2a8 508 if (flags & IP_LOOKUP_IF_MISS)
8407afee 509 ipcache_nbgethostbyname(name, dummy_handler, NULL);
30a4f2a8 510 return NULL;
090089c4 511}
512
b8d8561b 513static void
514ipcacheStatPrint(ipcache_entry * i, StoreEntry * sentry)
af00901c 515{
516 int k;
15576b6a 517 storeAppendPrintf(sentry, " %-32.32s %c%c %6d %6d %2d(%2d)",
af00901c 518 i->name,
519 ipcache_status_char[i->status],
233794cd 520 i->locks ? 'L' : ' ',
af00901c 521 (int) (squid_curtime - i->lastref),
522 (int) (i->expires - squid_curtime),
22c653cd 523 (int) i->addrs.count,
524 (int) i->addrs.badcount);
52926044 525 for (k = 0; k < (int) i->addrs.count; k++) {
22c653cd 526 storeAppendPrintf(sentry, " %15s-%3s", inet_ntoa(i->addrs.in_addrs[k]),
527 i->addrs.bad_mask[k] ? "BAD" : "OK ");
52926044 528 }
9973e9fe 529 storeAppendPrintf(sentry, "\n");
af00901c 530}
090089c4 531
090089c4 532/* process objects list */
b8d8561b 533void
534stat_ipcache_get(StoreEntry * sentry)
090089c4 535{
7b04dad5 536 dlink_node *m;
537 assert(ip_table != NULL);
15576b6a 538 storeAppendPrintf(sentry, "IP Cache Statistics:\n");
539 storeAppendPrintf(sentry, "IPcache Entries: %d\n",
59c4d35b 540 memInUse(MEM_IPCACHE_ENTRY));
15576b6a 541 storeAppendPrintf(sentry, "IPcache Requests: %d\n",
30a4f2a8 542 IpcacheStats.requests);
15576b6a 543 storeAppendPrintf(sentry, "IPcache Hits: %d\n",
30a4f2a8 544 IpcacheStats.hits);
15576b6a 545 storeAppendPrintf(sentry, "IPcache Pending Hits: %d\n",
30a4f2a8 546 IpcacheStats.pending_hits);
15576b6a 547 storeAppendPrintf(sentry, "IPcache Negative Hits: %d\n",
30a4f2a8 548 IpcacheStats.negative_hits);
15576b6a 549 storeAppendPrintf(sentry, "IPcache Misses: %d\n",
30a4f2a8 550 IpcacheStats.misses);
15576b6a 551 storeAppendPrintf(sentry, "Blocking calls to gethostbyname(): %d\n",
30a4f2a8 552 IpcacheStats.ghbn_calls);
15576b6a 553 storeAppendPrintf(sentry, "Attempts to release locked entries: %d\n",
429fdbec 554 IpcacheStats.release_locked);
15576b6a 555 storeAppendPrintf(sentry, "\n\n");
556 storeAppendPrintf(sentry, "IP Cache Contents:\n\n");
557 storeAppendPrintf(sentry, " %-29.29s %5s %6s %6s %1s\n",
af00901c 558 "Hostname",
559 "Flags",
560 "lstref",
561 "TTL",
562 "N");
7b04dad5 563 for (m = lru_list.head; m; m = m->next)
564 ipcacheStatPrint(m->data, sentry);
090089c4 565}
4d64d74a 566
caebbe00 567static void
79d39a72 568dummy_handler(const ipcache_addrs * addrsnotused, void *datanotused)
30a4f2a8 569{
caebbe00 570 return;
30a4f2a8 571}
572
b8d8561b 573void
0ee4272b 574ipcacheReleaseInvalid(const char *name)
877ed73e 575{
576 ipcache_entry *i;
55906d8e 577 if (NULL == name) {
578 debug(14, 1) ("ipcacheReleaseInvalid: NULL name\n");
579 return;
580 }
581 if (0 == strlen(name)) {
582 debug(14, 1) ("ipcacheReleaseInvalid: Empty name\n");
583 return;
584 }
877ed73e 585 if ((i = ipcache_get(name)) == NULL)
586 return;
587 if (i->status != IP_NEGATIVE_CACHED)
588 return;
589 ipcache_release(i);
590}
f900607e 591
b8d8561b 592void
0ee4272b 593ipcacheInvalidate(const char *name)
f900607e 594{
595 ipcache_entry *i;
596 if ((i = ipcache_get(name)) == NULL)
597 return;
6c11e193 598 i->expires = squid_curtime;
599 /* NOTE, don't call ipcache_release here becuase we might be here due
600 * to a thread started from ipcache_call_pending() which will cause a
601 * FMR */
f900607e 602}
af00901c 603
4d650936 604ipcache_addrs *
0ee4272b 605ipcacheCheckNumeric(const char *name)
af00901c 606{
429fdbec 607 struct in_addr ip;
af00901c 608 /* check if it's already a IP address in text form. */
429fdbec 609 if (!safe_inet_addr(name, &ip))
af00901c 610 return NULL;
e5f6c5c2 611 static_addrs.count = 1;
612 static_addrs.cur = 0;
429fdbec 613 static_addrs.in_addrs[0].s_addr = ip.s_addr;
22c653cd 614 static_addrs.bad_mask[0] = FALSE;
615 static_addrs.badcount = 0;
e5f6c5c2 616 return &static_addrs;
af00901c 617}
8905d949 618
b8d8561b 619static void
620ipcacheLockEntry(ipcache_entry * i)
620da955 621{
7b04dad5 622 if (i->locks++ == 0) {
623 dlinkDelete(&i->lru, &lru_list);
624 dlinkAdd(i, &i->lru, &lru_list);
625 }
620da955 626}
627
b8d8561b 628static void
629ipcacheUnlockEntry(ipcache_entry * i)
620da955 630{
f889842a 631 assert(i->locks > 0);
620da955 632 i->locks--;
633 if (ipcacheExpiredEntry(i))
634 ipcache_release(i);
635}
e5f6c5c2 636
52926044 637void
4b4cd312 638ipcacheCycleAddr(const char *name, ipcache_addrs * ia)
52926044 639{
640 ipcache_entry *i;
641 unsigned char k;
642 assert(name || ia);
643 if (NULL == ia) {
4b4cd312 644 if ((i = ipcache_get(name)) == NULL)
52926044 645 return;
4b4cd312 646 if (i->status != IP_CACHED)
52926044 647 return;
4b4cd312 648 ia = &i->addrs;
52926044 649 }
650 for (k = 0; k < ia->count; k++) {
651 if (++ia->cur == ia->count)
652 ia->cur = 0;
653 if (!ia->bad_mask[ia->cur])
654 break;;
655 }
656 if (k == ia->count) {
4b4cd312 657 /* All bad, reset to All good */
658 debug(14, 3) ("ipcacheCycleAddr: Changing ALL %s addrs from BAD to OK\n",
52926044 659 name);
4b4cd312 660 for (k = 0; k < ia->count; k++)
52926044 661 ia->bad_mask[k] = 0;
4b4cd312 662 ia->badcount = 0;
663 ia->cur = 0;
52926044 664 }
4b4cd312 665 debug(14, 3) ("ipcacheCycleAddr: %s now at %s\n", name,
52926044 666 inet_ntoa(ia->in_addrs[ia->cur]));
667}
e5f6c5c2 668
52926044 669/*
670 * Marks the given address as BAD and calls ipcacheCycleAddr to
671 * advance the current pointer to the next OK address.
22c653cd 672 */
e5f6c5c2 673void
22c653cd 674ipcacheMarkBadAddr(const char *name, struct in_addr addr)
e5f6c5c2 675{
676 ipcache_entry *i;
677 ipcache_addrs *ia;
678 int k;
679 if ((i = ipcache_get(name)) == NULL)
680 return;
681 ia = &i->addrs;
682 for (k = 0; k < (int) ia->count; k++) {
683 if (ia->in_addrs[k].s_addr == addr.s_addr)
684 break;
685 }
52926044 686 if (k == (int) ia->count) /* not found */
e5f6c5c2 687 return;
22c653cd 688 if (!ia->bad_mask[k]) {
689 ia->bad_mask[k] = TRUE;
690 ia->badcount++;
52926044 691 debug(14, 2) ("ipcacheMarkBadAddr: %s [%s]\n", name, inet_ntoa(addr));
22c653cd 692 }
52926044 693 ipcacheCycleAddr(name, ia);
e5f6c5c2 694}
56e15c50 695
22c653cd 696void
697ipcacheMarkGoodAddr(const char *name, struct in_addr addr)
698{
699 ipcache_entry *i;
700 ipcache_addrs *ia;
701 int k;
702 if ((i = ipcache_get(name)) == NULL)
703 return;
704 ia = &i->addrs;
705 for (k = 0; k < (int) ia->count; k++) {
706 if (ia->in_addrs[k].s_addr == addr.s_addr)
707 break;
708 }
52926044 709 if (k == (int) ia->count) /* not found */
22c653cd 710 return;
52926044 711 if (!ia->bad_mask[k]) /* already OK */
712 return;
713 ia->bad_mask[k] = FALSE;
714 ia->badcount--;
715 debug(14, 2) ("ipcacheMarkGoodAddr: %s [%s]\n", name, inet_ntoa(addr));
22c653cd 716}
717
ec878047 718static void
719ipcacheFreeEntry(void *data)
720{
721 ipcache_entry *i = data;
0e1a4726 722 ip_pending *p;
723 while ((p = i->pending_head)) {
724 i->pending_head = p->next;
725 memFree(MEM_IPCACHE_PENDING, p);
726 }
ec878047 727 safe_free(i->addrs.in_addrs);
728 safe_free(i->addrs.bad_mask);
729 safe_free(i->name);
730 safe_free(i->error_message);
731 memFree(MEM_IPCACHE_ENTRY, i);
732}
733
56e15c50 734void
735ipcacheFreeMemory(void)
736{
ec878047 737 hashFreeItems(ip_table, ipcacheFreeEntry);
56e15c50 738 hashFreeMemory(ip_table);
afe95a7e 739 ip_table = NULL;
56e15c50 740}
3fb036e8 741
742static void
743ipcacheChangeKey(ipcache_entry * i)
744{
745 static int index = 0;
746 LOCAL_ARRAY(char, new_key, 256);
747 hash_link *table_entry = hash_lookup(ip_table, i->name);
748 if (table_entry == NULL) {
a3d5953d 749 debug(14, 0) ("ipcacheChangeKey: Could not find key '%s'\n", i->name);
3fb036e8 750 return;
751 }
693e7ec9 752 assert(i == (ipcache_entry *) table_entry);
3fda0827 753 hash_remove_link(ip_table, table_entry);
137ee196 754 snprintf(new_key, 256, "%d/%s", ++index, i->name);
a3d5953d 755 debug(14, 1) ("ipcacheChangeKey: from '%s' to '%s'\n", i->name, new_key);
3fb036e8 756 safe_free(i->name);
757 i->name = xstrdup(new_key);
7b04dad5 758 hash_join(ip_table, (hash_link *) i);
3fb036e8 759}
429fdbec 760
761/* call during reconfigure phase to clear out all the
762 * pending and dispatched reqeusts that got lost */
763void
764ipcache_restart(void)
765{
766 ipcache_entry *this;
76a5501f 767 assert(ip_table != NULL);
0f6bebac 768 hash_first(ip_table);
769 while ((this = (ipcache_entry *) hash_next(ip_table))) {
429fdbec 770 if (this->status == IP_CACHED)
771 continue;
772 if (this->status == IP_NEGATIVE_CACHED)
773 continue;
429fdbec 774 }
775 /* recalculate these while we're at it */
776 ipcache_high = (long) (((float) Config.ipcache.size *
777 (float) Config.ipcache.high) / (float) 100);
778 ipcache_low = (long) (((float) Config.ipcache.size *
779 (float) Config.ipcache.low) / (float) 100);
780}
ce75f381 781
782#ifdef SQUID_SNMP
1f5b542b 783/*
135171fe 784 * The function to return the ip cache statistics to via SNMP
785 */
164f7660 786
86115da5 787variable_list *
1f5b542b 788snmp_netIpFn(variable_list * Var, snint * ErrP)
d60c11be 789{
86115da5 790 variable_list *Answer;
86115da5 791
1f5b542b 792 debug(49, 5) ("snmp_netIpFn: Processing request:\n", Var->name[LEN_SQ_NET + 1]);
793 snmpDebugOid(5, Var->name, Var->name_length);
86115da5 794
86115da5 795 Answer = snmp_var_new(Var->name, Var->name_length);
796 *ErrP = SNMP_ERR_NOERROR;
c6da280c 797 Answer->val_len = sizeof(snint);
451b07c5 798 Answer->val.integer = xmalloc(Answer->val_len);
1f5b542b 799 Answer->type = SMI_COUNTER32;
800
135171fe 801 switch (Var->name[LEN_SQ_NET + 1]) {
1f5b542b 802 case IP_ENT:
803 *(Answer->val.integer) = memInUse(MEM_IPCACHE_ENTRY);
804 Answer->type = SMI_GAUGE32;
135171fe 805 break;
1f5b542b 806 case IP_REQ:
807 *(Answer->val.integer) = IpcacheStats.requests;
135171fe 808 break;
1f5b542b 809 case IP_HITS:
810 *(Answer->val.integer) = IpcacheStats.hits;
135171fe 811 break;
1f5b542b 812 case IP_PENDHIT:
813 *(Answer->val.integer) = IpcacheStats.pending_hits;
814 Answer->type = SMI_GAUGE32;
135171fe 815 break;
1f5b542b 816 case IP_NEGHIT:
817 *(Answer->val.integer) = IpcacheStats.negative_hits;
135171fe 818 break;
1f5b542b 819 case IP_MISS:
820 *(Answer->val.integer) = IpcacheStats.misses;
135171fe 821 break;
1f5b542b 822 case IP_GHBN:
823 *(Answer->val.integer) = IpcacheStats.ghbn_calls;
135171fe 824 break;
1f5b542b 825 case IP_LOC:
826 *(Answer->val.integer) = IpcacheStats.release_locked;
135171fe 827 break;
74addf6c 828#if DELETE_ME
1f5b542b 829 case IP_LENG:
830 *(Answer->val.integer) = queue_length;
831 Answer->type = SMI_GAUGE32;
135171fe 832 break;
74addf6c 833#endif
ce75f381 834 default:
135171fe 835 *ErrP = SNMP_ERR_NOSUCHNAME;
836 snmp_var_free(Answer);
837 return (NULL);
86115da5 838 }
839 return Answer;
ce75f381 840}
1f5b542b 841
135171fe 842#endif /*SQUID_SNMP */