1
0
Fork 0

Compare commits

...

15 Commits

Author SHA1 Message Date
Gilou 2c52b553fd Merge branch 'devel-gilou' into 'devel'
Docs: mention libigloo dependency in README

See merge request xiph/icecast-server!17
2024-01-15 14:56:11 +00:00
Philipp Schafft 573c7e51ab Fix: Made more use of %#H 2024-01-14 16:47:51 +00:00
Philipp Schafft 75d7082e60 Feature: Added show-listeners parameter to stats.xml endpoint 2024-01-14 14:17:15 +00:00
Philipp Schafft 6f2540426a Update: Do not report for no definition in report db if no db has been loaded 2024-01-14 14:16:04 +00:00
Philipp Schafft 7f6abb6ca8 Fix: Typo SROUCE_HIDDEN -> SOURCE_HIDDEN
Thanks to Jordan Erickson for finding this.
2023-08-02 00:19:15 +00:00
Philipp Schafft 70067b12be Fix: Fixed clients in body queue running in undetected EOFs
Thanks to Jordan Erickson
2023-08-02 00:19:12 +00:00
Philipp Schafft 5cf8cb9a99 Fix: Fixed memory leak on legacy config style
Closes: #2473
2023-06-22 10:38:18 +00:00
Philipp Schafft 5cad25a180 Update: Avoid logging in signal handler
See also: #2472
2023-06-22 10:13:37 +00:00
Philipp Schafft 86635ee700 Fix: Avoid breaking windows port
Windows understands FD_SETSIZE as POSIX does but unlike Linux (and likely
*BSD) does. While Linux uses the value to mark the highest value of a
filehandle, Windows understands it as the number of handles.
2023-06-11 20:10:04 +00:00
Philipp Schafft 2357cca098 Feature: Report sizeof(fd_set) in version display 2023-06-11 20:09:31 +00:00
Philipp Schafft 6baae8267e Fix: Handle exec() in a better way avoiding dead locks 2023-06-04 10:41:33 +00:00
Philipp Schafft c4ea726db5 Feature: Added checks for more functions which may become useful in the future versions 2023-06-04 09:12:13 +00:00
Philipp Schafft 9a2e911bee Cleanup: Corrected formatting 2023-06-04 08:57:57 +00:00
Philipp Schafft d42646541c Fix: Remove locking from signal handler
See also: #2472
2023-06-03 19:30:59 +00:00
Philipp Schafft 00f8e94257 Feature: Added -V verbose version output 2023-06-03 18:43:01 +00:00
16 changed files with 324 additions and 129 deletions

View File

@ -101,6 +101,7 @@ AC_CHECK_HEADERS([sys/socket.h])
AC_CHECK_HEADERS([pwd.h grp.h])
AC_CHECK_HEADERS([sys/resource.h])
AC_CHECK_HEADERS([crypt.h])
AC_CHECK_HEADERS([spawn.h])
AC_C_BIGENDIAN
@ -123,6 +124,9 @@ AC_CHECK_FUNCS([gettimeofday])
AC_CHECK_FUNCS([ftime])
AC_CHECK_FUNCS([getrlimit])
dnl Checked only for reporting in version display as of now (may be used in future versions):
AC_CHECK_FUNCS([pipe pipe2 socketpair posix_spawn posix_spawnp])
dnl check for crypt():
AC_SEARCH_LIBS([crypt_r], [crypt], [
AC_DEFINE([HAVE_CRYPT_R], [1], [Define if you have crypt_r])
@ -147,6 +151,7 @@ AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_TYPE_SSIZE_T
AC_TYPE_UID_T
AC_CHECK_TYPES([sig_atomic_t], [], [], [[#include <signal.h>]])
dnl Checks for required libraries

View File

@ -6,6 +6,7 @@ bin_PROGRAMS = icecast
noinst_HEADERS = \
icecasttypes.h \
version.h \
admin.h \
resourcematch.h \
main.h \
@ -63,6 +64,7 @@ noinst_HEADERS = \
icecast_SOURCES = \
main.c \
version.c \
cfgfile.c \
logging.c \
sighandler.c \

View File

@ -37,25 +37,6 @@
#include <sys/select.h>
#endif
#ifdef HAVE_OPENSSL
#include <openssl/opensslv.h>
#endif
#include <vorbis/codec.h>
#ifdef HAVE_THEORA
#include <theora/theora.h>
#endif
#ifdef HAVE_SPEEX
#include <speex/speex.h>
#endif
#ifdef HAVE_CURL
#include <curl/curlver.h>
#include <curl/curl.h>
#endif
#ifdef HAVE_UNAME
#include <sys/utsname.h>
#endif
@ -65,6 +46,7 @@
#include "common/net/sock.h"
#include "admin.h"
#include "version.h"
#include "compat.h"
#include "cfgfile.h"
#include "connection.h"
@ -1360,12 +1342,22 @@ static void command_shoutcast_metadata(client_t *client,
static void command_stats(client_t *client, source_t *source, admin_format_t response)
{
unsigned int flags = (source) ? STATS_XML_FLAG_SHOW_HIDDEN|STATS_XML_FLAG_SHOW_LISTENERS : STATS_XML_FLAG_SHOW_HIDDEN;
unsigned int flags = STATS_XML_FLAG_SHOW_HIDDEN;
const char *mount = (source) ? source->mount : NULL;
xmlDocPtr doc;
const char *show_listeners;
ICECAST_LOG_DEBUG("Stats request, sending xml stats");
COMMAND_OPTIONAL(client, "show-listeners", show_listeners);
if (show_listeners) {
if (util_str_to_bool(show_listeners))
flags |= STATS_XML_FLAG_SHOW_LISTENERS;
} else {
if (source)
flags |= STATS_XML_FLAG_SHOW_LISTENERS;
}
doc = stats_get_xml(flags, mount, client);
admin_send_response(doc, client, response, STATS_HTML_REQUEST);
xmlFreeDoc(doc);
@ -1857,24 +1849,6 @@ static void command_dashboard (client_t *client, source_t *source, adm
refobject_unref(report);
}
#ifdef HAVE_SPEEX
static inline const char *get_speex_version(void)
{
const char *version;
if (speex_lib_ctl(SPEEX_LIB_GET_VERSION_STRING, &version) != 0)
return NULL;
return version;
}
#endif
static inline const char *get_igloo_version(void)
{
const char *version;
if (igloo_version_get(&version, NULL, NULL, NULL) != igloo_ERROR_NONE)
return NULL;
return version;
}
static void command_version (client_t *client, source_t *source, admin_format_t response)
{
reportxml_t *report = client_get_reportxml("8cdfc150-094d-42f7-9c61-f9fb9a6e07e7", NULL, NULL);
@ -1886,61 +1860,8 @@ static void command_version (client_t *client, source_t *source, adm
reportxml_node_t *cflags = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
reportxml_node_t *rflags = reportxml_node_new(REPORTXML_NODE_TYPE_VALUE, NULL, NULL, NULL);
ice_config_t *icecast_config;
#ifdef HAVE_CURL
const curl_version_info_data * curl_runtime_version = curl_version_info(CURLVERSION_NOW);
#endif
struct {
const char *name;
const char *compiletime;
const char *runtime;
} dependency_versions[] = {
{"libigloo", NULL, get_igloo_version()},
{"libxml2", LIBXML_DOTTED_VERSION, NULL},
#if defined(HAVE_OPENSSL) && defined(OPENSSL_VERSION_TEXT)
{"OpenSSL", OPENSSL_VERSION_TEXT, NULL},
#endif
{"libvorbis", NULL, vorbis_version_string()},
#ifdef HAVE_THEORA
{"libtheora", NULL, theora_version_string()},
#endif
#ifdef HAVE_SPEEX
{"libspeex", NULL, get_speex_version()},
#endif
#ifdef HAVE_CURL
{"libcurl", LIBCURL_VERSION, curl_runtime_version->version},
#endif
{NULL, NULL, NULL}
};
const char *compiletime_flags[] = {
#ifdef HAVE_POLL
"poll",
#endif
#ifdef HAVE_SYS_SELECT_H
"select",
#endif
#ifdef HAVE_UNAME
"uname",
#endif
#ifdef HAVE_GETHOSTNAME
"gethostname",
#endif
#ifdef HAVE_GETADDRINFO
"getaddrinfo",
#endif
#ifdef HAVE_CRYPT
"crypt",
#endif
#ifdef HAVE_CRYPT_R
"crypt_r",
#endif
#ifdef WIN32
"win32",
#endif
#ifdef DEVEL_LOGGING
"developer-logging",
#endif
NULL,
};
const char * const * compiletime_flags = version_get_compiletime_flags();
const icecast_dependency_t * dependency_versions = version_get_dependencies();
size_t i;
reportxml_node_set_attribute(resource, "type", "result");
@ -1951,6 +1872,7 @@ static void command_version (client_t *client, source_t *source, adm
#ifdef HAVE_SYS_SELECT_H
reportxml_helper_add_value_int(resource, "fd-set-size", FD_SETSIZE);
reportxml_helper_add_value_int(resource, "fd-set-object-size", sizeof(fd_set));
#endif
#ifdef HAVE_GETHOSTNAME

View File

@ -1053,7 +1053,7 @@ int config_parse_file(const char *filename, ice_config_t *configuration)
ICECAST_LOG_ERROR("Client limit (%i) is too small for given source limit (%i)", configuration->client_limit, configuration->source_limit);
}
#ifndef HAVE_POLL
#if !defined(HAVE_POLL) && !defined(_WIN32)
if (configuration->client_limit > (FD_SETSIZE - 32)) {
configuration->config_problems |= CONFIG_PROBLEM_VALIDATION;
ICECAST_LOG_ERROR("Client limit (%i) is too big for FD_SETSIZE (%i)", configuration->client_limit, FD_SETSIZE);
@ -2337,8 +2337,10 @@ static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
continue;
if (xmlStrcmp(node->name, XMLSTR("source-password")) == 0) {
if (xmlGetProp(node, XMLSTR("mount"))) {
xmlChar *tmp;
if ((tmp = xmlGetProp(node, XMLSTR("mount")))) {
ICECAST_LOG_ERROR("Mount level source password defined within global <authentication> section.");
xmlFree(tmp);
} else {
if (*source_password)
xmlFree(*source_password);

View File

@ -1019,6 +1019,7 @@ client_slurp_result_t client_body_skip(client_t *client)
{
char buf[2048];
int ret;
ssize_t got;
ICECAST_LOG_DEBUG("Slurping client %p", client);
@ -1038,8 +1039,17 @@ client_slurp_result_t client_body_skip(client_t *client)
if (left > sizeof(buf))
left = sizeof(buf);
client_body_read(client, buf, left);
got = client_body_read(client, buf, left);
} else {
got = client_body_read(client, buf, sizeof(buf));
}
if (got < 1) {
ICECAST_LOG_DEBUG("Slurping client %p ... got no data EOF or needs more data", client);
return CLIENT_SLURP_ERROR;
}
if (client->request_body_length != -1) {
if ((size_t)client->request_body_length == client->request_body_read) {
ICECAST_LOG_DEBUG("Slurping client %p ... was a success", client);
return CLIENT_SLURP_SUCCESS;
@ -1047,8 +1057,6 @@ client_slurp_result_t client_body_skip(client_t *client)
ICECAST_LOG_DEBUG("Slurping client %p ... needs more data", client);
return CLIENT_SLURP_NEEDS_MORE_DATA;
}
} else {
client_body_read(client, buf, sizeof(buf));
}
ret = client_body_eof(client);

View File

@ -471,7 +471,7 @@ connection_t *connection_create(sock_t sock, listensocket_t *listensocket_real,
if (!matchfile_match_allow_deny(allowed_ip, banned_ip, ip))
return NULL;
#ifndef HAVE_POLL
#if !defined(HAVE_POLL) && !defined(_WIN32)
if (sock >= FD_SETSIZE) {
ICECAST_LOG_ERROR("Can not create connection: System filehandle set overflow");
return NULL;
@ -737,6 +737,8 @@ static client_slurp_result_t process_request_body_queue_one(client_queue_entry_t
client_t *client = node->client;
client_slurp_result_t res;
node->ready = false;
if (client->parser->req_type == httpp_req_post) {
if (node->bodybuffer == NULL && client->request_body_read == 0) {
if (client->request_body_length < 0) {
@ -903,6 +905,7 @@ void connection_accept_loop(void)
connection_queue(con);
}
}
ICECAST_LOG_INFO("No longer running. Shutting down...");
/* Give all the other threads notification to shut down */

View File

@ -10,6 +10,7 @@
#include <config.h>
#endif
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
@ -181,7 +182,8 @@ static inline void __setup_environ(ice_config_t *config, event_exec_t *self, eve
if (source) {
__update_environ("SOURCE_MOUNTPOINT", source->mount);
__update_environ("SOURCE_PUBLIC", source->yp_public ? "true" : "false");
__update_environ("SROUCE_HIDDEN", source->hidden ? "true" : "false");
__update_environ("SOURCE_HIDDEN", source->hidden ? "true" : "false");
__update_environ("SROUCE_HIDDEN", source->hidden ? "true" : "false"); /* Typo, kept for compatibility */
}
avl_tree_unlock(global.source_tree);
}
@ -222,34 +224,35 @@ static inline void __setup_empty_script_environment(event_exec_t *self, event_t
static void _run_script (event_exec_t *self, event_t *event) {
pid_t pid, external_pid;
if (access(self->executable, R_OK|X_OK) != 0) {
ICECAST_LOG_ERROR("Bad permissions on command %#H (%s)", self->executable, strerror(errno));
}
ICECAST_LOG_DEBUG("Trying to start command %H", self->executable);
/* do a fork twice so that the command has init as parent */
external_pid = fork();
switch (external_pid)
{
switch (external_pid) {
case 0:
switch (pid = fork ())
{
switch (pid = fork()) {
case -1:
ICECAST_LOG_ERROR("Unable to fork %s (%s)", self->executable, strerror (errno));
/* We cannot log the error here as we're no longer in the main process */
_exit(EXIT_FAILURE);
break;
case 0: /* child */
if (access(self->executable, R_OK|X_OK) != 0) {
ICECAST_LOG_ERROR("Unable to run command %s (%s)", self->executable, strerror(errno));
exit(1);
}
ICECAST_LOG_DEBUG("Starting command %s", self->executable);
__setup_empty_script_environment(self, event);
execv(self->executable, __setup_argv(self, event));
exit(1);
_exit(EXIT_FAILURE);
default: /* parent */
break;
}
_exit(0);
_exit(EXIT_SUCCESS);
case -1:
ICECAST_LOG_ERROR("Unable to fork %s", strerror (errno));
/* fork() failed but we're still in main process and can therefore log */
ICECAST_LOG_ERROR("Unable to fork %s", strerror(errno));
break;
default: /* parent */
waitpid (external_pid, NULL, 0);
waitpid(external_pid, NULL, 0);
break;
}
}

View File

@ -21,6 +21,8 @@
#define ICECAST_VERSION_STRING "Icecast " PACKAGE_VERSION
#include <signal.h>
#include <igloo/igloo.h>
#include "common/thread/thread.h"
@ -37,7 +39,12 @@ typedef struct ice_global_tag
time_t sources_update;
int sources_legacy;
int clients;
int schedule_config_reread;
#ifdef HAVE_SIG_ATOMIC_T
volatile sig_atomic_t schedule_config_reread;
#else
volatile int schedule_config_reread;
#endif
avl_tree *source_tree;
/* for locally defined relays */

View File

@ -726,7 +726,7 @@ static int listensocket_refsock(listensocket_t *self, bool prefer_inet6)
return -1;
}
#ifndef HAVE_POLL
#if !defined(HAVE_POLL) && !defined(_WIN32)
if (self->sock >= FD_SETSIZE) {
sock_close(self->sock);
self->sock = SOCK_ERROR;

View File

@ -62,9 +62,14 @@
#include <pwd.h>
#endif
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <rhash.h>
#include "main.h"
#include "version.h"
#include "cfgfile.h"
#include "util.h"
#include "sighandler.h"
@ -222,6 +227,39 @@ void main_config_reload(ice_config_t *config)
pidfile_update(config, 0);
}
static void show_version(bool full)
{
printf("%s\n", ICECAST_VERSION_STRING);
if (full) {
const char * const * compiletime_flag = version_get_compiletime_flags();
const icecast_dependency_t * dependencies = version_get_dependencies();
size_t i;
printf("\n");
printf("Address bits: %u\n", (unsigned int)sizeof(void*)*8);
#ifdef HAVE_SYS_SELECT_H
printf("fd set size: %u entries\n", (unsigned int)FD_SETSIZE);
printf("fd_set size: %u Bytes\n", (unsigned int)sizeof(fd_set));
#endif
printf("Compile time flags: ");
for (i = 0; compiletime_flag[i]; i++)
printf("%s ", compiletime_flag[i]);
printf("\n");
printf("Dependencies:\n");
for (i = 0; dependencies[i].name; i++) {
printf(" %s:\n", dependencies[i].name);
if (dependencies[i].compiletime)
printf(" compile time: %s\n", dependencies[i].compiletime);
if (dependencies[i].runtime)
printf(" run time: %s\n", dependencies[i].runtime);
}
}
}
static bool _parse_config_opts(int argc, char **argv, char *filename, size_t size)
{
int i;
@ -258,7 +296,10 @@ static bool _parse_config_opts(int argc, char **argv, char *filename, size_t siz
background = true;
#endif
} else if (strcmp(opt, "-v") == 0 || strcmp(opt, "--version") == 0) {
fprintf(stdout, "%s\n", ICECAST_VERSION_STRING);
show_version(false);
exit(0);
} else if (strcmp(opt, "-V") == 0) {
show_version(true);
exit(0);
} else if (strcmp(opt, "-c") == 0) {
if ((i + 1) < argc) {

View File

@ -15,6 +15,7 @@
#endif
#include <string.h>
#include <stdbool.h>
#include "common/thread/thread.h"
#include "common/avl/avl.h"
@ -62,6 +63,7 @@ struct reportxml_database_tag {
mutex_t lock;
/* The tree of definitions */
avl_tree *definitions;
bool loaded;
};
/* The nodeattr structure is used to store definition of node attributes */
@ -1061,6 +1063,8 @@ int reportxml_database_add_report(reportxml_database_t *db,
avl_insert(db->definitions, copy);
}
db->loaded = true;
thread_mutex_unlock(&(db->lock));
refobject_unref(root);
@ -1310,7 +1314,10 @@ reportxml_t * reportxml_database_build_report(reportxml_database_t *db
/* first find the definition itself. This will be some REPORTXML_NODE_TYPE_DEFINITION node. */
definition = __reportxml_database_build_node_ext(db, id, depth, &type);
if (!definition) {
ICECAST_LOG_WARN("No matching definition for \"%H\"", id);
if (db->loaded) {
/* we ignore the log for db->loaded here as is most unlikely that we read a wrong value here AND this is just a diagnostic message */
ICECAST_LOG_WARN("No matching definition for \"%H\"", id);
}
return NULL;
}
@ -1435,7 +1442,10 @@ reportxml_node_t * reportxml_database_build_fragment(reportxml_database_t *
/* first find the definition itself. This will be some REPORTXML_NODE_TYPE_DEFINITION node. */
definition = __reportxml_database_build_node_ext(db, id, depth, &got);
if (!definition) {
ICECAST_LOG_WARN("No matching definition for \"%H\"", id);
if (db->loaded) {
/* we ignore the log for db->loaded here as is most unlikely that we read a wrong value here AND this is just a diagnostic message */
ICECAST_LOG_WARN("No matching definition for \"%H\"", id);
}
return NULL;
}

View File

@ -54,11 +54,7 @@ void _sig_ignore(int signo)
void _sig_hup(int signo)
{
ICECAST_LOG_INFO("Caught signal %d, scheduling config re-read...", signo);
global_lock();
global . schedule_config_reread = 1;
global_unlock();
global.schedule_config_reread = 1;
/* some OSes require us to reattach the signal handler */
signal(SIGHUP, _sig_hup);
@ -66,8 +62,6 @@ void _sig_hup(int signo)
void _sig_die(int signo)
{
ICECAST_LOG_INFO("Caught signal %d, shutting down...", signo);
/* inform the server to start shutting down */
global.running = ICECAST_HALTING;
}

View File

@ -883,6 +883,7 @@ static void *_slave_thread(void *arg)
/* re-read xml file if requested */
global_lock();
if (global.schedule_config_reread) {
ICECAST_LOG_INFO("Reloading config for reload was queued");
config_reread_config();
global.schedule_config_reread = 0;
}

View File

@ -554,7 +554,7 @@ static refbuf_t *get_next_buffer (source_t *source)
source->last_read = current;
refbuf = source->format->get_buffer(source);
if (client_body_eof(source->client)) {
ICECAST_LOG_INFO("End of Stream %s", source->mount);
ICECAST_LOG_INFO("End of Stream %H", source->mount);
source->running = 0;
continue;
}
@ -943,9 +943,9 @@ static void source_shutdown (source_t *source)
{
source->running = 0;
if (source->con && source->con->ip) {
ICECAST_LOG_INFO("Source from %s at \"%s\" exiting", source->con->ip, source->mount);
ICECAST_LOG_INFO("Source from %s at %#H exiting", source->con->ip, source->mount);
} else {
ICECAST_LOG_INFO("Source at \"%s\" exiting", source->mount);
ICECAST_LOG_INFO("Source at %#H exiting", source->mount);
}
event_emit_va("source-disconnect", EVENT_EXTRA_SOURCE, source, EVENT_EXTRA_CLIENT, source->client, EVENT_EXTRA_LIST_END);

173
src/version.c Normal file
View File

@ -0,0 +1,173 @@
/* Icecast
*
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2023-2023, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
/**
* Client authentication functions
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <igloo/igloo.h>
#include <igloo/error.h>
#ifdef HAVE_PTHREAD
#include <pthread.h>
#else
#error "No pthread support"
#endif
#include <libxml/xmlversion.h>
#ifdef HAVE_OPENSSL
#include <openssl/opensslv.h>
#endif
#include <vorbis/codec.h>
#ifdef HAVE_THEORA
#include <theora/theora.h>
#endif
#ifdef HAVE_SPEEX
#include <speex/speex.h>
#endif
#ifdef HAVE_CURL
#include <curl/curlver.h>
#include <curl/curl.h>
#endif
#include "version.h"
#include "logging.h"
#define CATMODULE "version"
const char * const * version_get_compiletime_flags(void)
{
static const char * const compiletime_flags[] = {
/* ---[ Functions ]--- */
#ifdef HAVE_POLL
"poll",
#endif
#ifdef HAVE_SYS_SELECT_H
"select",
#endif
#ifdef HAVE_UNAME
"uname",
#endif
#ifdef HAVE_GETHOSTNAME
"gethostname",
#endif
#ifdef HAVE_GETADDRINFO
"getaddrinfo",
#endif
#ifdef HAVE_CRYPT
"crypt",
#endif
#ifdef HAVE_CRYPT_R
"crypt_r",
#endif
#ifdef HAVE_PIPE
"pipe",
#endif
#ifdef HAVE_PIPE2
"pipe2",
#endif
#ifdef HAVE_SOCKETPAIR
"socketpair",
#endif
#ifdef HAVE_POSIX_SPAWN
"posix_spawn",
#endif
#ifdef HAVE_POSIX_SPAWNP
"posix_spawnp",
#endif
/* ---[ OS ]--- */
#ifdef WIN32
"win32",
#endif
/* ---[ Options ]--- */
#ifdef DEVEL_LOGGING
"developer-logging",
#endif
NULL,
};
return compiletime_flags;
}
#ifdef HAVE_SPEEX
static inline const char *get_speex_version(void)
{
const char *version;
if (speex_lib_ctl(SPEEX_LIB_GET_VERSION_STRING, &version) != 0)
return NULL;
return version;
}
#endif
static inline const char *get_igloo_version(void)
{
const char *version;
if (igloo_version_get(&version, NULL, NULL, NULL) != igloo_ERROR_NONE)
return NULL;
return version;
}
#ifdef HAVE_PTHREAD
static pthread_once_t version_detect = PTHREAD_ONCE_INIT;
static icecast_dependency_t dependency_versions_real[32];
static inline void dependency_versions_add(size_t i, const char *name, const char *compiletime, const char *runtime)
{
if (i >= ((sizeof(dependency_versions_real)/sizeof(*dependency_versions_real)) - 1)) /* substract 1 for final NULL-row */
return;
dependency_versions_real[i].name = name;
dependency_versions_real[i].compiletime = compiletime;
dependency_versions_real[i].runtime = runtime;
}
static void version_init(void)
{
#ifdef HAVE_CURL
const curl_version_info_data * curl_runtime_version = curl_version_info(CURLVERSION_NOW);
#endif
size_t i = 0;
dependency_versions_add(i++, "libigloo", NULL, get_igloo_version());
dependency_versions_add(i++, "libxml2", LIBXML_DOTTED_VERSION, NULL);
#if defined(HAVE_OPENSSL) && defined(OPENSSL_VERSION_TEXT)
dependency_versions_add(i++, "OpenSSL", OPENSSL_VERSION_TEXT, NULL);
#endif
dependency_versions_add(i++, "libvorbis", NULL, vorbis_version_string());
#ifdef HAVE_THEORA
dependency_versions_add(i++, "libtheora", NULL, theora_version_string());
#endif
#ifdef HAVE_SPEEX
dependency_versions_add(i++, "libspeex", NULL, get_speex_version());
#endif
#ifdef HAVE_CURL
dependency_versions_add(i++, "libcurl", LIBCURL_VERSION, curl_runtime_version->version);
#endif
}
#endif
const icecast_dependency_t * version_get_dependencies(void)
{
#ifdef HAVE_PTHREAD
if (pthread_once(&version_detect, version_init) != 0)
return NULL;
#endif
return dependency_versions_real;
}

24
src/version.h Normal file
View File

@ -0,0 +1,24 @@
/* Icecast
*
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2023-2023, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
#ifndef __VERSION_H__
#define __VERSION_H__
#include "icecasttypes.h"
typedef struct {
const char *name;
const char *compiletime;
const char *runtime;
} icecast_dependency_t;
const char * const * version_get_compiletime_flags(void);
const icecast_dependency_t * version_get_dependencies(void);
#endif /* __VERSION_H__ */