From cf6fad00bdbf4f0def0d11ba7b4f76ced0273730 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Thu, 22 Oct 2020 20:09:27 +0000 Subject: [PATCH 01/18] Feature: Added support for a mountpoint identifier --- src/Makefile.am | 2 ++ src/icecasttypes.h | 5 +++ src/main.c | 3 ++ src/navigation.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++ src/navigation.h | 21 ++++++++++++ 5 files changed, 111 insertions(+) create mode 100644 src/navigation.c create mode 100644 src/navigation.h diff --git a/src/Makefile.am b/src/Makefile.am index f8168ac0..8bff44c1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,6 +41,7 @@ noinst_HEADERS = \ xml2json.h \ listensocket.h \ fastevent.h \ + navigation.h \ event.h \ event_log.h \ event_exec.h \ @@ -92,6 +93,7 @@ icecast_SOURCES = \ xml2json.c \ listensocket.c \ fastevent.c \ + navigation.c \ format.c \ format_ogg.c \ format_mp3.c \ diff --git a/src/icecasttypes.h b/src/icecasttypes.h index f0c643c1..8a4c113b 100644 --- a/src/icecasttypes.h +++ b/src/icecasttypes.h @@ -126,6 +126,10 @@ typedef struct listensocket_tag listensocket_t; typedef struct digest_tag digest_t; +/* ---[ navigation.[ch] ]--- */ + +typedef struct mount_identifier_tag mount_identifier_t; + /* ---[ refobject.[ch] ]--- */ typedef struct refobject_base_tag refobject_base_t; @@ -142,6 +146,7 @@ typedef union __attribute__ ((__transparent_union__)) { listensocket_container_t *listensocket_container; listensocket_t *listensocket; digest_t *digest; + mount_identifier_t *mount_identifier; } refobject_t; #else typedef void * refobject_t; diff --git a/src/main.c b/src/main.c index 10a54a31..aecde897 100644 --- a/src/main.c +++ b/src/main.c @@ -80,6 +80,7 @@ #include "listensocket.h" #include "fastevent.h" #include "prng.h" +#include "navigation.h" #include @@ -146,6 +147,7 @@ static void initialize_subsystems(void) log_initialize(); thread_initialize(); prng_initialize(); + navigation_initialize(); global_initialize(); #ifndef FASTEVENT_ENABLED fastevent_initialize(); @@ -186,6 +188,7 @@ static void shutdown_subsystems(void) refobject_unref(fastevent_reg); fastevent_shutdown(); #endif + navigation_shutdown(); prng_shutdown(); global_shutdown(); thread_shutdown(); diff --git a/src/navigation.c b/src/navigation.c new file mode 100644 index 00000000..7d81db84 --- /dev/null +++ b/src/navigation.c @@ -0,0 +1,80 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2020, Philipp "ph3-der-loewe" Schafft + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "common/avl/avl.h" + +#include "navigation.h" + +#include "logging.h" +#define CATMODULE "navigation" + +struct mount_identifier_tag { + /* base object */ + refobject_base_t __base; +}; + +REFOBJECT_DEFINE_TYPE(mount_identifier_t); + +static avl_tree *mount_identifier_list; + +static int mount_identifier_compare(void *compare_arg, void *a, void *b) +{ + const char *id_a, *id_b; + + id_a = refobject_get_name(a); + id_b = refobject_get_name(b); + + if (!id_a || !id_b || id_a == id_b) { + return 0; + } else { + return strcmp(id_a, id_b); + } +} + +void navigation_initialize(void) +{ + mount_identifier_list = avl_tree_new(mount_identifier_compare, NULL); +} + +void navigation_shutdown(void) +{ + avl_tree_free(mount_identifier_list, (avl_free_key_fun_type)refobject_unref); +} + + +mount_identifier_t * mount_identifier_new(const char *mount) +{ + mount_identifier_t *n; + void *result; + + if (!mount) + return NULL; + + n = refobject_new_ext(mount_identifier_t, NULL, mount, NULL); + if (!n) + return NULL; + + avl_tree_wlock(mount_identifier_list); + if (avl_get_by_key(mount_identifier_list, n, &result) == 0) { + refobject_unref(n); + n = result; + refobject_ref(n); + } else { + refobject_ref(n); + avl_insert(mount_identifier_list, n); + } + avl_tree_unlock(mount_identifier_list); + + return n; +} diff --git a/src/navigation.h b/src/navigation.h new file mode 100644 index 00000000..4d468b64 --- /dev/null +++ b/src/navigation.h @@ -0,0 +1,21 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2020, Philipp "ph3-der-loewe" Schafft + */ + +#ifndef __NAVIGATION_H__ +#define __NAVIGATION_H__ + +#include "refobject.h" + +REFOBJECT_FORWARD_TYPE(mount_identifier_t); + +void navigation_initialize(void); +void navigation_shutdown(void); + +mount_identifier_t * mount_identifier_new(const char *mount); + +#endif From 6c1233402d4a87896f30ceb393f3d2ef8adc17a5 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 24 Oct 2020 07:56:12 +0000 Subject: [PATCH 02/18] Update: As of now we have no weak refs, so not store mount identifier in a tree --- src/navigation.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/navigation.c b/src/navigation.c index 7d81db84..abc93a01 100644 --- a/src/navigation.c +++ b/src/navigation.c @@ -26,8 +26,6 @@ struct mount_identifier_tag { REFOBJECT_DEFINE_TYPE(mount_identifier_t); -static avl_tree *mount_identifier_list; - static int mount_identifier_compare(void *compare_arg, void *a, void *b) { const char *id_a, *id_b; @@ -44,19 +42,16 @@ static int mount_identifier_compare(void *compare_arg, void *a, void *b) void navigation_initialize(void) { - mount_identifier_list = avl_tree_new(mount_identifier_compare, NULL); } void navigation_shutdown(void) { - avl_tree_free(mount_identifier_list, (avl_free_key_fun_type)refobject_unref); } mount_identifier_t * mount_identifier_new(const char *mount) { mount_identifier_t *n; - void *result; if (!mount) return NULL; @@ -65,16 +60,5 @@ mount_identifier_t * mount_identifier_new(const char *mount) if (!n) return NULL; - avl_tree_wlock(mount_identifier_list); - if (avl_get_by_key(mount_identifier_list, n, &result) == 0) { - refobject_unref(n); - n = result; - refobject_ref(n); - } else { - refobject_ref(n); - avl_insert(mount_identifier_list, n); - } - avl_tree_unlock(mount_identifier_list); - return n; } From 673dfb734cf26134c0d9ef047c09299fb139ba13 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 24 Oct 2020 07:59:05 +0000 Subject: [PATCH 03/18] Feature: Added mount_identifier_get_mount() and mount_identifier_compare() --- src/navigation.c | 11 ++++++++--- src/navigation.h | 4 +++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/navigation.c b/src/navigation.c index abc93a01..e1518d84 100644 --- a/src/navigation.c +++ b/src/navigation.c @@ -26,12 +26,12 @@ struct mount_identifier_tag { REFOBJECT_DEFINE_TYPE(mount_identifier_t); -static int mount_identifier_compare(void *compare_arg, void *a, void *b) +static int mount_identifier_compare__for_tree(void *compare_arg, void *a, void *b) { const char *id_a, *id_b; - id_a = refobject_get_name(a); - id_b = refobject_get_name(b); + id_a = mount_identifier_get_mount(a); + id_b = mount_identifier_get_mount(b); if (!id_a || !id_b || id_a == id_b) { return 0; @@ -62,3 +62,8 @@ mount_identifier_t * mount_identifier_new(const char *mount) return n; } + +int mount_identifier_compare(mount_identifier_t *a, mount_identifier_t *b) +{ + return mount_identifier_compare__for_tree(NULL, a, b); +} diff --git a/src/navigation.h b/src/navigation.h index 4d468b64..b42d7370 100644 --- a/src/navigation.h +++ b/src/navigation.h @@ -16,6 +16,8 @@ REFOBJECT_FORWARD_TYPE(mount_identifier_t); void navigation_initialize(void); void navigation_shutdown(void); -mount_identifier_t * mount_identifier_new(const char *mount); +mount_identifier_t * mount_identifier_new(const char *mount); +#define mount_identifier_get_mount(identifier) refobject_get_name((identifier)) +int mount_identifier_compare(mount_identifier_t *a, mount_identifier_t *b); #endif From 31659b3ed1413fb15d81e76858dc5b877d0a494c Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 24 Oct 2020 08:06:08 +0000 Subject: [PATCH 04/18] Feature: Added identifier to source_t --- src/source.c | 3 +++ src/source.h | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/source.c b/src/source.c index 69af0046..93851cd2 100644 --- a/src/source.c +++ b/src/source.c @@ -60,6 +60,7 @@ #include "event.h" #include "slave.h" #include "acl.h" +#include "navigation.h" #undef CATMODULE #define CATMODULE "source" @@ -105,6 +106,7 @@ source_t *source_reserve (const char *mount) /* make duplicates for strings or similar */ src->mount = strdup(mount); + src->identifier = mount_identifier_new(mount); src->max_listeners = -1; thread_mutex_create(&src->lock); @@ -315,6 +317,7 @@ void source_free_source (source_t *source) /* make sure all YP entries have gone */ yp_remove (source->mount); + refobject_unref(source->identifier); free (source->mount); free (source); diff --git a/src/source.h b/src/source.h index e35e9d90..51babaa3 100644 --- a/src/source.h +++ b/src/source.h @@ -33,7 +33,8 @@ struct source_tag { http_parser_t *parser; time_t client_stats_update; - char *mount; + char *mount; // TODO: Should we at some point migrate away from this to only use identifier? + mount_identifier_t *identifier; /* If this source drops, try to move all clients to this fallback */ char *fallback_mount; From 965c5e52d067fc8bc5457052c18d49b881630bb1 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 24 Oct 2020 08:54:48 +0000 Subject: [PATCH 05/18] Feature: Added support for a navigation (mountpoint) history --- src/navigation.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++-- src/navigation.h | 21 ++++++++++++ 2 files changed, 106 insertions(+), 2 deletions(-) diff --git a/src/navigation.c b/src/navigation.c index e1518d84..dfdba864 100644 --- a/src/navigation.c +++ b/src/navigation.c @@ -10,8 +10,6 @@ #include #endif -#include - #include "common/avl/avl.h" #include "navigation.h" @@ -67,3 +65,88 @@ int mount_identifier_compare(mount_identifier_t *a, mount_id { return mount_identifier_compare__for_tree(NULL, a, b); } + +static inline int navigation_history_pop(navigation_history_t *history) +{ + if (history->fill == 0) + return 0; + history->fill--; + refobject_unref(history->history[history->fill]); + history->history[history->fill] = NULL; + return 1; +} + +static inline int navigation_history_push(navigation_history_t *history, mount_identifier_t *identifier) +{ + if (refobject_ref(identifier) != 0) + return -1; + + if (history->fill == (sizeof(history->history)/sizeof(*history->history))) { + refobject_unref(history->history[0]); + memmove(history->history, &(history->history[1]), sizeof(history->history) - sizeof(*history->history)); + history->fill--; + } + + history->history[history->fill++] = identifier; + + return 0; +} + +void navigation_history_clear(navigation_history_t *history) +{ + if (!history) + return; + while (navigation_history_pop(history)); +} + +mount_identifier_t * navigation_history_get_up(navigation_history_t *history) +{ + if (!history) + return NULL; + + if (history->fill < 2) + return NULL; + + if (refobject_ref(history->history[history->fill - 2]) != 0) + return NULL; + + return history->history[history->fill - 2]; +} + +int navigation_history_navigate_to(navigation_history_t *history, mount_identifier_t *identifier, navigation_direction_t direction) +{ + if (!history || !identifier) + return -1; + + switch (direction) { + case NAVIGATION_DIRECTION_UP: + if (history->fill < 2) + return -1; + if (mount_identifier_compare(history->history[history->fill - 2], identifier) != 0) + return -1; + return navigation_history_pop(history); + break; + case NAVIGATION_DIRECTION_DOWN: + return navigation_history_push(history, identifier); + break; + case NAVIGATION_DIRECTION_REPLACE_CURRENT: + if (history->fill == 0) { + return navigation_history_push(history, identifier); + } else { + if (refobject_ref(identifier) != 0) + return -1; + refobject_unref(history->history[history->fill - 1]); + history->history[history->fill - 1] = identifier; + return 0; + } + break; + case NAVIGATION_DIRECTION_REPLACE_ALL: + navigation_history_clear(history); + if (history->fill != 0) + return -1; + return navigation_history_push(history, identifier); + break; + } + + return -1; +} diff --git a/src/navigation.h b/src/navigation.h index b42d7370..32e97341 100644 --- a/src/navigation.h +++ b/src/navigation.h @@ -9,8 +9,24 @@ #ifndef __NAVIGATION_H__ #define __NAVIGATION_H__ +#include + #include "refobject.h" +#define MAX_NAVIGATION_HISTORY_SIZE 8 + +typedef struct { + mount_identifier_t *history[MAX_NAVIGATION_HISTORY_SIZE]; + size_t fill; +} navigation_history_t; + +typedef enum { + NAVIGATION_DIRECTION_UP, + NAVIGATION_DIRECTION_DOWN, + NAVIGATION_DIRECTION_REPLACE_CURRENT, + NAVIGATION_DIRECTION_REPLACE_ALL +} navigation_direction_t; + REFOBJECT_FORWARD_TYPE(mount_identifier_t); void navigation_initialize(void); @@ -20,4 +36,9 @@ mount_identifier_t * mount_identifier_new(const char *mount); #define mount_identifier_get_mount(identifier) refobject_get_name((identifier)) int mount_identifier_compare(mount_identifier_t *a, mount_identifier_t *b); +#define navigation_history_init(history) memset((history), 0, sizeof(navigation_history_t)) +void navigation_history_clear(navigation_history_t *history); +mount_identifier_t * navigation_history_get_up(navigation_history_t *history); +int navigation_history_navigate_to(navigation_history_t *history, mount_identifier_t *identifier, navigation_direction_t direction); + #endif From d2f7b9c1123994ed67430a97b76ede0eef027902 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 24 Oct 2020 11:14:49 +0000 Subject: [PATCH 06/18] Fix: Use correct constructor --- src/navigation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/navigation.c b/src/navigation.c index dfdba864..b870fd63 100644 --- a/src/navigation.c +++ b/src/navigation.c @@ -54,7 +54,7 @@ mount_identifier_t * mount_identifier_new(const char *mount) if (!mount) return NULL; - n = refobject_new_ext(mount_identifier_t, NULL, mount, NULL); + n = refobject_new__new(mount_identifier_t, NULL, mount, NULL); if (!n) return NULL; From af35bd10d0737ff05fe0d628e7c5c6b20291e17e Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 24 Oct 2020 11:24:08 +0000 Subject: [PATCH 07/18] Feature: Added some devel debug logging --- src/navigation.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/navigation.c b/src/navigation.c index b870fd63..3eca889a 100644 --- a/src/navigation.c +++ b/src/navigation.c @@ -24,6 +24,18 @@ struct mount_identifier_tag { REFOBJECT_DEFINE_TYPE(mount_identifier_t); +static inline const char * navigation_direction_id2str(navigation_direction_t dir) +{ + switch (dir) { + case NAVIGATION_DIRECTION_UP: return "up"; break; + case NAVIGATION_DIRECTION_DOWN: return "down"; break; + case NAVIGATION_DIRECTION_REPLACE_CURRENT: return "replace-current"; break; + case NAVIGATION_DIRECTION_REPLACE_ALL: return "replace-all"; break; + } + + return NULL; +} + static int mount_identifier_compare__for_tree(void *compare_arg, void *a, void *b) { const char *id_a, *id_b; @@ -115,6 +127,8 @@ mount_identifier_t * navigation_history_get_up(navigation_history_t *history) int navigation_history_navigate_to(navigation_history_t *history, mount_identifier_t *identifier, navigation_direction_t direction) { + ICECAST_LOG_DDEBUG("Called with history=%p, identifier=%p (%#H), direction=%s", history, identifier, mount_identifier_get_mount(identifier), navigation_direction_id2str(direction)); + if (!history || !identifier) return -1; From 5c504ec3dd52e5b30c0809fc555ccb10d1277daa Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 24 Oct 2020 11:25:42 +0000 Subject: [PATCH 08/18] Feature: Added mount history to client and attach the client on initial attach --- src/client.c | 2 ++ src/client.h | 4 ++++ src/connection.c | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/src/client.c b/src/client.c index daa3fefc..97649b8e 100644 --- a/src/client.c +++ b/src/client.c @@ -164,6 +164,7 @@ int client_create(client_t **c_ptr, connection_t *con, http_parser_t *parser) client->refbuf->len = 0; /* force reader code to ignore buffer contents */ client->pos = 0; client->write_to_client = format_generic_write_to_client; + navigation_history_init(&(client->history)); *c_ptr = client; avl_tree_wlock(global_client_list); @@ -344,6 +345,7 @@ void client_destroy(client_t *client) free(client->password); free(client->role); acl_release(client->acl); + navigation_history_clear(&(client->history)); free(client); } diff --git a/src/client.h b/src/client.h index c440a52c..0d01ecfc 100644 --- a/src/client.h +++ b/src/client.h @@ -23,6 +23,7 @@ #include "common/httpp/encoding.h" #include "icecasttypes.h" +#include "navigation.h" #include "errors.h" #include "refbuf.h" #include "module.h" @@ -114,6 +115,9 @@ struct _client_tag { module_t *handler_module; char *handler_function; + /* History of navigated mount points */ + navigation_history_t history; + /* is client getting intro data */ long intro_offset; diff --git a/src/connection.c b/src/connection.c index 373e5cd1..807ce3dd 100644 --- a/src/connection.c +++ b/src/connection.c @@ -61,6 +61,7 @@ #include "refobject.h" #include "listensocket.h" #include "fastevent.h" +#include "navigation.h" #define CATMODULE "connection" @@ -966,6 +967,9 @@ static void __add_listener_to_source(source_t *source, client_t *client) client->refbuf->len = PER_CLIENT_REFBUF_SIZE; memset(client->refbuf->data, 0, PER_CLIENT_REFBUF_SIZE); + if (navigation_history_navigate_to(&(client->history), source->identifier, NAVIGATION_DIRECTION_REPLACE_ALL) != 0) + ICECAST_LOG_ERROR("Can not change history: navigation of client=%p{.con.id=%llu, ...} to source=%p{.mount=%#H, ...} failed", client, (unsigned long long int)client->con->id, source, source->mount); + /* lets add the client to the active list */ avl_tree_wlock(source->pending_tree); avl_insert(source->pending_tree, client); From 8a91113028f79b6523a98ee2c375e33be3046ae4 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sun, 25 Oct 2020 09:05:28 +0000 Subject: [PATCH 09/18] Feature: Correctly navigate clients between mounts --- src/connection.c | 7 ++++--- src/navigation.c | 10 ++++++++++ src/slave.c | 2 +- src/source.c | 15 ++++++++------- src/source.h | 2 +- 5 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/connection.c b/src/connection.c index 807ce3dd..3ad7e8e2 100644 --- a/src/connection.c +++ b/src/connection.c @@ -936,6 +936,9 @@ static void __add_listener_to_source(source_t *source, client_t *client) { size_t loop = 10; + if (navigation_history_navigate_to(&(client->history), source->identifier, NAVIGATION_DIRECTION_REPLACE_ALL) != 0) + ICECAST_LOG_ERROR("Can not change history: navigation of client=%p{.con.id=%llu, ...} to source=%p{.mount=%#H, ...} failed", client, (unsigned long long int)client->con->id, source, source->mount); + do { ICECAST_LOG_DEBUG("max on %s is %ld (cur %lu)", source->mount, source->max_listeners, source->listeners); @@ -954,6 +957,7 @@ static void __add_listener_to_source(source_t *source, client_t *client) } ICECAST_LOG_INFO("stream full, trying %s", next->mount); source = next; + navigation_history_navigate_to(&(client->history), source->identifier, NAVIGATION_DIRECTION_DOWN); loop--; continue; } @@ -967,9 +971,6 @@ static void __add_listener_to_source(source_t *source, client_t *client) client->refbuf->len = PER_CLIENT_REFBUF_SIZE; memset(client->refbuf->data, 0, PER_CLIENT_REFBUF_SIZE); - if (navigation_history_navigate_to(&(client->history), source->identifier, NAVIGATION_DIRECTION_REPLACE_ALL) != 0) - ICECAST_LOG_ERROR("Can not change history: navigation of client=%p{.con.id=%llu, ...} to source=%p{.mount=%#H, ...} failed", client, (unsigned long long int)client->con->id, source, source->mount); - /* lets add the client to the active list */ avl_tree_wlock(source->pending_tree); avl_insert(source->pending_tree, client); diff --git a/src/navigation.c b/src/navigation.c index 3eca889a..f93597da 100644 --- a/src/navigation.c +++ b/src/navigation.c @@ -90,6 +90,9 @@ static inline int navigation_history_pop(navigation_history_t *history) static inline int navigation_history_push(navigation_history_t *history, mount_identifier_t *identifier) { + if (history->fill > 0 && mount_identifier_compare(history->history[history->fill - 1], identifier) == 0) + return 0; + if (refobject_ref(identifier) != 0) return -1; @@ -132,6 +135,9 @@ int navigation_history_navigate_to(navigation_history_t *his if (!history || !identifier) return -1; + if (direction == NAVIGATION_DIRECTION_UP && history->fill < 2) + direction = NAVIGATION_DIRECTION_REPLACE_ALL; + switch (direction) { case NAVIGATION_DIRECTION_UP: if (history->fill < 2) @@ -147,6 +153,10 @@ int navigation_history_navigate_to(navigation_history_t *his if (history->fill == 0) { return navigation_history_push(history, identifier); } else { + if (history->fill > 1 && mount_identifier_compare(history->history[history->fill - 2], identifier) == 0) { + return navigation_history_pop(history); + } + if (refobject_ref(identifier) != 0) return -1; refobject_unref(history->history[history->fill - 1]); diff --git a/src/slave.c b/src/slave.c index cb4a5f7f..361d7083 100644 --- a/src/slave.c +++ b/src/slave.c @@ -469,7 +469,7 @@ static void *start_relay_stream (void *arg) fallback_source = source_find_mount(relay->source->fallback_mount); if (fallback_source != NULL) - source_move_clients(relay->source, fallback_source, NULL); + source_move_clients(relay->source, fallback_source, NULL, NAVIGATION_DIRECTION_DOWN); avl_tree_unlock(global.source_tree); } diff --git a/src/source.c b/src/source.c index 93851cd2..f16d6b46 100644 --- a/src/source.c +++ b/src/source.c @@ -345,7 +345,7 @@ client_t *source_find_client(source_t *source, connection_id_t id) return NULL; } -static inline void source_move_clients__single(source_t *source, avl_tree *from, avl_tree *to, client_t *client) { +static inline void source_move_clients__single(source_t *source, source_t *dest, avl_tree *from, avl_tree *to, client_t *client, navigation_direction_t direction) { avl_delete(from, client, NULL); /* when switching a client to a different queue, be wary of the @@ -360,6 +360,7 @@ static inline void source_move_clients__single(source_t *source, avl_tree *from, } avl_insert(to, (void *)client); + navigation_history_navigate_to(&(client->history), dest->identifier, direction); } /* Move clients from source to dest provided dest is running @@ -367,7 +368,7 @@ static inline void source_move_clients__single(source_t *source, avl_tree *from, * The only lock that should be held when this is called is the * source tree lock */ -void source_move_clients(source_t *source, source_t *dest, connection_id_t *id) +void source_move_clients(source_t *source, source_t *dest, connection_id_t *id, navigation_direction_t direction) { unsigned long count = 0; if (strcmp(source->mount, dest->mount) == 0) { @@ -414,7 +415,7 @@ void source_move_clients(source_t *source, source_t *dest, connection_id_t *id) fakeclient.con->id = *id; if (avl_get_by_key(source->client_tree, &fakeclient, &result) == 0) { - source_move_clients__single(source, source->client_tree, dest->pending_tree, result); + source_move_clients__single(source, dest, source->client_tree, dest->pending_tree, result, direction); count++; } } else { @@ -422,7 +423,7 @@ void source_move_clients(source_t *source, source_t *dest, connection_id_t *id) avl_node *node = avl_get_first(source->pending_tree); if (node == NULL) break; - source_move_clients__single(source, source->pending_tree, dest->pending_tree, node->key); + source_move_clients__single(source, dest, source->pending_tree, dest->pending_tree, node->key, direction); count++; } @@ -430,7 +431,7 @@ void source_move_clients(source_t *source, source_t *dest, connection_id_t *id) avl_node *node = avl_get_first(source->client_tree); if (node == NULL) break; - source_move_clients__single(source, source->client_tree, dest->pending_tree, node->key); + source_move_clients__single(source, dest, source->client_tree, dest->pending_tree, node->key, direction); count++; } } @@ -667,7 +668,7 @@ static void source_init (source_t *source) fallback_source = source_find_mount(source->fallback_mount); if (fallback_source) - source_move_clients(fallback_source, source, NULL); + source_move_clients(fallback_source, source, NULL, NAVIGATION_DIRECTION_UP); avl_tree_unlock(global.source_tree); } @@ -866,7 +867,7 @@ static void source_shutdown (source_t *source) fallback_source = source_find_mount(source->fallback_mount); if (fallback_source != NULL) - source_move_clients(source, fallback_source, NULL); + source_move_clients(source, fallback_source, NULL, NAVIGATION_DIRECTION_DOWN); avl_tree_unlock(global.source_tree); } diff --git a/src/source.h b/src/source.h index 51babaa3..42a380a5 100644 --- a/src/source.h +++ b/src/source.h @@ -97,7 +97,7 @@ source_t *source_find_mount_raw(const char *mount); client_t *source_find_client(source_t *source, connection_id_t id); int source_compare_sources(void *arg, void *a, void *b); void source_free_source(source_t *source); -void source_move_clients(source_t *source, source_t *dest, connection_id_t *id); +void source_move_clients(source_t *source, source_t *dest, connection_id_t *id, navigation_direction_t direction); int source_remove_client(void *key); void source_main(source_t *source); void source_recheck_mounts (int update_all); From b5b5e9cc075eb39a2ed03652c92a31eaf675fa62 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sun, 25 Oct 2020 13:04:17 +0000 Subject: [PATCH 10/18] Feature: Make navigation_direction_to_str() public --- src/navigation.c | 2 +- src/navigation.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/navigation.c b/src/navigation.c index f93597da..5e2a4bd7 100644 --- a/src/navigation.c +++ b/src/navigation.c @@ -24,7 +24,7 @@ struct mount_identifier_tag { REFOBJECT_DEFINE_TYPE(mount_identifier_t); -static inline const char * navigation_direction_id2str(navigation_direction_t dir) +const char * navigation_direction_to_str(navigation_direction_t dir) { switch (dir) { case NAVIGATION_DIRECTION_UP: return "up"; break; diff --git a/src/navigation.h b/src/navigation.h index 32e97341..f59baee5 100644 --- a/src/navigation.h +++ b/src/navigation.h @@ -29,6 +29,8 @@ typedef enum { REFOBJECT_FORWARD_TYPE(mount_identifier_t); +const char * navigation_direction_to_str(navigation_direction_t dir); + void navigation_initialize(void); void navigation_shutdown(void); From 8e224f45c2833ac9e590084daf88846b4bf20a9f Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sun, 25 Oct 2020 13:04:33 +0000 Subject: [PATCH 11/18] Fix: Corrected invalid return value --- src/navigation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/navigation.c b/src/navigation.c index 5e2a4bd7..1e2aedc8 100644 --- a/src/navigation.c +++ b/src/navigation.c @@ -85,7 +85,7 @@ static inline int navigation_history_pop(navigation_history_t *history) history->fill--; refobject_unref(history->history[history->fill]); history->history[history->fill] = NULL; - return 1; + return 0; } static inline int navigation_history_push(navigation_history_t *history, mount_identifier_t *identifier) From 2e148986f9596870c84a0dabdcb9b76dbf9644d6 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sun, 25 Oct 2020 13:04:59 +0000 Subject: [PATCH 12/18] Feature: Improved error logging --- src/navigation.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/navigation.c b/src/navigation.c index 1e2aedc8..027f8569 100644 --- a/src/navigation.c +++ b/src/navigation.c @@ -93,8 +93,10 @@ static inline int navigation_history_push(navigation_history_t *history, mount_i if (history->fill > 0 && mount_identifier_compare(history->history[history->fill - 1], identifier) == 0) return 0; - if (refobject_ref(identifier) != 0) + if (refobject_ref(identifier) != 0) { + ICECAST_LOG_ERROR("Can not reference identifier=%p, BAD.", identifier); return -1; + } if (history->fill == (sizeof(history->history)/sizeof(*history->history))) { refobject_unref(history->history[0]); @@ -130,7 +132,7 @@ mount_identifier_t * navigation_history_get_up(navigation_history_t *history) int navigation_history_navigate_to(navigation_history_t *history, mount_identifier_t *identifier, navigation_direction_t direction) { - ICECAST_LOG_DDEBUG("Called with history=%p, identifier=%p (%#H), direction=%s", history, identifier, mount_identifier_get_mount(identifier), navigation_direction_id2str(direction)); + ICECAST_LOG_DDEBUG("Called with history=%p, identifier=%p (%#H), direction=%s", history, identifier, mount_identifier_get_mount(identifier), navigation_direction_to_str(direction)); if (!history || !identifier) return -1; @@ -157,8 +159,10 @@ int navigation_history_navigate_to(navigation_history_t *his return navigation_history_pop(history); } - if (refobject_ref(identifier) != 0) + if (refobject_ref(identifier) != 0) { + ICECAST_LOG_ERROR("Can not reference identifier=%p, BAD.", identifier); return -1; + } refobject_unref(history->history[history->fill - 1]); history->history[history->fill - 1] = identifier; return 0; From c60a2113c98233d02cf6aa8d94003eef503835ed Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sun, 25 Oct 2020 13:07:27 +0000 Subject: [PATCH 13/18] Feature: Made fallback_override an enum --- src/cfgfile.c | 25 ++++++++++++++++++++++--- src/cfgfile.h | 8 +++++++- src/slave.c | 2 +- src/source.c | 20 ++++++++++++++++---- src/source.h | 2 +- 5 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/cfgfile.c b/src/cfgfile.c index 39b279c3..68dbf8e7 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -217,6 +217,25 @@ static listener_type_t config_str_to_listener_type(const char *str) } } +static fallback_override_t config_str_to_fallback_override_t(const char *str) +{ + if (!str || !*str || strcmp(str, "none") == 0) { + return FALLBACK_OVERRIDE_NONE; + } else if (strcasecmp(str, "all") == 0) { + return FALLBACK_OVERRIDE_ALL; + } else if (strcasecmp(str, "own") == 0) { + return FALLBACK_OVERRIDE_OWN; + } else { + if (util_str_to_bool(str)) { + ICECAST_LOG_WARN("Old style fallback override setting. Please replace %#H with \"all\".", str); + return FALLBACK_OVERRIDE_ALL; + } else { + ICECAST_LOG_WARN("Old style fallback override setting. Please replace %#H with \"none\".", str); + return FALLBACK_OVERRIDE_NONE; + } + } +} + char * config_href_to_id(const char *href) { if (!href || !*href) @@ -1538,7 +1557,7 @@ static void _parse_mount(xmlDocPtr doc, __read_int(doc, node, &mount->mp3_meta_interval, " must not be empty."); } else if (xmlStrcmp(node->name, XMLSTR("fallback-override")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); - mount->fallback_override = util_str_to_bool(tmp); + mount->fallback_override = config_str_to_fallback_override_t(tmp); if(tmp) xmlFree(tmp); } else if (xmlStrcmp(node->name, XMLSTR("no-mount")) == 0) { @@ -1695,7 +1714,7 @@ static void _parse_mount(xmlDocPtr doc, current = current->next; } - if (!mount->fallback_mount && (mount->fallback_when_full || mount->fallback_override)) { + if (!mount->fallback_mount && (mount->fallback_when_full || mount->fallback_override != FALLBACK_OVERRIDE_NONE)) { ICECAST_LOG_WARN("Config for mount %s contains fallback options " "but no fallback mount.", mount->mountname); } @@ -2675,7 +2694,7 @@ static void merge_mounts(mount_proxy * dst, mount_proxy * src) dst->max_listeners = src->max_listeners; if (!dst->fallback_mount) dst->fallback_mount = (char*)xmlStrdup((xmlChar*)src->fallback_mount); - if (!dst->fallback_override) + if (dst->fallback_override == FALLBACK_OVERRIDE_NONE) dst->fallback_override = src->fallback_override; if (!dst->no_mount) dst->no_mount = src->no_mount; diff --git a/src/cfgfile.h b/src/cfgfile.h index 3f621a6d..d980ccbf 100644 --- a/src/cfgfile.h +++ b/src/cfgfile.h @@ -67,6 +67,12 @@ typedef enum _mount_type { MOUNT_TYPE_DEFAULT } mount_type; +typedef enum { + FALLBACK_OVERRIDE_NONE = 0, + FALLBACK_OVERRIDE_ALL, + FALLBACK_OVERRIDE_OWN +} fallback_override_t; + typedef struct _mount_proxy { /* The mountpoint this proxy is used for */ char *mountname; @@ -89,7 +95,7 @@ typedef struct _mount_proxy { /* When this source arrives, do we steal back * clients from the fallback? */ - int fallback_override; + fallback_override_t fallback_override; /* Do we permit direct requests of this mountpoint? * (or only indirect, through fallbacks) */ diff --git a/src/slave.c b/src/slave.c index 361d7083..f108f0c8 100644 --- a/src/slave.c +++ b/src/slave.c @@ -538,7 +538,7 @@ static void check_relay_stream (relay_t *relay) { relay->source->on_demand = relay->config->on_demand; - if (source->fallback_mount && source->fallback_override) + if (source->fallback_mount && source->fallback_override != FALLBACK_OVERRIDE_NONE) { source_t *fallback; avl_tree_rlock (global.source_tree); diff --git a/src/source.c b/src/source.c index f16d6b46..ba623e6c 100644 --- a/src/source.c +++ b/src/source.c @@ -660,15 +660,27 @@ static void source_init (source_t *source) ** loop or jingle track or whatever the fallback is used for */ - if (source->fallback_override && source->fallback_mount) - { + ICECAST_LOG_DDEBUG("source=%p{.mount=%#H, .fallback_override=%i, .fallback_mount=%#H, ...}", source, source->mount, (int)source->fallback_override, source->fallback_mount); + if (source->fallback_override != FALLBACK_OVERRIDE_NONE && source->fallback_mount) { source_t *fallback_source; avl_tree_rlock(global.source_tree); fallback_source = source_find_mount(source->fallback_mount); - if (fallback_source) - source_move_clients(fallback_source, source, NULL, NAVIGATION_DIRECTION_UP); + if (fallback_source) { + ICECAST_LOG_DDEBUG("source=%p{.mount=%#H, .fallback_override=%i, ...}, fallback_source=%p{.mount=%#H, ...}", source, source->mount, (int)source->fallback_override, fallback_source, fallback_source->mount); + switch (source->fallback_override) { + case FALLBACK_OVERRIDE_NONE: + /* no-op */ + break; + case FALLBACK_OVERRIDE_ALL: + source_move_clients(fallback_source, source, NULL, NAVIGATION_DIRECTION_REPLACE_CURRENT); + break; + case FALLBACK_OVERRIDE_OWN: + source_move_clients(fallback_source, source, NULL, NAVIGATION_DIRECTION_UP); + break; + } + } avl_tree_unlock(global.source_tree); } diff --git a/src/source.h b/src/source.h index 42a380a5..55b55185 100644 --- a/src/source.h +++ b/src/source.h @@ -61,7 +61,7 @@ struct source_tag { unsigned long prev_listeners; long max_listeners; int yp_public; - int fallback_override; + fallback_override_t fallback_override; int fallback_when_full; int shoutcast_compat; From 68ace66bd30441685f8885c19db70d3d015ed200 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sun, 25 Oct 2020 13:08:21 +0000 Subject: [PATCH 14/18] Feature: Only move clients that allow navigation according to their history and direction --- src/source.c | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/src/source.c b/src/source.c index ba623e6c..a88f7541 100644 --- a/src/source.c +++ b/src/source.c @@ -345,7 +345,13 @@ client_t *source_find_client(source_t *source, connection_id_t id) return NULL; } -static inline void source_move_clients__single(source_t *source, source_t *dest, avl_tree *from, avl_tree *to, client_t *client, navigation_direction_t direction) { +static inline int source_move_clients__single(source_t *source, source_t *dest, avl_tree *from, avl_tree *to, client_t *client, navigation_direction_t direction) { + if (navigation_history_navigate_to(&(client->history), dest->identifier, direction) != 0) { + ICECAST_LOG_DWARN("Can not change history: navigation of client=%p{.con->id=%llu, ...} from source=%p{.mount=%#H, ...} to dest=%p{.mount=%#H, ...} with direction %s failed", + client, (unsigned long long int)client->con->id, source, source->mount, dest, dest->mount, navigation_direction_to_str(direction)); + return -1; + } + avl_delete(from, client, NULL); /* when switching a client to a different queue, be wary of the @@ -360,7 +366,7 @@ static inline void source_move_clients__single(source_t *source, source_t *dest, } avl_insert(to, (void *)client); - navigation_history_navigate_to(&(client->history), dest->identifier, direction); + return 0; } /* Move clients from source to dest provided dest is running @@ -415,24 +421,30 @@ void source_move_clients(source_t *source, source_t *dest, connection_id_t *id, fakeclient.con->id = *id; if (avl_get_by_key(source->client_tree, &fakeclient, &result) == 0) { - source_move_clients__single(source, dest, source->client_tree, dest->pending_tree, result, direction); - count++; + if (source_move_clients__single(source, dest, source->client_tree, dest->pending_tree, result, direction) == 0) + count++; } } else { - while (1) { - avl_node *node = avl_get_first(source->pending_tree); - if (node == NULL) - break; - source_move_clients__single(source, dest, source->pending_tree, dest->pending_tree, node->key, direction); - count++; + avl_node *next; + + next = avl_get_first(source->pending_tree); + while (next) { + avl_node *node = next; + + next = avl_get_next(next); + + if (source_move_clients__single(source, dest, source->pending_tree, dest->pending_tree, node->key, direction) == 0) + count++; } - while (1) { - avl_node *node = avl_get_first(source->client_tree); - if (node == NULL) - break; - source_move_clients__single(source, dest, source->client_tree, dest->pending_tree, node->key, direction); - count++; + next = avl_get_first(source->client_tree); + while (next) { + avl_node *node = next; + + next = avl_get_next(next); + + if (source_move_clients__single(source, dest, source->client_tree, dest->pending_tree, node->key, direction) == 0) + count++; } } From 7474fb8d8d4fd5b0b2f707938b9c2056a2d00a9b Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sun, 8 Nov 2020 18:23:03 +0000 Subject: [PATCH 15/18] Feature: Write correct history on initial attach of client --- src/connection.c | 5 +---- src/source.c | 17 +++++++++++++---- src/source.h | 3 ++- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/connection.c b/src/connection.c index 3ad7e8e2..ff0cb2ea 100644 --- a/src/connection.c +++ b/src/connection.c @@ -936,9 +936,6 @@ static void __add_listener_to_source(source_t *source, client_t *client) { size_t loop = 10; - if (navigation_history_navigate_to(&(client->history), source->identifier, NAVIGATION_DIRECTION_REPLACE_ALL) != 0) - ICECAST_LOG_ERROR("Can not change history: navigation of client=%p{.con.id=%llu, ...} to source=%p{.mount=%#H, ...} failed", client, (unsigned long long int)client->con->id, source, source->mount); - do { ICECAST_LOG_DEBUG("max on %s is %ld (cur %lu)", source->mount, source->max_listeners, source->listeners); @@ -1053,7 +1050,7 @@ static void _handle_get_request(client_t *client) { avl_tree_rlock(global.source_tree); /* let's see if this is a source or just a random fserve file */ - source = source_find_mount(client->uri); + source = source_find_mount_with_history(client->uri, &(client->history)); if (source) { /* true mount */ do { diff --git a/src/source.c b/src/source.c index a88f7541..fdecdd92 100644 --- a/src/source.c +++ b/src/source.c @@ -154,7 +154,7 @@ source_t *source_find_mount_raw(const char *mount) * check the fallback, and so on. Must have a global source lock to call * this function. */ -source_t *source_find_mount(const char *mount) +source_t *source_find_mount_with_history(const char *mount, navigation_history_t *history) { source_t *source = NULL; ice_config_t *config; @@ -166,10 +166,20 @@ source_t *source_find_mount(const char *mount) { source = source_find_mount_raw(mount); - if (source) - { + if (source) { + if (history) + navigation_history_navigate_to(history, source->identifier, NAVIGATION_DIRECTION_DOWN); + if (source->running || source->on_demand) break; + } else { + if (history) { + mount_identifier_t *identifier = mount_identifier_new(mount); + if (identifier) { + navigation_history_navigate_to(history, identifier, NAVIGATION_DIRECTION_DOWN); + refobject_unref(identifier); + } + } } /* we either have a source which is not active (relay) or no source @@ -188,7 +198,6 @@ source_t *source_find_mount(const char *mount) return source; } - int source_compare_sources(void *arg, void *a, void *b) { source_t *srca = (source_t *)a; diff --git a/src/source.h b/src/source.h index 55b55185..9184454d 100644 --- a/src/source.h +++ b/src/source.h @@ -92,7 +92,8 @@ void *source_client_thread (void *arg); void source_client_callback (client_t *client, void *source); void source_update_settings (ice_config_t *config, source_t *source, mount_proxy *mountinfo); void source_clear_source (source_t *source); -source_t *source_find_mount(const char *mount); +#define source_find_mount(mount) source_find_mount_with_history((mount), NULL) +source_t *source_find_mount_with_history(const char *mount, navigation_history_t *history); source_t *source_find_mount_raw(const char *mount); client_t *source_find_client(source_t *source, connection_id_t id); int source_compare_sources(void *arg, void *a, void *b); From 704df45ce570b7f0afc7293ff2dddee3ab466085 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Mon, 9 Nov 2020 20:19:01 +0000 Subject: [PATCH 16/18] Feature: Added support to give navigation direction via admin call for command_move_clients() --- admin/moveclients.xsl | 13 ++++++++++--- src/admin.c | 5 ++++- src/navigation.c | 18 ++++++++++++++++++ src/navigation.h | 1 + 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/admin/moveclients.xsl b/admin/moveclients.xsl index 9328998a..f5806f13 100644 --- a/admin/moveclients.xsl +++ b/admin/moveclients.xsl @@ -26,9 +26,9 @@
- + Move from + + to + with direction +   diff --git a/src/admin.c b/src/admin.c index 5923bd96..8373b52e 100644 --- a/src/admin.c +++ b/src/admin.c @@ -716,6 +716,7 @@ static void command_move_clients(client_t *client, { const char *dest_source; const char *idtext = NULL; + const char *directiontext = NULL; connection_id_t id; source_t *dest; char buf[255]; @@ -730,6 +731,8 @@ static void command_move_clients(client_t *client, } else { idtext = NULL; } + COMMAND_OPTIONAL(client, "direction", directiontext); + ICECAST_LOG_DEBUG("Done optional check (%d)", parameters_passed); if (!parameters_passed) { xmlDocPtr doc = admin_build_sourcelist(source->mount, client, response); @@ -766,7 +769,7 @@ static void command_move_clients(client_t *client, ICECAST_LOG_INFO("source is \"%s\", destination is \"%s\"", source->mount, dest->mount); - source_move_clients(source, dest, idtext ? &id : NULL); + source_move_clients(source, dest, idtext ? &id : NULL, navigation_str_to_direction(directiontext, NAVIGATION_DIRECTION_DOWN)); snprintf(buf, sizeof(buf), "Clients moved from %s to %s", source->mount, dest_source); diff --git a/src/navigation.c b/src/navigation.c index 027f8569..43eb2255 100644 --- a/src/navigation.c +++ b/src/navigation.c @@ -36,6 +36,24 @@ const char * navigation_direction_to_str(navigation_direction_t dir) return NULL; } +navigation_direction_t navigation_str_to_direction(const char *str, navigation_direction_t def) +{ + if (!str || !*str) + return def; + + if (strcasecmp(str, "up") == 0) { + return NAVIGATION_DIRECTION_UP; + } else if (strcasecmp(str, "down") == 0) { + return NAVIGATION_DIRECTION_DOWN; + } else if (strcasecmp(str, "replace_current") == 0 || strcasecmp(str, "replace-current") == 0) { + return NAVIGATION_DIRECTION_REPLACE_CURRENT; + } else if (strcasecmp(str, "replace_all") == 0 || strcasecmp(str, "replace-all") == 0) { + return NAVIGATION_DIRECTION_REPLACE_ALL; + } else { + return def; + } +} + static int mount_identifier_compare__for_tree(void *compare_arg, void *a, void *b) { const char *id_a, *id_b; diff --git a/src/navigation.h b/src/navigation.h index f59baee5..c38d6d5b 100644 --- a/src/navigation.h +++ b/src/navigation.h @@ -30,6 +30,7 @@ typedef enum { REFOBJECT_FORWARD_TYPE(mount_identifier_t); const char * navigation_direction_to_str(navigation_direction_t dir); +navigation_direction_t navigation_str_to_direction(const char *str, navigation_direction_t def); void navigation_initialize(void); void navigation_shutdown(void); From f2edcdb0ff8587d91d751966abcb80520838e8a5 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Tue, 10 Nov 2020 20:41:02 +0000 Subject: [PATCH 17/18] Update: Made NAVIGATION_DIRECTION_REPLACE_ALL the default for move of clients --- admin/moveclients.xsl | 2 +- src/admin.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/moveclients.xsl b/admin/moveclients.xsl index f5806f13..33ec6857 100644 --- a/admin/moveclients.xsl +++ b/admin/moveclients.xsl @@ -41,7 +41,7 @@ - +   diff --git a/src/admin.c b/src/admin.c index 8373b52e..5c3321c8 100644 --- a/src/admin.c +++ b/src/admin.c @@ -769,7 +769,7 @@ static void command_move_clients(client_t *client, ICECAST_LOG_INFO("source is \"%s\", destination is \"%s\"", source->mount, dest->mount); - source_move_clients(source, dest, idtext ? &id : NULL, navigation_str_to_direction(directiontext, NAVIGATION_DIRECTION_DOWN)); + source_move_clients(source, dest, idtext ? &id : NULL, navigation_str_to_direction(directiontext, NAVIGATION_DIRECTION_REPLACE_ALL)); snprintf(buf, sizeof(buf), "Clients moved from %s to %s", source->mount, dest_source); From d497412b5872b23092d7c4450029d6d7994951c7 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 21 Nov 2020 12:46:56 +0000 Subject: [PATCH 18/18] Feature: Export client history as part of stats XML --- src/admin.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/admin.c b/src/admin.c index 5c3321c8..f77dd9b0 100644 --- a/src/admin.c +++ b/src/admin.c @@ -830,6 +830,15 @@ static inline xmlNodePtr __add_listener(client_t *client, xmlNewTextChild(node, NULL, XMLSTR("protocol"), XMLSTR(client_protocol_to_string(client->protocol))); + do { + xmlNodePtr history = xmlNewChild(node, NULL, XMLSTR("history"), NULL); + size_t i; + + for (i = 0; i < client->history.fill; i++) { + xmlNewTextChild(history, NULL, XMLSTR("mount"), XMLSTR(mount_identifier_get_mount(client->history.history[i]))); + } + } while (0); + return node; }