mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2025-02-02 15:07:36 -05:00
Merge branch 'ph3-listen-sockets'
This commit is contained in:
commit
c26ee2fcfb
@ -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 \
|
||||
|
15
src/admin.c
15
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;
|
||||
|
@ -10,7 +10,7 @@
|
||||
* and others (see AUTHORS for details).
|
||||
* Copyright 2011, Dave 'justdave' Miller <justdave@mozilla.com>.
|
||||
* Copyright 2011-2014, Thomas B. "dm8tbr" Ruecker <thomas@ruecker.fi>,
|
||||
* Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
|
||||
* Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@ -172,6 +172,33 @@ 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 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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@ -569,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;
|
||||
}
|
||||
@ -580,6 +608,8 @@ listener_t *config_clear_listener(listener_t *listener)
|
||||
if (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);
|
||||
@ -999,7 +1029,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 +1774,20 @@ static void _parse_listen_socket(xmlDocPtr doc,
|
||||
return;
|
||||
listener->port = 8000;
|
||||
|
||||
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);
|
||||
|
||||
node = node->xmlChildrenNode;
|
||||
|
||||
do {
|
||||
if (node == NULL)
|
||||
break;
|
||||
@ -1964,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"));
|
||||
@ -2473,24 +2523,28 @@ 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++;
|
||||
}
|
||||
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->type = listener->type;
|
||||
n->id = (char*)xmlStrdup(XMLSTR(listener->id));
|
||||
if (listener->on_behalf_of) {
|
||||
n->on_behalf_of = strdup(listener->on_behalf_of);
|
||||
}
|
||||
return listener;
|
||||
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;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
* Karl Heyes <karl@xiph.org>
|
||||
* and others (see AUTHORS for details).
|
||||
* Copyright 2011, Dave 'justdave' Miller <justdave@mozilla.com>.
|
||||
* Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
|
||||
* Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
|
||||
*/
|
||||
|
||||
#ifndef __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;
|
||||
@ -147,8 +148,17 @@ typedef struct _resource {
|
||||
struct _resource *next;
|
||||
} resource_t;
|
||||
|
||||
typedef enum _listener_type_tag {
|
||||
LISTENER_TYPE_ERROR,
|
||||
LISTENER_TYPE_NORMAL,
|
||||
LISTENER_TYPE_VIRTUAL
|
||||
} listener_type_t;
|
||||
|
||||
typedef struct _listener_t {
|
||||
struct _listener_t *next;
|
||||
char *id;
|
||||
char *on_behalf_of;
|
||||
listener_type_t type;
|
||||
int port;
|
||||
int so_sndbuf;
|
||||
char *bind_address;
|
||||
@ -262,7 +272,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);
|
||||
|
91
src/client.c
91
src/client.c
@ -48,6 +48,7 @@
|
||||
|
||||
#include "util.h"
|
||||
#include "acl.h"
|
||||
#include "listensocket.h"
|
||||
|
||||
/* for ADMIN_COMMAND_ERROR */
|
||||
#include "admin.h"
|
||||
@ -110,7 +111,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 */
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
232
src/connection.c
232
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,7 @@ void connection_shutdown(void)
|
||||
void connection_reread_config(ice_config_t *config)
|
||||
{
|
||||
get_tls_certificate(config);
|
||||
listensocket_container_configure_and_setup(global.listensockets, config);
|
||||
}
|
||||
|
||||
static unsigned long _next_connection_id(void)
|
||||
@ -245,13 +248,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 +366,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 +604,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,7 +623,7 @@ static client_queue_t *create_client_node(client_t *client)
|
||||
node->shoutcast_mount = strdup(listener->shoutcast_mount);
|
||||
}
|
||||
|
||||
config_release_config();
|
||||
listensocket_release_listener(client->con->listensocket_effective);
|
||||
|
||||
return node;
|
||||
}
|
||||
@ -776,7 +674,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 +1132,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 +1144,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;
|
||||
@ -1278,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;
|
||||
@ -1320,6 +1221,7 @@ static int _handle_resources(client_t *client, char **uri)
|
||||
break;
|
||||
}
|
||||
|
||||
listensocket_release_listener(client->con->listensocket_effective);
|
||||
config_release_config();
|
||||
|
||||
if (new_uri) {
|
||||
@ -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,15 +1411,18 @@ 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;
|
||||
listener = config_get_listen_sock(config, client->con);
|
||||
|
||||
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();
|
||||
@ -1732,22 +1637,27 @@ static void _handle_connection(void)
|
||||
}
|
||||
|
||||
|
||||
/* called when listening thread is not checking for incoming connections */
|
||||
int connection_setup_sockets (ice_config_t *config)
|
||||
static void __on_sock_count(size_t count, void *userdata)
|
||||
{
|
||||
int count = 0;
|
||||
listener_t *listener, **prev;
|
||||
(void)userdata;
|
||||
|
||||
global_lock();
|
||||
if (global.serversock) {
|
||||
for (; count < global.server_sockets; count++)
|
||||
sock_close (global.serversock [count]);
|
||||
free (global.serversock);
|
||||
global.serversock = NULL;
|
||||
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)
|
||||
{
|
||||
global_lock();
|
||||
refobject_unref(global.listensockets);
|
||||
|
||||
if (config == NULL) {
|
||||
global_unlock();
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* setup the banned/allowed IP filenames from the xml */
|
||||
@ -1763,57 +1673,13 @@ 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_set_sockcount_cb(global.listensockets, __on_sock_count, NULL);
|
||||
listensocket_container_setup(global.listensockets);;
|
||||
}
|
||||
|
||||
|
||||
@ -1829,5 +1695,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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
28
src/fserve.c
28
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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
838
src/listensocket.c
Normal file
838
src/listensocket.c
Normal file
@ -0,0 +1,838 @@
|
||||
/* 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 <lion@lion.leolix.org>,
|
||||
*/
|
||||
|
||||
/**
|
||||
* Listen socket operations.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
#include <poll.h>
|
||||
#else
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "common/net/sock.h"
|
||||
#include "common/thread/thread.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;
|
||||
mutex_t lock;
|
||||
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;
|
||||
size_t sockrefc;
|
||||
mutex_t lock;
|
||||
rwlock_t listener_rwlock;
|
||||
listener_t *listener;
|
||||
listener_t *listener_update;
|
||||
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);
|
||||
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);
|
||||
#else
|
||||
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 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)
|
||||
return;
|
||||
|
||||
self->sockcount_cb(listensocket_container_sockcount__unlocked(self), self->sockcount_userdata);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
__call_sockcount_cb(self);
|
||||
}
|
||||
|
||||
|
||||
static void __listensocket_container_free(refobject_t self, void **userdata)
|
||||
{
|
||||
listensocket_container_t *container = REFOBJECT_TO_TYPE(self, listensocket_container_t *);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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]);
|
||||
test = __listener_cmp(listener, b);
|
||||
listensocket_release_listener(self->sock[i]);
|
||||
if (test == 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)
|
||||
{
|
||||
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;
|
||||
listener_t *cur;
|
||||
int *r;
|
||||
int *m;
|
||||
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) {
|
||||
__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;
|
||||
}
|
||||
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_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;
|
||||
|
||||
thread_mutex_lock(&self->lock);
|
||||
cb = self->sockcount_cb;
|
||||
self->sockcount_cb = NULL;
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
listener_type_t type;
|
||||
size_t i;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; i < self->sock_len; i++) {
|
||||
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 {
|
||||
ICECAST_LOG_DEBUG("Can not ref socket.");
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__call_sockcount_cb(self);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static listensocket_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 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;
|
||||
__call_sockcount_cb(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 self->sock[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
int listensocket_container_set_sockcount_cb(listensocket_container_t *self, void (*cb)(size_t count, void *userdata), void *userdata)
|
||||
{
|
||||
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 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++;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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_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) {
|
||||
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;
|
||||
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
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",
|
||||
__string_default(self->listener->bind_address, "<ANY>"),
|
||||
self->listener->port,
|
||||
__string_default(self->listener_update->bind_address, "<ANY>"),
|
||||
self->listener_update->port
|
||||
);
|
||||
thread_rwlock_unlock(&self->listener_rwlock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
listener = self->listener_update;
|
||||
} else {
|
||||
listener = self->listener;
|
||||
}
|
||||
|
||||
if (self->sock != SOCK_ERROR) {
|
||||
if (listener->so_sndbuf)
|
||||
sock_set_send_buffer(self->sock, listener->so_sndbuf);
|
||||
|
||||
sock_set_blocking(self->sock, 0);
|
||||
}
|
||||
|
||||
if (self->listener_update) {
|
||||
while ((self->listener = config_clear_listener(self->listener)));
|
||||
self->listener = self->listener_update;
|
||||
self->listener_update = NULL;
|
||||
}
|
||||
|
||||
thread_rwlock_unlock(&self->listener_rwlock);
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
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, "<ANY>"), self->listener->port);
|
||||
thread_rwlock_unlock(&self->listener_rwlock);
|
||||
thread_mutex_unlock(&self->lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listensocket_apply_config__unlocked(self) == -1) {
|
||||
thread_mutex_unlock(&self->lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
self->sockrefc++;
|
||||
thread_mutex_unlock(&self->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int listensocket_unrefsock(listensocket_t *self)
|
||||
{
|
||||
if (!self)
|
||||
return -1;
|
||||
|
||||
thread_mutex_lock(&self->lock);
|
||||
self->sockrefc--;
|
||||
if (self->sockrefc) {
|
||||
thread_mutex_unlock(&self->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
connection_t * listensocket_accept(listensocket_t *self, listensocket_container_t *container)
|
||||
{
|
||||
connection_t *con;
|
||||
listensocket_t *effective = NULL;
|
||||
sock_t sock;
|
||||
char *ip;
|
||||
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
ip = calloc(MAX_ADDR_LEN, 1);
|
||||
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;
|
||||
}
|
||||
|
||||
if (strncmp(ip, "::ffff:", 7) == 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
con = connection_create(sock, self, effective, ip);
|
||||
|
||||
refobject_unref(effective);
|
||||
|
||||
if (con == NULL) {
|
||||
sock_close(sock);
|
||||
free(ip);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return con;
|
||||
}
|
||||
|
||||
const listener_t * listensocket_get_listener(listensocket_t *self)
|
||||
{
|
||||
const listener_t *ret;
|
||||
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!self)
|
||||
return -1;
|
||||
|
||||
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
|
30
src/listensocket.h
Normal file
30
src/listensocket.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* 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 <lion@lion.leolix.org>,
|
||||
*/
|
||||
|
||||
#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_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);
|
||||
ssize_t listensocket_container_sockcount(listensocket_container_t *self);
|
||||
|
||||
int listensocket_refsock(listensocket_t *self);
|
||||
int listensocket_unrefsock(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);
|
||||
|
||||
#endif
|
22
src/main.c
22
src/main.c
@ -77,6 +77,7 @@
|
||||
#include "yp.h"
|
||||
#include "auth.h"
|
||||
#include "event.h"
|
||||
#include "listensocket.h"
|
||||
|
||||
#include <libxml/xmlmemory.h>
|
||||
|
||||
@ -318,20 +319,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,11 +376,10 @@ static int _server_proc_init(void)
|
||||
{
|
||||
ice_config_t *config = config_get_config_unlocked();
|
||||
|
||||
if (connection_setup_sockets (config) < 1)
|
||||
return 0;
|
||||
connection_setup_sockets(config);
|
||||
|
||||
if (!_start_listening()) {
|
||||
_fatal_error("Failed trying to listen on server socket");
|
||||
if (listensocket_container_sockcount(global.listensockets) < 1) {
|
||||
ICECAST_LOG_ERROR("Can not listen on any sockets.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
16
src/source.c
16
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);
|
||||
|
18
src/stats.c
18
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);
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <libxml/tree.h>
|
||||
|
||||
#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__ */
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "stats.h"
|
||||
#include "fserve.h"
|
||||
#include "util.h"
|
||||
#include "cfgfile.h"
|
||||
|
||||
#define CATMODULE "xslt"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user