Commit 80078cce authored by Ed "oddsock" Zaleski's avatar Ed "oddsock" Zaleski
Browse files

* support for the Shoutcast DSP (yay!).

    You can now use the Shoutcast DSP as a source client.  The connection 
    protocol is a bit odd, and we had to handle it separately, and thus 
    we've added a new config option (<shoutcast-compat>) that is set at 
    the listener port level.
* support for NSV (and the nsvscsrc source client).
    After adding support for the connection protocol of the shoutcast DSP, 
    adding NSV was just a simple of a few special handling cases.
* removed all traces of the earlier attempt at the shoutcast DSP connection 
  protocol
* Due to the growing complexity of the config files, I've also created a 
  few alternate config files, namely one for a "shoutcast compat" setup
  as well as a "minimal" one for quick basic configurations.

svn path=/icecast/trunk/icecast/; revision=8191
parent 04dc8fb1
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
AUTOMAKE_OPTIONS = foreign AUTOMAKE_OPTIONS = foreign
EXTRA_DIST = icecast.xml.in EXTRA_DIST = icecast.xml.in icecast_minimal.xml.in icecast_shoutcast_compat.xml.in
DISTCLEANFILES = icecast.xml.dist DISTCLEANFILES = icecast.xml.dist icecast_minimal.xml.dist icecast_shoutcast_compat.xml.dist
docdir = $(datadir)/$(PACKAGE)/doc docdir = $(datadir)/$(PACKAGE)/doc
doc_DATA = icecast.xml.dist doc_DATA = icecast.xml.dist icecast_minimal.xml.dist icecast_shoutcast_compat.xml.dist
install-data-hook: install-data-hook:
$(mkinstalldirs) $(DESTDIR)$(sysconfdir) $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
...@@ -20,6 +20,12 @@ edit = sed -e 's,@pkgdatadir\@,$(pkgdatadir),g' \ ...@@ -20,6 +20,12 @@ edit = sed -e 's,@pkgdatadir\@,$(pkgdatadir),g' \
icecast.xml.dist: $(srcdir)/icecast.xml.in icecast.xml.dist: $(srcdir)/icecast.xml.in
$(edit) $(srcdir)/icecast.xml.in > icecast.xml.dist $(edit) $(srcdir)/icecast.xml.in > icecast.xml.dist
icecast_minimal.xml.dist: $(srcdir)/icecast_minimal.xml.in
$(edit) $(srcdir)/icecast_minimal.xml.in > icecast_minimal.xml.dist
icecast_shoutcast_compat.xml.dist: $(srcdir)/icecast_shoutcast_compat.xml.in
$(edit) $(srcdir)/icecast_shoutcast_compat.xml.in > icecast_shoutcast_compat.xml.dist
debug: debug:
$(MAKE) all CFLAGS="@DEBUG@" $(MAKE) all CFLAGS="@DEBUG@"
......
...@@ -157,6 +157,11 @@ The URL which icecast2 uses to communicate with the Directory server. The value ...@@ -157,6 +157,11 @@ The URL which icecast2 uses to communicate with the Directory server. The value
&lt;port&gt;8000&lt;/port&gt; &lt;port&gt;8000&lt;/port&gt;
&lt;bind-address&gt;127.0.0.1&lt;/bind-address&gt; &lt;bind-address&gt;127.0.0.1&lt;/bind-address&gt;
&lt;/listen-socket&gt; &lt;/listen-socket&gt;
&lt;listen-socket&gt;
&lt;port&gt;8001&lt;/port&gt;
&lt;bind-address&gt;127.0.0.1&lt;/bind-address&gt;
&lt;shoutcast-compat&gt;1&lt;/shoutcast-compat&gt;
&lt;/listen-socket&gt;
&lt;fileserve&gt;1&lt;/fileserve&gt; &lt;fileserve&gt;1&lt;/fileserve&gt;
</pre> </pre>
...@@ -170,6 +175,10 @@ The TCP port that will be used to accept client connections. ...@@ -170,6 +175,10 @@ The TCP port that will be used to accept client connections.
<div class="indentedbox"> <div class="indentedbox">
And option IP address that can be used to bind to a specific network card. If not supplied, then &lt;hostname&gt; will be used. And option IP address that can be used to bind to a specific network card. If not supplied, then &lt;hostname&gt; will be used.
</div> </div>
<h4>shoutcast-compat</h4>
<div class="indentedbox">
This optional flag will indicate that this port will operate in 'shoutcast-compatibility' mode. Due to major differences in the source client connection protocol, if you wish to use any of the shoutcast DJ tools, you will need to configure at least one socket as shoutcast-compatible. Note that when in this mode, only source clients (and specifically shoutcast source clients) will be able to attach to this port. All listeners may connect to any of the ports defined without this flag. Also, for proper Shoutcast DSP compatibility, you must define a listen socket with a port one less than the one defined as 'shoutcast-compat'. This means if you define 8001 as shoutcast-compat, then you will need to define a listen port of 8000 and it must not also be defined as shoutcast-compat. See the example config file is the distribution for more info.
</div>
<h4>fileserve</h4> <h4>fileserve</h4>
<div class="indentedbox"> <div class="indentedbox">
This flag turns on the icecast2 fileserver from which static files can be served. All files are served relative to the path specified in the &lt;paths&gt;&lt;webroot&gt; configuration setting. This flag turns on the icecast2 fileserver from which static files can be served. All files are served relative to the path specified in the &lt;paths&gt;&lt;webroot&gt; configuration setting.
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#define COMMAND_RAW_SHOW_LISTENERS 3 #define COMMAND_RAW_SHOW_LISTENERS 3
#define COMMAND_RAW_MOVE_CLIENTS 4 #define COMMAND_RAW_MOVE_CLIENTS 4
#define COMMAND_RAW_MANAGEAUTH 5 #define COMMAND_RAW_MANAGEAUTH 5
#define COMMAND_SHOUTCAST_METADATA_UPDATE 6
#define COMMAND_TRANSFORMED_FALLBACK 50 #define COMMAND_TRANSFORMED_FALLBACK 50
#define COMMAND_TRANSFORMED_SHOW_LISTENERS 53 #define COMMAND_TRANSFORMED_SHOW_LISTENERS 53
...@@ -78,6 +79,7 @@ ...@@ -78,6 +79,7 @@
#define FALLBACK_RAW_REQUEST "fallbacks" #define FALLBACK_RAW_REQUEST "fallbacks"
#define FALLBACK_TRANSFORMED_REQUEST "fallbacks.xsl" #define FALLBACK_TRANSFORMED_REQUEST "fallbacks.xsl"
#define SHOUTCAST_METADATA_REQUEST "admin.cgi"
#define METADATA_REQUEST "metadata" #define METADATA_REQUEST "metadata"
#define LISTCLIENTS_RAW_REQUEST "listclients" #define LISTCLIENTS_RAW_REQUEST "listclients"
#define LISTCLIENTS_TRANSFORMED_REQUEST "listclients.xsl" #define LISTCLIENTS_TRANSFORMED_REQUEST "listclients.xsl"
...@@ -112,6 +114,8 @@ int admin_get_command(char *command) ...@@ -112,6 +114,8 @@ int admin_get_command(char *command)
return COMMAND_TRANSFORMED_FALLBACK; return COMMAND_TRANSFORMED_FALLBACK;
else if(!strcmp(command, METADATA_REQUEST)) else if(!strcmp(command, METADATA_REQUEST))
return COMMAND_METADATA_UPDATE; return COMMAND_METADATA_UPDATE;
else if(!strcmp(command, SHOUTCAST_METADATA_REQUEST))
return COMMAND_SHOUTCAST_METADATA_UPDATE;
else if(!strcmp(command, LISTCLIENTS_RAW_REQUEST)) else if(!strcmp(command, LISTCLIENTS_RAW_REQUEST))
return COMMAND_RAW_SHOW_LISTENERS; return COMMAND_RAW_SHOW_LISTENERS;
else if(!strcmp(command, LISTCLIENTS_TRANSFORMED_REQUEST)) else if(!strcmp(command, LISTCLIENTS_TRANSFORMED_REQUEST))
...@@ -158,6 +162,7 @@ int admin_get_command(char *command) ...@@ -158,6 +162,7 @@ int admin_get_command(char *command)
static void command_fallback(client_t *client, source_t *source, int response); static void command_fallback(client_t *client, source_t *source, int response);
static void command_metadata(client_t *client, source_t *source); static void command_metadata(client_t *client, source_t *source);
static void command_shoutcast_metadata(client_t *client, source_t *source);
static void command_show_listeners(client_t *client, source_t *source, static void command_show_listeners(client_t *client, source_t *source,
int response); int response);
static void command_move_clients(client_t *client, source_t *source, static void command_move_clients(client_t *client, source_t *source,
...@@ -269,13 +274,20 @@ void admin_handle_request(client_t *client, char *uri) ...@@ -269,13 +274,20 @@ void admin_handle_request(client_t *client, char *uri)
int command; int command;
int noauth = 0; int noauth = 0;
if(strncmp("/admin/", uri, 7)) { DEBUG1("Admin request (%s)", uri);
if (!((strcmp(uri, "/admin.cgi") == 0) ||
(strncmp("/admin/", uri, 7) == 0))) {
ERROR0("Internal error: admin request isn't"); ERROR0("Internal error: admin request isn't");
client_send_401(client); client_send_401(client);
return; return;
} }
command_string = uri + 7; if (strcmp(uri, "/admin.cgi") == 0) {
command_string = uri + 1;
}
else {
command_string = uri + 7;
}
DEBUG1("Got command (%s)", command_string); DEBUG1("Got command (%s)", command_string);
command = admin_get_command(command_string); command = admin_get_command(command_string);
...@@ -289,6 +301,31 @@ void admin_handle_request(client_t *client, char *uri) ...@@ -289,6 +301,31 @@ void admin_handle_request(client_t *client, char *uri)
mount = httpp_get_query_param(client->parser, "mount"); mount = httpp_get_query_param(client->parser, "mount");
if (command == COMMAND_SHOUTCAST_METADATA_UPDATE) {
source_t *source;
mount = "/";
noauth = 1;
avl_tree_rlock(global.source_tree);
source = source_find_mount_raw(mount);
if (source == NULL) {
WARN2("Admin command %s on non-existent source %s",
command_string, mount);
avl_tree_unlock(global.source_tree);
client_send_400(client, "Mount / does not exist");
return;
}
else {
if (source->shoutcast_compat == 0) {
ERROR0("Illegal call to change metadata, source not shoutcast compatible");
avl_tree_unlock (global.source_tree);
client_send_400 (client, "Illegal metadata call");
return;
}
}
avl_tree_unlock(global.source_tree);
}
if(mount != NULL) { if(mount != NULL) {
source_t *source; source_t *source;
...@@ -319,13 +356,15 @@ void admin_handle_request(client_t *client, char *uri) ...@@ -319,13 +356,15 @@ void admin_handle_request(client_t *client, char *uri)
} }
else else
{ {
if (source->running == 0) if (!source->shoutcast_compat) {
{ if (source->running == 0)
INFO2("Received admin command %s on unavailable mount \"%s\"", {
command_string, mount); INFO2("Received admin command %s on unavailable mount \"%s\"",
avl_tree_unlock (global.source_tree); command_string, mount);
client_send_400 (client, "Source is not available"); avl_tree_unlock (global.source_tree);
return; client_send_400 (client, "Source is not available");
return;
}
} }
INFO2("Received admin command %s on mount \"%s\"", INFO2("Received admin command %s on mount \"%s\"",
command_string, mount); command_string, mount);
...@@ -403,6 +442,9 @@ static void admin_handle_mount_request(client_t *client, source_t *source, ...@@ -403,6 +442,9 @@ static void admin_handle_mount_request(client_t *client, source_t *source,
case COMMAND_METADATA_UPDATE: case COMMAND_METADATA_UPDATE:
command_metadata(client, source); command_metadata(client, source);
break; break;
case COMMAND_SHOUTCAST_METADATA_UPDATE:
command_shoutcast_metadata(client, source);
break;
case COMMAND_RAW_SHOW_LISTENERS: case COMMAND_RAW_SHOW_LISTENERS:
command_show_listeners(client, source, RAW); command_show_listeners(client, source, RAW);
break; break;
...@@ -784,7 +826,8 @@ static void command_metadata(client_t *client, source_t *source) ...@@ -784,7 +826,8 @@ static void command_metadata(client_t *client, source_t *source)
COMMAND_REQUIRE(client, "mode", action); COMMAND_REQUIRE(client, "mode", action);
COMMAND_REQUIRE(client, "song", value); COMMAND_REQUIRE(client, "song", value);
if (source->format->type != FORMAT_TYPE_MP3) if ((source->format->type != FORMAT_TYPE_MP3) &&
(source->format->type != FORMAT_TYPE_NSV))
{ {
client_send_400 (client, "Not mp3, cannot update metadata"); client_send_400 (client, "Not mp3, cannot update metadata");
return; return;
...@@ -811,6 +854,64 @@ static void command_metadata(client_t *client, source_t *source) ...@@ -811,6 +854,64 @@ static void command_metadata(client_t *client, source_t *source)
html_success(client, "Metadata update successful"); html_success(client, "Metadata update successful");
} }
static void command_shoutcast_metadata(client_t *client, source_t *source)
{
char *action;
char *value;
char *source_pass;
char *config_source_pass;
ice_config_t *config;
mp3_state *state;
DEBUG0("Got shoutcast metadata update request");
COMMAND_REQUIRE(client, "mode", action);
COMMAND_REQUIRE(client, "song", value);
COMMAND_REQUIRE(client, "pass", source_pass);
config = config_get_config();
config_source_pass = strdup(config->source_password);
config_release_config();
if ((source->format->type != FORMAT_TYPE_MP3) &&
(source->format->type != FORMAT_TYPE_NSV))
{
client_send_400 (client, "Not mp3 or NSV, cannot update metadata");
return;
}
if (strcmp (action, "updinfo") != 0)
{
client_send_400 (client, "No such action");
return;
}
if (strcmp(source_pass, config_source_pass) != 0)
{
ERROR0("Invalid source password specified, metadata not updated");
client_send_400 (client, "Invalid source password");
return;
}
if (config_source_pass) {
free(config_source_pass);
}
state = source->format->_state;
mp3_set_tag (source->format, "title", value);
DEBUG2("Metadata on mountpoint %s changed to \"%s\"",
source->mount, value);
stats_event(source->mount, "title", value);
/* If we get an update on the mountpoint, force a
yp touch */
yp_touch (source->mount);
html_success(client, "Metadata update successful");
}
static void command_stats(client_t *client, int response) { static void command_stats(client_t *client, int response) {
xmlDocPtr doc; xmlDocPtr doc;
......
...@@ -321,6 +321,7 @@ static void _set_defaults(ice_config_t *configuration) ...@@ -321,6 +321,7 @@ static void _set_defaults(ice_config_t *configuration)
configuration->port = 0; configuration->port = 0;
configuration->listeners[0].port = 0; configuration->listeners[0].port = 0;
configuration->listeners[0].bind_address = NULL; configuration->listeners[0].bind_address = NULL;
configuration->listeners[0].shoutcast_compat = 0;
configuration->master_server = NULL; configuration->master_server = NULL;
configuration->master_server_port = 0; configuration->master_server_port = 0;
configuration->master_update_interval = CONFIG_MASTER_UPDATE_INTERVAL; configuration->master_update_interval = CONFIG_MASTER_UPDATE_INTERVAL;
...@@ -667,6 +668,11 @@ static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node, ...@@ -667,6 +668,11 @@ static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
listener->port = atoi(tmp); listener->port = atoi(tmp);
if(tmp) xmlFree(tmp); if(tmp) xmlFree(tmp);
} }
else if (strcmp(node->name, "shoutcast-compat") == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
listener->shoutcast_compat = atoi(tmp);
if(tmp) xmlFree(tmp);
}
else if (strcmp(node->name, "bind-address") == 0) { else if (strcmp(node->name, "bind-address") == 0) {
listener->bind_address = (char *)xmlNodeListGetString(doc, listener->bind_address = (char *)xmlNodeListGetString(doc,
node->xmlChildrenNode, 1); node->xmlChildrenNode, 1);
......
...@@ -75,6 +75,7 @@ typedef struct _aliases { ...@@ -75,6 +75,7 @@ typedef struct _aliases {
typedef struct { typedef struct {
int port; int port;
char *bind_address; char *bind_address;
int shoutcast_compat;
} listener_t; } listener_t;
typedef struct ice_config_tag typedef struct ice_config_tag
......
...@@ -65,6 +65,23 @@ ...@@ -65,6 +65,23 @@
#define CATMODULE "connection" #define CATMODULE "connection"
/* Two different major types of source authentication.
Shoutcast style is used only by the Shoutcast DSP
and is a crazy version of HTTP. It looks like :
Source Client -> Connects to port + 1
Source Client -> sends encoder password (plaintext)\r\n
Icecast -> reads encoder password, if ok, sends OK2\r\n, else disconnects
Source Client -> reads OK2\r\n, then sends http-type request headers
that contain the stream details (icy-name, etc..)
Icecast -> reads headers, stores them
Source Client -> starts sending MP3 data
Source Client -> periodically updates metadata via admin.cgi call
Icecast auth style uses HTTP and Basic Authorization.
*/
#define SHOUTCAST_SOURCE_AUTH 1
#define ICECAST_SOURCE_AUTH 0
typedef struct con_queue_tag { typedef struct con_queue_tag {
connection_t *con; connection_t *con;
struct con_queue_tag *next; struct con_queue_tag *next;
...@@ -664,7 +681,7 @@ int connection_check_source_pass(http_parser_t *parser, char *mount) ...@@ -664,7 +681,7 @@ int connection_check_source_pass(http_parser_t *parser, char *mount)
static void _handle_source_request(connection_t *con, static void _handle_source_request(connection_t *con,
http_parser_t *parser, char *uri) http_parser_t *parser, char *uri, int auth_style)
{ {
client_t *client; client_t *client;
source_t *source; source_t *source;
...@@ -680,18 +697,23 @@ static void _handle_source_request(connection_t *con, ...@@ -680,18 +697,23 @@ static void _handle_source_request(connection_t *con,
return; return;
} }
if (!connection_check_source_pass(parser, uri)) { if (auth_style == ICECAST_SOURCE_AUTH) {
/* We commonly get this if the source client is using the wrong if (!connection_check_source_pass(parser, uri)) {
* protocol: attempt to diagnose this and return an error /* We commonly get this if the source client is using the wrong
*/ * protocol: attempt to diagnose this and return an error
/* TODO: Do what the above comment says */ */
INFO1("Source (%s) attempted to login with invalid or missing password", uri); /* TODO: Do what the above comment says */
client_send_401(client); INFO1("Source (%s) attempted to login with invalid or missing password", uri);
return; client_send_401(client);
return;
}
} }
source = source_reserve (uri); source = source_reserve (uri);
if (source) if (source)
{ {
if (auth_style == SHOUTCAST_SOURCE_AUTH) {
source->shoutcast_compat = 1;
}
source->client = client; source->client = client;
source->parser = parser; source->parser = parser;
source->con = con; source->con = con;
...@@ -796,7 +818,8 @@ static void _handle_get_request(connection_t *con, ...@@ -796,7 +818,8 @@ static void _handle_get_request(connection_t *con,
stats_event_inc(NULL, "client_connections"); stats_event_inc(NULL, "client_connections");
/* Dispatch all admin requests */ /* Dispatch all admin requests */
if (strncmp(uri, "/admin/", 7) == 0) { if ((strcmp(uri, "/admin.cgi") == 0) ||
(strncmp(uri, "/admin/", 7) == 0)) {
admin_handle_request(client, uri); admin_handle_request(client, uri);
if (uri != passed_uri) free (uri); if (uri != passed_uri) free (uri);
return; return;
...@@ -965,6 +988,74 @@ static void _handle_get_request(connection_t *con, ...@@ -965,6 +988,74 @@ static void _handle_get_request(connection_t *con,
if (uri != passed_uri) free (uri); if (uri != passed_uri) free (uri);
} }
void _handle_shoutcast_compatible(connection_t *con, char *source_password) {
char shoutcast_password[256];
char shoutcast_source[256];
char *http_compliant;
int http_compliant_len = 0;
char header[4096];
http_parser_t *parser;
memset(shoutcast_password, 0, sizeof (shoutcast_password));
/* Step one of shoutcast auth protocol, read encoder password (1 line) */
if (util_read_header(con->sock, shoutcast_password,
sizeof (shoutcast_password),
READ_LINE) == 0) {
/* either we didn't get a complete line, or we timed out */
connection_close(con);
return;
}
/* Get rid of trailing \n */
shoutcast_password[strlen(shoutcast_password)-1] = '\000';
if (strcmp(shoutcast_password, source_password)) {
ERROR0("Invalid source password");
connection_close(con);
return;
}
/* Step two of shoutcast auth protocol, send OK2. For those
interested, OK2 means it supports metadata updates via admin.cgi,
and the string "OK" can also be sent, but will indicate to the
shoutcast source client to not send metadata updates.
I believe icecast 1.x used to send OK. */
sock_write(con->sock, "%s\r\n", "OK2");
memset(header, 0, sizeof (header));
/* Step three of shoutcast auth protocol, read HTTP-style
request headers and process them.*/
if (util_read_header(con->sock, header, sizeof (header),
READ_ENTIRE_HEADER) == 0) {
/* either we didn't get a complete header, or we timed out */
connection_close(con);
return;
}
/* Here we create a valid HTTP request based of the information
that was passed in via the non-HTTP style protocol above. This
means we can use some of our existing code to handle this case */
memset(shoutcast_source, 0, sizeof (shoutcast_source));
strcpy(shoutcast_source, "SOURCE / HTTP/1.0\r\n");
http_compliant_len = strlen(shoutcast_source) +
strlen(header) + 1;
http_compliant = (char *)calloc(1, http_compliant_len);
sprintf(http_compliant, "%s%s", shoutcast_source,
header);
parser = httpp_create_parser();
httpp_initialize(parser, NULL);
if (httpp_parse(parser, http_compliant,
strlen(http_compliant))) {
_handle_source_request(con, parser, "/", SHOUTCAST_SOURCE_AUTH);
free(http_compliant);
return;
}
else {
ERROR0("Invalid source request");
connection_close(con);
free(http_compliant);
httpp_destroy(parser);
return;
}
return;
}
static void *_handle_connection(void *arg) static void *_handle_connection(void *arg)
{ {
char header[4096]; char header[4096];
...@@ -972,6 +1063,10 @@ static void *_handle_connection(void *arg) ...@@ -972,6 +1063,10 @@ static void *_handle_connection(void *arg)
http_parser_t *parser; http_parser_t *parser;
char *rawuri, *uri; char *rawuri, *uri;
client_t *client; client_t *client;
int i = 0;
int continue_flag = 0;
ice_config_t *config;
char *source_password;
while (global.running == ICE_RUNNING) { while (global.running == ICE_RUNNING) {
...@@ -996,9 +1091,30 @@ static void *_handle_connection(void *arg) ...@@ -996,9 +1091,30 @@ static void *_handle_connection(void *arg)
sock_set_blocking(con->sock, SOCK_BLOCK); sock_set_blocking(con->sock, SOCK_BLOCK);
continue_flag = 0;
/* Check for special shoutcast compatability processing */
for(i = 0; i < MAX_LISTEN_SOCKETS; i++) {
if(global.serversock[i] == con->serversock) {
config = config_get_config();
if (config->listeners[i].shoutcast_compat) {
source_password = strdup(config->source_password);
config_release_config();
_handle_shoutcast_compatible(con, source_password);
free(source_password);
continue_flag = 1;
break;
}
config_release_config();
}
}
if(continue_flag) {
continue;
}
/* fill header with the http header */ /* fill header with the http header */
memset(header, 0, sizeof (header)); memset(header, 0, sizeof (header));
if (util_read_header(con->sock, header, sizeof (header)) == 0) { if (util_read_header(con->sock, header, sizeof (header),
READ_ENTIRE_HEADER) == 0) {
/* either we didn't get a complete header, or we timed out */ /* either we didn't get a complete header, or we timed out */
connection_close(con); connection_close(con);
continue; continue;
...@@ -1027,7 +1143,7 @@ static void *_handle_connection(void *arg) ...@@ -1027,7 +1143,7 @@ static void *_handle_connection(void *arg)
} }
if (parser->req_type == httpp_req_source) { if (parser->req_type == httpp_req_source) {
_handle_source_request(con, parser, uri); _handle_source_request(con, parser, uri, ICECAST_SOURCE_AUTH);
} }
else if (parser->req_type == httpp_req_stats) { else if (parser->req_type == httpp_req_stats) {
_handle_stats_request(con, parser, uri); _handle_stats_request(con, parser, uri);
...@@ -1044,22 +1160,6 @@ static void *_handle_connection(void *arg) ...@@ -1044,22 +1160,6 @@ static void *_handle_connection(void *arg)
free(uri); free(uri);
continue; continue;
} }
else if(httpp_parse_icy(parser, header, strlen(header))) {
/* TODO: Map incoming icy connections to /icy_0, etc. */
char mount[20];
unsigned i = 0;
strcpy(mount, "/");
avl_tree_rlock(global.source_tree);
while (source_find_mount (mount) != NULL) {
snprintf (mount, sizeof (mount), "/icy_%u", i++);
}
avl_tree_unlock(global.source_tree);
_handle_source_request(con, parser, mount);
continue;
}
else { else {
ERROR0("HTTP request parsing failed"); ERROR0("HTTP request parsing failed");
connection_close(con); connection_close(con);
...