diff --git a/src/Makefile.am b/src/Makefile.am index 936345f9..2be43133 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,6 +45,7 @@ noinst_HEADERS = \ fastevent.h \ navigation.h \ event.h \ + ping.h \ acl.h auth.h \ metadata_xiph.h \ format.h \ @@ -121,6 +122,7 @@ icecast_SOURCES = \ if HAVE_CURL icecast_SOURCES += \ curl.c \ + ping.c \ auth_url.c \ event_url.c endif @@ -143,6 +145,7 @@ endif EXTRA_icecast_SOURCES = \ curl.c \ + ping.c \ yp.c \ auth_url.c \ event_url.c \ diff --git a/src/event_url.c b/src/event_url.c index b501dd43..6fb9c775 100644 --- a/src/event_url.c +++ b/src/event_url.c @@ -19,7 +19,7 @@ #include "global.h" /* for igloo_instance */ #include "string_renderer.h" -#include "curl.h" +#include "ping.h" #include "event.h" #include "cfgfile.h" #include "util.h" @@ -31,23 +31,10 @@ typedef struct event_url { bool legacy; char *url; char *action; - char *userpwd; - CURL *handle; - char errormsg[CURL_ERROR_SIZE]; + char *username; + char *password; } event_url_t; -static size_t handle_returned (void *ptr, size_t size, size_t nmemb, void *stream) { - (void)ptr, (void)stream; - return size * nmemb; -} - -static inline char *__escape(const char *src, const char *default_value) { - if (src) - return util_url_escape(src); - - return strdup(default_value); -} - static int event_url_emit(void *state, event_t *event) { event_url_t *self = state; ice_config_t *config; @@ -92,18 +79,7 @@ static int event_url_emit(void *state, event_t *event) { string_renderer_end_list(renderer); - - if (strchr(self->url, '@') == NULL && self->userpwd) { - curl_easy_setopt(self->handle, CURLOPT_USERPWD, self->userpwd); - } else { - curl_easy_setopt(self->handle, CURLOPT_USERPWD, ""); - } - - curl_easy_setopt(self->handle, CURLOPT_URL, self->url); - curl_easy_setopt(self->handle, CURLOPT_POSTFIELDS, string_renderer_to_string_zero_copy(renderer)); - - if (curl_easy_perform(self->handle)) - ICECAST_LOG_WARN("auth to server %s failed with %s", self->url, self->errormsg); + ping_simple(self->url, self->username, self->password, string_renderer_to_string_zero_copy(renderer)); igloo_ro_unref(&renderer); @@ -112,17 +88,15 @@ static int event_url_emit(void *state, event_t *event) { static void event_url_free(void *state) { event_url_t *self = state; - icecast_curl_free(self->handle); free(self->url); free(self->action); - free(self->userpwd); + free(self->username); + free(self->password); free(self); } int event_get_url(event_registration_t *er, config_options_t *options) { event_url_t *self = calloc(1, sizeof(event_url_t)); - const char *username = NULL; - const char *password = NULL; if (!self) return -1; @@ -144,9 +118,9 @@ int event_get_url(event_registration_t *er, config_options_t *options) { if (strcmp(options->name, "url") == 0) { util_replace_string(&(self->url), options->value); } else if (strcmp(options->name, "username") == 0) { - username = options->value; + util_replace_string(&(self->username), options->value); } else if (strcmp(options->name, "password") == 0) { - password = options->value; + util_replace_string(&(self->password), options->value); } else if (strcmp(options->name, "action") == 0) { util_replace_string(&(self->action), options->value); } else if (strcmp(options->name, "legacy") == 0) { @@ -157,27 +131,12 @@ int event_get_url(event_registration_t *er, config_options_t *options) { } while ((options = options->next)); } - self->handle = icecast_curl_new(NULL, NULL); - /* check if we are in sane state */ - if (!self->url || !self->handle) { + if (!self->url) { event_url_free(self); return -1; } - curl_easy_setopt(self->handle, CURLOPT_HEADERFUNCTION, handle_returned); - curl_easy_setopt(self->handle, CURLOPT_ERRORBUFFER, self->errormsg); - - if (username && password) { - size_t len = strlen(username) + strlen(password) + 2; - self->userpwd = malloc(len); - if (!self->userpwd) { - event_url_free(self); - return -1; - } - snprintf(self->userpwd, len, "%s:%s", username, password); - } - er->state = self; er->emit = event_url_emit; er->free = event_url_free; diff --git a/src/main.c b/src/main.c index 7bbb36c3..3ce3eb22 100644 --- a/src/main.c +++ b/src/main.c @@ -82,6 +82,7 @@ #include "yp.h" #include "auth.h" #include "event.h" +#include "ping.h" #include "listensocket.h" #include "fastevent.h" #include "prng.h" @@ -169,6 +170,7 @@ static void initialize_subsystems(void) xslt_initialize(); #ifdef HAVE_CURL icecast_curl_initialize(); + ping_initialize(); #endif } @@ -182,6 +184,9 @@ static void shutdown_subsystems(void) auth_shutdown(); yp_shutdown(); stats_shutdown(); +#ifdef HAVE_CURL + ping_shutdown(); +#endif ICECAST_LOG_DEBUG("Shuting down connection related subsystems..."); connection_shutdown(); diff --git a/src/ping.c b/src/ping.c new file mode 100644 index 00000000..31bcd097 --- /dev/null +++ b/src/ping.c @@ -0,0 +1,161 @@ +/* Icecast + * + * Copyright 2023 Philipp "ph3-der-loewe" Schafft + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "thread/thread.h" + +#include "ping.h" +#include "logging.h" +#include "curl.h" + +#define CATMODULE "ping" + +typedef struct ping_queue_tag ping_queue_t; + +struct ping_queue_tag { + CURL *curl; + ping_queue_t *next; +}; + +static bool ping_running = false; +static thread_type *ping_thread_id; +static mutex_t ping_mutex; +static ping_queue_t *ping_queue; +static cond_t ping_cond; + +static void on_done(ping_queue_t *entry) +{ + icecast_curl_free(entry->curl); + free(entry); +} + +static void *ping_thread(void *arg) +{ + CURLM *curl_multi = curl_multi_init(); + + while (ping_running) { + ping_queue_t *take; + int status; + + thread_mutex_lock(&ping_mutex); + take = ping_queue; + ping_queue = NULL; + thread_mutex_unlock(&ping_mutex); + + while (take) { + ping_queue_t *entry = take; + + take = take->next; + entry->next = NULL; + + curl_easy_setopt(entry->curl, CURLOPT_PRIVATE, entry); + curl_multi_add_handle(curl_multi, entry->curl); + } + + if (curl_multi_perform(curl_multi, &status) != CURLM_OK) + break; + + if (!status) { + if (!ping_running) + break; + thread_cond_wait(&ping_cond); + continue; + } + + if (curl_multi_wait(curl_multi, NULL, 0, 1000, &status) != CURLM_OK) + break; + + while (true) { + struct CURLMsg *m = curl_multi_info_read(curl_multi, &status); + + if (!m) + break; + + if (m->msg == CURLMSG_DONE) { + ping_queue_t *entry = NULL; + CURL *e = m->easy_handle; + curl_multi_remove_handle(curl_multi, e); + curl_easy_getinfo(e, CURLINFO_PRIVATE, &entry); + on_done(entry); + } + } + } + + curl_multi_cleanup(curl_multi); + + return NULL; +} + +static void ping_add_to_queue(ping_queue_t *entry) +{ + thread_mutex_lock(&ping_mutex); + entry->next = ping_queue; + ping_queue = entry; + thread_mutex_unlock(&ping_mutex); + thread_cond_broadcast(&ping_cond); +} + +void ping_simple(const char *url, const char *username, const char *password, const char *data) +{ + ping_queue_t *entry = calloc(1, sizeof(*entry)); + + if (!entry) + return; + + entry->curl = icecast_curl_new(url, NULL); + if (!entry->curl) { + free(entry); + return; + } + + if (strchr(url, '@') == NULL) { + if (username) + curl_easy_setopt(entry->curl, CURLOPT_USERNAME, username); + if (password) + curl_easy_setopt(entry->curl, CURLOPT_PASSWORD, password); + } + + if (data) + curl_easy_setopt(entry->curl, CURLOPT_COPYPOSTFIELDS, data); + + ping_add_to_queue(entry); +} + +void ping_initialize(void) +{ + if (ping_running) + return; + + thread_mutex_create(&ping_mutex); + thread_cond_create(&ping_cond); + + ping_running = true; + ping_thread_id = thread_create("Ping Thread", ping_thread, NULL, THREAD_ATTACHED); +} + +void ping_shutdown(void) +{ + if (!ping_running) + return; + + ping_running = false; + ICECAST_LOG_DEBUG("Waiting for ping thread"); + thread_cond_broadcast(&ping_cond); + thread_join(ping_thread_id); + thread_mutex_destroy(&ping_mutex); + thread_cond_destroy(&ping_cond); + ICECAST_LOG_DEBUG("Joined ping thread, good job!"); +} diff --git a/src/ping.h b/src/ping.h new file mode 100644 index 00000000..78bc9fff --- /dev/null +++ b/src/ping.h @@ -0,0 +1,17 @@ +/* Icecast + * + * Copyright 2023 Philipp "ph3-der-loewe" Schafft + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + */ + +#ifndef __PING_H__ +#define __PING_H__ + +void ping_initialize(void); +void ping_shutdown(void); + +void ping_simple(const char *url, const char *username, const char *password, const char *data); + +#endif /* __PING_H__ */