diff --git a/src/cfgfile.c b/src/cfgfile.c index 42880d17..220263f2 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -275,6 +275,23 @@ static fallback_override_t config_str_to_fallback_override_t(ice_config_t *confi } } +static interpolation_t config_str_to_interpolation_t(ice_config_t *configuration, xmlNodePtr node, const char *str) +{ + if (!str || !*str || strcmp(str, "default") == 0) { + return INTERPOLATION_DEFAULT; + } else if (strcasecmp(str, "none") == 0) { + return INTERPOLATION_NONE; + } else if (strcasecmp(str, "strftime") == 0) { + return INTERPOLATION_STRFTIME; + } else if (strcasecmp(str, "uuid") == 0) { + return INTERPOLATION_UUID; + } else { + __found_bad_tag(configuration, node, BTR_INVALID, str); + ICECAST_LOG_ERROR("Unknown interpolation type \"%s\", falling back to DEFAULT.", str); + return INTERPOLATION_DEFAULT; + } +} + char * config_href_to_id(ice_config_t *configuration, xmlNodePtr node, const char *href) { if (!href || !*href) @@ -1744,8 +1761,13 @@ static void _parse_mount(xmlDocPtr doc, password = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp(node->name, XMLSTR("dump-file")) == 0) { + xmlChar * interpolation = xmlGetProp(node, XMLSTR("interpolation")); + if (interpolation) { + mount->dumpfile_interpolation = config_str_to_interpolation_t(configuration, node, (const char *)interpolation); + xmlFree(interpolation); + } mount->dumpfile = (char *)xmlNodeListGetString(doc, - node->xmlChildrenNode, 1); + node->xmlChildrenNode, 1); } else if (xmlStrcmp(node->name, XMLSTR("dump-file-size-limit")) == 0) { unsigned int val = mount->dumpfile_size_limit; __read_unsigned_int(configuration, doc, node, &val, 0, UINT_MAX); @@ -3008,6 +3030,8 @@ static void merge_mounts(mount_proxy * dst, mount_proxy * src) if (!dst->dumpfile) dst->dumpfile = (char*)xmlStrdup((xmlChar*)src->dumpfile); + if (dst->dumpfile_interpolation == INTERPOLATION_DEFAULT) + dst->dumpfile_interpolation = src->dumpfile_interpolation; if (!dst->dumpfile_size_limit) dst->dumpfile_size_limit = src->dumpfile_size_limit; if (!dst->dumpfile_time_limit) diff --git a/src/cfgfile.h b/src/cfgfile.h index 8a151f78..a01cee03 100644 --- a/src/cfgfile.h +++ b/src/cfgfile.h @@ -79,6 +79,13 @@ typedef enum { FALLBACK_OVERRIDE_OWN } fallback_override_t; +typedef enum { + INTERPOLATION_DEFAULT = 0, + INTERPOLATION_NONE, + INTERPOLATION_STRFTIME, + INTERPOLATION_UUID +} interpolation_t; + typedef struct _mount_proxy { /* The mountpoint this proxy is used for */ char *mountname; @@ -88,6 +95,7 @@ typedef struct _mount_proxy { * NULL to not dump. */ char *dumpfile; + interpolation_t dumpfile_interpolation; uint64_t dumpfile_size_limit; unsigned int dumpfile_time_limit; /* Send contents of file to client before the stream */ diff --git a/src/source.c b/src/source.c index 862397d9..a4e468d5 100644 --- a/src/source.c +++ b/src/source.c @@ -634,12 +634,9 @@ static void send_to_listener (source_t *source, client_t *client, int deletion_e static bool source_open_dumpfile(source_t *source) { const char *filename = source->dumpfilename; + interpolation_t interpolation = source->dumpfile_interpolation; time_t curtime = time(NULL); -#ifndef _WIN32 - /* some of the below functions seems not to be standard winapi functions */ char buffer[PATH_MAX]; - struct tm *loctime; -#endif if (!filename) { ICECAST_LOG_WARN("Can not open dump file for source %#H. No filename defined.", source->mount); @@ -661,13 +658,46 @@ static bool source_open_dumpfile(source_t *source) ICECAST_LOG_DDEBUG("source=%p{.mount=%#H, .burst_point=%p, .stream_data=%p, .stream_data_tail=%p, ...}", source, source->mount, source->burst_point, source->stream_data, source->stream_data_tail); + if (interpolation == INTERPOLATION_DEFAULT) { #ifndef _WIN32 - /* Convert it to local time representation. */ - loctime = localtime(&curtime); - - strftime(buffer, sizeof(buffer), filename, loctime); - filename = buffer; + interpolation = INTERPOLATION_STRFTIME; +#else + interpolation = INTERPOLATION_NONE; #endif + } + + switch (interpolation) { + case INTERPOLATION_NONE: + /* no-op */ + break; + case INTERPOLATION_STRFTIME: +#ifndef _WIN32 + { + /* some of the below functions seems not to be standard winapi functions */ + struct tm *loctime; + + /* Convert it to local time representation. */ + loctime = localtime(&curtime); + + strftime(buffer, sizeof(buffer), filename, loctime); + filename = buffer; + } +#else + ICECAST_LOG_ERROR("Can not interpolation dump file filename for source %#H. strftime() interpolation is not supported by your operating system.", source->mount); +#endif + break; + case INTERPOLATION_UUID: + if (!util_interpolation_uuid(buffer, sizeof(buffer), filename)) { + ICECAST_LOG_WARN("Can not open dump file for source %#H. Filename does not interpolate.", source->mount); + event_emit_va("dumpfile-error", EVENT_EXTRA_SOURCE, source, EVENT_EXTRA_LIST_END); + return false; + } + filename = buffer; + break; + default: + ICECAST_LOG_ERROR("Bug. Bad interpolation %i. Source %p on %#H.", (int)interpolation, source, source->mount); + break; + } source->dumpfile = fopen(filename, "ab"); @@ -1258,11 +1288,13 @@ static void source_apply_mount (ice_config_t *config, source_t *source, mount_pr } if (mountinfo) { - source->dumpfile_size_limit = mountinfo->dumpfile_size_limit; - source->dumpfile_time_limit = mountinfo->dumpfile_time_limit; + source->dumpfile_size_limit = mountinfo->dumpfile_size_limit; + source->dumpfile_time_limit = mountinfo->dumpfile_time_limit; + source->dumpfile_interpolation = mountinfo->dumpfile_interpolation; } else { - source->dumpfile_size_limit = 0; - source->dumpfile_time_limit = 0; + source->dumpfile_size_limit = 0; + source->dumpfile_time_limit = 0; + source->dumpfile_interpolation = INTERPOLATION_DEFAULT; } diff --git a/src/source.h b/src/source.h index cb552307..077917d6 100644 --- a/src/source.h +++ b/src/source.h @@ -73,6 +73,7 @@ struct source_tag { /* Dumpfile related data */ /* Config */ char *dumpfilename; /* Name of a file to dump incoming stream to */ + interpolation_t dumpfile_interpolation; uint64_t dumpfile_size_limit; unsigned int dumpfile_time_limit; /* Runtime */ diff --git a/src/util.c b/src/util.c index fdce4171..fff724e7 100644 --- a/src/util.c +++ b/src/util.c @@ -39,6 +39,9 @@ #include #endif +#include +#include /* for igloo_ERROR_NONE */ + #include "common/net/sock.h" #include "common/thread/thread.h" @@ -53,6 +56,7 @@ #include "auth.h" #include "acl.h" #include "listensocket.h" +#include "global.h" /* for igloo_instance */ #define CATMODULE "util" @@ -1271,3 +1275,82 @@ int get_line(FILE *file, char *buf, size_t siz) } return 0; } + +bool util_interpolation_uuid(char * buffer, size_t bufferlen, const char *in) +{ + char *random_uuid = NULL; + + if (!buffer || bufferlen < 1 || !in) + return false; + + for (; *in; in++) { + if (*in == '%') { + in++; + switch (*in) { + case '%': + if (!bufferlen) { + free(random_uuid); + return false; + } + + *buffer++ = *in; + bufferlen--; + break; + case 'r': + case 'g': + if (true) { + const char *str; + size_t len; + + switch (*in) { + case 'r': + if (!random_uuid) { + if (igloo_uuid_new_random_cstr(&random_uuid, igloo_instance) != igloo_ERROR_NONE) { + return false; + } + } + str = random_uuid; + break; + case 'g': + str = global_instance_uuid(); + break; + default: + free(random_uuid); + return false; + } + + len = strlen(str); + + if (bufferlen <= len) { + free(random_uuid); + return false; + } + + memcpy(buffer, str, len); + buffer += len; + bufferlen -= len; + } + break; + default: + free(random_uuid); + return false; + } + } else { + if (!bufferlen) { + free(random_uuid); + return false; + } + + *buffer++ = *in; + bufferlen--; + } + } + + free(random_uuid); + + if (bufferlen) { + *buffer = 0; + return true; + } + return false; +} diff --git a/src/util.h b/src/util.h index c525e79b..420fdb49 100644 --- a/src/util.h +++ b/src/util.h @@ -124,4 +124,8 @@ struct tm *localtime_r(const time_t *timep, struct tm *result); char *util_conv_string (const char *string, const char *in_charset, const char *out_charset); int get_line(FILE *file, char *buf, size_t siz); + +/* returns true on successi, when returning false buffer[] is in undefined state. */ +bool util_interpolation_uuid(char * buffer, size_t bufferlen, const char *in); + #endif /* __UTIL_H__ */