Coverage Report

Created: 2025-11-06 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dnsmasq/src/blockdata.c
Line
Count
Source
1
/* dnsmasq is Copyright (c) 2000-2025 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 add_blocks(int n)
23
0
{
24
0
  struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
25
  
26
0
  if (new)
27
0
    {
28
0
      int i;
29
      
30
0
      new[n-1].next = keyblock_free;
31
0
      keyblock_free = new;
32
33
0
      for (i = 0; i < n - 1; i++)
34
0
  new[i].next = &new[i+1];
35
36
0
      blockdata_alloced += n;
37
0
    }
38
0
}
39
40
/* Preallocate some blocks, proportional to cachesize, to reduce heap fragmentation. */
41
void blockdata_init(void)
42
0
{
43
0
  keyblock_free = NULL;
44
0
  blockdata_alloced = 0;
45
0
  blockdata_count = 0;
46
0
  blockdata_hwm = 0;
47
48
  /* Note that daemon->cachesize is enforced to have non-zero size if OPT_DNSSEC_VALID is set */  
49
0
  if (option_bool(OPT_DNSSEC_VALID))
50
0
    add_blocks(daemon->cachesize);
51
0
}
52
53
void blockdata_report(void)
54
0
{
55
0
  my_syslog(LOG_INFO, _("pool memory in use %zu, max %zu, allocated %zu"), 
56
0
      blockdata_count * sizeof(struct blockdata),  
57
0
      blockdata_hwm * sizeof(struct blockdata),  
58
0
      blockdata_alloced * sizeof(struct blockdata));
59
0
} 
60
61
static struct blockdata *new_block(void)
62
0
{
63
0
  struct blockdata *block;
64
65
0
  if (!keyblock_free)
66
0
    add_blocks(50);
67
  
68
0
  if (keyblock_free)
69
0
    {
70
0
      block = keyblock_free;
71
0
      keyblock_free = block->next;
72
0
      blockdata_count++;
73
0
      if (blockdata_hwm < blockdata_count)
74
0
  blockdata_hwm = blockdata_count;
75
0
      block->next = NULL;
76
0
      return block;
77
0
    }
78
  
79
0
  return NULL;
80
0
}
81
82
static struct blockdata *blockdata_alloc_real(int fd, char *data, size_t len)
83
0
{
84
0
  struct blockdata *block, *ret = NULL;
85
0
  struct blockdata **prev = &ret;
86
0
  size_t blen;
87
88
0
  do
89
0
    {
90
0
      if (!(block = new_block()))
91
0
  {
92
    /* failed to alloc, free partial chain */
93
0
    blockdata_free(ret);
94
0
    return NULL;
95
0
  }
96
97
0
      if ((blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len) > 0)
98
0
  {
99
0
    if (data)
100
0
      {
101
0
        memcpy(block->key, data, blen);
102
0
        data += blen;
103
0
      }
104
0
    else if (!read_write(fd, block->key, blen, RW_READ))
105
0
      {
106
        /* failed read free partial chain */
107
0
        blockdata_free(ret);
108
0
        return NULL;
109
0
      }
110
0
  }
111
      
112
0
      len -= blen;
113
0
      *prev = block;
114
0
      prev = &block->next;
115
0
    } while (len != 0);
116
  
117
0
  return ret;
118
0
}
119
120
struct blockdata *blockdata_alloc(char *data, size_t len)
121
0
{
122
0
  return blockdata_alloc_real(0, data, len);
123
0
}
124
125
/* Add data to the end of the block. 
126
   newlen is length of new data, NOT total new length. 
127
   Use blockdata_alloc(NULL, 0) to make empty block to add to. */
128
int blockdata_expand(struct blockdata *block, size_t oldlen, char *data, size_t newlen)
129
0
{
130
0
  struct blockdata *b;
131
  
132
  /* find size of current final block */
133
0
  for (b = block; oldlen > KEYBLOCK_LEN && b;  b = b->next, oldlen -= KEYBLOCK_LEN);
134
135
  /* chain to short for length, something is broken */
136
0
  if (oldlen > KEYBLOCK_LEN)
137
0
    {
138
0
      blockdata_free(block);
139
0
      return 0;
140
0
    }
141
142
0
  while (1)
143
0
    {
144
0
      struct blockdata *new;
145
0
      size_t blocksize = KEYBLOCK_LEN - oldlen;
146
0
      size_t size = (newlen <= blocksize) ? newlen : blocksize;
147
      
148
0
      if (size != 0)
149
0
  {
150
0
    memcpy(&b->key[oldlen], data, size);
151
0
    data += size;
152
0
    newlen -= size;
153
0
  }
154
      
155
      /* full blocks from now on. */
156
0
      oldlen = 0;
157
158
0
      if (newlen == 0)
159
0
  break;
160
161
0
      if ((new = new_block()))
162
0
  {
163
0
    b->next = new;
164
0
    b = new;
165
0
  }
166
0
      else
167
0
  {
168
    /* failed to alloc, free partial chain */
169
0
    blockdata_free(block);
170
0
    return 0;
171
0
  }
172
0
    }
173
174
0
  return 1;
175
0
}
176
177
void blockdata_free(struct blockdata *blocks)
178
0
{
179
0
  struct blockdata *tmp;
180
  
181
0
  if (blocks)
182
0
    {
183
0
      for (tmp = blocks; tmp->next; tmp = tmp->next)
184
0
  blockdata_count--;
185
0
      tmp->next = keyblock_free;
186
0
      keyblock_free = blocks; 
187
0
      blockdata_count--;
188
0
    }
189
0
}
190
191
/* if data == NULL, return pointer to static block of sufficient size */
192
void *blockdata_retrieve(struct blockdata *block, size_t len, void *data)
193
0
{
194
0
  size_t blen;
195
0
  struct  blockdata *b;
196
0
  uint8_t *new, *d;
197
  
198
0
  static unsigned int buff_len = 0;
199
0
  static unsigned char *buff = NULL;
200
   
201
0
  if (!data)
202
0
    {
203
0
      if (len > buff_len)
204
0
  {
205
0
    if (!(new = whine_malloc(len)))
206
0
      return NULL;
207
0
    if (buff)
208
0
      free(buff);
209
0
    buff = new;
210
0
  }
211
0
      data = buff;
212
0
    }
213
  
214
0
  for (d = data, b = block; len > 0 && b;  b = b->next)
215
0
    {
216
0
      blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
217
0
      memcpy(d, b->key, blen);
218
0
      d += blen;
219
0
      len -= blen;
220
0
    }
221
222
0
  return data;
223
0
}
224
225
226
void blockdata_write(struct blockdata *block, size_t len, int fd)
227
0
{
228
0
  for (; len > 0 && block; block = block->next)
229
0
    {
230
0
      size_t blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
231
0
      read_write(fd, block->key, blen, RW_WRITE);
232
0
      len -= blen;
233
0
    }
234
0
}
235
236
struct blockdata *blockdata_read(int fd, size_t len)
237
0
{
238
  return blockdata_alloc_real(fd, NULL, len);
239
0
}