1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2025-02-02 15:07:36 -05:00

Merge branch 'feature-singel-client-move'

This commit is contained in:
Philipp Schafft 2020-09-30 19:52:38 +00:00
commit a6f8c0f246
6 changed files with 96 additions and 81 deletions

View File

@ -36,7 +36,11 @@
<td><xsl:value-of select="role" /></td>
<td><xsl:value-of select="connected" /></td>
<td><xsl:value-of select="useragent" /></td>
<td><a href="killclient.xsl?mount={../@mount}&amp;id={id}">Kick</a></td>
<td>
<a href="killclient.xsl?mount={../@mount}&amp;id={id}">Kick</a>
&#160;
<a href="moveclients.xsl?mount={../@mount}&amp;id={id}">Move</a>
</td>
</tr>
</xsl:for-each>
</tbody>

View File

@ -17,7 +17,15 @@
</xsl:call-template>
<xsl:choose>
<xsl:when test="source">
<xsl:choose>
<xsl:when test="param-id">
<input type="hidden" name="id" value="{param-id}" />
<p>Choose the mountpoint to which you want to move the listener to:</p>
</xsl:when>
<xsl:otherwise>
<p>Choose the mountpoint to which you want to move the listeners to:</p>
</xsl:otherwise>
</xsl:choose>
<form method="post" action="moveclients.xsl">
<label for="moveto" class="hidden">
Move from <code><xsl:value-of select="current_source" /></code> to

View File

@ -617,6 +617,8 @@ static void command_move_clients(client_t *client,
admin_format_t response)
{
const char *dest_source;
const char *idtext = NULL;
connection_id_t id;
source_t *dest;
xmlDocPtr doc;
xmlNodePtr node;
@ -627,9 +629,18 @@ static void command_move_clients(client_t *client,
if((COMMAND_OPTIONAL(client, "destination", dest_source))) {
parameters_passed = 1;
}
if ((COMMAND_OPTIONAL(client, "id", idtext))) {
id = atoi(idtext);
} else {
idtext = NULL;
}
ICECAST_LOG_DEBUG("Done optional check (%d)", parameters_passed);
if (!parameters_passed) {
doc = admin_build_sourcelist(source->mount);
if (idtext) {
xmlNodePtr root = xmlDocGetRootElement(doc);
xmlNewTextChild(root, NULL, XMLSTR("param-id"), XMLSTR(idtext));
}
admin_send_response(doc, client, response,
MOVECLIENTS_HTML_REQUEST);
xmlFreeDoc(doc);
@ -659,7 +670,7 @@ static void command_move_clients(client_t *client,
node = admin_build_rootnode(doc, "iceresponse");
xmlDocSetRootElement(doc, node);
source_move_clients(source, dest);
source_move_clients(source, dest, idtext ? &id : NULL);
snprintf(buf, sizeof(buf), "Clients moved from %s to %s",
source->mount, dest_source);

View File

@ -467,7 +467,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);
source_move_clients(relay->source, fallback_source, NULL);
avl_tree_unlock(global.source_tree);
}

View File

@ -323,7 +323,7 @@ void source_free_source (source_t *source)
}
client_t *source_find_client(source_t *source, int id)
client_t *source_find_client(source_t *source, connection_id_t id)
{
client_t fakeclient;
void *result;
@ -343,17 +343,32 @@ client_t *source_find_client(source_t *source, int id)
return NULL;
}
static inline void source_move_clients__single(source_t *source, avl_tree *from, avl_tree *to, client_t *client) {
avl_delete(from, client, NULL);
/* when switching a client to a different queue, be wary of the
* refbuf it's referring to, if it's http headers then we need
* to write them so don't release it.
*/
if (client->check_buffer != format_check_http_buffer) {
client_set_queue(client, NULL);
client->check_buffer = format_check_file_buffer;
if (source->con == NULL)
client->intro_offset = -1;
}
avl_insert(to, (void *)client);
}
/* Move clients from source to dest provided dest is running
* and that the stream format is the same.
* 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)
void source_move_clients(source_t *source, source_t *dest, connection_id_t *id)
{
unsigned long count = 0;
if (strcmp (source->mount, dest->mount) == 0)
{
if (strcmp(source->mount, dest->mount) == 0) {
ICECAST_LOG_WARN("src and dst are the same \"%s\", skipping", source->mount);
return;
}
@ -363,89 +378,65 @@ void source_move_clients(source_t *source, source_t *dest)
/* if the destination is not running then we can't move clients */
avl_tree_wlock(dest->pending_tree);
if (dest->running == 0 && dest->on_demand == 0)
{
if (dest->running == 0 && dest->on_demand == 0) {
ICECAST_LOG_WARN("destination mount %s not running, unable to move clients ", dest->mount);
avl_tree_unlock(dest->pending_tree);
thread_mutex_unlock(&move_clients_mutex);
return;
}
do
{
client_t *client;
/* we need to move the client and pending trees - we must take the
* locks in this order to avoid deadlocks */
avl_tree_wlock(source->pending_tree);
avl_tree_wlock(source->client_tree);
if (source->on_demand == 0 && source->format == NULL)
{
do {
if (source->on_demand == 0 && source->format == NULL) {
ICECAST_LOG_INFO("source mount %s is not available", source->mount);
break;
}
if (source->format && dest->format)
{
if (source->format->type != dest->format->type)
{
if (source->format && dest->format) {
if (source->format->type != dest->format->type) {
ICECAST_LOG_WARN("stream %s and %s are of different types, ignored", source->mount, dest->mount);
break;
}
}
while (1)
{
if (id) {
client_t fakeclient;
connection_t fakecon;
void *result;
fakeclient.con = &fakecon;
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);
count++;
}
} else {
while (1) {
avl_node *node = avl_get_first(source->pending_tree);
if (node == NULL)
break;
client = (client_t *)(node->key);
avl_delete (source->pending_tree, client, NULL);
/* when switching a client to a different queue, be wary of the
* refbuf it's referring to, if it's http headers then we need
* to write them so don't release it.
*/
if (client->check_buffer != format_check_http_buffer)
{
client_set_queue (client, NULL);
client->check_buffer = format_check_file_buffer;
if (source->con == NULL)
client->intro_offset = -1;
}
avl_insert (dest->pending_tree, (void *)client);
source_move_clients__single(source, source->pending_tree, dest->pending_tree, node->key);
count++;
}
while (1)
{
while (1) {
avl_node *node = avl_get_first(source->client_tree);
if (node == NULL)
break;
client = (client_t *)(node->key);
avl_delete (source->client_tree, client, NULL);
/* when switching a client to a different queue, be wary of the
* refbuf it's referring to, if it's http headers then we need
* to write them so don't release it.
*/
if (client->check_buffer != format_check_http_buffer)
{
client_set_queue (client, NULL);
client->check_buffer = format_check_file_buffer;
if (source->con == NULL)
client->intro_offset = -1;
}
avl_insert (dest->pending_tree, (void *)client);
source_move_clients__single(source, source->client_tree, dest->pending_tree, node->key);
count++;
}
}
ICECAST_LOG_INFO("passing %lu listeners to \"%s\"", count, dest->mount);
source->listeners = 0;
stats_event (source->mount, "listeners", "0");
source->listeners -= count;
stats_event_sub(source->mount, "listeners", count);
} while (0);
avl_tree_unlock(source->pending_tree);
@ -674,7 +665,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);
source_move_clients(fallback_source, source, NULL);
avl_tree_unlock(global.source_tree);
}
@ -873,7 +864,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);
source_move_clients(source, fallback_source, NULL);
avl_tree_unlock(global.source_tree);
}

View File

@ -20,6 +20,7 @@
#include "common/httpp/httpp.h"
#include "icecasttypes.h"
#include "connection.h"
#include "yp.h"
#include "util.h"
#include "format.h"
@ -91,10 +92,10 @@ void source_update_settings (ice_config_t *config, source_t *source, mount_proxy
void source_clear_source (source_t *source);
source_t *source_find_mount(const char *mount);
source_t *source_find_mount_raw(const char *mount);
client_t *source_find_client(source_t *source, int id);
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);
void source_move_clients(source_t *source, source_t *dest, connection_id_t *id);
int source_remove_client(void *key);
void source_main(source_t *source);
void source_recheck_mounts (int update_all);