From 80ffdca7d10f5cfa26ffa28db672e450e65b72b9 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 30 Jun 2018 13:51:42 +0000 Subject: [PATCH] Feature: Allow listen sockets to virtually handle other sockets traffic. This adds on-behalf-of="#id" to . It allows a socket to handle the traffic that was originally meant of another (virtual) listen socket. --- src/cfgfile.c | 23 +++++++++++++++++++++++ src/cfgfile.h | 1 + src/listensocket.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/src/cfgfile.c b/src/cfgfile.c index 232b6b85..ae86d42f 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -186,6 +186,19 @@ static listener_type_t config_str_to_listener_type(const char *str) } } +char * config_href_to_id(const char *href) +{ + if (!href || !*href) + return NULL; + + if (*href != '#') { + ICECAST_LOG_ERROR("Can not convert string \"%H\" to ID.", href); + return NULL; + } + + return strdup(href+1); +} + static void create_locks(void) { thread_mutex_create(&_locks.relay_lock); @@ -595,6 +608,7 @@ listener_t *config_clear_listener(listener_t *listener) { next = listener->next; if (listener->id) xmlFree(listener->id); + if (listener->on_behalf_of) free(listener->on_behalf_of); if (listener->bind_address) xmlFree(listener->bind_address); if (listener->shoutcast_mount) xmlFree(listener->shoutcast_mount); free (listener); @@ -1761,6 +1775,12 @@ static void _parse_listen_socket(xmlDocPtr doc, listener->id = (char *)xmlGetProp(node, XMLSTR("id")); + tmp = (char*)xmlGetProp(node, XMLSTR("on-behalf-of")); + if (tmp) { + listener->on_behalf_of = config_href_to_id(tmp); + xmlFree(tmp); + } + tmp = (char *)xmlGetProp(node, XMLSTR("type")); listener->type = config_str_to_listener_type(tmp); xmlFree(tmp); @@ -2511,6 +2531,9 @@ listener_t *config_copy_listener_one(const listener_t *listener) { n->so_sndbuf = listener->so_sndbuf; n->type = listener->type; n->id = (char*)xmlStrdup(XMLSTR(listener->id)); + if (listener->on_behalf_of) { + n->on_behalf_of = strdup(listener->on_behalf_of); + } n->bind_address = (char*)xmlStrdup(XMLSTR(listener->bind_address)); n->shoutcast_compat = listener->shoutcast_compat; n->shoutcast_mount = (char*)xmlStrdup(XMLSTR(listener->shoutcast_mount)); diff --git a/src/cfgfile.h b/src/cfgfile.h index 11a9aa15..875a904e 100644 --- a/src/cfgfile.h +++ b/src/cfgfile.h @@ -156,6 +156,7 @@ typedef enum _listener_type_tag { typedef struct _listener_t { struct _listener_t *next; char *id; + char *on_behalf_of; listener_type_t type; int port; int so_sndbuf; diff --git a/src/listensocket.c b/src/listensocket.c index aef0c0eb..6aa17607 100644 --- a/src/listensocket.c +++ b/src/listensocket.c @@ -53,6 +53,7 @@ struct listensocket_tag { sock_t sock; }; +static listensocket_t * listensocket_container_get_by_id(listensocket_container_t *self, const char *id); static int listensocket_container_configure__unlocked(listensocket_container_t *self, const ice_config_t *config); static int listensocket_container_setup__unlocked(listensocket_container_t *self); static ssize_t listensocket_container_sockcount__unlocked(listensocket_container_t *self); @@ -466,6 +467,29 @@ static ssize_t listensocket_container_sockcount__unlocked(listensocket_container return count; } +static listensocket_t * listensocket_container_get_by_id(listensocket_container_t *self, const char *id) +{ + size_t i; + const listener_t *listener; + + for (i = 0; i < self->sock_len; i++) { + if (self->sock[i] != NULL) { + listener = listensocket_get_listener(self->sock[i]); + if (listener) { + if (strcmp(listener->id, id) == 0) { + listensocket_release_listener(self->sock[i]); + if (refobject_ref(self->sock[i]) == 0) { + return self->sock[i]; + } + } + listensocket_release_listener(self->sock[i]); + } + } + } + + return NULL; +} + /* ---------------------------------------------------------------------------- */ static void __listensocket_free(refobject_t self, void **userdata) @@ -679,6 +703,16 @@ connection_t * listensocket_accept(listensocket_t *self, listensock memmove(ip, ip+7, strlen(ip+7)+1); } + ICECAST_LOG_DEBUG("Client on socket \"%H\".", self->listener->id); + + if (self->listener->on_behalf_of) { + ICECAST_LOG_DEBUG("This socket is acting on behalf of \"%H\"", self->listener->on_behalf_of); + effective = listensocket_container_get_by_id(container, self->listener->on_behalf_of); + if (!effective) { + ICECAST_LOG_ERROR("Can not find listen socket with ID \"%H\". Will continue on behalf of myself.", self->listener->on_behalf_of); + } + } + if (!effective) { effective = self; refobject_ref(effective);