From 453ede09133ff65ce60992f41d429f9aebcb21ac Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Mon, 18 Aug 2025 13:20:52 -0400 Subject: [PATCH] MT#61977 add http/curl wrappers Change-Id: Iefa4f0acfadabae38ff1da4c20dda51718f9580f --- lib/http.c | 82 ++++++++++++++++++++++++++++++++++ lib/http.h | 31 +++++++++++++ recording-daemon/Makefile | 2 +- recording-daemon/notify.c | 93 ++++++--------------------------------- 4 files changed, 128 insertions(+), 80 deletions(-) create mode 100644 lib/http.c create mode 100644 lib/http.h diff --git a/lib/http.c b/lib/http.c new file mode 100644 index 000000000..7f4ba24b2 --- /dev/null +++ b/lib/http.c @@ -0,0 +1,82 @@ +#include "http.h" + +CURL *http_create_req(const char *uri, + size_t (*write_fn)(char *, size_t, size_t, void *), + size_t (*read_fn)(char *, size_t, size_t, void *), + const struct curl_slist *headers, + bool tls_verify, + CURLcode *errcode, + const char **errmsg) +{ + CURLcode ret = CURLE_FAILED_INIT; + + const char *err = "failed to create cURL object"; + g_autoptr(CURL) c = curl_easy_init(); + if (!c) + goto fail; + + err = "setting CURLOPT_URL"; + if ((ret = curl_easy_setopt(c, CURLOPT_URL, uri)) != CURLE_OK) + goto fail; + + err = "setting CURLOPT_WRITEFUNCTION"; + if ((ret = curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, write_fn)) != CURLE_OK) + goto fail; + + err = "setting CURLOPT_READFUNCTION"; + if ((ret = curl_easy_setopt(c, CURLOPT_READFUNCTION, read_fn)) != CURLE_OK) + goto fail; + + /* allow redirects */ + err = "setting CURLOPT_FOLLOWLOCATION"; + if ((ret = curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L)) != CURLE_OK) + goto fail; + + /* max 5 redirects */ + err = "setting CURLOPT_MAXREDIRS"; + if ((ret = curl_easy_setopt(c, CURLOPT_MAXREDIRS, 5L)) != CURLE_OK) + goto fail; + + /* add headers */ + err = "setting CURLOPT_HTTPHEADER"; + if ((ret = curl_easy_setopt(c, CURLOPT_HTTPHEADER, headers)) != CURLE_OK) + goto fail; + + /* cert verify (enabled by default) */ + if (!tls_verify) { + err = "setting CURLOPT_SSL_VERIFYPEER"; + if ((ret = curl_easy_setopt(c, CURLOPT_SSL_VERIFYPEER, 0L)) != CURLE_OK) + goto fail; + } + + // all ok + *errmsg = NULL; + *errcode = CURLE_OK; + + CURL *o = c; + c = NULL; // prevent auto cleanup + return o; + +fail: + *errmsg = err; + *errcode = ret; + return NULL; +} + + +void http_add_header(struct curl_slist **hdrs, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + char *s = g_strdup_vprintf(fmt, ap); + *hdrs = curl_slist_append(*hdrs, s); + g_free(s); + va_end(ap); +} + + +size_t http_dummy_write(char *ptr, size_t size, size_t nmemb, void *userdata) { + return size * nmemb; +} +size_t http_dummy_read(char *ptr, size_t size, size_t nmemb, void *userdata) { + return 0; +} diff --git a/lib/http.h b/lib/http.h new file mode 100644 index 000000000..2f1af743b --- /dev/null +++ b/lib/http.h @@ -0,0 +1,31 @@ +#ifndef _HTTP_H_ +#define _HTTP_H_ + +#include +#include +#include + + +CURL *http_create_req(const char *uri, + size_t (*write_fn)(char *, size_t, size_t, void *), + size_t (*read_fn)(char *, size_t, size_t, void *), + const struct curl_slist *headers, + bool tls_verify, + CURLcode *errcode, + const char **errmsg); + + +__attribute__ ((format (printf, 2, 3))) +void http_add_header(struct curl_slist **, const char *fmt, ...); + +size_t http_dummy_write(char *ptr, size_t size, size_t nmemb, void *userdata); +size_t http_dummy_read(char *ptr, size_t size, size_t nmemb, void *userdata); + + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURL, curl_easy_cleanup) +#if CURL_AT_LEAST_VERSION(7,56,0) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(curl_mime, curl_mime_free) +#endif + + +#endif diff --git a/recording-daemon/Makefile b/recording-daemon/Makefile index b929fac38..6a91fb7e1 100644 --- a/recording-daemon/Makefile +++ b/recording-daemon/Makefile @@ -50,7 +50,7 @@ CFLAGS+= -DCUSTOM_POLLER SRCS= epoll.c garbage.c inotify.c main.c metafile.c stream.c recaux.c packet.c \ decoder.c output.c mix.c db.c log.c forward.c tag.c custom_poller.c notify.c tls_send.c LIBSRCS= loglib.c auxlib.c rtplib.c codeclib.strhash.c resample.c str.c socket.c streambuf.c ssllib.c \ - dtmflib.c bufferpool.c bencode.c + dtmflib.c bufferpool.c bencode.c http.c LIBASM= mvr2s_x64_avx2.S mvr2s_x64_avx512.S mix_in_x64_avx2.S mix_in_x64_avx512bw.S mix_in_x64_sse2.S MDS= rtpengine-recording.ronn diff --git a/recording-daemon/notify.c b/recording-daemon/notify.c index 43ecaede8..30df1046c 100644 --- a/recording-daemon/notify.c +++ b/recording-daemon/notify.c @@ -5,6 +5,7 @@ #include "log.h" #include "recaux.h" #include "output.h" +#include "http.h" static GThreadPool *notify_threadpool; @@ -15,56 +16,20 @@ static pthread_t notify_waiter; static GTree *notify_timers; -static size_t dummy_write(char *ptr, size_t size, size_t nmemb, void *userdata) { - return size * nmemb; -} -static size_t dummy_read(char *ptr, size_t size, size_t nmemb, void *userdata) { - return 0; -} - static bool do_notify_http(notif_req_t *req) { const char *err = NULL; CURLcode ret; - bool success = false; ilog(LOG_DEBUG, "Launching HTTP notification for '%s%s%s'", FMT_M(req->name)); - /* set up the CURL request */ - #if CURL_AT_LEAST_VERSION(7,56,0) - curl_mime *mime = NULL; + g_autoptr(curl_mime) mime = NULL; #endif - CURL *c = curl_easy_init(); - if (!c) - goto fail; - - err = "setting CURLOPT_URL"; - if ((ret = curl_easy_setopt(c, CURLOPT_URL, notify_uri)) != CURLE_OK) - goto fail; - - /* no output */ - err = "setting CURLOPT_WRITEFUNCTION"; - if ((ret = curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, dummy_write)) != CURLE_OK) - goto fail; - - /* no input */ - err = "setting CURLOPT_READFUNCTION"; - if ((ret = curl_easy_setopt(c, CURLOPT_READFUNCTION, dummy_read)) != CURLE_OK) - goto fail; - - /* allow redirects */ - err = "setting CURLOPT_FOLLOWLOCATION"; - if ((ret = curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L)) != CURLE_OK) - goto fail; - /* max 5 redirects */ - err = "setting CURLOPT_MAXREDIRS"; - if ((ret = curl_easy_setopt(c, CURLOPT_MAXREDIRS, 5L)) != CURLE_OK) - goto fail; - - /* add headers */ - err = "setting CURLOPT_HTTPHEADER"; - if ((ret = curl_easy_setopt(c, CURLOPT_HTTPHEADER, req->headers)) != CURLE_OK) + g_autoptr(CURL) c = http_create_req(notify_uri, + http_dummy_write, http_dummy_read, + req->headers, !notify_nverify, &ret, &err); + if (!c) goto fail; /* POST vs GET */ @@ -74,13 +39,6 @@ static bool do_notify_http(notif_req_t *req) { goto fail; } - /* cert verify (enabled by default) */ - if (notify_nverify) { - err = "setting CURLOPT_SSL_VERIFYPEER"; - if ((ret = curl_easy_setopt(c, CURLOPT_SSL_VERIFYPEER, 0L)) != CURLE_OK) - goto fail; - } - #if CURL_AT_LEAST_VERSION(7,56,0) if (req->content) { err = "initializing curl mime&part"; @@ -114,33 +72,17 @@ static bool do_notify_http(notif_req_t *req) { /* success */ - success = true; - ilog(LOG_NOTICE, "HTTP notification for '%s%s%s' was successful", FMT_M(req->name)); - goto cleanup; + return true; fail: - if (c) - ilog(LOG_ERR, "Failed to perform HTTP notification for '%s%s%s': " - "Error while %s: %s", - FMT_M(req->name), - err, curl_easy_strerror(ret)); - else - ilog(LOG_ERR, "Failed to perform HTTP notification for '%s%s%s': " - "Failed to create CURL object", - FMT_M(req->name)); + ilog(LOG_ERR, "Failed to perform HTTP notification for '%s%s%s': " + "Error while %s: %s", + FMT_M(req->name), + err, curl_easy_strerror(ret)); -cleanup: - if (c) - curl_easy_cleanup(c); - -#if CURL_AT_LEAST_VERSION(7,56,0) - if (mime) - curl_mime_free(mime); -#endif - - return success; + return false; } static void failed_http(notif_req_t *req) { @@ -289,15 +231,8 @@ void notify_cleanup(void) { -__attribute__ ((format (printf, 2, 3))) -static void notify_add_header(notif_req_t *req, const char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - char *s = g_strdup_vprintf(fmt, ap); - req->headers = curl_slist_append(req->headers, s); - g_free(s); - va_end(ap); -} +#define notify_add_header(req, f, ...) http_add_header(&(req)->headers, f, __VA_ARGS__) + static void notify_req_setup_http(notif_req_t *req, output_t *o, metafile_t *mf, tag_t *tag) { double now = (double) now_us() / 1000000.;