blob: dc8188370babf5d68607ae88a02cf4ab19f80f67 [file] [log] [blame]
Simon Kelleyc8e8f5c2021-01-24 21:59:37 +00001/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
Simon Kelley98c098b2014-01-08 17:31:16 +00002
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
Simon Kelley82e3f452014-01-31 21:05:48 +000019static struct blockdata *keyblock_free;
20static unsigned int blockdata_count, blockdata_hwm, blockdata_alloced;
21
Simon Kelley8d718cb2014-02-03 16:27:37 +000022static void blockdata_expand(int n)
23{
24 struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
25
Simon Kelleyad9c6f02017-10-27 22:13:49 +010026 if (new)
Simon Kelley8d718cb2014-02-03 16:27:37 +000027 {
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
Simon Kelley82e3f452014-01-31 21:05:48 +000040/* Preallocate some blocks, proportional to cachesize, to reduce heap fragmentation. */
41void blockdata_init(void)
42{
Simon Kelley8d718cb2014-02-03 16:27:37 +000043 keyblock_free = NULL;
44 blockdata_alloced = 0;
Simon Kelley82e3f452014-01-31 21:05:48 +000045 blockdata_count = 0;
46 blockdata_hwm = 0;
Simon Kelleyb692f232014-05-09 10:29:43 +010047
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))
Simon Kelley6340ca72018-01-30 21:39:01 +000050 blockdata_expand(daemon->cachesize);
Simon Kelley82e3f452014-01-31 21:05:48 +000051}
Simon Kelleyc2207682014-01-08 18:04:20 +000052
53void blockdata_report(void)
54{
Simon Kelley5b99eae2019-01-06 23:09:50 +000055 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));
Simon Kelleyc2207682014-01-08 18:04:20 +000059}
Simon Kelley98c098b2014-01-08 17:31:16 +000060
Simon Kelleya799ca02018-10-18 19:35:29 +010061static struct blockdata *blockdata_alloc_real(int fd, char *data, size_t len)
Simon Kelley98c098b2014-01-08 17:31:16 +000062{
63 struct blockdata *block, *ret = NULL;
64 struct blockdata **prev = &ret;
65 size_t blen;
66
67 while (len > 0)
68 {
Simon Kelley8d718cb2014-02-03 16:27:37 +000069 if (!keyblock_free)
70 blockdata_expand(50);
71
Simon Kelley98c098b2014-01-08 17:31:16 +000072 if (keyblock_free)
73 {
74 block = keyblock_free;
75 keyblock_free = block->next;
Simon Kelleyc2207682014-01-08 18:04:20 +000076 blockdata_count++;
Simon Kelley98c098b2014-01-08 17:31:16 +000077 }
Simon Kelley5f938532014-02-03 16:44:32 +000078 else
Simon Kelley98c098b2014-01-08 17:31:16 +000079 {
80 /* failed to alloc, free partial chain */
81 blockdata_free(ret);
82 return NULL;
83 }
Simon Kelley82e3f452014-01-31 21:05:48 +000084
85 if (blockdata_hwm < blockdata_count)
86 blockdata_hwm = blockdata_count;
Simon Kelley98c098b2014-01-08 17:31:16 +000087
88 blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
Simon Kelleya799ca02018-10-18 19:35:29 +010089 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 }
Simon Kelley98c098b2014-01-08 17:31:16 +0000100 len -= blen;
101 *prev = block;
102 prev = &block->next;
103 block->next = NULL;
104 }
105
106 return ret;
107}
108
Simon Kelleya799ca02018-10-18 19:35:29 +0100109struct blockdata *blockdata_alloc(char *data, size_t len)
110{
111 return blockdata_alloc_real(0, data, len);
112}
Simon Kelleyad9c6f02017-10-27 22:13:49 +0100113
Simon Kelley98c098b2014-01-08 17:31:16 +0000114void blockdata_free(struct blockdata *blocks)
115{
116 struct blockdata *tmp;
Simon Kelley82e3f452014-01-31 21:05:48 +0000117
Simon Kelley98c098b2014-01-08 17:31:16 +0000118 if (blocks)
119 {
Simon Kelleyc2207682014-01-08 18:04:20 +0000120 for (tmp = blocks; tmp->next; tmp = tmp->next)
121 blockdata_count--;
Simon Kelley98c098b2014-01-08 17:31:16 +0000122 tmp->next = keyblock_free;
Simon Kelleyc2207682014-01-08 18:04:20 +0000123 keyblock_free = blocks;
124 blockdata_count--;
Simon Kelley98c098b2014-01-08 17:31:16 +0000125 }
126}
127
Simon Kelley86bec2d2014-01-13 21:31:20 +0000128/* if data == NULL, return pointer to static block of sufficient size */
129void *blockdata_retrieve(struct blockdata *block, size_t len, void *data)
Simon Kelley98c098b2014-01-08 17:31:16 +0000130{
131 size_t blen;
132 struct blockdata *b;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000133 void *new, *d;
Simon Kelley98c098b2014-01-08 17:31:16 +0000134
Simon Kelley86bec2d2014-01-13 21:31:20 +0000135 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)
Simon Kelley98c098b2014-01-08 17:31:16 +0000152 {
153 blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
Simon Kelley86bec2d2014-01-13 21:31:20 +0000154 memcpy(d, b->key, blen);
155 d += blen;
Simon Kelley98c098b2014-01-08 17:31:16 +0000156 len -= blen;
157 }
Simon Kelleyb6e9e7c2014-01-08 21:21:20 +0000158
Simon Kelley86bec2d2014-01-13 21:31:20 +0000159 return data;
Simon Kelley98c098b2014-01-08 17:31:16 +0000160}
Simon Kelleya799ca02018-10-18 19:35:29 +0100161
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}
177