1/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley 2 3 This program is free software; you can redistribute it and/or modify 4 it under the terms of the GNU General Public License as published by 5 the Free Software Foundation; version 2 dated June, 1991, or 6 (at your option) version 3 dated 29 June, 2007. 7 8 This program is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License 14 along with this program. If not, see <http://www.gnu.org/licenses/>. 15*/ 16 17#include "dnsmasq.h" 18 19#ifdef HAVE_DNSSEC 20 21static struct blockdata *keyblock_free; 22static unsigned int blockdata_count, blockdata_hwm, blockdata_alloced; 23 24static void blockdata_expand(int n) 25{ 26 struct blockdata *new = whine_malloc(n * sizeof(struct blockdata)); 27 28 if (n > 0 && new) 29 { 30 int i; 31 32 new[n-1].next = keyblock_free; 33 keyblock_free = new; 34 35 for (i = 0; i < n - 1; i++) 36 new[i].next = &new[i+1]; 37 38 blockdata_alloced += n; 39 } 40} 41 42/* Preallocate some blocks, proportional to cachesize, to reduce heap fragmentation. */ 43void blockdata_init(void) 44{ 45 keyblock_free = NULL; 46 blockdata_alloced = 0; 47 blockdata_count = 0; 48 blockdata_hwm = 0; 49 50 /* Note that daemon->cachesize is enforced to have non-zero size if OPT_DNSSEC_VALID is set */ 51 if (option_bool(OPT_DNSSEC_VALID)) 52 blockdata_expand((daemon->cachesize * 100) / sizeof(struct blockdata)); 53} 54 55void blockdata_report(void) 56{ 57 if (option_bool(OPT_DNSSEC_VALID)) 58 my_syslog(LOG_INFO, _("DNSSEC memory in use %u, max %u, allocated %u"), 59 blockdata_count * sizeof(struct blockdata), 60 blockdata_hwm * sizeof(struct blockdata), 61 blockdata_alloced * sizeof(struct blockdata)); 62} 63 64struct blockdata *blockdata_alloc(char *data, size_t len) 65{ 66 struct blockdata *block, *ret = NULL; 67 struct blockdata **prev = &ret; 68 size_t blen; 69 70 while (len > 0) 71 { 72 if (!keyblock_free) 73 blockdata_expand(50); 74 75 if (keyblock_free) 76 { 77 block = keyblock_free; 78 keyblock_free = block->next; 79 blockdata_count++; 80 } 81 else 82 { 83 /* failed to alloc, free partial chain */ 84 blockdata_free(ret); 85 return NULL; 86 } 87 88 if (blockdata_hwm < blockdata_count) 89 blockdata_hwm = blockdata_count; 90 91 blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len; 92 memcpy(block->key, data, blen); 93 data += blen; 94 len -= blen; 95 *prev = block; 96 prev = &block->next; 97 block->next = NULL; 98 } 99 100 return ret; 101} 102 103void blockdata_free(struct blockdata *blocks) 104{ 105 struct blockdata *tmp; 106 107 if (blocks) 108 { 109 for (tmp = blocks; tmp->next; tmp = tmp->next) 110 blockdata_count--; 111 tmp->next = keyblock_free; 112 keyblock_free = blocks; 113 blockdata_count--; 114 } 115} 116 117/* if data == NULL, return pointer to static block of sufficient size */ 118void *blockdata_retrieve(struct blockdata *block, size_t len, void *data) 119{ 120 size_t blen; 121 struct blockdata *b; 122 void *new, *d; 123 124 static unsigned int buff_len = 0; 125 static unsigned char *buff = NULL; 126 127 if (!data) 128 { 129 if (len > buff_len) 130 { 131 if (!(new = whine_malloc(len))) 132 return NULL; 133 if (buff) 134 free(buff); 135 buff = new; 136 } 137 data = buff; 138 } 139 140 for (d = data, b = block; len > 0 && b; b = b->next) 141 { 142 blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len; 143 memcpy(d, b->key, blen); 144 d += blen; 145 len -= blen; 146 } 147 148 return data; 149} 150 151#endif 152