blob: f7740b5e9ce9737e0bd4bf64009fa9beb7c13302 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* dnsmasq is Copyright (c) 2000-2021 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
19static struct blockdata *keyblock_free;
20static unsigned int blockdata_count, blockdata_hwm, blockdata_alloced;
21
22static void blockdata_expand(int n)
23{
24 struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
25
26 if (new)
27 {
28 int i;
29
30 new[n-1].next = keyblock_free;
31 keyblock_free = new;
32
33 for (i = 0; i < n - 1; i++)
34 new[i].next = &new[i+1];
35
36 blockdata_alloced += n;
37 }
38}
39
40/* Preallocate some blocks, proportional to cachesize, to reduce heap fragmentation. */
41void blockdata_init(void)
42{
43 keyblock_free = NULL;
44 blockdata_alloced = 0;
45 blockdata_count = 0;
46 blockdata_hwm = 0;
47
48 /* Note that daemon->cachesize is enforced to have non-zero size if OPT_DNSSEC_VALID is set */
49 if (option_bool(OPT_DNSSEC_VALID))
50 blockdata_expand(daemon->cachesize);
51}
52
53void blockdata_report(void)
54{
55 my_syslog(LOG_INFO, _("pool memory in use %u, max %u, allocated %u"),
56 blockdata_count * sizeof(struct blockdata),
57 blockdata_hwm * sizeof(struct blockdata),
58 blockdata_alloced * sizeof(struct blockdata));
59}
60
61static struct blockdata *blockdata_alloc_real(int fd, char *data, size_t len)
62{
63 struct blockdata *block, *ret = NULL;
64 struct blockdata **prev = &ret;
65 size_t blen;
66
67 while (len > 0)
68 {
69 if (!keyblock_free)
70 blockdata_expand(50);
71
72 if (keyblock_free)
73 {
74 block = keyblock_free;
75 keyblock_free = block->next;
76 blockdata_count++;
77 }
78 else
79 {
80 /* failed to alloc, free partial chain */
81 blockdata_free(ret);
82 return NULL;
83 }
84
85 if (blockdata_hwm < blockdata_count)
86 blockdata_hwm = blockdata_count;
87
88 blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
89 if (data)
90 {
91 memcpy(block->key, data, blen);
92 data += blen;
93 }
94 else if (!read_write(fd, block->key, blen, 1))
95 {
96 /* failed read free partial chain */
97 blockdata_free(ret);
98 return NULL;
99 }
100 len -= blen;
101 *prev = block;
102 prev = &block->next;
103 block->next = NULL;
104 }
105
106 return ret;
107}
108
109struct blockdata *blockdata_alloc(char *data, size_t len)
110{
111 return blockdata_alloc_real(0, data, len);
112}
113
114void blockdata_free(struct blockdata *blocks)
115{
116 struct blockdata *tmp;
117
118 if (blocks)
119 {
120 for (tmp = blocks; tmp->next; tmp = tmp->next)
121 blockdata_count--;
122 tmp->next = keyblock_free;
123 keyblock_free = blocks;
124 blockdata_count--;
125 }
126}
127
128/* if data == NULL, return pointer to static block of sufficient size */
129void *blockdata_retrieve(struct blockdata *block, size_t len, void *data)
130{
131 size_t blen;
132 struct blockdata *b;
133 void *new, *d;
134
135 static unsigned int buff_len = 0;
136 static unsigned char *buff = NULL;
137
138 if (!data)
139 {
140 if (len > buff_len)
141 {
142 if (!(new = whine_malloc(len)))
143 return NULL;
144 if (buff)
145 free(buff);
146 buff = new;
147 }
148 data = buff;
149 }
150
151 for (d = data, b = block; len > 0 && b; b = b->next)
152 {
153 blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
154 memcpy(d, b->key, blen);
155 d += blen;
156 len -= blen;
157 }
158
159 return data;
160}
161
162
163void blockdata_write(struct blockdata *block, size_t len, int fd)
164{
165 for (; len > 0 && block; block = block->next)
166 {
167 size_t blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
168 read_write(fd, block->key, blen, 0);
169 len -= blen;
170 }
171}
172
173struct blockdata *blockdata_read(int fd, size_t len)
174{
175 return blockdata_alloc_real(fd, NULL, len);
176}