1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2025-01-03 14:56:34 -05:00
icecast-server/src/ping.c

162 lines
3.6 KiB
C

/* Icecast
*
* Copyright 2023 Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>
*
* 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 <config.h>
#endif
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#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!");
}