Imported Upstream version 2.88
[platform/upstream/dnsmasq.git] / src / blockdata.c
1 /* dnsmasq is Copyright (c) 2000-2022 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 static struct blockdata *keyblock_free;
20 static unsigned int blockdata_count, blockdata_hwm, blockdata_alloced;
21
22 static 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. */
41 void 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
53 void blockdata_report(void)
54 {
55   my_syslog(LOG_INFO, _("pool memory in use %zu, max %zu, allocated %zu"), 
56             blockdata_count * sizeof(struct blockdata),  
57             blockdata_hwm * sizeof(struct blockdata),  
58             blockdata_alloced * sizeof(struct blockdata));
59
60
61 static 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
109 struct blockdata *blockdata_alloc(char *data, size_t len)
110 {
111   return blockdata_alloc_real(0, data, len);
112 }
113
114 void 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 */
129 void *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
163 void 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
173 struct blockdata *blockdata_read(int fd, size_t len)
174 {
175   return blockdata_alloc_real(fd, NULL, len);
176 }