From: Michael Tremer Date: Fri, 10 Jul 2026 10:27:59 +0000 (+0000) Subject: request: Create scaffolding to create a HTTP request X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b7183bb25e84dc9ba9aa6f243f33761e4af195da;p=telemetry.git request: Create scaffolding to create a HTTP request Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index ddb96d1..cc0b6e9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -188,6 +188,8 @@ dist_telemetryd_SOURCES = \ src/daemon/proto.h \ src/daemon/queue.c \ src/daemon/queue.h \ + src/daemon/request.c \ + src/daemon/request.h \ src/daemon/sensors.c \ src/daemon/sensors.h \ src/daemon/source.c \ diff --git a/src/daemon/client.c b/src/daemon/client.c index e2f3eb3..ef6a893 100644 --- a/src/daemon/client.c +++ b/src/daemon/client.c @@ -26,6 +26,7 @@ #include "ctx.h" #include "client.h" +#include "request.h" struct td_client { td_ctx* ctx; @@ -45,7 +46,8 @@ struct td_client { }; static int td_client_action(td_client* self) { - void* p = NULL; + td_request* request = NULL; + int r; CURLMsg* msg = NULL; int msgs_left = 0; @@ -59,11 +61,10 @@ static int td_client_action(td_client* self) { switch (msg->msg) { case CURLMSG_DONE: // Update reference to transfer - curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &p); + curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &request); -#if 0 // Call the done callback - r = td_request_done(p, self->loop, msg->data.result); + r = td_request_done(request, msg->data.result); if (r < 0) { switch (-r) { case EAGAIN: @@ -82,7 +83,6 @@ static int td_client_action(td_client* self) { return r; } } -#endif break; default: diff --git a/src/daemon/request.c b/src/daemon/request.c new file mode 100644 index 0000000..218ae3b --- /dev/null +++ b/src/daemon/request.c @@ -0,0 +1,263 @@ +/*############################################################################# +# # +# telemetryd - The IPFire Telemetry Collection Service # +# Copyright (C) 2026 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 "buffer.h" +#include "client.h" +#include "ctx.h" +#include "request.h" + +struct td_request { + td_ctx* ctx; + int nrefs; + + // HTTP Client + td_client* client; + + // cURL handle + CURL* handle; + + // URL + CURLU* url; + + // Output Buffer + td_buffer* buffer; +}; + +static int td_request_debug_callback(CURL *handle, curl_infotype type, + char* data, size_t size, void* p) { + td_request* self = p; + + switch (type) { + case CURLINFO_TEXT: + DEBUG(self->ctx, "cURL: %.*s", (int)size, data); + break; + + // Log headers + case CURLINFO_HEADER_IN: + DEBUG(self->ctx, "cURL: < %.*s", (int)size, data); + break; + + case CURLINFO_HEADER_OUT: + DEBUG(self->ctx, "cURL: > %.*s", (int)size, data); + break; + + // Ignore everything else + default: + break; + } + + return 0; +} + +static size_t td_request_write(char* data, size_t size, size_t nmemb, void* p) { + td_request* self = p; + + // Write everything to the buffer + return td_buffer_write(self->buffer, data, nmemb); +} + +static int td_request_setup(td_request* self) { + int r; + + // XXX Share Handle + + // Be a good net citizen and set a user agent + r = curl_easy_setopt(self->handle, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; " + PACKAGE_NAME "/" PACKAGE_VERSION "; +https://www.ipfire.org/)"); + if (r) + goto ERROR; + + // Enable logging/debugging + r = curl_easy_setopt(self->handle, CURLOPT_VERBOSE, 1L); + if (r) + goto ERROR; + + r = curl_easy_setopt(self->handle, CURLOPT_DEBUGFUNCTION, td_request_debug_callback); + if (r) + goto ERROR; + + r = curl_easy_setopt(self->handle, CURLOPT_DEBUGDATA, self); + if (r) + goto ERROR; + + // Raise any HTTP errors + r = curl_easy_setopt(self->handle, CURLOPT_FAILONERROR, 1L); + if (r) + goto ERROR; + + // Allow all support encodings + r = curl_easy_setopt(self->handle, CURLOPT_ACCEPT_ENCODING, ""); + if (r) + goto ERROR; + + // Reference back to this request + r = curl_easy_setopt(self->handle, CURLOPT_PRIVATE, self); + if (r) + goto ERROR; + + // Follow any redirects + r = curl_easy_setopt(self->handle, CURLOPT_FOLLOWLOCATION, 1L); + if (r) + goto ERROR; + + // Only follow up to 30 redirects + r = curl_easy_setopt(self->handle, CURLOPT_MAXREDIRS, 30L); + if (r) + goto ERROR; + + // Write all data to the callback function + r = curl_easy_setopt(self->handle, CURLOPT_WRITEFUNCTION, td_request_write); + if (r) + goto ERROR; + + r = curl_easy_setopt(self->handle, CURLOPT_WRITEDATA, self); + if (r) + goto ERROR; + + // Configure the URL + r = curl_easy_setopt(self->handle, CURLOPT_CURLU, self->url); + if (r) + goto ERROR; + +ERROR: + return r; +} + +static void td_request_free(td_request* self) { + if (self->handle) + curl_easy_cleanup(self->handle); + if (self->buffer) + td_buffer_unref(self->buffer); + if (self->client) + td_client_unref(self->client); + if (self->url) + curl_url_cleanup(self->url); + if (self->ctx) + td_ctx_unref(self->ctx); + free(self); +} + +int td_request_create(td_request** request, td_ctx* ctx, td_client* client) { + td_request* self = NULL; + int r; + + // Allocate some memory + self = calloc(1, sizeof(*self)); + if (!self) + return -errno; + + // Store a reference to the context + self->ctx = td_ctx_ref(ctx); + + // Initialize the reference counter + self->nrefs = 1; + + // Store a reference to the client + self->client = td_client_ref(client); + + // Allocate a handle + self->handle = curl_easy_init(); + if (!self->handle) { + r = -ENOMEM; + goto ERROR; + } + + // Allocate the URL + self->url = curl_url(); + if (!self->url) { + ERROR(self->ctx, "Failed to allocate the URL: %m\n"); + r = -errno; + goto ERROR; + } + + // Allocate an output buffer + r = td_buffer_create(&self->buffer, self->ctx); + if (r < 0) + goto ERROR; + + // Setup the request + r = td_request_setup(self); + if (r) + goto ERROR; + + // Return the pointer + *request = self; + return 0; + +ERROR: + td_request_free(self); + + return r; +} + +td_request* td_request_ref(td_request* self) { + ++self->nrefs; + return self; +} + +td_request* td_request_unref(td_request* self) { + if (--self->nrefs > 0) + return self; + + td_request_free(self); + return NULL; +} + +char* td_request_get_url(td_request* self) { + char* url = NULL; + int r; + + // Format the URL + r = curl_url_get(self->url, CURLUPART_URL, &url, 0); + if (r < 0) + return NULL; + + return url; +} + +int td_request_set_url(td_request* self, const char* url) { + int r; + + // Store the URL + r = curl_url_set(self->url, CURLUPART_URL, url, 0); + if (r < 0) { + ERROR(self->ctx, "Could not set the URL: %s\n", curl_easy_strerror(r)); + return -EINVAL; + } + + return 0; +} + +CURL* td_request_handle(td_request* self) { + return self->handle; +} + +int td_request_launch(td_request* self) { + return td_client_launch_request(self->client, self); +} + +int td_request_done(td_request* self, int code) { + return 0; +} diff --git a/src/daemon/request.h b/src/daemon/request.h new file mode 100644 index 0000000..dcd8af8 --- /dev/null +++ b/src/daemon/request.h @@ -0,0 +1,44 @@ +/*############################################################################# +# # +# telemetryd - The IPFire Telemetry Collection Service # +# Copyright (C) 2026 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 TELEMETRY_REQUEST_H +#define TELEMETRY_REQUEST_H + +#include + +typedef struct td_request td_request; + +#include "client.h" +#include "ctx.h" + +int td_request_create(td_request** request, td_ctx* ctx, td_client* client); + +td_request* td_request_ref(td_request* self); +td_request* td_request_unref(td_request* self); + +char* td_request_get_url(td_request* self); +int td_request_set_url(td_request* self, const char* url); + +CURL* td_request_handle(td_request* self); + +int td_request_launch(td_request* self); +int td_request_done(td_request* self, int code); + +#endif /* TELEMETRY_REQUEST_H */