~clint-fewbar/ubuntu/precise/squid3/ignore-sighup-early

« back to all changes in this revision

Viewing changes to src/fqdncache.cc

  • Committer: Bazaar Package Importer
  • Author(s): Luigi Gangitano
  • Date: 2006-11-11 10:32:06 UTC
  • Revision ID: james.westby@ubuntu.com-20061111103206-f3p0r9g0vq44rp3r
Tags: upstream-3.0.PRE5
ImportĀ upstreamĀ versionĀ 3.0.PRE5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
 * $Id: fqdncache.cc,v 1.170 2006/08/21 00:50:41 robertc Exp $
 
4
 *
 
5
 * DEBUG: section 35    FQDN Cache
 
6
 * AUTHOR: Harvest Derived
 
7
 *
 
8
 * SQUID Web Proxy Cache          http://www.squid-cache.org/
 
9
 * ----------------------------------------------------------
 
10
 *
 
11
 *  Squid is the result of efforts by numerous individuals from
 
12
 *  the Internet community; see the CONTRIBUTORS file for full
 
13
 *  details.   Many organizations have provided support for Squid's
 
14
 *  development; see the SPONSORS file for full details.  Squid is
 
15
 *  Copyrighted (C) 2001 by the Regents of the University of
 
16
 *  California; see the COPYRIGHT file for full details.  Squid
 
17
 *  incorporates software developed and/or copyrighted by other
 
18
 *  sources; see the CREDITS file for full details.
 
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
 
32
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 
33
 *
 
34
 */
 
35
 
 
36
#include "squid.h"
 
37
#include "cbdata.h"
 
38
#include "event.h"
 
39
#include "CacheManager.h"
 
40
#include "SquidTime.h"
 
41
#include "Store.h"
 
42
#include "wordlist.h"
 
43
 
 
44
#define FQDN_LOW_WATER       90
 
45
#define FQDN_HIGH_WATER      95
 
46
 
 
47
typedef struct _fqdncache_entry fqdncache_entry;
 
48
 
 
49
struct _fqdncache_entry
 
50
{
 
51
    hash_link hash;             /* must be first */
 
52
    time_t lastref;
 
53
    time_t expires;
 
54
    unsigned char name_count;
 
55
    char *names[FQDN_MAX_NAMES + 1];
 
56
    FQDNH *handler;
 
57
    void *handlerData;
 
58
    char *error_message;
 
59
 
 
60
    struct timeval request_time;
 
61
    dlink_node lru;
 
62
    unsigned short locks;
 
63
 
 
64
    struct
 
65
    {
 
66
 
 
67
unsigned int negcached:
 
68
        1;
 
69
 
 
70
unsigned int fromhosts:
 
71
        1;
 
72
    }
 
73
 
 
74
    flags;
 
75
};
 
76
 
 
77
static struct
 
78
{
 
79
    int requests;
 
80
    int replies;
 
81
    int hits;
 
82
    int misses;
 
83
    int negative_hits;
 
84
}
 
85
 
 
86
FqdncacheStats;
 
87
 
 
88
static dlink_list lru_list;
 
89
 
 
90
#if USE_DNSSERVERS
 
91
static HLPCB fqdncacheHandleReply;
 
92
static int fqdncacheParse(fqdncache_entry *, const char *buf);
 
93
#else
 
94
static IDNSCB fqdncacheHandleReply;
 
95
static int fqdncacheParse(fqdncache_entry *, rfc1035_rr *, int, const char *error_message);
 
96
#endif
 
97
static void fqdncacheRelease(fqdncache_entry *);
 
98
static fqdncache_entry *fqdncacheCreateEntry(const char *name);
 
99
static void fqdncacheCallback(fqdncache_entry *);
 
100
static fqdncache_entry *fqdncache_get(const char *);
 
101
static FQDNH dummy_handler;
 
102
static int fqdncacheExpiredEntry(const fqdncache_entry *);
 
103
static void fqdncacheLockEntry(fqdncache_entry * f);
 
104
static void fqdncacheUnlockEntry(fqdncache_entry * f);
 
105
static FREE fqdncacheFreeEntry;
 
106
static void fqdncacheAddEntry(fqdncache_entry * f);
 
107
 
 
108
static hash_table *fqdn_table = NULL;
 
109
 
 
110
static long fqdncache_low = 180;
 
111
static long fqdncache_high = 200;
 
112
 
 
113
/* removes the given fqdncache entry */
 
114
static void
 
115
fqdncacheRelease(fqdncache_entry * f)
 
116
{
 
117
    int k;
 
118
    hash_remove_link(fqdn_table, (hash_link *) f);
 
119
 
 
120
    for (k = 0; k < (int) f->name_count; k++)
 
121
        safe_free(f->names[k]);
 
122
 
 
123
    debug(35, 5) ("fqdncacheRelease: Released FQDN record for '%s'.\n",
 
124
                  hashKeyStr(&f->hash));
 
125
 
 
126
    dlinkDelete(&f->lru, &lru_list);
 
127
 
 
128
    safe_free(f->hash.key);
 
129
 
 
130
    safe_free(f->error_message);
 
131
 
 
132
    memFree(f, MEM_FQDNCACHE_ENTRY);
 
133
}
 
134
 
 
135
/* return match for given name */
 
136
static fqdncache_entry *
 
137
fqdncache_get(const char *name)
 
138
{
 
139
    hash_link *e;
 
140
    static fqdncache_entry *f;
 
141
    f = NULL;
 
142
 
 
143
    if (fqdn_table) {
 
144
        if ((e = (hash_link *)hash_lookup(fqdn_table, name)) != NULL)
 
145
            f = (fqdncache_entry *) e;
 
146
    }
 
147
 
 
148
    return f;
 
149
}
 
150
 
 
151
static int
 
152
fqdncacheExpiredEntry(const fqdncache_entry * f)
 
153
{
 
154
    /* all static entries are locked, so this takes care of them too */
 
155
 
 
156
    if (f->locks != 0)
 
157
        return 0;
 
158
 
 
159
    if (f->expires > squid_curtime)
 
160
        return 0;
 
161
 
 
162
    return 1;
 
163
}
 
164
 
 
165
void
 
166
fqdncache_purgelru(void *notused)
 
167
{
 
168
    dlink_node *m;
 
169
    dlink_node *prev = NULL;
 
170
    fqdncache_entry *f;
 
171
    int removed = 0;
 
172
    eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 10.0, 1);
 
173
 
 
174
    for (m = lru_list.tail; m; m = prev) {
 
175
        if (memInUse(MEM_FQDNCACHE_ENTRY) < fqdncache_low)
 
176
            break;
 
177
 
 
178
        prev = m->prev;
 
179
 
 
180
        f = (fqdncache_entry *)m->data;
 
181
 
 
182
        if (f->locks != 0)
 
183
            continue;
 
184
 
 
185
        fqdncacheRelease(f);
 
186
 
 
187
        removed++;
 
188
    }
 
189
 
 
190
    debug(35, 9) ("fqdncache_purgelru: removed %d entries\n", removed);
 
191
}
 
192
 
 
193
static void
 
194
purge_entries_fromhosts(void)
 
195
{
 
196
    dlink_node *m = lru_list.head;
 
197
    fqdncache_entry *i = NULL;
 
198
    fqdncache_entry *t;
 
199
 
 
200
    while (m) {
 
201
        if (i != NULL) {        /* need to delay deletion */
 
202
            fqdncacheRelease(i);        /* we just override locks */
 
203
            i = NULL;
 
204
        }
 
205
 
 
206
        t = (fqdncache_entry *)m->data;
 
207
 
 
208
        if (t->flags.fromhosts)
 
209
            i = t;
 
210
 
 
211
        m = m->next;
 
212
    }
 
213
 
 
214
    if (i != NULL)
 
215
        fqdncacheRelease(i);
 
216
}
 
217
 
 
218
/* create blank fqdncache_entry */
 
219
static fqdncache_entry *
 
220
fqdncacheCreateEntry(const char *name)
 
221
{
 
222
    static fqdncache_entry *f;
 
223
    f = (fqdncache_entry *)memAllocate(MEM_FQDNCACHE_ENTRY);
 
224
    f->hash.key = xstrdup(name);
 
225
    f->expires = squid_curtime + Config.negativeDnsTtl;
 
226
    return f;
 
227
}
 
228
 
 
229
static void
 
230
fqdncacheAddEntry(fqdncache_entry * f)
 
231
{
 
232
    hash_link *e = (hash_link *)hash_lookup(fqdn_table, f->hash.key);
 
233
 
 
234
    if (NULL != e) {
 
235
        /* avoid colission */
 
236
        fqdncache_entry *q = (fqdncache_entry *) e;
 
237
        fqdncacheRelease(q);
 
238
    }
 
239
 
 
240
    hash_join(fqdn_table, &f->hash);
 
241
    dlinkAdd(f, &f->lru, &lru_list);
 
242
    f->lastref = squid_curtime;
 
243
}
 
244
 
 
245
/* walks down the pending list, calling handlers */
 
246
static void
 
247
fqdncacheCallback(fqdncache_entry * f)
 
248
{
 
249
    FQDNH *callback;
 
250
    void *cbdata;
 
251
    f->lastref = squid_curtime;
 
252
 
 
253
    if (!f->handler)
 
254
        return;
 
255
 
 
256
    fqdncacheLockEntry(f);
 
257
 
 
258
    callback = f->handler;
 
259
 
 
260
    f->handler = NULL;
 
261
 
 
262
    if (cbdataReferenceValidDone(f->handlerData, &cbdata)) {
 
263
        dns_error_message = f->error_message;
 
264
        callback(f->flags.negcached ? NULL : f->names[0], cbdata);
 
265
    }
 
266
 
 
267
    fqdncacheUnlockEntry(f);
 
268
}
 
269
 
 
270
#if USE_DNSSERVERS
 
271
static int
 
272
fqdncacheParse(fqdncache_entry *f, const char *inbuf)
 
273
{
 
274
    LOCAL_ARRAY(char, buf, DNS_INBUF_SZ);
 
275
    char *token;
 
276
    int ttl;
 
277
    const char *name = (const char *)f->hash.key;
 
278
    f->expires = squid_curtime + Config.negativeDnsTtl;
 
279
    f->flags.negcached = 1;
 
280
 
 
281
    if (inbuf == NULL) {
 
282
        debug(35, 1) ("fqdncacheParse: Got <NULL> reply in response to '%s'\n", name);
 
283
        f->error_message = xstrdup("Internal Error");
 
284
        return -1;
 
285
    }
 
286
 
 
287
    xstrncpy(buf, inbuf, DNS_INBUF_SZ);
 
288
    debug(35, 5) ("fqdncacheParse: parsing: {%s}\n", buf);
 
289
    token = strtok(buf, w_space);
 
290
 
 
291
    if (NULL == token) {
 
292
        debug(35, 1) ("fqdncacheParse: Got <NULL>, expecting '$name' in response to '%s'\n", name);
 
293
        f->error_message = xstrdup("Internal Error");
 
294
        return -1;
 
295
    }
 
296
 
 
297
    if (0 == strcmp(token, "$fail")) {
 
298
        token = strtok(NULL, "\n");
 
299
        assert(NULL != token);
 
300
        f->error_message = xstrdup(token);
 
301
        return 0;
 
302
    }
 
303
 
 
304
    if (0 != strcmp(token, "$name")) {
 
305
        debug(35, 1) ("fqdncacheParse: Got '%s', expecting '$name' in response to '%s'\n", inbuf, name);
 
306
        f->error_message = xstrdup("Internal Error");
 
307
        return -1;
 
308
    }
 
309
 
 
310
    token = strtok(NULL, w_space);
 
311
 
 
312
    if (NULL == token) {
 
313
        debug(35, 1) ("fqdncacheParse: Got '%s', expecting TTL in response to '%s'\n", inbuf, name);
 
314
        f->error_message = xstrdup("Internal Error");
 
315
        return -1;
 
316
    }
 
317
 
 
318
    ttl = atoi(token);
 
319
 
 
320
    token = strtok(NULL, w_space);
 
321
 
 
322
    if (NULL == token) {
 
323
        debug(35, 1) ("fqdncacheParse: Got '%s', expecting hostname in response to '%s'\n", inbuf, name);
 
324
        f->error_message = xstrdup("Internal Error");
 
325
        return -1;
 
326
    }
 
327
 
 
328
    f->names[0] = xstrdup(token);
 
329
    f->name_count = 1;
 
330
 
 
331
    if (ttl == 0 || ttl > Config.positiveDnsTtl)
 
332
        ttl = Config.positiveDnsTtl;
 
333
 
 
334
    if (ttl < Config.negativeDnsTtl)
 
335
        ttl = Config.negativeDnsTtl;
 
336
 
 
337
    f->expires = squid_curtime + ttl;
 
338
 
 
339
    f->flags.negcached = 0;
 
340
 
 
341
    return f->name_count;
 
342
}
 
343
 
 
344
#else
 
345
static int
 
346
fqdncacheParse(fqdncache_entry *f, rfc1035_rr * answers, int nr, const char *error_message)
 
347
{
 
348
    int k;
 
349
    int ttl = 0;
 
350
    const char *name = (const char *)f->hash.key;
 
351
    f->expires = squid_curtime + Config.negativeDnsTtl;
 
352
    f->flags.negcached = 1;
 
353
 
 
354
    if (nr < 0) {
 
355
        debug(35, 3) ("fqdncacheParse: Lookup of '%s' failed (%s)\n", name, error_message);
 
356
        f->error_message = xstrdup(error_message);
 
357
        return -1;
 
358
    }
 
359
 
 
360
    if (nr == 0) {
 
361
        debug(35, 3) ("fqdncacheParse: No DNS records for '%s'\n", name);
 
362
        f->error_message = xstrdup("No DNS records");
 
363
        return 0;
 
364
    }
 
365
 
 
366
    debug(35, 3) ("fqdncacheParse: %d answers for '%s'\n", nr, name);
 
367
    assert(answers);
 
368
 
 
369
    for (k = 0; k < nr; k++) {
 
370
        if (answers[k]._class != RFC1035_CLASS_IN)
 
371
            continue;
 
372
 
 
373
        if (answers[k].type == RFC1035_TYPE_PTR) {
 
374
            if (!answers[k].rdata[0]) {
 
375
                debug(35, 2) ("fqdncacheParse: blank PTR record for '%s'\n", name);
 
376
                continue;
 
377
            }
 
378
 
 
379
            if (strchr(answers[k].rdata, ' ')) {
 
380
                debug(35, 2) ("fqdncacheParse: invalid PTR record '%s' for '%s'\n", answers[k].rdata, name);
 
381
                continue;
 
382
            }
 
383
 
 
384
            f->names[f->name_count++] = xstrdup(answers[k].rdata);
 
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
        debug(35, 1) ("fqdncacheParse: No PTR record for '%s'\n", name);
 
397
        return 0;
 
398
    }
 
399
 
 
400
    if (ttl == 0 || 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 = 0;
 
409
 
 
410
    return f->name_count;
 
411
}
 
412
 
 
413
#endif
 
414
 
 
415
 
 
416
static void
 
417
#if USE_DNSSERVERS
 
418
fqdncacheHandleReply(void *data, char *reply)
 
419
#else
 
420
fqdncacheHandleReply(void *data, rfc1035_rr * answers, int na, const char *error_message)
 
421
#endif
 
422
{
 
423
    int n;
 
424
    fqdncache_entry *f;
 
425
    static_cast<generic_cbdata *>(data)->unwrap(&f);
 
426
    n = ++FqdncacheStats.replies;
 
427
    statHistCount(&statCounter.dns.svc_time,
 
428
                  tvSubMsec(f->request_time, current_time));
 
429
#if USE_DNSSERVERS
 
430
 
 
431
    fqdncacheParse(f, reply);
 
432
    ;
 
433
#else
 
434
 
 
435
    fqdncacheParse(f, answers, na, error_message);
 
436
#endif
 
437
 
 
438
    fqdncacheAddEntry(f);
 
439
 
 
440
    fqdncacheCallback(f);
 
441
}
 
442
 
 
443
void
 
444
 
 
445
fqdncache_nbgethostbyaddr(struct IN_ADDR addr, FQDNH * handler, void *handlerData)
 
446
{
 
447
    fqdncache_entry *f = NULL;
 
448
    char *name = inet_ntoa(addr);
 
449
    generic_cbdata *c;
 
450
    assert(handler);
 
451
    debug(35, 4) ("fqdncache_nbgethostbyaddr: Name '%s'.\n", name);
 
452
    FqdncacheStats.requests++;
 
453
 
 
454
    if (name == NULL || name[0] == '\0')
 
455
    {
 
456
        debug(35, 4) ("fqdncache_nbgethostbyaddr: Invalid name!\n");
 
457
        dns_error_message = "Invalid hostname";
 
458
        handler(NULL, handlerData);
 
459
        return;
 
460
    }
 
461
 
 
462
    f = fqdncache_get(name);
 
463
 
 
464
    if (NULL == f)
 
465
    {
 
466
        /* miss */
 
467
        (void) 0;
 
468
    } else if (fqdncacheExpiredEntry(f))
 
469
    {
 
470
        /* hit, but expired -- bummer */
 
471
        fqdncacheRelease(f);
 
472
        f = NULL;
 
473
    } else
 
474
    {
 
475
        /* hit */
 
476
        debug(35, 4) ("fqdncache_nbgethostbyaddr: HIT for '%s'\n", name);
 
477
 
 
478
        if (f->flags.negcached)
 
479
            FqdncacheStats.negative_hits++;
 
480
        else
 
481
            FqdncacheStats.hits++;
 
482
 
 
483
        f->handler = handler;
 
484
 
 
485
        f->handlerData = cbdataReference(handlerData);
 
486
 
 
487
        fqdncacheCallback(f);
 
488
 
 
489
        return;
 
490
    }
 
491
 
 
492
    debug(35, 5) ("fqdncache_nbgethostbyaddr: MISS for '%s'\n", name);
 
493
    FqdncacheStats.misses++;
 
494
    f = fqdncacheCreateEntry(name);
 
495
    f->handler = handler;
 
496
    f->handlerData = cbdataReference(handlerData);
 
497
    f->request_time = current_time;
 
498
    c = new generic_cbdata(f);
 
499
#if USE_DNSSERVERS
 
500
 
 
501
    dnsSubmit(hashKeyStr(&f->hash), fqdncacheHandleReply, c);
 
502
#else
 
503
 
 
504
    idnsPTRLookup(addr, fqdncacheHandleReply, c);
 
505
#endif
 
506
}
 
507
 
 
508
/* initialize the fqdncache */
 
509
void
 
510
fqdncache_init(void)
 
511
{
 
512
    int n;
 
513
 
 
514
    if (fqdn_table)
 
515
        return;
 
516
 
 
517
    debug(35, 3) ("Initializing FQDN Cache...\n");
 
518
 
 
519
    memset(&FqdncacheStats, '\0', sizeof(FqdncacheStats));
 
520
 
 
521
    memset(&lru_list, '\0', sizeof(lru_list));
 
522
 
 
523
    fqdncache_high = (long) (((float) Config.fqdncache.size *
 
524
                              (float) FQDN_HIGH_WATER) / (float) 100);
 
525
 
 
526
    fqdncache_low = (long) (((float) Config.fqdncache.size *
 
527
                             (float) FQDN_LOW_WATER) / (float) 100);
 
528
 
 
529
    n = hashPrime(fqdncache_high / 4);
 
530
 
 
531
    fqdn_table = hash_create((HASHCMP *) strcmp, n, hash4);
 
532
 
 
533
    memDataInit(MEM_FQDNCACHE_ENTRY, "fqdncache_entry",
 
534
                sizeof(fqdncache_entry), 0);
 
535
}
 
536
 
 
537
void
 
538
fqdncacheRegisterWithCacheManager(CacheManager & manager)
 
539
{
 
540
    manager.registerAction("fqdncache",
 
541
                           "FQDN Cache Stats and Contents",
 
542
                           fqdnStats, 0, 1);
 
543
 
 
544
}
 
545
 
 
546
const char *
 
547
 
 
548
fqdncache_gethostbyaddr(struct IN_ADDR addr, int flags)
 
549
{
 
550
    char *name = inet_ntoa(addr);
 
551
    fqdncache_entry *f = NULL;
 
552
 
 
553
    struct IN_ADDR ip;
 
554
    assert(name);
 
555
    FqdncacheStats.requests++;
 
556
    f = fqdncache_get(name);
 
557
 
 
558
    if (NULL == f)
 
559
    {
 
560
        (void) 0;
 
561
    } else if (fqdncacheExpiredEntry(f))
 
562
    {
 
563
        fqdncacheRelease(f);
 
564
        f = NULL;
 
565
    } else if (f->flags.negcached)
 
566
    {
 
567
        FqdncacheStats.negative_hits++;
 
568
        dns_error_message = f->error_message;
 
569
        return NULL;
 
570
    } else
 
571
    {
 
572
        FqdncacheStats.hits++;
 
573
        f->lastref = squid_curtime;
 
574
        dns_error_message = f->error_message;
 
575
        return f->names[0];
 
576
    }
 
577
 
 
578
    dns_error_message = NULL;
 
579
 
 
580
    /* check if it's already a FQDN address in text form. */
 
581
 
 
582
    if (!safe_inet_addr(name, &ip))
 
583
        return name;
 
584
 
 
585
    FqdncacheStats.misses++;
 
586
 
 
587
    if (flags & FQDN_LOOKUP_IF_MISS)
 
588
        fqdncache_nbgethostbyaddr(addr, dummy_handler, NULL);
 
589
 
 
590
    return NULL;
 
591
}
 
592
 
 
593
 
 
594
/* process objects list */
 
595
void
 
596
fqdnStats(StoreEntry * sentry)
 
597
{
 
598
    fqdncache_entry *f = NULL;
 
599
    int k;
 
600
    int ttl;
 
601
 
 
602
    if (fqdn_table == NULL)
 
603
        return;
 
604
 
 
605
    storeAppendPrintf(sentry, "FQDN Cache Statistics:\n");
 
606
 
 
607
    storeAppendPrintf(sentry, "FQDNcache Entries: %d\n",
 
608
                      memInUse(MEM_FQDNCACHE_ENTRY));
 
609
 
 
610
    storeAppendPrintf(sentry, "FQDNcache Requests: %d\n",
 
611
                      FqdncacheStats.requests);
 
612
 
 
613
    storeAppendPrintf(sentry, "FQDNcache Hits: %d\n",
 
614
                      FqdncacheStats.hits);
 
615
 
 
616
    storeAppendPrintf(sentry, "FQDNcache Negative Hits: %d\n",
 
617
                      FqdncacheStats.negative_hits);
 
618
 
 
619
    storeAppendPrintf(sentry, "FQDNcache Misses: %d\n",
 
620
                      FqdncacheStats.misses);
 
621
 
 
622
    storeAppendPrintf(sentry, "FQDN Cache Contents:\n\n");
 
623
 
 
624
    storeAppendPrintf(sentry, "%-15.15s %3s %3s %3s %s\n",
 
625
                      "Address", "Flg", "TTL", "Cnt", "Hostnames");
 
626
 
 
627
    hash_first(fqdn_table);
 
628
 
 
629
    while ((f = (fqdncache_entry *) hash_next(fqdn_table))) {
 
630
        ttl = (f->flags.fromhosts ? -1 : (f->expires - squid_curtime));
 
631
        storeAppendPrintf(sentry, "%-15.15s  %c%c %3.3d % 3d",
 
632
                          hashKeyStr(&f->hash),
 
633
                          f->flags.negcached ? 'N' : ' ',
 
634
                          f->flags.fromhosts ? 'H' : ' ',
 
635
                          ttl,
 
636
                          (int) f->name_count);
 
637
 
 
638
        for (k = 0; k < (int) f->name_count; k++)
 
639
            storeAppendPrintf(sentry, " %s", f->names[k]);
 
640
 
 
641
        storeAppendPrintf(sentry, "\n");
 
642
    }
 
643
}
 
644
 
 
645
static void
 
646
dummy_handler(const char *bufnotused, void *datanotused)
 
647
{
 
648
    return;
 
649
}
 
650
 
 
651
const char *
 
652
 
 
653
fqdnFromAddr(struct IN_ADDR addr)
 
654
{
 
655
    const char *n;
 
656
    static char buf[32];
 
657
 
 
658
    if (Config.onoff.log_fqdn && (n = fqdncache_gethostbyaddr(addr, 0)))
 
659
        return n;
 
660
 
 
661
    xstrncpy(buf, inet_ntoa(addr), 32);
 
662
 
 
663
    return buf;
 
664
}
 
665
 
 
666
static void
 
667
fqdncacheLockEntry(fqdncache_entry * f)
 
668
{
 
669
    if (f->locks++ == 0) {
 
670
        dlinkDelete(&f->lru, &lru_list);
 
671
        dlinkAdd(f, &f->lru, &lru_list);
 
672
    }
 
673
}
 
674
 
 
675
static void
 
676
fqdncacheUnlockEntry(fqdncache_entry * f)
 
677
{
 
678
    assert(f->locks > 0);
 
679
    f->locks--;
 
680
 
 
681
    if (fqdncacheExpiredEntry(f))
 
682
        fqdncacheRelease(f);
 
683
}
 
684
 
 
685
static void
 
686
fqdncacheFreeEntry(void *data)
 
687
{
 
688
    fqdncache_entry *f = (fqdncache_entry *)data;
 
689
    int k;
 
690
 
 
691
    for (k = 0; k < (int) f->name_count; k++)
 
692
        safe_free(f->names[k]);
 
693
 
 
694
    safe_free(f->hash.key);
 
695
 
 
696
    safe_free(f->error_message);
 
697
 
 
698
    memFree(f, MEM_FQDNCACHE_ENTRY);
 
699
}
 
700
 
 
701
void
 
702
fqdncacheFreeMemory(void)
 
703
{
 
704
    hashFreeItems(fqdn_table, fqdncacheFreeEntry);
 
705
    hashFreeMemory(fqdn_table);
 
706
    fqdn_table = NULL;
 
707
}
 
708
 
 
709
/* Recalculate FQDN cache size upon reconfigure */
 
710
void
 
711
fqdncache_restart(void)
 
712
{
 
713
    fqdncache_high = (long) (((float) Config.fqdncache.size *
 
714
                              (float) FQDN_HIGH_WATER) / (float) 100);
 
715
    fqdncache_low = (long) (((float) Config.fqdncache.size *
 
716
                             (float) FQDN_LOW_WATER) / (float) 100);
 
717
    purge_entries_fromhosts();
 
718
}
 
719
 
 
720
/*
 
721
 *  adds a "static" entry from /etc/hosts.  the worldist is to be
 
722
 *  managed by the caller, including pointed-to strings
 
723
 */
 
724
void
 
725
fqdncacheAddEntryFromHosts(char *addr, wordlist * hostnames)
 
726
{
 
727
    fqdncache_entry *fce;
 
728
    int j = 0;
 
729
 
 
730
    if ((fce = fqdncache_get(addr))) {
 
731
        if (1 == fce->flags.fromhosts) {
 
732
            fqdncacheUnlockEntry(fce);
 
733
        } else if (fce->locks > 0) {
 
734
            debug(35, 1) ("fqdncacheAddEntryFromHosts: can't add static entry for locked address '%s'\n", addr);
 
735
            return;
 
736
        } else {
 
737
            fqdncacheRelease(fce);
 
738
        }
 
739
    }
 
740
 
 
741
    fce = fqdncacheCreateEntry(addr);
 
742
 
 
743
    while (hostnames) {
 
744
        fce->names[j] = xstrdup(hostnames->key);
 
745
        j++;
 
746
        hostnames = hostnames->next;
 
747
 
 
748
        if (j >= FQDN_MAX_NAMES)
 
749
            break;
 
750
    }
 
751
 
 
752
    fce->name_count = j;
 
753
    fce->names[j] = NULL;       /* it's safe */
 
754
    fce->flags.fromhosts = 1;
 
755
    fqdncacheAddEntry(fce);
 
756
    fqdncacheLockEntry(fce);
 
757
}
 
758
 
 
759
 
 
760
#ifdef SQUID_SNMP
 
761
/*
 
762
 * The function to return the fqdn statistics via SNMP
 
763
 */
 
764
 
 
765
variable_list *
 
766
snmp_netFqdnFn(variable_list * Var, snint * ErrP)
 
767
{
 
768
    variable_list *Answer = NULL;
 
769
    debug(49, 5) ("snmp_netFqdnFn: Processing request:\n");
 
770
    snmpDebugOid(5, Var->name, Var->name_length);
 
771
    *ErrP = SNMP_ERR_NOERROR;
 
772
 
 
773
    switch (Var->name[LEN_SQ_NET + 1]) {
 
774
 
 
775
    case FQDN_ENT:
 
776
        Answer = snmp_var_new_integer(Var->name, Var->name_length,
 
777
                                      memInUse(MEM_FQDNCACHE_ENTRY),
 
778
                                      SMI_GAUGE32);
 
779
        break;
 
780
 
 
781
    case FQDN_REQ:
 
782
        Answer = snmp_var_new_integer(Var->name, Var->name_length,
 
783
                                      FqdncacheStats.requests,
 
784
                                      SMI_COUNTER32);
 
785
        break;
 
786
 
 
787
    case FQDN_HITS:
 
788
        Answer = snmp_var_new_integer(Var->name, Var->name_length,
 
789
                                      FqdncacheStats.hits,
 
790
                                      SMI_COUNTER32);
 
791
        break;
 
792
 
 
793
    case FQDN_PENDHIT:
 
794
        /* this is now worthless */
 
795
        Answer = snmp_var_new_integer(Var->name, Var->name_length,
 
796
                                      0,
 
797
                                      SMI_GAUGE32);
 
798
        break;
 
799
 
 
800
    case FQDN_NEGHIT:
 
801
        Answer = snmp_var_new_integer(Var->name, Var->name_length,
 
802
                                      FqdncacheStats.negative_hits,
 
803
                                      SMI_COUNTER32);
 
804
        break;
 
805
 
 
806
    case FQDN_MISS:
 
807
        Answer = snmp_var_new_integer(Var->name, Var->name_length,
 
808
                                      FqdncacheStats.misses,
 
809
                                      SMI_COUNTER32);
 
810
        break;
 
811
 
 
812
    case FQDN_GHBN:
 
813
        Answer = snmp_var_new_integer(Var->name, Var->name_length,
 
814
                                      0, /* deprecated */
 
815
                                      SMI_COUNTER32);
 
816
        break;
 
817
 
 
818
    default:
 
819
        *ErrP = SNMP_ERR_NOSUCHNAME;
 
820
        break;
 
821
    }
 
822
 
 
823
    return Answer;
 
824
}
 
825
 
 
826
#endif /*SQUID_SNMP */