From: Michael Tremer Date: Wed, 8 Oct 2025 15:42:55 +0000 (+0000) Subject: buffer: Add a buffer implementation to write larger data to X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b8197e9ddca14d7e1ce45f7a6fbe2245fe69178d;p=telemetry.git buffer: Add a buffer implementation to write larger data to Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index f3b17e3..5ad4d4c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -92,6 +92,8 @@ bin_PROGRAMS += \ dist_collectyd_SOURCES = \ src/daemon/args.c \ src/daemon/args.h \ + src/daemon/buffer.c \ + src/daemon/buffer.h \ src/daemon/bus.c \ src/daemon/bus.h \ src/daemon/colors.h \ diff --git a/src/daemon/buffer.c b/src/daemon/buffer.c new file mode 100644 index 0000000..4fb187b --- /dev/null +++ b/src/daemon/buffer.c @@ -0,0 +1,222 @@ +/*############################################################################# +# # +# collecty - A system statistics collection daemon for IPFire # +# Copyright (C) 2025 IPFire Development Team # +# # +# 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, either version 3 of the License, or # +# (at your option) any later version. # +# # +# 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 . # +# # +#############################################################################*/ + +#include +#include +#include +#include + +#include "ctx.h" +#include "buffer.h" + +struct collecty_buffer { + collecty_ctx* ctx; + int nrefs; + + // File Handle + FILE* f; + + // Flags + enum { + COLLECTY_BUFFER_LOCKED = (1 << 0), + } flags; + + // Data & Length + char* data; + size_t length; + + // Pointer + off_t p; +}; + +static void collecty_buffer_free(collecty_buffer* self) { + if (self->f) + fclose(self->f); + if (self->data) + free(self->data); + if (self->ctx) + collecty_ctx_unref(self->ctx); + free(self); +} + +int collecty_buffer_create(collecty_buffer** buffer, collecty_ctx* ctx) { + collecty_buffer* self = NULL; + + // Allocate some memory + self = calloc(1, sizeof(*self)); + if (!self) + return -errno; + + // Initialize the reference counter + self->nrefs = 1; + + // Store a reference to the context + self->ctx = collecty_ctx_ref(ctx); + + // Return pointer + *buffer = self; + return 0; +} + +collecty_buffer* collecty_buffer_ref(collecty_buffer* self) { + ++self->nrefs; + return self; +} + +collecty_buffer* collecty_buffer_unref(collecty_buffer* self) { + if (--self->nrefs > 0) + return self; + + collecty_buffer_free(self); + return NULL; +} + +static int collecty_buffer_has_flag(collecty_buffer* self, int flag) { + return self->flags & flag; +} + +static void collecty_buffer_lock(collecty_buffer* self) { + self->flags |= COLLECTY_BUFFER_LOCKED; +} + +static ssize_t __collecty_buffer_read(void* cookie, char* buffer, size_t length) { + collecty_buffer* self = cookie; + + // Determine how much data is left + size_t bytes_left = self->length - self->p; + + // Cap reading beyond the end + if (length > bytes_left) + length = bytes_left; + + // We have reached the end already + if (!length) + return 0; + + // Check if p is in range + if (self->p < 0 || self->p > (off_t)self->length) { + errno = -ERANGE; + return -1; + } + + // Copy the data to the buffer + memcpy(buffer, self->data + self->p, length); + + // Advance p + self->p += length; + + return length; +} + +static int __collecty_buffer_seek(void* cookie, off_t* offset, int whence) { + collecty_buffer* self = cookie; + + // Update p + switch (whence) { + case SEEK_SET: + self->p = *offset; + break; + + case SEEK_CUR: + self->p += *offset; + break; + + case SEEK_END: + self->p = self->length + *offset; + } + + // Update offset + *offset = self->p; + + return 0; +} + +static int __collecty_buffer_close(void* cookie) { + collecty_buffer* self = cookie; + + // Drop the reference to the buffer + collecty_buffer_unref(self); + + return 0; +} + +cookie_io_functions_t collecty_buffer_io_funcs = { + .read = __collecty_buffer_read, + .seek = __collecty_buffer_seek, + .close = __collecty_buffer_close, +}; + +FILE* collecty_buffer_fopen(collecty_buffer* self, const char* mode) { + // Check if mode was passed + if (!mode) { + errno = EINVAL; + return NULL; + } + + // We only support read mode + if (!(*mode == 'r')) { + errno = -ENOTSUP; + return NULL; + } + + // Lock the buffer + collecty_buffer_lock(self); + + // Reset p + self->p = 0; + + // Return a file handle + return fopencookie(collecty_buffer_ref(self), mode, collecty_buffer_io_funcs); +} + +int collecty_buffer_write(collecty_buffer* self, const char* chunk, size_t length) { + char* data = NULL; + int r; + + // Cannot write if the buffer is locked + if (collecty_buffer_has_flag(self, COLLECTY_BUFFER_LOCKED)) + return -ENOTSUP; + + // Increase the size of the buffer + data = realloc(self->data, self->length + length); + if (!data) { + ERROR(self->ctx, "Failed to increase the buffer size: %m\n"); + r = -errno; + goto ERROR; + } + + // Copy the chunk + memcpy(data + self->length, chunk, length); + + // Update the data pointer + self->data = data; + + // Increase the size of the buffer + self->length += length; + + // Done + return 0; + +ERROR: + if (data) + free(data); + + return r; +} diff --git a/src/daemon/buffer.h b/src/daemon/buffer.h new file mode 100644 index 0000000..bc6939e --- /dev/null +++ b/src/daemon/buffer.h @@ -0,0 +1,39 @@ +/*############################################################################# +# # +# collecty - A system statistics collection daemon for IPFire # +# Copyright (C) 2025 IPFire Development Team # +# # +# 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, either version 3 of the License, or # +# (at your option) any later version. # +# # +# 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 . # +# # +#############################################################################*/ + +#ifndef COLLECTY_BUFFER_H +#define COLLECTY_BUFFER_H + +#include + +typedef struct collecty_buffer collecty_buffer; + +#include "ctx.h" + +int collecty_buffer_create(collecty_buffer** buffer, collecty_ctx* ctx); + +collecty_buffer* collecty_buffer_ref(collecty_buffer* self); +collecty_buffer* collecty_buffer_unref(collecty_buffer* self); + +FILE* collecty_buffer_fopen(collecty_buffer* self, const char* mode); + +int collecty_buffer_write(collecty_buffer* self, const char* chunk, size_t length); + +#endif /* COLLECTY_BUFFER_H */