From 5490120d4d71987a1245f9569e922f9ad25f894f Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 18 Apr 2018 05:43:46 +0000 Subject: [PATCH 01/19] Update: Rewrote listen socket handling code comepletly. This moves all the listen socket code into a nice and abstracting file. Notes: * Altering listen socket setup does not yet work on config reload. (Did it ever work?) * Server will start with no listen sockets. (There are unconfirmed rumours it sometimes(?) did before.) This is to be re-implemented in another commit. It can also be improved to work allow checking on reload or other config changes. * For slave connections the server address is now checked against the allow/deny-IP list. --- src/Makefile.am | 2 + src/cfgfile.c | 37 ++-- src/cfgfile.h | 3 +- src/client.c | 2 +- src/connection.c | 218 ++++------------------- src/connection.h | 7 +- src/global.c | 2 +- src/global.h | 4 +- src/icecasttypes.h | 7 + src/listensocket.c | 421 +++++++++++++++++++++++++++++++++++++++++++++ src/listensocket.h | 25 +++ src/main.c | 22 +-- src/slave.c | 2 +- 13 files changed, 519 insertions(+), 233 deletions(-) create mode 100644 src/listensocket.c create mode 100644 src/listensocket.h diff --git a/src/Makefile.am b/src/Makefile.am index 0f4255ee..61e94508 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -32,6 +32,7 @@ noinst_HEADERS = \ refobject.h \ module.h \ reportxml.h \ + listensocket.h \ event.h \ event_log.h \ event_exec.h \ @@ -74,6 +75,7 @@ icecast_SOURCES = \ refobject.c \ module.c \ reportxml.c \ + listensocket.c \ format.c \ format_ogg.c \ format_mp3.c \ diff --git a/src/cfgfile.c b/src/cfgfile.c index dc1feb43..5c3c2d62 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -2473,24 +2473,23 @@ mount_proxy *config_find_mount (ice_config_t *config, return mountinfo; } -/* Helper function to locate the configuration details of the listening - * socket - */ -listener_t *config_get_listen_sock(ice_config_t *config, connection_t *con) -{ - listener_t *listener; - int i = 0; +listener_t *config_copy_listener_one(const listener_t *listener) { + listener_t *n; - listener = config->listen_sock; - while (listener) { - if (i >= global.server_sockets) { - listener = NULL; - } else { - if (global.serversock[i] == con->serversock) - break; - listener = listener->next; - i++; - } - } - return listener; + if (listener == NULL) + return NULL; + + n = calloc(1, sizeof(*n)); + if (n == NULL) + return NULL; + + n->next = NULL; + n->port = listener->port; + n->so_sndbuf = listener->so_sndbuf; + n->bind_address = (char*)xmlStrdup(XMLSTR(listener->bind_address)); + n->shoutcast_compat = listener->shoutcast_compat; + n->shoutcast_mount = (char*)xmlStrdup(XMLSTR(listener->shoutcast_mount)); + n->tls = listener->tls; + + return n; } diff --git a/src/cfgfile.h b/src/cfgfile.h index 66117a9d..31da5675 100644 --- a/src/cfgfile.h +++ b/src/cfgfile.h @@ -262,7 +262,8 @@ void config_set_config(ice_config_t *config); listener_t *config_clear_listener (listener_t *listener); void config_clear(ice_config_t *config); mount_proxy *config_find_mount(ice_config_t *config, const char *mount, mount_type type); -listener_t *config_get_listen_sock(ice_config_t *config, connection_t *con); + +listener_t *config_copy_listener_one(const listener_t *listener); config_options_t *config_parse_options(xmlNodePtr node); void config_clear_options(config_options_t *options); diff --git a/src/client.c b/src/client.c index dbf4cea3..b4373042 100644 --- a/src/client.c +++ b/src/client.c @@ -110,7 +110,7 @@ static inline void client_reuseconnection(client_t *client) { return; con = client->con; - con = connection_create(con->sock, con->serversock, strdup(con->ip)); + con = connection_create(con->sock, con->listensocket_real, con->listensocket_effective, strdup(con->ip)); reuse = client->reuse; client->con->sock = -1; /* TODO: do not use magic */ diff --git a/src/connection.c b/src/connection.c index d480a05f..7041d879 100644 --- a/src/connection.c +++ b/src/connection.c @@ -58,6 +58,8 @@ #include "matchfile.h" #include "tls.h" #include "acl.h" +#include "refobject.h" +#include "listensocket.h" #define CATMODULE "connection" @@ -144,6 +146,13 @@ void connection_shutdown(void) void connection_reread_config(ice_config_t *config) { get_tls_certificate(config); + /* This does not work yet. + * listensocket_container_configure() should keep sockets that are the same. + * Otherwise the Kernel doesn't let us do it. + * -- ph3-der-loewe, 2018-04-17 + listensocket_container_configure(global.listensockets, config); + listensocket_container_setup(global.listensockets); + */ } static unsigned long _next_connection_id(void) @@ -245,13 +254,21 @@ static int connection_send(connection_t *con, const void *buf, size_t len) return bytes; } -connection_t *connection_create (sock_t sock, sock_t serversock, char *ip) +connection_t *connection_create(sock_t sock, listensocket_t *listensocket_real, listensocket_t* listensocket_effective, char *ip) { connection_t *con; + + if (!matchfile_match_allow_deny(allowed_ip, banned_ip, ip)) + return NULL; + con = (connection_t *)calloc(1, sizeof(connection_t)); if (con) { + refobject_ref(listensocket_real); + refobject_ref(listensocket_effective); + con->sock = sock; - con->serversock = serversock; + con->listensocket_real = listensocket_real; + con->listensocket_effective = listensocket_effective; con->con_time = time(NULL); con->id = _next_connection_id(); con->ip = ip; @@ -355,117 +372,6 @@ int connection_read_put_back(connection_t *con, const void *buf, size_t len) } } -static sock_t wait_for_serversock(int timeout) -{ -#ifdef HAVE_POLL - struct pollfd ufds [global.server_sockets]; - int i, ret; - - for(i=0; i < global.server_sockets; i++) { - ufds[i].fd = global.serversock[i]; - ufds[i].events = POLLIN; - ufds[i].revents = 0; - } - - ret = poll(ufds, global.server_sockets, timeout); - if(ret < 0) { - return SOCK_ERROR; - } else if(ret == 0) { - return SOCK_ERROR; - } else { - int dst; - for(i=0; i < global.server_sockets; i++) { - if(ufds[i].revents & POLLIN) - return ufds[i].fd; - if(ufds[i].revents & (POLLHUP|POLLERR|POLLNVAL)) { - if (ufds[i].revents & (POLLHUP|POLLERR)) { - sock_close (global.serversock[i]); - ICECAST_LOG_WARN("Had to close a listening socket"); - } - global.serversock[i] = SOCK_ERROR; - } - } - /* remove any closed sockets */ - for(i=0, dst=0; i < global.server_sockets; i++) { - if (global.serversock[i] == SOCK_ERROR) - continue; - if (i!=dst) - global.serversock[dst] = global.serversock[i]; - dst++; - } - global.server_sockets = dst; - return SOCK_ERROR; - } -#else - fd_set rfds; - struct timeval tv, *p=NULL; - int i, ret; - sock_t max = SOCK_ERROR; - - FD_ZERO(&rfds); - - for(i=0; i < global.server_sockets; i++) { - FD_SET(global.serversock[i], &rfds); - if (max == SOCK_ERROR || global.serversock[i] > max) - max = global.serversock[i]; - } - - if(timeout >= 0) { - tv.tv_sec = timeout/1000; - tv.tv_usec = (timeout % 1000) * 1000; - p = &tv; - } - - ret = select(max+1, &rfds, NULL, NULL, p); - if(ret < 0) { - return SOCK_ERROR; - } else if(ret == 0) { - return SOCK_ERROR; - } else { - for(i=0; i < global.server_sockets; i++) { - if(FD_ISSET(global.serversock[i], &rfds)) - return global.serversock[i]; - } - return SOCK_ERROR; /* Should be impossible, stop compiler warnings */ - } -#endif -} - -static connection_t *_accept_connection(int duration) -{ - sock_t sock, serversock; - char *ip; - - serversock = wait_for_serversock (duration); - if (serversock == SOCK_ERROR) - return NULL; - - /* malloc enough room for a full IP address (including ipv6) */ - ip = (char *)malloc(MAX_ADDR_LEN); - - sock = sock_accept(serversock, ip, MAX_ADDR_LEN); - if (sock != SOCK_ERROR) { - connection_t *con = NULL; - /* Make any IPv4 mapped IPv6 address look like a normal IPv4 address */ - if (strncmp(ip, "::ffff:", 7) == 0) - memmove(ip, ip+7, strlen (ip+7)+1); - - if (matchfile_match_allow_deny(allowed_ip, banned_ip, ip)) - con = connection_create (sock, serversock, ip); - if (con) - return con; - sock_close(sock); - } else { - if (!sock_recoverable(sock_error())) { - ICECAST_LOG_WARN("accept() failed with error %d: %s", sock_error(), strerror(sock_error())); - thread_sleep(500000); - } - } - free(ip); - return NULL; -} - - /* add client to connection queue. At this point some header information * has been collected, so we now pass it onto the connection thread for * further processing @@ -704,16 +610,14 @@ static void _add_request_queue(client_queue_t *node) static client_queue_t *create_client_node(client_t *client) { client_queue_t *node = calloc (1, sizeof (client_queue_t)); - ice_config_t *config; - listener_t *listener; + const listener_t *listener; if (!node) return NULL; node->client = client; - config = config_get_config(); - listener = config_get_listen_sock(config, client->con); + listener = listensocket_get_listener(client->con->listensocket_effective); if (listener) { if (listener->shoutcast_compat) @@ -725,8 +629,6 @@ static client_queue_t *create_client_node(client_t *client) node->shoutcast_mount = strdup(listener->shoutcast_mount); } - config_release_config(); - return node; } @@ -776,7 +678,7 @@ void connection_accept_loop(void) config_release_config(); while (global.running == ICECAST_RUNNING) { - con = _accept_connection (duration); + con = listensocket_container_accept(global.listensockets, duration); if (con) { connection_queue(con); @@ -1234,7 +1136,7 @@ static int _handle_resources(client_t *client, char **uri) char *vhost_colon; char *new_uri = NULL; ice_config_t *config; - listener_t *listen_sock; + const listener_t *listen_sock; resource_t *resource; if (http_host) { @@ -1246,8 +1148,8 @@ static int _handle_resources(client_t *client, char **uri) } } + listen_sock = listensocket_get_listener(client->con->listensocket_effective); config = config_get_config(); - listen_sock = config_get_listen_sock (config, client->con); if (listen_sock) { serverhost = listen_sock->bind_address; serverport = listen_sock->port; @@ -1497,7 +1399,7 @@ static void __prepare_shoutcast_admin_cgi_request(client_t *client) ice_config_t *config; const char *sc_mount; const char *pass = httpp_get_query_param(client->parser, "pass"); - listener_t *listener; + const listener_t *listener; if (pass == NULL) { ICECAST_LOG_ERROR("missing pass parameter"); @@ -1509,10 +1411,10 @@ static void __prepare_shoutcast_admin_cgi_request(client_t *client) return; } + listener = listensocket_get_listener(client->con->listensocket_effective); global_lock(); config = config_get_config(); sc_mount = config->shoutcast_mount; - listener = config_get_listen_sock(config, client->con); if (listener && listener->shoutcast_mount) sc_mount = listener->shoutcast_mount; @@ -1733,21 +1635,14 @@ static void _handle_connection(void) /* called when listening thread is not checking for incoming connections */ -int connection_setup_sockets (ice_config_t *config) +void connection_setup_sockets (ice_config_t *config) { - int count = 0; - listener_t *listener, **prev; - global_lock(); - if (global.serversock) { - for (; count < global.server_sockets; count++) - sock_close (global.serversock [count]); - free (global.serversock); - global.serversock = NULL; - } + refobject_unref(global.listensockets); + if (config == NULL) { global_unlock(); - return 0; + return; } /* setup the banned/allowed IP filenames from the xml */ @@ -1763,57 +1658,12 @@ int connection_setup_sockets (ice_config_t *config) allowed_ip = matchfile_new(config->allowfile); } - count = 0; - global.serversock = calloc(config->listen_sock_count, sizeof(sock_t)); + global.listensockets = listensocket_container_new(); + listensocket_container_configure(global.listensockets, config); - listener = config->listen_sock; - prev = &config->listen_sock; - while (listener) { - int successful = 0; - - do { - sock_t sock = sock_get_server_socket (listener->port, listener->bind_address); - if (sock == SOCK_ERROR) - break; - if (sock_listen (sock, ICECAST_LISTEN_QUEUE) == SOCK_ERROR) { - sock_close (sock); - break; - } - /* some win32 setups do not do TCP win scaling well, so allow an override */ - if (listener->so_sndbuf) - sock_set_send_buffer (sock, listener->so_sndbuf); - sock_set_blocking (sock, 0); - successful = 1; - global.serversock [count] = sock; - count++; - } while(0); - if (successful == 0) { - if (listener->bind_address) { - ICECAST_LOG_ERROR("Could not create listener socket on port %d bind %s", - listener->port, listener->bind_address); - } else { - ICECAST_LOG_ERROR("Could not create listener socket on port %d", listener->port); - } - /* remove failed connection */ - *prev = config_clear_listener (listener); - listener = *prev; - continue; - } - if (listener->bind_address) { - ICECAST_LOG_INFO("listener socket on port %d address %s", listener->port, listener->bind_address); - } else { - ICECAST_LOG_INFO("listener socket on port %d", listener->port); - } - prev = &listener->next; - listener = listener->next; - } - global.server_sockets = count; global_unlock(); - if (count == 0) - ICECAST_LOG_ERROR("No listening sockets established"); - - return count; + listensocket_container_setup(global.listensockets);; } @@ -1829,5 +1679,7 @@ void connection_close(connection_t *con) free(con->ip); if (con->readbufferlen) free(con->readbuffer); + refobject_unref(con->listensocket_real); + refobject_unref(con->listensocket_effective); free(con); } diff --git a/src/connection.h b/src/connection.h index 3782b4ae..34795857 100644 --- a/src/connection.h +++ b/src/connection.h @@ -32,7 +32,8 @@ struct connection_tag { uint64_t sent_bytes; sock_t sock; - sock_t serversock; + listensocket_t *listensocket_real; + listensocket_t *listensocket_effective; int error; tlsmode_t tlsmode; @@ -50,9 +51,9 @@ void connection_initialize(void); void connection_shutdown(void); void connection_reread_config(ice_config_t *config); void connection_accept_loop(void); -int connection_setup_sockets(ice_config_t *config); +void connection_setup_sockets(ice_config_t *config); void connection_close(connection_t *con); -connection_t *connection_create(sock_t sock, sock_t serversock, char *ip); +connection_t *connection_create(sock_t sock, listensocket_t *listensocket_real, listensocket_t* listensocket_effective, char *ip); int connection_complete_source(source_t *source, int response); void connection_queue(connection_t *con); void connection_uses_tls(connection_t *con); diff --git a/src/global.c b/src/global.c index 3b61081a..db126887 100644 --- a/src/global.c +++ b/src/global.c @@ -31,7 +31,7 @@ static mutex_t _global_mutex; void global_initialize(void) { - global.server_sockets = 0; + global.listensockets = NULL; global.relays = NULL; global.master_relays = NULL; global.running = 0; diff --git a/src/global.h b/src/global.h index bc02de8d..5329f85c 100644 --- a/src/global.h +++ b/src/global.h @@ -22,13 +22,11 @@ #include "common/thread/thread.h" #include "common/avl/avl.h" -#include "common/net/sock.h" #include "icecasttypes.h" typedef struct ice_global_tag { - sock_t *serversock; - int server_sockets; + listensocket_container_t *listensockets; int running; diff --git a/src/icecasttypes.h b/src/icecasttypes.h index 1792af0c..40f4d57f 100644 --- a/src/icecasttypes.h +++ b/src/icecasttypes.h @@ -104,6 +104,11 @@ typedef struct reportxml_tag reportxml_t; typedef struct reportxml_node_tag reportxml_node_t; typedef struct reportxml_database_tag reportxml_database_t; +/* ---[ listensocket.[ch] ]--- */ + +typedef struct listensocket_container_tag listensocket_container_t; +typedef struct listensocket_tag listensocket_t; + /* ---[ refobject.[ch] ]--- */ typedef struct refobject_base_tag refobject_base_t; @@ -116,6 +121,8 @@ typedef union __attribute__ ((__transparent_union__)) { reportxml_t *reportxml; reportxml_node_t *reportxml_node; reportxml_database_t *reportxml_database; + listensocket_container_t *listensocket_container; + listensocket_t *listensocket; } refobject_t; #else typedef void * refobject_t; diff --git a/src/listensocket.c b/src/listensocket.c new file mode 100644 index 00000000..b7970021 --- /dev/null +++ b/src/listensocket.c @@ -0,0 +1,421 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2018, Philipp "ph3-der-loewe" Schafft , + */ + +/** + * Listen socket operations. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_POLL +#include +#else +#include +#endif + +#include + +#include "common/net/sock.h" + +#include "listensocket.h" +#include "global.h" +#include "connection.h" +#include "refobject.h" + +#include "logging.h" +#define CATMODULE "listensocket" + + +struct listensocket_container_tag { + refobject_base_t __base; + listensocket_t **sock; + int *sockref; + size_t sock_len; +}; +struct listensocket_tag { + refobject_base_t __base; + size_t sockrefc; + listener_t *listener; + sock_t sock; +}; + +static listensocket_t * listensocket_new(const listener_t *listener); +#ifdef HAVE_POLL +static int listensocket__poll_fill(listensocket_t *self, struct pollfd *p); +#else +static int listensocket__select_set(listensocket_t *self, fd_set *set, int *max); +static int listensocket__select_isset(listensocket_t *self, fd_set *set); +#endif + +static void listensocket_container_clear_sockets(listensocket_container_t *self) +{ + size_t i; + + if (self->sock == NULL) + return; + + for (i = 0; i < self->sock_len; i++) { + if (self->sock[i] != NULL) { + if (self->sockref[i]) { + listensocket_unrefsock(self->sock[i]); + } + refobject_unref(self->sock[i]); + self->sock[i] = NULL; + } + } + + self->sock_len = 0; + free(self->sock); + free(self->sockref); + self->sock = NULL; + self->sockref = NULL; +} + + +static void __listensocket_container_free(refobject_t self, void **userdata) +{ + listensocket_container_t *container = REFOBJECT_TO_TYPE(self, listensocket_container_t *); + listensocket_container_clear_sockets(container); +} + +listensocket_container_t * listensocket_container_new(void) +{ + listensocket_container_t *self = REFOBJECT_TO_TYPE(refobject_new(sizeof(listensocket_container_t), __listensocket_container_free, NULL, NULL, NULL), listensocket_container_t *); + if (!self) + return NULL; + + + self->sock = NULL; + self->sock_len = 0; + + return self; +} + +int listensocket_container_configure(listensocket_container_t *self, const ice_config_t *config) +{ + listensocket_t **n; + listener_t *cur; + int *r; + size_t i; + + if (!self || !config) + return -1; + + if (!config->listen_sock_count) { + listensocket_container_clear_sockets(self); + return 0; + } + + n = calloc(config->listen_sock_count, sizeof(listensocket_t *)); + r = calloc(config->listen_sock_count, sizeof(int)); + if (!n || !r) { + free(n); + free(r); + return -1; + } + + cur = config->listen_sock; + for (i = 0; i < config->listen_sock_count; i++) { + if (cur) { + n[i] = listensocket_new(cur); + } else { + n[i] = NULL; + } + if (n[i] == NULL) { + for (; i; i--) { + refobject_unref(n[i - 1]); + } + return -1; + } + + cur = cur->next; + } + + listensocket_container_clear_sockets(self); + + self->sock = n; + self->sockref = r; + self->sock_len = config->listen_sock_count; + + return 0; +} + +int listensocket_container_setup(listensocket_container_t *self) { + size_t i; + int ret = 0; + + if (!self) + return -1; + + for (i = 0; i < self->sock_len; i++) { + if (self->sockref[i]) + continue; + + if (listensocket_refsock(self->sock[i]) == 0) { + self->sockref[i] = 1; + } else { + ret = 1; + } + } + + return ret; +} + +static connection_t * listensocket_container_accept__inner(listensocket_container_t *self, int timeout) +{ +#ifdef HAVE_POLL + struct pollfd ufds[self->sock_len]; + listensocket_t *socks[self->sock_len]; + size_t i, found, p; + int ok; + int ret; + + for (i = 0, found = 0; i < self->sock_len; i++) { + ok = self->sockref[i]; + + if (ok && listensocket__poll_fill(self->sock[i], &(ufds[found])) == -1) { + ICECAST_LOG_WARN("Can not poll on closed socket."); + ok = 0; + } + + if (ok) { + socks[found] = self->sock[i]; + found++; + } + } + + if (!found) { + ICECAST_LOG_ERROR("No sockets found to poll on."); + return NULL; + } + + ret = poll(ufds, found, timeout); + if (ret <= 0) + return NULL; + + for (i = 0; i < found; i++) { + if (ufds[i].revents & POLLIN) { + return listensocket_accept(socks[i]); + } + + if (!(ufds[i].revents & (POLLHUP|POLLERR|POLLNVAL))) + continue; + + for (p = 0; p < self->sock_len; p++) { + if (self->sock[p] == socks[i]) { + if (self->sockref[p]) { + ICECAST_LOG_ERROR("Closing listen socket in error state."); + listensocket_unrefsock(socks[i]); + self->sockref[p] = 0; + } + } + } + } + + return NULL; +#else + fd_set rfds; + size_t i; + struct timeval tv, *p=NULL; + int ret; + int max = -1; + + FD_ZERO(&rfds); + + if (timeout >= 0) { + tv.tv_sec = timeout/1000; + tv.tv_usec = (timeout % 1000) * 1000; + p = &tv; + } + + for (i = 0; i < self->sock_len; i++) { + if (self->sockref[i]) { + listensocket__select_set(self->sock[i], &rfds, &max); + } + } + + ret = select(max+1, &rfds, NULL, NULL, p); + if (ret <= 0) + return NULL; + + for (i = 0; i < self->sock_len; i++) { + if (self->sockref[i]) { + if (listensocket__select_isset(self->sock[i], &rfds)) { + return listensocket_accept(self->sock[i]); + } + } + } + + return NULL; +#endif +} +connection_t * listensocket_container_accept(listensocket_container_t *self, int timeout) +{ + if (!self) + return NULL; + + return listensocket_container_accept__inner(self, timeout); +} + +static void __listensocket_free(refobject_t self, void **userdata) +{ + listensocket_t *listensocket = REFOBJECT_TO_TYPE(self, listensocket_t *); + + if (listensocket->sockrefc) { + ICECAST_LOG_ERROR("BUG: listensocket->sockrefc == 0 && listensocket->sockrefc == %zu", listensocket->sockrefc); + listensocket->sockrefc = 1; + listensocket_unrefsock(listensocket); + } + + while ((listensocket->listener = config_clear_listener(listensocket->listener))); +} + +static listensocket_t * listensocket_new(const listener_t *listener) { + listensocket_t *self; + + if (listener == NULL) + return NULL; + + self = REFOBJECT_TO_TYPE(refobject_new(sizeof(listensocket_t), __listensocket_free, NULL, NULL, NULL), listensocket_t *); + if (!self) + return NULL; + + self->sock = SOCK_ERROR; + + self->listener = config_copy_listener_one(listener); + if (self->listener == NULL) { + refobject_unref(self); + return NULL; + } + + return self; +} + +int listensocket_refsock(listensocket_t *self) +{ + if (!self) + return -1; + + if (self->sockrefc) { + self->sockrefc++; + return 0; + } + + self->sock = sock_get_server_socket(self->listener->port, self->listener->bind_address); + if (self->sock == SOCK_ERROR) + return -1; + + if (sock_listen(self->sock, ICECAST_LISTEN_QUEUE) == SOCK_ERROR) { + sock_close(self->sock); + self->sock = SOCK_ERROR; + return -1; + } + + if (self->listener->so_sndbuf) + sock_set_send_buffer(self->sock, self->listener->so_sndbuf); + + sock_set_blocking(self->sock, 0); + + self->sockrefc++; + + return 0; +} + +int listensocket_unrefsock(listensocket_t *self) +{ + if (!self) + return -1; + + self->sockrefc--; + if (self->sockrefc) + return 0; + + if (self->sock == SOCK_ERROR) + return 0; + + sock_close(self->sock); + self->sock = SOCK_ERROR; + + return 0; +} + +connection_t * listensocket_accept(listensocket_t *self) +{ + connection_t *con; + sock_t sock; + char *ip; + + if (!self) + return NULL; + + ip = calloc(MAX_ADDR_LEN, 1); + if (!ip) + return NULL; + + sock = sock_accept(self->sock, ip, MAX_ADDR_LEN); + if (sock == SOCK_ERROR) { + free(ip); + return NULL; + } + + if (strncmp(ip, "::ffff:", 7) == 0) { + memmove(ip, ip+7, strlen(ip+7)+1); + } + + con = connection_create(sock, self, self, ip); + if (con == NULL) { + sock_close(sock); + free(ip); + return NULL; + } + + return con; +} + +const listener_t * listensocket_get_listener(listensocket_t *self) +{ + if (!self) + return NULL; + + return self->listener; +} + +#ifdef HAVE_POLL +static int listensocket__poll_fill(listensocket_t *self, struct pollfd *p) +{ + if (!self || self->sock == SOCK_ERROR) + return -1; + + memset(p, 0, sizeof(*p)); + p->fd = self->sock; + p->events = POLLIN; + p->revents = 0; + + return 0; +} +#else +static int listensocket__select_set(listensocket_t *self, fd_set *set, int *max) +{ + if (!self || self->sock == SOCK_ERROR) + return -1; + + if (*max < self->sock) + *max = self->sock; + + FD_SET(self->sock, set); + return 0; +} +static int listensocket__select_isset(listensocket_t *self, fd_set *set) +{ + if (!self || self->sock == SOCK_ERROR) + return -1; + return FD_ISSET(self->sock, set); +} +#endif diff --git a/src/listensocket.h b/src/listensocket.h new file mode 100644 index 00000000..e6f4b05b --- /dev/null +++ b/src/listensocket.h @@ -0,0 +1,25 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2018, Philipp "ph3-der-loewe" Schafft , + */ + +#ifndef __LISTENSOCKET_H__ +#define __LISTENSOCKET_H__ + +#include "icecasttypes.h" +#include "cfgfile.h" + +listensocket_container_t * listensocket_container_new(void); +int listensocket_container_configure(listensocket_container_t *self, const ice_config_t *config); +int listensocket_container_setup(listensocket_container_t *self); +connection_t * listensocket_container_accept(listensocket_container_t *self, int timeout); + +int listensocket_refsock(listensocket_t *self); +int listensocket_unrefsock(listensocket_t *self); +connection_t * listensocket_accept(listensocket_t *self); +const listener_t * listensocket_get_listener(listensocket_t *self); + +#endif diff --git a/src/main.c b/src/main.c index 74277778..86998bfb 100644 --- a/src/main.c +++ b/src/main.c @@ -318,20 +318,6 @@ static int _start_logging(void) return 0; } - -static int _start_listening(void) -{ - int i; - for(i=0; i < global.server_sockets; i++) { - if (sock_listen(global.serversock[i], ICECAST_LISTEN_QUEUE) == SOCK_ERROR) - return 0; - - sock_set_blocking(global.serversock[i], 0); - } - - return 1; -} - static void pidfile_update(ice_config_t *config, int always_try) { char *newpidfile = NULL; @@ -389,13 +375,7 @@ static int _server_proc_init(void) { ice_config_t *config = config_get_config_unlocked(); - if (connection_setup_sockets (config) < 1) - return 0; - - if (!_start_listening()) { - _fatal_error("Failed trying to listen on server socket"); - return 0; - } + connection_setup_sockets(config); pidfile_update(config, 1); diff --git a/src/slave.c b/src/slave.c index e5ede252..d1353295 100644 --- a/src/slave.c +++ b/src/slave.c @@ -200,7 +200,7 @@ static client_t *open_relay_connection (relay_server *relay) ICECAST_LOG_WARN("Failed to connect to %s:%d", server, port); break; } - con = connection_create (streamsock, -1, strdup (server)); + con = connection_create(streamsock, NULL, NULL, strdup(server)); /* At this point we may not know if we are relaying an mp3 or vorbis * stream, but only send the icy-metadata header if the relay details From c401bbcc12eeaa6543f847fb2466c11e42451997 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 9 May 2018 09:58:09 +0000 Subject: [PATCH 02/19] Feature: Added listensocket_container_set_sockcount_cb() and listensocket_container_sockcount() --- src/listensocket.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/listensocket.h | 2 ++ 2 files changed, 48 insertions(+) diff --git a/src/listensocket.c b/src/listensocket.c index b7970021..9eec86fc 100644 --- a/src/listensocket.c +++ b/src/listensocket.c @@ -38,6 +38,8 @@ struct listensocket_container_tag { listensocket_t **sock; int *sockref; size_t sock_len; + void (*sockcount_cb)(size_t count, void *userdata); + void *sockcount_userdata; }; struct listensocket_tag { refobject_base_t __base; @@ -54,6 +56,14 @@ static int listensocket__select_set(listensocket_t *self, fd_set *set, int *max) static int listensocket__select_isset(listensocket_t *self, fd_set *set); #endif +static inline void __call_sockcount_cb(listensocket_container_t *self) +{ + if (self->sockcount_cb == NULL) + return; + + self->sockcount_cb(listensocket_container_sockcount(self), self->sockcount_userdata); +} + static void listensocket_container_clear_sockets(listensocket_container_t *self) { size_t i; @@ -76,6 +86,8 @@ static void listensocket_container_clear_sockets(listensocket_container_t *self) free(self->sockref); self->sock = NULL; self->sockref = NULL; + + __call_sockcount_cb(self); } @@ -94,6 +106,8 @@ listensocket_container_t * listensocket_container_new(void) self->sock = NULL; self->sock_len = 0; + self->sockcount_cb = NULL; + self->sockcount_userdata = NULL; return self; } @@ -161,10 +175,13 @@ int listensocket_container_setup(listensocket_container_ if (listensocket_refsock(self->sock[i]) == 0) { self->sockref[i] = 1; } else { + ICECAST_LOG_DEBUG("Can not ref socket."); ret = 1; } } + __call_sockcount_cb(self); + return ret; } @@ -214,6 +231,7 @@ static connection_t * listensocket_container_accept__inner(listensocket_co ICECAST_LOG_ERROR("Closing listen socket in error state."); listensocket_unrefsock(socks[i]); self->sockref[p] = 0; + __call_sockcount_cb(self); } } } @@ -264,6 +282,34 @@ connection_t * listensocket_container_accept(listensocket_container return listensocket_container_accept__inner(self, timeout); } +int listensocket_container_set_sockcount_cb(listensocket_container_t *self, void (*cb)(size_t count, void *userdata), void *userdata) +{ + if (!self) + return -1; + + self->sockcount_cb = cb; + self->sockcount_userdata = userdata; + + return 0; +} + +ssize_t listensocket_container_sockcount(listensocket_container_t *self) +{ + ssize_t count = 0; + size_t i; + + if (!self) + return -1; + + for (i = 0; i < self->sock_len; i++) { + if (self->sockref[i]) { + count++; + } + } + + return count; +} + static void __listensocket_free(refobject_t self, void **userdata) { listensocket_t *listensocket = REFOBJECT_TO_TYPE(self, listensocket_t *); diff --git a/src/listensocket.h b/src/listensocket.h index e6f4b05b..6c4576c0 100644 --- a/src/listensocket.h +++ b/src/listensocket.h @@ -16,6 +16,8 @@ listensocket_container_t * listensocket_container_new(void); int listensocket_container_configure(listensocket_container_t *self, const ice_config_t *config); int listensocket_container_setup(listensocket_container_t *self); connection_t * listensocket_container_accept(listensocket_container_t *self, int timeout); +int listensocket_container_set_sockcount_cb(listensocket_container_t *self, void (*cb)(size_t count, void *userdata), void *userdata); +ssize_t listensocket_container_sockcount(listensocket_container_t *self); int listensocket_refsock(listensocket_t *self); int listensocket_unrefsock(listensocket_t *self); From 4279a6caeaffab3e6125feb4a76a98028bb661d5 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 9 May 2018 13:48:32 +0000 Subject: [PATCH 03/19] Update: Make use of listensocket_container_set_sockcount_cb() and listensocket_container_sockcount() This fixes the starts-up-with-no-listen-sockets bug. --- src/connection.c | 13 +++++++++++++ src/main.c | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/src/connection.c b/src/connection.c index 7041d879..aed2feba 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1634,6 +1634,18 @@ static void _handle_connection(void) } +static void __on_sock_count(size_t count, void *userdata) +{ + (void)userdata; + + ICECAST_LOG_DEBUG("Listen socket count is now %zu.", count); + + if (count == 0 && global.running == ICECAST_RUNNING) { + ICECAST_LOG_INFO("No more listen sockets. Exiting."); + global.running = ICECAST_HALTING; + } +} + /* called when listening thread is not checking for incoming connections */ void connection_setup_sockets (ice_config_t *config) { @@ -1663,6 +1675,7 @@ void connection_setup_sockets (ice_config_t *config) global_unlock(); + listensocket_container_set_sockcount_cb(global.listensockets, __on_sock_count, NULL); listensocket_container_setup(global.listensockets);; } diff --git a/src/main.c b/src/main.c index 86998bfb..0f997b88 100644 --- a/src/main.c +++ b/src/main.c @@ -77,6 +77,7 @@ #include "yp.h" #include "auth.h" #include "event.h" +#include "listensocket.h" #include @@ -377,6 +378,11 @@ static int _server_proc_init(void) connection_setup_sockets(config); + if (listensocket_container_sockcount(global.listensockets) < 1) { + ICECAST_LOG_ERROR("Can not listen on any sockets."); + return 0; + } + pidfile_update(config, 1); return 1; From 8848d74e58d9276ddd4986ed559e92040ccec942 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 9 May 2018 13:49:41 +0000 Subject: [PATCH 04/19] Fix: Correctly detect error condition --- src/listensocket.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/listensocket.c b/src/listensocket.c index 9eec86fc..3364449b 100644 --- a/src/listensocket.c +++ b/src/listensocket.c @@ -358,9 +358,10 @@ int listensocket_refsock(listensocket_t *self) if (self->sock == SOCK_ERROR) return -1; - if (sock_listen(self->sock, ICECAST_LISTEN_QUEUE) == SOCK_ERROR) { + if (sock_listen(self->sock, ICECAST_LISTEN_QUEUE) == 0) { sock_close(self->sock); self->sock = SOCK_ERROR; + ICECAST_LOG_ERROR("Can not listen on socket: %s port %i", self->listener->bind_address ? self->listener->bind_address : "", self->listener->port); return -1; } From 6054f5cce42a3d8c0ddb98a6269742fcefa64313 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Thu, 10 May 2018 07:10:19 +0000 Subject: [PATCH 05/19] Cleanup: Mark static function as inline --- src/listensocket.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/listensocket.c b/src/listensocket.c index 3364449b..42f4b9b2 100644 --- a/src/listensocket.c +++ b/src/listensocket.c @@ -50,10 +50,10 @@ struct listensocket_tag { static listensocket_t * listensocket_new(const listener_t *listener); #ifdef HAVE_POLL -static int listensocket__poll_fill(listensocket_t *self, struct pollfd *p); +static inline int listensocket__poll_fill(listensocket_t *self, struct pollfd *p); #else -static int listensocket__select_set(listensocket_t *self, fd_set *set, int *max); -static int listensocket__select_isset(listensocket_t *self, fd_set *set); +static inline int listensocket__select_set(listensocket_t *self, fd_set *set, int *max); +static inline int listensocket__select_isset(listensocket_t *self, fd_set *set); #endif static inline void __call_sockcount_cb(listensocket_container_t *self) @@ -435,7 +435,7 @@ const listener_t * listensocket_get_listener(listensocket_t *self) } #ifdef HAVE_POLL -static int listensocket__poll_fill(listensocket_t *self, struct pollfd *p) +static inline int listensocket__poll_fill(listensocket_t *self, struct pollfd *p) { if (!self || self->sock == SOCK_ERROR) return -1; @@ -448,7 +448,7 @@ static int listensocket__poll_fill(listensocket_t *self, struct pollfd *p) return 0; } #else -static int listensocket__select_set(listensocket_t *self, fd_set *set, int *max) +static inline int listensocket__select_set(listensocket_t *self, fd_set *set, int *max) { if (!self || self->sock == SOCK_ERROR) return -1; @@ -459,7 +459,7 @@ static int listensocket__select_set(listensocket_t *self, fd_set *set, int *max) FD_SET(self->sock, set); return 0; } -static int listensocket__select_isset(listensocket_t *self, fd_set *set) +static inline int listensocket__select_isset(listensocket_t *self, fd_set *set) { if (!self || self->sock == SOCK_ERROR) return -1; From e661e14beea1687525ea0826d7b61d6091c8c07e Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Thu, 10 May 2018 08:25:17 +0000 Subject: [PATCH 06/19] Moved config apply on listensocket objects into it's own function --- src/listensocket.c | 65 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/src/listensocket.c b/src/listensocket.c index 42f4b9b2..b4b303f8 100644 --- a/src/listensocket.c +++ b/src/listensocket.c @@ -49,6 +49,7 @@ struct listensocket_tag { }; static listensocket_t * listensocket_new(const listener_t *listener); +static int listensocket_apply_config(listensocket_t *self, const listener_t *listener); #ifdef HAVE_POLL static inline int listensocket__poll_fill(listensocket_t *self, struct pollfd *p); #else @@ -56,6 +57,11 @@ static inline int listensocket__select_set(listensocket_t *self, fd_set *set, in static inline int listensocket__select_isset(listensocket_t *self, fd_set *set); #endif +static inline const char * __string_default(const char *str, const char *def) +{ + return str != NULL ? str : def; +} + static inline void __call_sockcount_cb(listensocket_container_t *self) { if (self->sockcount_cb == NULL) @@ -344,6 +350,57 @@ static listensocket_t * listensocket_new(const listener_t *listener) { return self; } +static int listensocket_apply_config(listensocket_t *self, const listener_t *listener) +{ + listener_t *copy = NULL; + + if (!self || !listener) + return -1; + + if (listener != self->listener) { + if (listener->port != self->listener->port) { + ICECAST_LOG_ERROR("Tried to apply incomplete configuration to listensocket: port missmatch: have %i, got %i", self->listener->port, listener->port); + return -1; + } + + if ((listener->bind_address == NULL && self->listener->bind_address != NULL) || + (listener->bind_address != NULL && self->listener->bind_address == NULL) + ) { + ICECAST_LOG_ERROR("Tried to apply incomplete configuration to listensocket: bind address nature missmatch: have %s, got %s", + __string_default(self->listener->bind_address, ""), + __string_default(listener->bind_address, "") + ); + return -1; + } + + if (listener->bind_address != NULL && self->listener->bind_address != NULL && strcmp(listener->bind_address, self->listener->bind_address) != 0) { + ICECAST_LOG_ERROR("Tried to apply incomplete configuration to listensocket: bind address value missmatch: have %s, got %s", + __string_default(self->listener->bind_address, ""), + __string_default(listener->bind_address, "") + ); + return -1; + } + + copy = config_copy_listener_one(listener); + if (copy == NULL) { + ICECAST_LOG_ERROR("Can not copy listen socket configuration"); + return -1; + } + } + + if (listener->so_sndbuf) + sock_set_send_buffer(self->sock, listener->so_sndbuf); + + sock_set_blocking(self->sock, 0); + + if (copy != NULL) { + while ((self->listener = config_clear_listener(self->listener))); + self->listener = copy; + } + + return 0; +} + int listensocket_refsock(listensocket_t *self) { if (!self) @@ -361,14 +418,12 @@ int listensocket_refsock(listensocket_t *self) if (sock_listen(self->sock, ICECAST_LISTEN_QUEUE) == 0) { sock_close(self->sock); self->sock = SOCK_ERROR; - ICECAST_LOG_ERROR("Can not listen on socket: %s port %i", self->listener->bind_address ? self->listener->bind_address : "", self->listener->port); + ICECAST_LOG_ERROR("Can not listen on socket: %s port %i", __string_default(self->listener->bind_address, ""), self->listener->port); return -1; } - if (self->listener->so_sndbuf) - sock_set_send_buffer(self->sock, self->listener->so_sndbuf); - - sock_set_blocking(self->sock, 0); + if (listensocket_apply_config(self, self->listener) == -1) + return -1; self->sockrefc++; From a6ff1cb2d74cca2761e85042700ef107ebb011aa Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Thu, 10 May 2018 08:30:34 +0000 Subject: [PATCH 07/19] Update: Moved compare of two listeners into __listener_cmp() --- src/listensocket.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/listensocket.c b/src/listensocket.c index b4b303f8..8a93675d 100644 --- a/src/listensocket.c +++ b/src/listensocket.c @@ -62,6 +62,25 @@ static inline const char * __string_default(const char *str, const char *def) return str != NULL ? str : def; } +static inline int __listener_cmp(const listener_t *a, const listener_t *b) +{ + if (a == b) + return 1; + + if (a->port != b->port) + return 0; + + if ((a->bind_address == NULL && b->bind_address != NULL) || + (a->bind_address != NULL && b->bind_address == NULL)) + return 0; + + + if (a->bind_address != NULL && b->bind_address != NULL && strcmp(a->bind_address, b->bind_address) != 0) + return 0; + + return 1; +} + static inline void __call_sockcount_cb(listensocket_container_t *self) { if (self->sockcount_cb == NULL) @@ -358,25 +377,12 @@ static int listensocket_apply_config(listensocket_t *self, const li return -1; if (listener != self->listener) { - if (listener->port != self->listener->port) { - ICECAST_LOG_ERROR("Tried to apply incomplete configuration to listensocket: port missmatch: have %i, got %i", self->listener->port, listener->port); - return -1; - } - - if ((listener->bind_address == NULL && self->listener->bind_address != NULL) || - (listener->bind_address != NULL && self->listener->bind_address == NULL) - ) { - ICECAST_LOG_ERROR("Tried to apply incomplete configuration to listensocket: bind address nature missmatch: have %s, got %s", + if (__listener_cmp(listener, self->listener) != 1) { + ICECAST_LOG_ERROR("Tried to apply incomplete configuration to listensocket: bind address missmatch: have %s:%i, got %s:%i", __string_default(self->listener->bind_address, ""), - __string_default(listener->bind_address, "") - ); - return -1; - } - - if (listener->bind_address != NULL && self->listener->bind_address != NULL && strcmp(listener->bind_address, self->listener->bind_address) != 0) { - ICECAST_LOG_ERROR("Tried to apply incomplete configuration to listensocket: bind address value missmatch: have %s, got %s", - __string_default(self->listener->bind_address, ""), - __string_default(listener->bind_address, "") + self->listener->port, + __string_default(listener->bind_address, ""), + listener->port ); return -1; } From b495a407f934e80f8848ee7d827055886243e849 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Thu, 10 May 2018 08:33:19 +0000 Subject: [PATCH 08/19] Feature: Added listensocket_container_configure_and_setup() that combines configure and setup into one call --- src/listensocket.c | 23 +++++++++++++++++++++++ src/listensocket.h | 1 + 2 files changed, 24 insertions(+) diff --git a/src/listensocket.c b/src/listensocket.c index 8a93675d..90670ca0 100644 --- a/src/listensocket.c +++ b/src/listensocket.c @@ -186,6 +186,29 @@ int listensocket_container_configure(listensocket_contai return 0; } +int listensocket_container_configure_and_setup(listensocket_container_t *self, const ice_config_t *config) +{ + void (*cb)(size_t count, void *userdata); + int ret; + + if (!self) + return -1; + + cb = self->sockcount_cb; + self->sockcount_cb = NULL; + + if (listensocket_container_configure(self, config) == 0) { + ret = listensocket_container_setup(self); + } else { + ret = -1; + } + + self->sockcount_cb = cb; + __call_sockcount_cb(self); + + return ret; +} + int listensocket_container_setup(listensocket_container_t *self) { size_t i; int ret = 0; diff --git a/src/listensocket.h b/src/listensocket.h index 6c4576c0..b3a03e6a 100644 --- a/src/listensocket.h +++ b/src/listensocket.h @@ -14,6 +14,7 @@ listensocket_container_t * listensocket_container_new(void); int listensocket_container_configure(listensocket_container_t *self, const ice_config_t *config); +int listensocket_container_configure_and_setup(listensocket_container_t *self, const ice_config_t *config); int listensocket_container_setup(listensocket_container_t *self); connection_t * listensocket_container_accept(listensocket_container_t *self, int timeout); int listensocket_container_set_sockcount_cb(listensocket_container_t *self, void (*cb)(size_t count, void *userdata), void *userdata); From fcef3f12d6c6cf0ccf44010f30041d69b3629639 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Fri, 11 May 2018 06:52:03 +0000 Subject: [PATCH 09/19] Feature: Allow complete reconfiguration of sockets on config reload --- src/connection.c | 8 +--- src/listensocket.c | 100 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 77 insertions(+), 31 deletions(-) diff --git a/src/connection.c b/src/connection.c index aed2feba..973c7a07 100644 --- a/src/connection.c +++ b/src/connection.c @@ -146,13 +146,7 @@ void connection_shutdown(void) void connection_reread_config(ice_config_t *config) { get_tls_certificate(config); - /* This does not work yet. - * listensocket_container_configure() should keep sockets that are the same. - * Otherwise the Kernel doesn't let us do it. - * -- ph3-der-loewe, 2018-04-17 - listensocket_container_configure(global.listensockets, config); - listensocket_container_setup(global.listensockets); - */ + listensocket_container_configure_and_setup(global.listensockets, config); } static unsigned long _next_connection_id(void) diff --git a/src/listensocket.c b/src/listensocket.c index 90670ca0..bddbee00 100644 --- a/src/listensocket.c +++ b/src/listensocket.c @@ -45,11 +45,13 @@ struct listensocket_tag { refobject_base_t __base; size_t sockrefc; listener_t *listener; + listener_t *listener_update; sock_t sock; }; static listensocket_t * listensocket_new(const listener_t *listener); -static int listensocket_apply_config(listensocket_t *self, const listener_t *listener); +static int listensocket_apply_config(listensocket_t *self); +static int listensocket_set_update(listensocket_t *self, const listener_t *listener); #ifdef HAVE_POLL static inline int listensocket__poll_fill(listensocket_t *self, struct pollfd *p); #else @@ -137,11 +139,35 @@ listensocket_container_t * listensocket_container_new(void) return self; } +static inline void __find_matching_entry(listensocket_container_t *self, const listener_t *listener, listensocket_t ***found, int **ref) +{ + const listener_t *b; + size_t i; + + for (i = 0; i < self->sock_len; i++) { + if (self->sock[i] != NULL) { + if (self->sockref[i]) { + b = listensocket_get_listener(self->sock[i]); + if (__listener_cmp(listener, b) == 1) { + *found = &(self->sock[i]); + *ref = &(self->sockref[i]); + return; + } + } + } + } + + *found = NULL; + *ref = NULL; +} + int listensocket_container_configure(listensocket_container_t *self, const ice_config_t *config) { listensocket_t **n; + listensocket_t **match; listener_t *cur; int *r; + int *m; size_t i; if (!self || !config) @@ -163,7 +189,16 @@ int listensocket_container_configure(listensocket_contai cur = config->listen_sock; for (i = 0; i < config->listen_sock_count; i++) { if (cur) { - n[i] = listensocket_new(cur); + __find_matching_entry(self, cur, &match, &m); + if (match) { + n[i] = *match; + r[i] = 1; + *match = NULL; + *m = 0; + listensocket_set_update(n[i], cur); + } else { + n[i] = listensocket_new(cur); + } } else { n[i] = NULL; } @@ -217,14 +252,15 @@ int listensocket_container_setup(listensocket_container_ return -1; for (i = 0; i < self->sock_len; i++) { - if (self->sockref[i]) - continue; - - if (listensocket_refsock(self->sock[i]) == 0) { - self->sockref[i] = 1; + if (self->sockref[i]) { + listensocket_apply_config(self->sock[i]); } else { - ICECAST_LOG_DEBUG("Can not ref socket."); - ret = 1; + if (listensocket_refsock(self->sock[i]) == 0) { + self->sockref[i] = 1; + } else { + ICECAST_LOG_DEBUG("Can not ref socket."); + ret = 1; + } } } @@ -369,6 +405,7 @@ static void __listensocket_free(refobject_t self, void **userdata) } while ((listensocket->listener = config_clear_listener(listensocket->listener))); + while ((listensocket->listener_update = config_clear_listener(listensocket->listener_update))); } static listensocket_t * listensocket_new(const listener_t *listener) { @@ -392,29 +429,27 @@ static listensocket_t * listensocket_new(const listener_t *listener) { return self; } -static int listensocket_apply_config(listensocket_t *self, const listener_t *listener) +static int listensocket_apply_config(listensocket_t *self) { - listener_t *copy = NULL; + const listener_t *listener; - if (!self || !listener) + if (!self) return -1; - if (listener != self->listener) { - if (__listener_cmp(listener, self->listener) != 1) { + if (self->listener_update) { + if (__listener_cmp(self->listener, self->listener_update) != 1) { ICECAST_LOG_ERROR("Tried to apply incomplete configuration to listensocket: bind address missmatch: have %s:%i, got %s:%i", __string_default(self->listener->bind_address, ""), self->listener->port, - __string_default(listener->bind_address, ""), - listener->port + __string_default(self->listener_update->bind_address, ""), + self->listener_update->port ); return -1; } - copy = config_copy_listener_one(listener); - if (copy == NULL) { - ICECAST_LOG_ERROR("Can not copy listen socket configuration"); - return -1; - } + listener = self->listener_update; + } else { + listener = self->listener; } if (listener->so_sndbuf) @@ -422,14 +457,31 @@ static int listensocket_apply_config(listensocket_t *self, const li sock_set_blocking(self->sock, 0); - if (copy != NULL) { + if (self->listener_update) { while ((self->listener = config_clear_listener(self->listener))); - self->listener = copy; + self->listener = self->listener_update; + self->listener_update = NULL; } return 0; } +static int listensocket_set_update(listensocket_t *self, const listener_t *listener) +{ + listener_t *n; + + if (!self || !listener) + return -1; + + n = config_copy_listener_one(listener); + if (n == NULL) + return -1; + + while ((self->listener_update = config_clear_listener(self->listener_update))); + self->listener_update = n; + return 0; +} + int listensocket_refsock(listensocket_t *self) { if (!self) @@ -451,7 +503,7 @@ int listensocket_refsock(listensocket_t *self) return -1; } - if (listensocket_apply_config(self, self->listener) == -1) + if (listensocket_apply_config(self) == -1) return -1; self->sockrefc++; From ab8d1639bad5ddec31368a3448d56f78027b0902 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Fri, 11 May 2018 08:08:38 +0000 Subject: [PATCH 10/19] Update: Made listensocket_* perfect thread safe. --- src/connection.c | 7 +- src/listensocket.c | 213 +++++++++++++++++++++++++++++++++++++++------ src/listensocket.h | 1 + 3 files changed, 195 insertions(+), 26 deletions(-) diff --git a/src/connection.c b/src/connection.c index 973c7a07..2da136f6 100644 --- a/src/connection.c +++ b/src/connection.c @@ -623,6 +623,8 @@ static client_queue_t *create_client_node(client_t *client) node->shoutcast_mount = strdup(listener->shoutcast_mount); } + listensocket_release_listener(client->con->listensocket_effective); + return node; } @@ -1216,6 +1218,7 @@ static int _handle_resources(client_t *client, char **uri) break; } + listensocket_release_listener(client->con->listensocket_effective); config_release_config(); if (new_uri) { @@ -1405,15 +1408,17 @@ static void __prepare_shoutcast_admin_cgi_request(client_t *client) return; } - listener = listensocket_get_listener(client->con->listensocket_effective); global_lock(); config = config_get_config(); sc_mount = config->shoutcast_mount; + listener = listensocket_get_listener(client->con->listensocket_effective); if (listener && listener->shoutcast_mount) sc_mount = listener->shoutcast_mount; httpp_set_query_param(client->parser, "mount", sc_mount); + listensocket_release_listener(client->con->listensocket_effective); + httpp_setvar(client->parser, HTTPP_VAR_PROTOCOL, "ICY"); client->password = strdup(pass); config_release_config(); diff --git a/src/listensocket.c b/src/listensocket.c index bddbee00..9ff1fde6 100644 --- a/src/listensocket.c +++ b/src/listensocket.c @@ -23,6 +23,7 @@ #include #include "common/net/sock.h" +#include "common/thread/thread.h" #include "listensocket.h" #include "global.h" @@ -35,6 +36,7 @@ struct listensocket_container_tag { refobject_base_t __base; + mutex_t lock; listensocket_t **sock; int *sockref; size_t sock_len; @@ -44,13 +46,19 @@ struct listensocket_container_tag { struct listensocket_tag { refobject_base_t __base; size_t sockrefc; + mutex_t lock; + rwlock_t listener_rwlock; listener_t *listener; listener_t *listener_update; sock_t sock; }; +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); static listensocket_t * listensocket_new(const listener_t *listener); static int listensocket_apply_config(listensocket_t *self); +static int listensocket_apply_config__unlocked(listensocket_t *self); static int listensocket_set_update(listensocket_t *self, const listener_t *listener); #ifdef HAVE_POLL static inline int listensocket__poll_fill(listensocket_t *self, struct pollfd *p); @@ -88,10 +96,10 @@ static inline void __call_sockcount_cb(listensocket_container_t *self) if (self->sockcount_cb == NULL) return; - self->sockcount_cb(listensocket_container_sockcount(self), self->sockcount_userdata); + self->sockcount_cb(listensocket_container_sockcount__unlocked(self), self->sockcount_userdata); } -static void listensocket_container_clear_sockets(listensocket_container_t *self) +static void __listensocket_container_clear_sockets(listensocket_container_t *self) { size_t i; @@ -121,7 +129,10 @@ static void listensocket_container_clear_sockets(listensocket_container_t *self) static void __listensocket_container_free(refobject_t self, void **userdata) { listensocket_container_t *container = REFOBJECT_TO_TYPE(self, listensocket_container_t *); - listensocket_container_clear_sockets(container); + thread_mutex_lock(&container->lock); + __listensocket_container_clear_sockets(container); + thread_mutex_unlock(&container->lock); + thread_mutex_destroy(&container->lock); } listensocket_container_t * listensocket_container_new(void) @@ -130,25 +141,29 @@ listensocket_container_t * listensocket_container_new(void) if (!self) return NULL; - self->sock = NULL; self->sock_len = 0; self->sockcount_cb = NULL; self->sockcount_userdata = NULL; + thread_mutex_create(&self->lock); + return self; } static inline void __find_matching_entry(listensocket_container_t *self, const listener_t *listener, listensocket_t ***found, int **ref) { const listener_t *b; + int test; size_t i; for (i = 0; i < self->sock_len; i++) { if (self->sock[i] != NULL) { if (self->sockref[i]) { b = listensocket_get_listener(self->sock[i]); - if (__listener_cmp(listener, b) == 1) { + test = __listener_cmp(listener, b); + listensocket_release_listener(self->sock[i]); + if (test == 1) { *found = &(self->sock[i]); *ref = &(self->sockref[i]); return; @@ -162,6 +177,20 @@ static inline void __find_matching_entry(listensocket_container_t *self, const l } int listensocket_container_configure(listensocket_container_t *self, const ice_config_t *config) +{ + int ret; + + if (!self) + return -1; + + thread_mutex_lock(&self->lock); + ret = listensocket_container_configure__unlocked(self, config); + thread_mutex_unlock(&self->lock); + + return ret; +} + +static int listensocket_container_configure__unlocked(listensocket_container_t *self, const ice_config_t *config) { listensocket_t **n; listensocket_t **match; @@ -174,7 +203,7 @@ int listensocket_container_configure(listensocket_contai return -1; if (!config->listen_sock_count) { - listensocket_container_clear_sockets(self); + __listensocket_container_clear_sockets(self); return 0; } @@ -212,7 +241,7 @@ int listensocket_container_configure(listensocket_contai cur = cur->next; } - listensocket_container_clear_sockets(self); + __listensocket_container_clear_sockets(self); self->sock = n; self->sockref = r; @@ -229,28 +258,41 @@ int listensocket_container_configure_and_setup(listensoc if (!self) return -1; + thread_mutex_lock(&self->lock); cb = self->sockcount_cb; self->sockcount_cb = NULL; - if (listensocket_container_configure(self, config) == 0) { - ret = listensocket_container_setup(self); + if (listensocket_container_configure__unlocked(self, config) == 0) { + ret = listensocket_container_setup__unlocked(self); } else { ret = -1; } self->sockcount_cb = cb; __call_sockcount_cb(self); + thread_mutex_unlock(&self->lock); return ret; } -int listensocket_container_setup(listensocket_container_t *self) { - size_t i; - int ret = 0; +int listensocket_container_setup(listensocket_container_t *self) +{ + int ret; if (!self) return -1; + thread_mutex_lock(&self->lock); + ret = listensocket_container_setup__unlocked(self); + thread_mutex_unlock(&self->lock); + + return ret; +} +static int listensocket_container_setup__unlocked(listensocket_container_t *self) +{ + size_t i; + int ret = 0; + for (i = 0; i < self->sock_len; i++) { if (self->sockref[i]) { listensocket_apply_config(self->sock[i]); @@ -360,10 +402,15 @@ static connection_t * listensocket_container_accept__inner(listensocket_co } connection_t * listensocket_container_accept(listensocket_container_t *self, int timeout) { + connection_t *ret; + if (!self) return NULL; - return listensocket_container_accept__inner(self, timeout); + thread_mutex_lock(&self->lock); + ret = listensocket_container_accept__inner(self, timeout); + thread_mutex_unlock(&self->lock); + return ret; } int listensocket_container_set_sockcount_cb(listensocket_container_t *self, void (*cb)(size_t count, void *userdata), void *userdata) @@ -371,20 +418,33 @@ int listensocket_container_set_sockcount_cb(listensocket if (!self) return -1; + thread_mutex_lock(&self->lock); self->sockcount_cb = cb; self->sockcount_userdata = userdata; + thread_mutex_unlock(&self->lock); return 0; } ssize_t listensocket_container_sockcount(listensocket_container_t *self) { - ssize_t count = 0; - size_t i; + ssize_t ret; if (!self) return -1; + thread_mutex_lock(&self->lock); + ret = listensocket_container_sockcount__unlocked(self); + thread_mutex_unlock(&self->lock); + + return ret; +} + +static ssize_t listensocket_container_sockcount__unlocked(listensocket_container_t *self) +{ + ssize_t count = 0; + size_t i; + for (i = 0; i < self->sock_len; i++) { if (self->sockref[i]) { count++; @@ -394,18 +454,27 @@ ssize_t listensocket_container_sockcount(listensocket_contai return count; } +/* ---------------------------------------------------------------------------- */ + static void __listensocket_free(refobject_t self, void **userdata) { listensocket_t *listensocket = REFOBJECT_TO_TYPE(self, listensocket_t *); + thread_mutex_lock(&listensocket->lock); + if (listensocket->sockrefc) { ICECAST_LOG_ERROR("BUG: listensocket->sockrefc == 0 && listensocket->sockrefc == %zu", listensocket->sockrefc); listensocket->sockrefc = 1; listensocket_unrefsock(listensocket); } - while ((listensocket->listener = config_clear_listener(listensocket->listener))); while ((listensocket->listener_update = config_clear_listener(listensocket->listener_update))); + thread_rwlock_wlock(&listensocket->listener_rwlock); + while ((listensocket->listener = config_clear_listener(listensocket->listener))); + thread_rwlock_unlock(&listensocket->listener_rwlock); + thread_rwlock_destroy(&listensocket->listener_rwlock); + thread_mutex_unlock(&listensocket->lock); + thread_mutex_destroy(&listensocket->lock); } static listensocket_t * listensocket_new(const listener_t *listener) { @@ -420,6 +489,9 @@ static listensocket_t * listensocket_new(const listener_t *listener) { self->sock = SOCK_ERROR; + thread_mutex_create(&self->lock); + thread_rwlock_create(&self->listener_rwlock); + self->listener = config_copy_listener_one(listener); if (self->listener == NULL) { refobject_unref(self); @@ -430,12 +502,27 @@ static listensocket_t * listensocket_new(const listener_t *listener) { } static int listensocket_apply_config(listensocket_t *self) +{ + int ret; + + if (!self) + return -1; + + thread_mutex_lock(&self->lock); + ret = listensocket_apply_config__unlocked(self); + thread_mutex_unlock(&self->lock); + + return ret; +} + +static int listensocket_apply_config__unlocked(listensocket_t *self) { const listener_t *listener; if (!self) return -1; + thread_rwlock_wlock(&self->listener_rwlock); if (self->listener_update) { if (__listener_cmp(self->listener, self->listener_update) != 1) { ICECAST_LOG_ERROR("Tried to apply incomplete configuration to listensocket: bind address missmatch: have %s:%i, got %s:%i", @@ -444,6 +531,7 @@ static int listensocket_apply_config(listensocket_t *self) __string_default(self->listener_update->bind_address, ""), self->listener_update->port ); + thread_rwlock_unlock(&self->listener_rwlock); return -1; } @@ -463,6 +551,8 @@ static int listensocket_apply_config(listensocket_t *self) self->listener_update = NULL; } + thread_rwlock_unlock(&self->listener_rwlock); + return 0; } @@ -477,8 +567,10 @@ static int listensocket_set_update(listensocket_t *self, const list if (n == NULL) return -1; + thread_mutex_lock(&self->lock); while ((self->listener_update = config_clear_listener(self->listener_update))); self->listener_update = n; + thread_mutex_unlock(&self->lock); return 0; } @@ -487,26 +579,38 @@ int listensocket_refsock(listensocket_t *self) if (!self) return -1; + thread_mutex_lock(&self->lock); if (self->sockrefc) { self->sockrefc++; + thread_mutex_unlock(&self->lock); return 0; } + thread_rwlock_rlock(&self->listener_rwlock); self->sock = sock_get_server_socket(self->listener->port, self->listener->bind_address); - if (self->sock == SOCK_ERROR) + thread_rwlock_unlock(&self->listener_rwlock); + if (self->sock == SOCK_ERROR) { + thread_mutex_unlock(&self->lock); return -1; + } if (sock_listen(self->sock, ICECAST_LISTEN_QUEUE) == 0) { sock_close(self->sock); self->sock = SOCK_ERROR; + thread_rwlock_rlock(&self->listener_rwlock); ICECAST_LOG_ERROR("Can not listen on socket: %s port %i", __string_default(self->listener->bind_address, ""), self->listener->port); + thread_rwlock_unlock(&self->listener_rwlock); + thread_mutex_unlock(&self->lock); return -1; } - if (listensocket_apply_config(self) == -1) + if (listensocket_apply_config__unlocked(self) == -1) { + thread_mutex_unlock(&self->lock); return -1; + } self->sockrefc++; + thread_mutex_unlock(&self->lock); return 0; } @@ -516,15 +620,21 @@ int listensocket_unrefsock(listensocket_t *self) if (!self) return -1; + thread_mutex_lock(&self->lock); self->sockrefc--; - if (self->sockrefc) + if (self->sockrefc) { + thread_mutex_unlock(&self->lock); return 0; + } - if (self->sock == SOCK_ERROR) + if (self->sock == SOCK_ERROR) { + thread_mutex_unlock(&self->lock); return 0; + } sock_close(self->sock); self->sock = SOCK_ERROR; + thread_mutex_unlock(&self->lock); return 0; } @@ -542,7 +652,9 @@ connection_t * listensocket_accept(listensocket_t *self) if (!ip) return NULL; + thread_mutex_lock(&self->lock); sock = sock_accept(self->sock, ip, MAX_ADDR_LEN); + thread_mutex_unlock(&self->lock); if (sock == SOCK_ERROR) { free(ip); return NULL; @@ -564,41 +676,92 @@ connection_t * listensocket_accept(listensocket_t *self) const listener_t * listensocket_get_listener(listensocket_t *self) { + const listener_t *ret; + if (!self) return NULL; - return self->listener; + thread_mutex_lock(&self->lock); + thread_rwlock_rlock(&self->listener_rwlock); + ret = self->listener; + thread_mutex_unlock(&self->lock); + + return ret; +} + +int listensocket_release_listener(listensocket_t *self) +{ + if (!self) + return -1; + + /* This is safe with no self->lock holding as unref requires a wlock. + * A wlock can not be acquired when someone still holds the rlock. + * In fact this must be done in unlocked state as otherwise we could end up in a + * dead lock with some 3rd party holding the self->lock for an unrelated operation + * waiting for a wlock to be come available. + * -- ph3-der-loewe, 2018-05-11 + */ + thread_rwlock_unlock(&self->listener_rwlock); + + return 0; } #ifdef HAVE_POLL static inline int listensocket__poll_fill(listensocket_t *self, struct pollfd *p) { - if (!self || self->sock == SOCK_ERROR) + if (!self) return -1; + thread_mutex_lock(&self->lock); + if (self->sock == SOCK_ERROR) { + thread_mutex_unlock(&self->lock); + return -1; + } + memset(p, 0, sizeof(*p)); p->fd = self->sock; p->events = POLLIN; p->revents = 0; + thread_mutex_unlock(&self->lock); + return 0; } #else static inline int listensocket__select_set(listensocket_t *self, fd_set *set, int *max) { - if (!self || self->sock == SOCK_ERROR) + if (!self) return -1; + thread_mutex_lock(&self->lock); + if (self->sock == SOCK_ERROR) { + thread_mutex_unlock(&self->lock); + return -1; + } + if (*max < self->sock) *max = self->sock; FD_SET(self->sock, set); + thread_mutex_unlock(&self->lock); + return 0; } static inline int listensocket__select_isset(listensocket_t *self, fd_set *set) { - if (!self || self->sock == SOCK_ERROR) + int ret; + + if (!self) return -1; - return FD_ISSET(self->sock, set); + + thread_mutex_lock(&self->lock); + if (self->sock == SOCK_ERROR) { + thread_mutex_unlock(&self->lock); + return -1; + } + ret = FD_ISSET(self->sock, set); + thread_mutex_unlock(&self->lock); + return ret; + } #endif diff --git a/src/listensocket.h b/src/listensocket.h index b3a03e6a..43c18c9b 100644 --- a/src/listensocket.h +++ b/src/listensocket.h @@ -24,5 +24,6 @@ int listensocket_refsock(listensocket_t *self); int listensocket_unrefsock(listensocket_t *self); connection_t * listensocket_accept(listensocket_t *self); const listener_t * listensocket_get_listener(listensocket_t *self); +int listensocket_release_listener(listensocket_t *self); #endif From e1f944a3f5feca92df5cb9758aa1f807306387fd Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Fri, 11 May 2018 08:10:00 +0000 Subject: [PATCH 11/19] Update: Added comment about global lock in __prepare_shoutcast_admin_cgi_request() --- src/connection.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/connection.c b/src/connection.c index 2da136f6..15d6a727 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1408,6 +1408,7 @@ static void __prepare_shoutcast_admin_cgi_request(client_t *client) return; } + /* Why do we acquire a global lock here? -- ph3-der-loewe, 2018-05-11 */ global_lock(); config = config_get_config(); sc_mount = config->shoutcast_mount; From 6ad7f8d3dbebe58ec7163ee3046d32ac7691fe7b Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Fri, 11 May 2018 14:01:11 +0000 Subject: [PATCH 12/19] Feature: Added id and type property to --- src/cfgfile.c | 24 +++++++++++++++++++++++- src/cfgfile.h | 6 ++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/cfgfile.c b/src/cfgfile.c index 5c3c2d62..c04b3cf3 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -172,6 +172,18 @@ operation_mode config_str_to_omode(const char *str) } } +static listener_type_t config_str_to_listener_type(const char *str) +{ + if (!str || !*str) { + return LISTENER_TYPE_NORMAL; + } else if (strcasecmp(str, "normal") == 0) { + return LISTENER_TYPE_NORMAL; + } else { + ICECAST_LOG_ERROR("Unknown listener type \"%s\", falling back to NORMAL.", str); + return LISTENER_TYPE_NORMAL; + } +} + static void create_locks(void) { thread_mutex_create(&_locks.relay_lock); @@ -580,6 +592,7 @@ listener_t *config_clear_listener(listener_t *listener) if (listener) { next = listener->next; + if (listener->id) xmlFree(listener->id); if (listener->bind_address) xmlFree(listener->bind_address); if (listener->shoutcast_mount) xmlFree(listener->shoutcast_mount); free (listener); @@ -999,7 +1012,7 @@ static void _parse_root(xmlDocPtr doc, xmlFree(configuration->mimetypes_fn); configuration->mimetypes_fn = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (xmlStrcmp(node->name, XMLSTR("listen-socket")) == 0) { - _parse_listen_socket(doc, node->xmlChildrenNode, configuration); + _parse_listen_socket(doc, node, configuration); } else if (xmlStrcmp(node->name, XMLSTR("port")) == 0) { tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); if (tmp && *tmp) { @@ -1744,6 +1757,14 @@ static void _parse_listen_socket(xmlDocPtr doc, return; listener->port = 8000; + listener->id = (char *)xmlGetProp(node, XMLSTR("id")); + + tmp = (char *)xmlGetProp(node, XMLSTR("type")); + listener->type = config_str_to_listener_type(tmp); + xmlFree(tmp); + + node = node->xmlChildrenNode; + do { if (node == NULL) break; @@ -2486,6 +2507,7 @@ listener_t *config_copy_listener_one(const listener_t *listener) { n->next = NULL; n->port = listener->port; n->so_sndbuf = listener->so_sndbuf; + n->id = (char*)xmlStrdup(XMLSTR(listener->id)); 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 31da5675..06eb5b56 100644 --- a/src/cfgfile.h +++ b/src/cfgfile.h @@ -147,8 +147,14 @@ typedef struct _resource { struct _resource *next; } resource_t; +typedef enum _listener_type_tag { + LISTENER_TYPE_NORMAL +} listener_type_t; + typedef struct _listener_t { struct _listener_t *next; + char *id; + listener_type_t type; int port; int so_sndbuf; char *bind_address; From 75be23b5506a76de2d71031f6f0ec46aa3019fe0 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Fri, 18 May 2018 13:20:38 +0000 Subject: [PATCH 13/19] Fix: Also copy listener type --- src/cfgfile.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cfgfile.c b/src/cfgfile.c index c04b3cf3..ec593ff7 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -2507,6 +2507,7 @@ listener_t *config_copy_listener_one(const listener_t *listener) { n->next = NULL; n->port = listener->port; n->so_sndbuf = listener->so_sndbuf; + n->type = listener->type; n->id = (char*)xmlStrdup(XMLSTR(listener->id)); n->bind_address = (char*)xmlStrdup(XMLSTR(listener->bind_address)); n->shoutcast_compat = listener->shoutcast_compat; From 58848cbe5646c5712dc0220d3dd83e71de05c2e5 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Fri, 18 May 2018 13:49:15 +0000 Subject: [PATCH 14/19] Feature: Allow listen sockets to be of type "virtual" --- src/cfgfile.c | 2 ++ src/cfgfile.h | 4 +++- src/listensocket.c | 34 ++++++++++++++++++++++++++++------ src/listensocket.h | 1 + 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/cfgfile.c b/src/cfgfile.c index ec593ff7..232b6b85 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -178,6 +178,8 @@ static listener_type_t config_str_to_listener_type(const char *str) return LISTENER_TYPE_NORMAL; } else if (strcasecmp(str, "normal") == 0) { return LISTENER_TYPE_NORMAL; + } else if (strcasecmp(str, "virtual") == 0) { + return LISTENER_TYPE_VIRTUAL; } else { ICECAST_LOG_ERROR("Unknown listener type \"%s\", falling back to NORMAL.", str); return LISTENER_TYPE_NORMAL; diff --git a/src/cfgfile.h b/src/cfgfile.h index 06eb5b56..11a9aa15 100644 --- a/src/cfgfile.h +++ b/src/cfgfile.h @@ -148,7 +148,9 @@ typedef struct _resource { } resource_t; typedef enum _listener_type_tag { - LISTENER_TYPE_NORMAL + LISTENER_TYPE_ERROR, + LISTENER_TYPE_NORMAL, + LISTENER_TYPE_VIRTUAL } listener_type_t; typedef struct _listener_t { diff --git a/src/listensocket.c b/src/listensocket.c index 9ff1fde6..ee40573e 100644 --- a/src/listensocket.c +++ b/src/listensocket.c @@ -290,13 +290,19 @@ int listensocket_container_setup(listensocket_container_ } static int listensocket_container_setup__unlocked(listensocket_container_t *self) { + listener_type_t type; size_t i; int ret = 0; for (i = 0; i < self->sock_len; i++) { - if (self->sockref[i]) { - listensocket_apply_config(self->sock[i]); - } else { + listensocket_apply_config(self->sock[i]); + + type = listensocket_get_type(self->sock[i]); + if (self->sockref[i] && type == LISTENER_TYPE_VIRTUAL) { + if (listensocket_unrefsock(self->sock[i]) == 0) { + self->sockref[i] = 0; + } + } else if (!self->sockref[i] && type != LISTENER_TYPE_VIRTUAL) { if (listensocket_refsock(self->sock[i]) == 0) { self->sockref[i] = 1; } else { @@ -540,10 +546,12 @@ static int listensocket_apply_config__unlocked(listensocket_t *self listener = self->listener; } - if (listener->so_sndbuf) - sock_set_send_buffer(self->sock, listener->so_sndbuf); + if (self->sock != SOCK_ERROR) { + if (listener->so_sndbuf) + sock_set_send_buffer(self->sock, listener->so_sndbuf); - sock_set_blocking(self->sock, 0); + sock_set_blocking(self->sock, 0); + } if (self->listener_update) { while ((self->listener = config_clear_listener(self->listener))); @@ -706,6 +714,20 @@ int listensocket_release_listener(listensocket_t *self) return 0; } +listener_type_t listensocket_get_type(listensocket_t *self) +{ + listener_type_t ret; + + if (!self) + return LISTENER_TYPE_ERROR; + + thread_mutex_lock(&self->lock); + ret = self->listener->type; + thread_mutex_unlock(&self->lock); + + return ret; +} + #ifdef HAVE_POLL static inline int listensocket__poll_fill(listensocket_t *self, struct pollfd *p) { diff --git a/src/listensocket.h b/src/listensocket.h index 43c18c9b..7d2256ff 100644 --- a/src/listensocket.h +++ b/src/listensocket.h @@ -25,5 +25,6 @@ int listensocket_unrefsock(listensocket_t *self); connection_t * listensocket_accept(listensocket_t *self); const listener_t * listensocket_get_listener(listensocket_t *self); int listensocket_release_listener(listensocket_t *self); +listener_type_t listensocket_get_type(listensocket_t *self); #endif From 33588fc9cfca4f731dcbbf58d54d4b738d428851 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Fri, 18 May 2018 13:58:51 +0000 Subject: [PATCH 15/19] Update: Prepare listensocket_*() API for uses with real listen socket != effective listen socket --- src/listensocket.c | 27 +++++++++++++++++++++------ src/listensocket.h | 2 +- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/listensocket.c b/src/listensocket.c index ee40573e..aef0c0eb 100644 --- a/src/listensocket.c +++ b/src/listensocket.c @@ -317,7 +317,7 @@ static int listensocket_container_setup__unlocked(listensocket_container_t *self return ret; } -static connection_t * listensocket_container_accept__inner(listensocket_container_t *self, int timeout) +static listensocket_t * listensocket_container_accept__inner(listensocket_container_t *self, int timeout) { #ifdef HAVE_POLL struct pollfd ufds[self->sock_len]; @@ -351,7 +351,7 @@ static connection_t * listensocket_container_accept__inner(listensocket_co for (i = 0; i < found; i++) { if (ufds[i].revents & POLLIN) { - return listensocket_accept(socks[i]); + return socks[i]; } if (!(ufds[i].revents & (POLLHUP|POLLERR|POLLNVAL))) @@ -398,7 +398,7 @@ static connection_t * listensocket_container_accept__inner(listensocket_co for (i = 0; i < self->sock_len; i++) { if (self->sockref[i]) { if (listensocket__select_isset(self->sock[i], &rfds)) { - return listensocket_accept(self->sock[i]); + return self->sock[i]; } } } @@ -408,14 +408,20 @@ static connection_t * listensocket_container_accept__inner(listensocket_co } connection_t * listensocket_container_accept(listensocket_container_t *self, int timeout) { + listensocket_t *ls; connection_t *ret; if (!self) return NULL; thread_mutex_lock(&self->lock); - ret = listensocket_container_accept__inner(self, timeout); + ls = listensocket_container_accept__inner(self, timeout); + refobject_ref(ls); thread_mutex_unlock(&self->lock); + + ret = listensocket_accept(ls, self); + refobject_unref(ls); + return ret; } @@ -647,9 +653,10 @@ int listensocket_unrefsock(listensocket_t *self) return 0; } -connection_t * listensocket_accept(listensocket_t *self) +connection_t * listensocket_accept(listensocket_t *self, listensocket_container_t *container) { connection_t *con; + listensocket_t *effective = NULL; sock_t sock; char *ip; @@ -672,7 +679,15 @@ connection_t * listensocket_accept(listensocket_t *self) memmove(ip, ip+7, strlen(ip+7)+1); } - con = connection_create(sock, self, self, ip); + if (!effective) { + effective = self; + refobject_ref(effective); + } + + con = connection_create(sock, self, effective, ip); + + refobject_unref(effective); + if (con == NULL) { sock_close(sock); free(ip); diff --git a/src/listensocket.h b/src/listensocket.h index 7d2256ff..4991892d 100644 --- a/src/listensocket.h +++ b/src/listensocket.h @@ -22,7 +22,7 @@ ssize_t listensocket_container_sockcount(listensocket_contai int listensocket_refsock(listensocket_t *self); int listensocket_unrefsock(listensocket_t *self); -connection_t * listensocket_accept(listensocket_t *self); +connection_t * listensocket_accept(listensocket_t *self, listensocket_container_t *container); const listener_t * listensocket_get_listener(listensocket_t *self); int listensocket_release_listener(listensocket_t *self); listener_type_t listensocket_get_type(listensocket_t *self); From 7742bf0a217dcdbb98814742b575bd2cc1930e0e Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 19 May 2018 07:41:45 +0000 Subject: [PATCH 16/19] Fix: Report correct listen URL to client. The URL is constructed considering Protocol, TLS Mode, Host, and Port. This considers: - The Host:-header as provided by the client, - The effective listensocket of the client, - Global configuration. This works for: - Playlist generation, - Admin authed playlist generation, - Stats based XSLT. It also unifies code: - Default stats values. Not yet included: - YP requests. --- src/admin.c | 15 ++------- src/client.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/client.h | 1 + src/fserve.c | 28 ++--------------- src/source.c | 16 ++-------- src/stats.c | 18 +++++++---- src/stats.h | 3 +- src/xslt.c | 1 + 8 files changed, 110 insertions(+), 61 deletions(-) diff --git a/src/admin.c b/src/admin.c index e2bbea4f..eca2837c 100644 --- a/src/admin.c +++ b/src/admin.c @@ -747,7 +747,6 @@ static void command_buildm3u(client_t *client, source_t *source, admin_format_t const char *mount = source->mount; const char *username = NULL; const char *password = NULL; - ice_config_t *config; ssize_t ret; COMMAND_REQUIRE(client, "username", username); @@ -766,17 +765,7 @@ static void command_buildm3u(client_t *client, source_t *source, admin_format_t } - config = config_get_config(); - snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, - "Content-Disposition: attachment; filename=listen.m3u\r\n\r\n" - "http://%s:%s@%s:%d%s\r\n", - username, - password, - config->hostname, - config->port, - mount - ); - config_release_config(); + client_get_baseurl(client, NULL, client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, username, password, "Content-Disposition: attachment; filename=listen.m3u\r\n\r\n", mount, "\r\n"); client->respcode = 200; client->refbuf->len = strlen (client->refbuf->data); @@ -1131,7 +1120,7 @@ static void command_stats(client_t *client, source_t *source, admin_format_t res ICECAST_LOG_DEBUG("Stats request, sending xml stats"); - doc = stats_get_xml(1, mount, client->mode); + doc = stats_get_xml(1, mount, client); admin_send_response(doc, client, response, STATS_HTML_REQUEST); xmlFreeDoc(doc); return; diff --git a/src/client.c b/src/client.c index b4373042..bfcf4844 100644 --- a/src/client.c +++ b/src/client.c @@ -48,6 +48,7 @@ #include "util.h" #include "acl.h" +#include "listensocket.h" /* for ADMIN_COMMAND_ERROR */ #include "admin.h" @@ -766,3 +767,91 @@ client_slurp_result_t client_body_skip(client_t *client) break; } } + +ssize_t client_get_baseurl(client_t *client, listensocket_t *listensocket, char *buf, size_t len, const char *user, const char *pw, const char *prefix, const char *suffix0, const char *suffix1) +{ + const listener_t *listener = NULL; + const ice_config_t *config = NULL; + const char *host = NULL; + const char *proto = "http"; + int port = 0; + ssize_t ret; + tlsmode_t tlsmode = ICECAST_TLSMODE_AUTO; + protocol_t protocol = ICECAST_PROTOCOL_HTTP; + + if (!buf || !len) + return -1; + + if (!prefix) + prefix = ""; + + if (!suffix0) + suffix0 = ""; + + if (!suffix1) + suffix1 = ""; + + if (client) { + host = httpp_getvar(client->parser, "host"); + + /* at least a couple of players (fb2k/winamp) are reported to send a + * host header but without the port number. So if we are missing the + * port then lets treat it as if no host line was sent */ + if (host && strchr(host, ':') == NULL) + host = NULL; + + listensocket = client->con->listensocket_effective; + tlsmode = client->con->tlsmode; + protocol = client->protocol; + } + + if (!host && listensocket) { + listener = listensocket_get_listener(listensocket); + if (listener) { + host = listener->bind_address; + port = listener->port; + if (!client) + tlsmode = listener->tls; + } + } + + if (!host) { + config = config_get_config(); + host = config->hostname; + if (!port) + port = config->port; + } + + switch (tlsmode) { + case ICECAST_TLSMODE_DISABLED: + case ICECAST_TLSMODE_AUTO: + switch (protocol) { + case ICECAST_PROTOCOL_HTTP: proto = "http"; break; + case ICECAST_PROTOCOL_SHOUTCAST: proto = "icy"; break; + } + break; + case ICECAST_TLSMODE_AUTO_NO_PLAIN: + case ICECAST_TLSMODE_RFC2817: + case ICECAST_TLSMODE_RFC2818: + switch (protocol) { + case ICECAST_PROTOCOL_HTTP: proto = "https"; break; + case ICECAST_PROTOCOL_SHOUTCAST: proto = "icys"; break; + } + break; + } + + if (host && port) { + ret = snprintf(buf, len, "%s%s://%s%s%s%s%s:%i%s%s", prefix, proto, user ? user : "", pw ? ":" : "", pw ? pw : "", (user || pw) ? "@" : "", host, port, suffix0, suffix1); + } else if (host) { + ret = snprintf(buf, len, "%s%s://%s%s%s%s%s%s%s", prefix, proto, user ? user : "", pw ? ":" : "", pw ? pw : "", (user || pw) ? "@" : "", host, suffix0, suffix1); + } else { + ret = -1; + } + + if (config) + config_release_config(); + if (listener) + listensocket_release_listener(listensocket); + + return ret; +} diff --git a/src/client.h b/src/client.h index 9d426c44..e3c0bb58 100644 --- a/src/client.h +++ b/src/client.h @@ -151,5 +151,6 @@ ssize_t client_body_read(client_t *client, void *buf, size_t len); int client_body_eof(client_t *client); client_slurp_result_t client_body_slurp(client_t *client, void *buf, size_t *len); client_slurp_result_t client_body_skip(client_t *client); +ssize_t client_get_baseurl(client_t *client, listensocket_t *listensocket, char *buf, size_t len, const char *user, const char *pw, const char *prefix, const char *suffix0, const char *suffix1); #endif /* __CLIENT_H__ */ diff --git a/src/fserve.c b/src/fserve.c index e7158449..f526c0db 100644 --- a/src/fserve.c +++ b/src/fserve.c @@ -452,16 +452,9 @@ int fserve_client_create (client_t *httpclient, const char *path) if (m3u_requested && m3u_file_available == 0) { - const char *host = httpp_getvar (httpclient->parser, "host"); char *sourceuri = strdup (path); char *dot = strrchr(sourceuri, '.'); - /* at least a couple of players (fb2k/winamp) are reported to send a - * host header but without the port number. So if we are missing the - * port then lets treat it as if no host line was sent */ - if (host && strchr (host, ':') == NULL) - host = NULL; - *dot = 0; httpclient->respcode = 200; ret = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0, @@ -473,24 +466,7 @@ int fserve_client_create (client_t *httpclient, const char *path) free(sourceuri); return -1; } - if (host == NULL) - { - config = config_get_config(); - snprintf (httpclient->refbuf->data + ret, BUFSIZE - ret, - "http://%s:%d%s\r\n", - config->hostname, config->port, - sourceuri - ); - config_release_config(); - } - else - { - snprintf (httpclient->refbuf->data + ret, BUFSIZE - ret, - "http://%s%s\r\n", - host, - sourceuri - ); - } + client_get_baseurl(httpclient, NULL, httpclient->refbuf->data + ret, BUFSIZE - ret, NULL, NULL, NULL, sourceuri, "\r\n"); httpclient->refbuf->len = strlen (httpclient->refbuf->data); fserve_add_client (httpclient, NULL); free (sourceuri); @@ -504,7 +480,7 @@ int fserve_client_create (client_t *httpclient, const char *path) char *eol = strrchr (reference, '.'); if (eol) *eol = '\0'; - doc = stats_get_xml (0, reference, httpclient->mode); + doc = stats_get_xml (0, reference, httpclient); free (reference); admin_send_response (doc, httpclient, ADMIN_FORMAT_HTML, xslt_playlist_requested); xmlFreeDoc(doc); diff --git a/src/source.c b/src/source.c index 7a7e0a65..2887322c 100644 --- a/src/source.c +++ b/src/source.c @@ -616,19 +616,8 @@ static FILE * source_open_dumpfile(const char * filename) { */ static void source_init (source_t *source) { - ice_config_t *config = config_get_config(); - char *listenurl; + char listenurl[512]; const char *str; - int listen_url_size; - - /* 6 for max size of port */ - listen_url_size = strlen("http://") + strlen(config->hostname) + - strlen(":") + 6 + strlen(source->mount) + 1; - - listenurl = malloc (listen_url_size); - snprintf (listenurl, listen_url_size, "http://%s:%d%s", - config->hostname, config->port, source->mount); - config_release_config(); str = httpp_getvar(source->parser, "ice-audio-info"); source->audio_info = util_dict_new(); @@ -638,10 +627,9 @@ static void source_init (source_t *source) stats_event (source->mount, "audio_info", str); } + client_get_baseurl(NULL, NULL, listenurl, sizeof(listenurl), NULL, NULL, NULL, NULL, NULL); stats_event (source->mount, "listenurl", listenurl); - free(listenurl); - if (source->dumpfilename != NULL) { source->dumpfile = source_open_dumpfile (source->dumpfilename); diff --git a/src/stats.c b/src/stats.c index 07cf534c..0f9d9ce9 100644 --- a/src/stats.c +++ b/src/stats.c @@ -829,7 +829,7 @@ static inline void __add_authstack (auth_stack_t *stack, xmlNodePtr parent) { auth_stack_next(&stack); } } -static xmlNodePtr _dump_stats_to_doc (xmlNodePtr root, const char *show_mount, int hidden) { +static xmlNodePtr _dump_stats_to_doc (xmlNodePtr root, const char *show_mount, int hidden, client_t *client) { avl_node *avlnode; xmlNodePtr ret = NULL; ice_config_t *config; @@ -870,7 +870,13 @@ static xmlNodePtr _dump_stats_to_doc (xmlNodePtr root, const char *show_mount, i while (avlnode2) { stats_node_t *stat = avlnode2->key; - xmlNewTextChild (xmlnode, NULL, XMLSTR(stat->name), XMLSTR(stat->value)); + if (client && strcmp(stat->name, "listenurl") == 0) { + char buf[512]; + client_get_baseurl(client, NULL, buf, sizeof(buf), NULL, NULL, NULL, source->source, NULL); + xmlNewTextChild (xmlnode, NULL, XMLSTR(stat->name), XMLSTR(buf)); + } else { + xmlNewTextChild (xmlnode, NULL, XMLSTR(stat->name), XMLSTR(stat->value)); + } avlnode2 = avl_get_next (avlnode2); } @@ -1022,7 +1028,7 @@ void stats_transform_xslt(client_t *client, const char *uri) char *xslpath = util_get_path_from_normalised_uri(uri); const char *mount = httpp_get_param(client->parser, "mount"); - doc = stats_get_xml(0, mount, client->mode); + doc = stats_get_xml(0, mount, client); xslt_transform(doc, xslpath, client, 200); @@ -1053,7 +1059,7 @@ static void __add_metadata(xmlNodePtr node, const char *tag) { free(name); } -xmlDocPtr stats_get_xml(int show_hidden, const char *show_mount, operation_mode mode) +xmlDocPtr stats_get_xml(int show_hidden, const char *show_mount, client_t *client) { xmlDocPtr doc; xmlNodePtr node; @@ -1063,12 +1069,12 @@ xmlDocPtr stats_get_xml(int show_hidden, const char *show_mount, operation_mode node = xmlNewDocNode (doc, NULL, XMLSTR("icestats"), NULL); xmlDocSetRootElement(doc, node); - node = _dump_stats_to_doc (node, show_mount, show_hidden); + node = _dump_stats_to_doc(node, show_mount, show_hidden, client); if (show_mount && node) { avl_tree_rlock(global.source_tree); source = source_find_mount_raw(show_mount); - admin_add_listeners_to_mount(source, node, mode); + admin_add_listeners_to_mount(source, node, client->mode); avl_tree_unlock(global.source_tree); } diff --git a/src/stats.h b/src/stats.h index 3ec72214..d004782f 100644 --- a/src/stats.h +++ b/src/stats.h @@ -18,7 +18,6 @@ #include #include "icecasttypes.h" -#include "cfgfile.h" #include "refbuf.h" typedef struct _stats_node_tag @@ -95,7 +94,7 @@ void stats_callback (client_t *client, void *notused); void stats_transform_xslt(client_t *client, const char *uri); void stats_sendxml(client_t *client); -xmlDocPtr stats_get_xml(int show_hidden, const char *show_mount, operation_mode mode); +xmlDocPtr stats_get_xml(int show_hidden, const char *show_mount, client_t *client); char *stats_get_value(const char *source, const char *name); #endif /* __STATS_H__ */ diff --git a/src/xslt.c b/src/xslt.c index 366ed4c2..821660ef 100644 --- a/src/xslt.c +++ b/src/xslt.c @@ -53,6 +53,7 @@ #include "stats.h" #include "fserve.h" #include "util.h" +#include "cfgfile.h" #define CATMODULE "xslt" From 80ffdca7d10f5cfa26ffa28db672e450e65b72b9 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 30 Jun 2018 13:51:42 +0000 Subject: [PATCH 17/19] 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); From 2febabcddd501f7e179e7a9f86b308614ac21a10 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 30 Jun 2018 13:57:37 +0000 Subject: [PATCH 18/19] Update: Corrected copyright --- src/cfgfile.c | 2 +- src/cfgfile.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cfgfile.c b/src/cfgfile.c index ae86d42f..0a5347bd 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -10,7 +10,7 @@ * and others (see AUTHORS for details). * Copyright 2011, Dave 'justdave' Miller . * Copyright 2011-2014, Thomas B. "dm8tbr" Ruecker , - * Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft , + * Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft , */ #ifdef HAVE_CONFIG_H diff --git a/src/cfgfile.h b/src/cfgfile.h index 875a904e..b9cee049 100644 --- a/src/cfgfile.h +++ b/src/cfgfile.h @@ -9,7 +9,7 @@ * Karl Heyes * and others (see AUTHORS for details). * Copyright 2011, Dave 'justdave' Miller . - * Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft , + * Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft , */ #ifndef __CFGFILE_H__ From d9e96a55e7e1794d6f6d6e6542e3eba90b1e00d8 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Sat, 30 Jun 2018 14:06:05 +0000 Subject: [PATCH 19/19] Feature: Allow to match on a specific listen-socket --- src/cfgfile.c | 7 +++++++ src/cfgfile.h | 1 + src/connection.c | 3 +++ 3 files changed, 11 insertions(+) diff --git a/src/cfgfile.c b/src/cfgfile.c index 0a5347bd..87e46883 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -596,6 +596,7 @@ static void config_clear_resource(resource_t *resource) xmlFree(resource->vhost); xmlFree(resource->module); xmlFree(resource->handler); + free(resource->listen_socket); free(resource); resource = nextresource; } @@ -2007,6 +2008,12 @@ static void _parse_resource(xmlDocPtr doc, resource->bind_address = (char *)xmlGetProp(node, XMLSTR("bind-address")); + temp = (char *)xmlGetProp(node, XMLSTR("listen-socket")); + if (temp) { + resource->listen_socket = config_href_to_id(temp); + xmlFree(temp); + } + resource->vhost = (char *)xmlGetProp(node, XMLSTR("vhost")); resource->module = (char *)xmlGetProp(node, XMLSTR("module")); diff --git a/src/cfgfile.h b/src/cfgfile.h index b9cee049..e7f0b071 100644 --- a/src/cfgfile.h +++ b/src/cfgfile.h @@ -139,6 +139,7 @@ typedef struct _resource { char *destination; int port; char *bind_address; + char *listen_socket; char *vhost; char *module; char *handler; diff --git a/src/connection.c b/src/connection.c index 15d6a727..02ec6dfd 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1176,6 +1176,9 @@ static int _handle_resources(client_t *client, char **uri) if (resource->bind_address != NULL && serverhost != NULL && strcmp(resource->bind_address, serverhost) != 0) continue; + if (resource->listen_socket != NULL && (listen_sock->id == NULL || strcmp(resource->listen_socket, listen_sock->id) != 0)) + continue; + /* Check for the vhost to match. */ if (resource->vhost != NULL && vhost != NULL && strcmp(resource->vhost, vhost) != 0) continue;