mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-20 02:38:32 +00:00
I am attaching an incremental git-am ready patch to go on top your Git HEAD, to fix all sorts of issues and make this conforming C99 with default options set, and fix another load of warnings you receive when setting the compiler to pick the nits, -pedantic-errors -std=c99 (or c11, c18, c2x). It changes many void * to uint8_t * to make the "increment by bytes" explicit. You can't do: void *foo; // ... foo += 2.
240 lines
5.3 KiB
C
240 lines
5.3 KiB
C
/* dnsmasq is Copyright (c) 2000-2024 Simon Kelley
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 dated June, 1991, or
|
|
(at your option) version 3 dated 29 June, 2007.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "dnsmasq.h"
|
|
|
|
static struct blockdata *keyblock_free;
|
|
static unsigned int blockdata_count, blockdata_hwm, blockdata_alloced;
|
|
|
|
static void add_blocks(int n)
|
|
{
|
|
struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
|
|
|
|
if (new)
|
|
{
|
|
int i;
|
|
|
|
new[n-1].next = keyblock_free;
|
|
keyblock_free = new;
|
|
|
|
for (i = 0; i < n - 1; i++)
|
|
new[i].next = &new[i+1];
|
|
|
|
blockdata_alloced += n;
|
|
}
|
|
}
|
|
|
|
/* Preallocate some blocks, proportional to cachesize, to reduce heap fragmentation. */
|
|
void blockdata_init(void)
|
|
{
|
|
keyblock_free = NULL;
|
|
blockdata_alloced = 0;
|
|
blockdata_count = 0;
|
|
blockdata_hwm = 0;
|
|
|
|
/* Note that daemon->cachesize is enforced to have non-zero size if OPT_DNSSEC_VALID is set */
|
|
if (option_bool(OPT_DNSSEC_VALID))
|
|
add_blocks(daemon->cachesize);
|
|
}
|
|
|
|
void blockdata_report(void)
|
|
{
|
|
my_syslog(LOG_INFO, _("pool memory in use %zu, max %zu, allocated %zu"),
|
|
blockdata_count * sizeof(struct blockdata),
|
|
blockdata_hwm * sizeof(struct blockdata),
|
|
blockdata_alloced * sizeof(struct blockdata));
|
|
}
|
|
|
|
static struct blockdata *new_block(void)
|
|
{
|
|
struct blockdata *block;
|
|
|
|
if (!keyblock_free)
|
|
add_blocks(50);
|
|
|
|
if (keyblock_free)
|
|
{
|
|
block = keyblock_free;
|
|
keyblock_free = block->next;
|
|
blockdata_count++;
|
|
if (blockdata_hwm < blockdata_count)
|
|
blockdata_hwm = blockdata_count;
|
|
block->next = NULL;
|
|
return block;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static struct blockdata *blockdata_alloc_real(int fd, char *data, size_t len)
|
|
{
|
|
struct blockdata *block, *ret = NULL;
|
|
struct blockdata **prev = &ret;
|
|
size_t blen;
|
|
|
|
do
|
|
{
|
|
if (!(block = new_block()))
|
|
{
|
|
/* failed to alloc, free partial chain */
|
|
blockdata_free(ret);
|
|
return NULL;
|
|
}
|
|
|
|
if ((blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len) > 0)
|
|
{
|
|
if (data)
|
|
{
|
|
memcpy(block->key, data, blen);
|
|
data += blen;
|
|
}
|
|
else if (!read_write(fd, block->key, blen, RW_READ))
|
|
{
|
|
/* failed read free partial chain */
|
|
blockdata_free(ret);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
len -= blen;
|
|
*prev = block;
|
|
prev = &block->next;
|
|
} while (len != 0);
|
|
|
|
return ret;
|
|
}
|
|
|
|
struct blockdata *blockdata_alloc(char *data, size_t len)
|
|
{
|
|
return blockdata_alloc_real(0, data, len);
|
|
}
|
|
|
|
/* Add data to the end of the block.
|
|
newlen is length of new data, NOT total new length.
|
|
Use blockdata_alloc(NULL, 0) to make empty block to add to. */
|
|
int blockdata_expand(struct blockdata *block, size_t oldlen, char *data, size_t newlen)
|
|
{
|
|
struct blockdata *b;
|
|
|
|
/* find size of current final block */
|
|
for (b = block; oldlen > KEYBLOCK_LEN && b; b = b->next, oldlen -= KEYBLOCK_LEN);
|
|
|
|
/* chain to short for length, something is broken */
|
|
if (oldlen > KEYBLOCK_LEN)
|
|
{
|
|
blockdata_free(block);
|
|
return 0;
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
struct blockdata *new;
|
|
size_t blocksize = KEYBLOCK_LEN - oldlen;
|
|
size_t size = (newlen <= blocksize) ? newlen : blocksize;
|
|
|
|
if (size != 0)
|
|
{
|
|
memcpy(&b->key[oldlen], data, size);
|
|
data += size;
|
|
newlen -= size;
|
|
}
|
|
|
|
/* full blocks from now on. */
|
|
oldlen = 0;
|
|
|
|
if (newlen == 0)
|
|
break;
|
|
|
|
if ((new = new_block()))
|
|
{
|
|
b->next = new;
|
|
b = new;
|
|
}
|
|
else
|
|
{
|
|
/* failed to alloc, free partial chain */
|
|
blockdata_free(block);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void blockdata_free(struct blockdata *blocks)
|
|
{
|
|
struct blockdata *tmp;
|
|
|
|
if (blocks)
|
|
{
|
|
for (tmp = blocks; tmp->next; tmp = tmp->next)
|
|
blockdata_count--;
|
|
tmp->next = keyblock_free;
|
|
keyblock_free = blocks;
|
|
blockdata_count--;
|
|
}
|
|
}
|
|
|
|
/* if data == NULL, return pointer to static block of sufficient size */
|
|
void *blockdata_retrieve(struct blockdata *block, size_t len, void *data)
|
|
{
|
|
size_t blen;
|
|
struct blockdata *b;
|
|
uint8_t *new, *d;
|
|
|
|
static unsigned int buff_len = 0;
|
|
static unsigned char *buff = NULL;
|
|
|
|
if (!data)
|
|
{
|
|
if (len > buff_len)
|
|
{
|
|
if (!(new = whine_malloc(len)))
|
|
return NULL;
|
|
if (buff)
|
|
free(buff);
|
|
buff = new;
|
|
}
|
|
data = buff;
|
|
}
|
|
|
|
for (d = data, b = block; len > 0 && b; b = b->next)
|
|
{
|
|
blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
|
|
memcpy(d, b->key, blen);
|
|
d += blen;
|
|
len -= blen;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
|
|
void blockdata_write(struct blockdata *block, size_t len, int fd)
|
|
{
|
|
for (; len > 0 && block; block = block->next)
|
|
{
|
|
size_t blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
|
|
read_write(fd, block->key, blen, RW_WRITE);
|
|
len -= blen;
|
|
}
|
|
}
|
|
|
|
struct blockdata *blockdata_read(int fd, size_t len)
|
|
{
|
|
return blockdata_alloc_real(fd, NULL, len);
|
|
}
|