1
0
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:
Philipp Schafft 2018-06-30 14:12:08 +00:00
commit c26ee2fcfb
20 changed files with 1136 additions and 292 deletions

View File

@ -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 \

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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
View 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
View 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

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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__ */

View File

@ -53,6 +53,7 @@
#include "stats.h"
#include "fserve.h"
#include "util.h"
#include "cfgfile.h"
#define CATMODULE "xslt"