source: spf2/vendor/current/src/libspf2/spf_dns_cache.c@ 302

Last change on this file since 302 was 302, checked in by Yuri Dario, 14 years ago

spf2: initial vendor import of spf2 1.2.9.

File size: 17.0 KB
Line 
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of either:
4 *
5 * a) The GNU Lesser General Public License as published by the Free
6 * Software Foundation; either version 2.1, or (at your option) any
7 * later version,
8 *
9 * OR
10 *
11 * b) The two-clause BSD license.
12 *
13 * These licenses can be found with the distribution in the file LICENSES
14 */
15
16#include "spf_sys_config.h"
17
18#ifdef STDC_HEADERS
19# include <stdio.h> /* stdin / stdout */
20# include <stdlib.h> /* malloc / free */
21#endif
22
23
24#ifdef HAVE_STRING_H
25# include <string.h> /* strstr / strdup */
26#else
27# ifdef HAVE_STRINGS_H
28# include <strings.h> /* strstr / strdup */
29# endif
30#endif
31
32#ifdef HAVE_MEMORY_H
33#include <memory.h>
34#endif
35#if TIME_WITH_SYS_TIME
36# include <sys/time.h>
37# include <time.h>
38#else
39# if HAVE_SYS_TIME_H
40# include <sys/time.h>
41# else
42# include <time.h>
43# endif
44#endif
45
46#ifdef HAVE_NETDB_H
47# include <netdb.h>
48#endif
49
50#ifdef HAVE_PTHREAD_H
51# include <pthread.h>
52#endif
53
54#include "spf.h"
55#include "spf_dns.h"
56#include "spf_internal.h"
57#include "spf_dns_internal.h"
58#include "spf_dns_cache.h"
59
60
61/**
62 * @file
63 *
64 * Implements a simple cache using a list hash. There is no reclaim
65 * list, since GNU malloc has clue.
66 *
67 * This original description from Wayne is no longer true:
68 *
69 * This is really little more than a proof-of-concept cache.
70 *
71 * The cache size is fixed and uses the CRC-32 function as a hash
72 * generator. Little is done about hash collisions, no alternate hash
73 * functions, no buckets, no linked lists, etc. There is a small
74 * reclaim list and if you add multiple DNS cache layers of different
75 * sizes you get slightly different hash functions. (The CRC-32
76 * function was chosen because I had a copy handy, it is pretty fast,
77 * and single bit changes are guarenteed to give a different hash.
78 * So, mx1.foo.com and mx2.foo.com will not collide)
79 */
80
81
82typedef
83struct _SPF_dns_cache_bucket_t {
84 struct _SPF_dns_cache_bucket_t *next;
85 SPF_dns_rr_t *rr;
86} SPF_dns_cache_bucket_t;
87
88typedef struct
89{
90 SPF_dns_cache_bucket_t **cache;
91 int cache_size;
92 pthread_mutex_t cache_lock;
93
94 int hash_mask;
95 int max_hash_len;
96
97#if 0
98 int hit;
99 int miss;
100#endif
101
102 time_t min_ttl;
103 time_t err_ttl;
104 time_t txt_ttl;
105 time_t rdns_ttl;
106
107 int conserve_cache;
108
109
110} SPF_dns_cache_config_t;
111
112
113static inline SPF_dns_cache_config_t *SPF_voidp2spfhook( void *hook )
114 { return (SPF_dns_cache_config_t *)hook; }
115static inline void *SPF_spfhook2voidp( SPF_dns_cache_config_t *spfhook )
116 { return (void *)spfhook; }
117
118
119/*
120** calculate CRC-32 stuff.
121*/
122
123/*
124 * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
125 * code or tables extracted from it, as desired without restriction.
126 *
127 * First, the polynomial itself and its table of feedback terms. The
128 * polynomial is
129 * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
130 *
131 * Note that we take it "backwards" and put the highest-order term in
132 * the lowest-order bit. The X^32 term is "implied"; the LSB is the
133 * X^31 term, etc. The X^0 term (usually shown as "+1") results in
134 * the MSB being 1
135 *
136 * Note that the usual hardware shift register implementation, which
137 * is what we're using (we're merely optimizing it by doing eight-bit
138 * chunks at a time) shifts bits into the lowest-order term. In our
139 * implementation, that means shifting towards the right. Why do we
140 * do it this way? Because the calculated CRC must be transmitted in
141 * order from highest-order term to lowest-order term. UARTs transmit
142 * characters in order from LSB to MSB. By storing the CRC this way
143 * we hand it to the UART in the order low-byte to high-byte; the UART
144 * sends each low-bit to hight-bit; and the result is transmission bit
145 * by bit from highest- to lowest-order term without requiring any bit
146 * shuffling on our part. Reception works similarly
147 *
148 * The feedback terms table consists of 256, 32-bit entries. Notes
149 *
150 * The table can be generated at runtime if desired; code to do so
151 * is shown later. It might not be obvious, but the feedback
152 * terms simply represent the results of eight shift/xor opera
153 * tions for all combinations of data and CRC register values
154 *
155 * The values must be right-shifted by eight bits by the "updcrc
156 * logic; the shift must be unsigned (bring in zeroes). On some
157 * hardware you could probably optimize the shift in assembler by
158 * using byte-swap instructions
159 * polynomial $edb88320
160 */
161
162const unsigned int crc_32_tab[256] = {
163 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
164 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
165 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
166 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
167 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
168 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
169 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
170 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
171 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
172 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
173 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
174 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
175 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
176 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
177 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
178 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
179 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
180 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
181 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
182 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
183 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
184 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
185 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
186 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
187 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
188 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
189 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
190 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
191 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
192 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
193 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
194 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
195 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
196 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
197 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
198 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
199 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
200 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
201 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
202 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
203 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
204 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
205 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
206 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
207 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
208 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
209 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
210 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
211 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
212 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
213 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
214 0x2d02ef8dL
215};
216
217static inline int
218crc32str(unsigned int accum, const char *str, int max_hash_len)
219{
220 for( ; *str != '\0' && max_hash_len > 0; str++ ) {
221 if ( *str == '.' )
222 continue;
223
224 accum = crc_32_tab[ (unsigned char)accum ^ (unsigned char)*str ]
225 ^ (unsigned char)(accum >> 8);
226
227 max_hash_len--;
228 }
229
230
231 return accum;
232}
233
234// #define hash(h,s,a) (crc32str(a,s,h->max_hash_len) & (h->hash_mask))
235#define hash(h,s,a) crc32str(a,s,h->max_hash_len)
236
237/* This must be called with the lock held. */
238static SPF_dns_cache_bucket_t *
239SPF_dns_cache_bucket_find(SPF_dns_cache_config_t *spfhook,
240 const char *domain, ns_type rr_type, int idx)
241{
242 SPF_dns_cache_bucket_t *bucket;
243 SPF_dns_cache_bucket_t *prev;
244 SPF_dns_rr_t *rr;
245 time_t now;
246
247 bucket = spfhook->cache[idx];
248 prev = NULL;
249 time(&now);
250
251 while (bucket != NULL) {
252 rr = bucket->rr;
253
254 if (rr->utc_ttl < now) {
255 /* Unlink the bucket. */
256 if (prev != NULL)
257 prev->next = bucket->next;
258 else
259 spfhook->cache[idx] = bucket->next;
260 /* Free the bucket. */
261 if (bucket->rr)
262 SPF_dns_rr_free(bucket->rr);
263 free(bucket);
264 /* Set iterator back one step. */
265 bucket = prev; /* Might be NULL */
266 }
267 else if (rr->rr_type != rr_type) {
268 /* Types differ */
269 }
270 else if (strcmp(rr->domain, domain) != 0) {
271 /* Domains differ */
272 }
273 else {
274 /* Move the bucket to the top of the chain. */
275 if (prev != NULL) {
276 prev->next = bucket->next;
277 bucket->next = spfhook->cache[idx];
278 spfhook->cache[idx] = bucket;
279 }
280 return bucket;
281 }
282
283 prev = bucket; /* Might be NULL */
284 if (bucket == NULL) /* After an unlink */
285 bucket = spfhook->cache[idx];
286 else
287 bucket = bucket->next;
288 }
289
290 return NULL;
291}
292
293/* This must be called with the lock held. */
294static SPF_errcode_t
295SPF_dns_cache_bucket_add(SPF_dns_cache_config_t *spfhook,
296 SPF_dns_rr_t *rr, int idx)
297{
298 SPF_dns_cache_bucket_t *bucket;
299
300 bucket = (SPF_dns_cache_bucket_t *)
301 malloc(sizeof(SPF_dns_cache_bucket_t));
302 if (! bucket)
303 return SPF_E_NO_MEMORY;
304 bucket->next = spfhook->cache[idx];
305 spfhook->cache[idx] = bucket;
306 bucket->rr = rr;
307 return SPF_E_SUCCESS;
308}
309
310
311/**
312 * Patches up an rr for insertion into the cache.
313 */
314static SPF_errcode_t
315SPF_dns_cache_rr_fixup(SPF_dns_cache_config_t *spfhook,
316 SPF_dns_rr_t *cached_rr,
317 const char *domain, ns_type rr_type)
318{
319 char *p;
320
321 /* make sure the RR has enough data to be useful for caching */
322 if (cached_rr->rr_type == ns_t_any)
323 cached_rr->rr_type = rr_type;
324
325 /* XXX I'm still not sure about this bit. */
326 if (cached_rr->domain == NULL || cached_rr->domain[0] != '\0') {
327 char *new_domain;
328 size_t new_len = strlen(domain) + 1;
329
330 if (cached_rr->domain_buf_len < new_len) {
331 new_domain = realloc(cached_rr->domain, new_len);
332 if (new_domain == NULL)
333 return SPF_E_NO_MEMORY;
334 cached_rr->domain = new_domain;
335 cached_rr->domain_buf_len = new_len;
336 }
337 strcpy(cached_rr->domain, domain);
338 }
339
340 /* set up the ttl values */
341 if ( cached_rr->ttl < spfhook->min_ttl )
342 cached_rr->ttl = spfhook->min_ttl;
343
344 if ( cached_rr->ttl < spfhook->txt_ttl
345 && cached_rr->rr_type == ns_t_txt )
346 cached_rr->ttl = spfhook->txt_ttl;
347
348 if ( cached_rr->ttl < spfhook->err_ttl
349 && cached_rr->herrno != NETDB_SUCCESS )
350 cached_rr->ttl = spfhook->err_ttl;
351
352 if ( cached_rr->ttl < spfhook->rdns_ttl ) {
353 p = strstr( cached_rr->domain, ".arpa" );
354 if ( p && p[ sizeof( ".arpa" )-1 ] == '\0' )
355 cached_rr->ttl = spfhook->rdns_ttl;
356 }
357
358 cached_rr->utc_ttl = cached_rr->ttl + time(NULL);
359
360 return SPF_E_SUCCESS;
361}
362
363
364/**
365 * Can return NULL on out-of-memory condition.
366 */
367static SPF_dns_rr_t *
368SPF_dns_cache_lookup(SPF_dns_server_t *spf_dns_server,
369 const char *domain, ns_type rr_type, int should_cache)
370{
371 SPF_dns_cache_config_t *spfhook;
372 SPF_dns_cache_bucket_t *bucket;
373 SPF_dns_rr_t *cached_rr;
374 SPF_dns_rr_t *rr;
375 int idx;
376
377 spfhook = SPF_voidp2spfhook(spf_dns_server->hook);
378
379 /* max_hash_len and cache_size are constant, so this be done
380 * outside the lock. */
381 idx = hash(spfhook, domain, 0 /* spfhook->hash_mask+rr_type */);
382 idx &= (spfhook->cache_size - 1);
383
384 pthread_mutex_lock(&(spfhook->cache_lock));
385
386 bucket = SPF_dns_cache_bucket_find(spfhook, domain, rr_type, idx);
387 if (bucket != NULL) {
388 if (bucket->rr != NULL) {
389 if (SPF_dns_rr_dup(&rr, bucket->rr) == SPF_E_SUCCESS) {
390 pthread_mutex_unlock(&(spfhook->cache_lock));
391 return rr;
392 }
393 else if (rr != NULL) {
394 SPF_dns_rr_free(rr); /* Within the lock. :-( */
395 }
396 }
397 }
398
399 /* Make sure we don't hang onto this outside the lock.
400 * idx is presumably safe. */
401 bucket = NULL;
402
403 pthread_mutex_unlock(&(spfhook->cache_lock));
404
405 if (!spf_dns_server->layer_below)
406 return SPF_dns_rr_new_nxdomain(spf_dns_server, domain);
407
408 rr = SPF_dns_lookup( spf_dns_server->layer_below,
409 domain, rr_type, should_cache );
410 if (spfhook->conserve_cache && !should_cache)
411 return rr;
412
413 pthread_mutex_lock(&(spfhook->cache_lock));
414
415 if (SPF_dns_rr_dup(&cached_rr, rr) == SPF_E_SUCCESS) {
416 if (SPF_dns_cache_rr_fixup(spfhook, cached_rr, domain, rr_type) == SPF_E_SUCCESS){
417 if (SPF_dns_cache_bucket_add(spfhook, cached_rr, idx) == SPF_E_SUCCESS) {
418 pthread_mutex_unlock(&(spfhook->cache_lock));
419 return rr;
420 }
421 }
422 }
423
424 pthread_mutex_unlock(&(spfhook->cache_lock));
425
426 if (cached_rr)
427 SPF_dns_rr_free(cached_rr);
428
429 return rr;
430
431}
432
433
434static void
435SPF_dns_cache_free( SPF_dns_server_t *spf_dns_server )
436{
437 SPF_dns_cache_config_t *spfhook;
438 SPF_dns_cache_bucket_t *bucket;
439 SPF_dns_cache_bucket_t *prev;
440 int i;
441
442 SPF_ASSERT_NOTNULL(spf_dns_server);
443
444 spfhook = SPF_voidp2spfhook( spf_dns_server->hook );
445 if ( spfhook ) {
446 pthread_mutex_lock(&(spfhook->cache_lock));
447
448 if (spfhook->cache) {
449 for( i = 0; i < spfhook->cache_size; i++ ) {
450 bucket = spfhook->cache[i];
451 while (bucket != NULL) {
452 prev = bucket;
453 bucket = bucket->next;
454
455 /* Free the bucket. */
456 if (prev->rr)
457 SPF_dns_rr_free(prev->rr);
458 free(prev);
459 }
460 }
461 free(spfhook->cache);
462 spfhook->cache = NULL;
463 }
464
465 pthread_mutex_unlock(&(spfhook->cache_lock));
466
467 /*
468 * There is a risk that something might grab the mutex
469 * here and try to look things up and try to resolve
470 * stuff from a mashed cache it might happen but that's
471 * what you get for trying to simultaneously free and
472 * use a resource destroy will then return EBUSY but
473 * it'll probably segfault so there ain't much to be
474 * done really.
475 */
476 pthread_mutex_destroy(&(spfhook->cache_lock));
477
478 free(spfhook);
479 }
480
481 free(spf_dns_server);
482}
483
484
485
486SPF_dns_server_t *
487SPF_dns_cache_new(SPF_dns_server_t *layer_below,
488 const char *name, int debug, int cache_bits)
489{
490 SPF_dns_server_t *spf_dns_server;
491 SPF_dns_cache_config_t *spfhook;
492
493 SPF_ASSERT_NOTNULL(layer_below);
494
495 if ( cache_bits < 1 || cache_bits > 16 )
496 SPF_error( "cache bits out of range (1..16)." );
497
498
499 spf_dns_server = malloc(sizeof(SPF_dns_server_t));
500 if (spf_dns_server == NULL)
501 return NULL;
502 memset(spf_dns_server, 0, sizeof(SPF_dns_server_t));
503
504 spf_dns_server->hook = malloc(sizeof(SPF_dns_cache_config_t));
505 if (spf_dns_server->hook == NULL) {
506 free(spf_dns_server);
507 return NULL;
508 }
509 memset(spf_dns_server->hook, 0, sizeof(SPF_dns_cache_config_t));
510
511 if (name == NULL)
512 name = "cache";
513
514 spf_dns_server->destroy = SPF_dns_cache_free;
515 spf_dns_server->lookup = SPF_dns_cache_lookup;
516 spf_dns_server->get_spf = NULL;
517 spf_dns_server->get_exp = NULL;
518 spf_dns_server->add_cache = NULL;
519 spf_dns_server->layer_below = layer_below;
520 spf_dns_server->name = name;
521 spf_dns_server->debug = debug;
522
523 spfhook = SPF_voidp2spfhook( spf_dns_server->hook );
524
525 spfhook->cache_size = 1 << cache_bits;
526 spfhook->hash_mask = spfhook->cache_size - 1;
527 spfhook->max_hash_len = cache_bits > 4 ? cache_bits * 2 : 8;
528
529 spfhook->cache = calloc(spfhook->cache_size,
530 sizeof(*spfhook->cache));
531
532#if 0
533 spfhook->hit = 0;
534 spfhook->miss = 0;
535#endif
536
537 spfhook->min_ttl = 30;
538 spfhook->err_ttl = 30*60;
539 spfhook->txt_ttl = 30*60;
540 spfhook->rdns_ttl = 30*60;
541 spfhook->conserve_cache = cache_bits < 12;
542
543 if (spfhook->cache == NULL) {
544 free(spfhook);
545 free(spf_dns_server);
546 return NULL;
547 }
548
549 pthread_mutex_init(&(spfhook->cache_lock),NULL);
550
551 return spf_dns_server;
552}
553
554void
555SPF_dns_cache_set_ttl( SPF_dns_server_t *spf_dns_server,
556 time_t min_ttl, time_t err_ttl,
557 time_t txt_ttl, time_t rdns_ttl )
558{
559 SPF_dns_cache_config_t *spfhook;
560
561 SPF_ASSERT_NOTNULL(spf_dns_server);
562
563 spfhook = SPF_voidp2spfhook( spf_dns_server->hook );
564
565 if (spfhook != NULL) {
566 pthread_mutex_lock(&(spfhook->cache_lock));
567 spfhook->min_ttl = min_ttl;
568 spfhook->err_ttl = err_ttl;
569 spfhook->txt_ttl = txt_ttl;
570 spfhook->rdns_ttl = rdns_ttl;
571 pthread_mutex_unlock(&(spfhook->cache_lock));
572 }
573}
574
575
576void
577SPF_dns_set_conserve_cache( SPF_dns_server_t *spf_dns_server,
578 int conserve_cache )
579{
580 SPF_dns_cache_config_t *spfhook;
581
582 SPF_ASSERT_NOTNULL(spf_dns_server);
583
584 spfhook = SPF_voidp2spfhook( spf_dns_server->hook );
585 /* This is a boolean and it doesn't matter if it
586 * changes suddenly, thus no lock. */
587 if (spfhook != NULL)
588 spfhook->conserve_cache = conserve_cache;
589}
Note: See TracBrowser for help on using the repository browser.