mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-11-03 04:17:17 -05:00
resync with recent work on trunk, playlistlog, shoutcast-mount
svn path=/icecast/branches/kh/icecast/; revision=8215
This commit is contained in:
parent
4987a4265d
commit
87e69eb421
@ -164,6 +164,7 @@ The URL which icecast2 uses to communicate with the Directory server. The value
|
||||
</listen-socket>
|
||||
|
||||
<fileserve>1</fileserve>
|
||||
<shoutcast-mount>/live.nsv</shoutcast-mount>
|
||||
</pre>
|
||||
<p>This section contains miscellaneous server settings. Note that multiple listen-socket sections may be configured in order to have icecast2 listen on multiple network interfaces. If a bind-address is not specified for a particular listen-socket, then the hostname parameter will be used to specify the address that will be bound.
|
||||
</p>
|
||||
@ -183,6 +184,12 @@ This optional flag will indicate that this port will operate in 'shoutcast-compa
|
||||
<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 <paths><webroot> configuration setting.
|
||||
</div>
|
||||
<h4>shoutcast-mount</h4>
|
||||
<div class="indentedbox">
|
||||
An optional mountpoint to use when shoutcast DSP compatible clients connect. The default is /stream but can
|
||||
be overridden here to use an alternative name which may include an extension that some clients require for
|
||||
certain formats.
|
||||
</div>
|
||||
<p>
|
||||
<br />
|
||||
<br />
|
||||
@ -471,6 +478,7 @@ Aliases are used to provide a way to create multiple mountpoints that refer to t
|
||||
<logging>
|
||||
<accesslog>access.log</accesslog>
|
||||
<errorlog>error.log</errorlog>
|
||||
<playlistlog>playlist.log</playlistlog>
|
||||
<loglevel>4</loglevel> <-- 4 Debug, 3 Info, 2 Warn, 1 Error -->
|
||||
</logging>
|
||||
</pre>
|
||||
@ -486,6 +494,10 @@ Into this file, all requests made to the icecast2 will be logged. This file is
|
||||
<div class="indentedbox">
|
||||
All icecast generated log messages will be written to this file. If the loglevel is set too high (Debug for instance) then this file can grow fairly large over time. Currently, there is no log-rotation implemented.
|
||||
</div>
|
||||
<h4>playlistlog</h4>
|
||||
<div class="indentedbox">
|
||||
Into this file, a log of all metadata for each mountpoint will be written. The format of the logfile will most likely change over time as we narrow in on a standard format for this. Currently, the file is pipe delimited. This option is optional and can be removed entirely from the config file.
|
||||
</div>
|
||||
<h4>loglevel</h4>
|
||||
<div class="indentedbox">
|
||||
Indicates what messages are logged by icecast. Log messages are categorized into one of 4 types, Debug, Info, Warn, and Error.<br /><br />The following mapping can be used to set the appropraite value :
|
||||
|
56
src/admin.c
56
src/admin.c
@ -294,7 +294,6 @@ void admin_handle_request(client_t *client, char *uri)
|
||||
{
|
||||
char *mount, *command_string;
|
||||
int command;
|
||||
int noauth = 0;
|
||||
|
||||
DEBUG1("Admin request (%s)", uri);
|
||||
if (!((strcmp(uri, "/admin.cgi") == 0) ||
|
||||
@ -321,33 +320,15 @@ void admin_handle_request(client_t *client, char *uri)
|
||||
return;
|
||||
}
|
||||
|
||||
mount = httpp_get_query_param(client->parser, "mount");
|
||||
|
||||
if (command == COMMAND_SHOUTCAST_METADATA_UPDATE) {
|
||||
source_t *source;
|
||||
ice_config_t *config = config_get_config ();
|
||||
|
||||
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);
|
||||
httpp_set_query_param (client->parser, "mount", config->shoutcast_mount);
|
||||
config_release_config ();
|
||||
}
|
||||
|
||||
mount = httpp_get_query_param(client->parser, "mount");
|
||||
|
||||
if(mount != NULL) {
|
||||
source_t *source;
|
||||
|
||||
@ -372,7 +353,9 @@ void admin_handle_request(client_t *client, char *uri)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!source->shoutcast_compat)
|
||||
INFO2("Received admin command %s on mount \"%s\"",
|
||||
command_string, mount);
|
||||
if (source->shoutcast_compat == 0)
|
||||
{
|
||||
if (source->running == 0 && source->on_demand == 0)
|
||||
{
|
||||
@ -382,18 +365,16 @@ void admin_handle_request(client_t *client, char *uri)
|
||||
client_send_400 (client, "Source is not available");
|
||||
return;
|
||||
}
|
||||
}
|
||||
INFO2("Received admin command %s on mount \"%s\"",
|
||||
command_string, mount);
|
||||
if (client->authenticated != 1)
|
||||
{
|
||||
if (connection_check_source_pass(client->parser, mount) == 0)
|
||||
if (client->authenticated != 1)
|
||||
{
|
||||
INFO1("Bad or missing password on mount modification admin "
|
||||
"request (command: %s)", command_string);
|
||||
avl_tree_unlock(global.source_tree);
|
||||
client_send_401(client);
|
||||
return;
|
||||
if (connection_check_source_pass(client->parser, mount) == 0)
|
||||
{
|
||||
INFO1("Bad or missing password on mount modification admin "
|
||||
"request (command: %s)", command_string);
|
||||
avl_tree_unlock(global.source_tree);
|
||||
client_send_401(client);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
admin_handle_mount_request (client, source, command);
|
||||
@ -1007,6 +988,9 @@ static void command_shoutcast_metadata(client_t *client, source_t *source)
|
||||
DEBUG2("Metadata on mountpoint %s changed to \"%s\"",
|
||||
source->mount, value);
|
||||
stats_event(source->mount, "title", value);
|
||||
/* At this point, we assume that the metadata passed in
|
||||
is encoded in UTF-8 */
|
||||
logging_playlist(source->mount, value, source->listeners);
|
||||
/* If we get an update on the mountpoint, force a
|
||||
* yp touch */
|
||||
yp_touch (source->mount);
|
||||
|
@ -39,10 +39,12 @@
|
||||
#define CONFIG_DEFAULT_SOURCE_TIMEOUT 10
|
||||
#define CONFIG_DEFAULT_SOURCE_PASSWORD "changeme"
|
||||
#define CONFIG_DEFAULT_RELAY_PASSWORD "changeme"
|
||||
#define CONFIG_DEFAULT_SHOUTCAST_MOUNT "/stream"
|
||||
#define CONFIG_DEFAULT_ICE_LOGIN 0
|
||||
#define CONFIG_DEFAULT_FILESERVE 1
|
||||
#define CONFIG_DEFAULT_TOUCH_FREQ 5
|
||||
#define CONFIG_DEFAULT_HOSTNAME "localhost"
|
||||
#define CONFIG_DEFAULT_PLAYLIST_LOG NULL
|
||||
#define CONFIG_DEFAULT_ACCESS_LOG "access.log"
|
||||
#define CONFIG_DEFAULT_ERROR_LOG "error.log"
|
||||
#define CONFIG_DEFAULT_LOG_LEVEL 4
|
||||
@ -150,10 +152,14 @@ void config_clear(ice_config_t *c)
|
||||
xmlFree(c->adminroot_dir);
|
||||
if (c->pidfile)
|
||||
xmlFree(c->pidfile);
|
||||
if (c->playlist_log && c->playlist_log != CONFIG_DEFAULT_PLAYLIST_LOG)
|
||||
xmlFree(c->playlist_log);
|
||||
if (c->access_log && c->access_log != CONFIG_DEFAULT_ACCESS_LOG)
|
||||
xmlFree(c->access_log);
|
||||
if (c->error_log && c->error_log != CONFIG_DEFAULT_ERROR_LOG)
|
||||
xmlFree(c->error_log);
|
||||
if (c->shoutcast_mount && c->shoutcast_mount != CONFIG_DEFAULT_SHOUTCAST_MOUNT)
|
||||
xmlFree(c->shoutcast_mount);
|
||||
for(i=0; i < MAX_LISTEN_SOCKETS; i++) {
|
||||
if (c->listeners[i].bind_address) xmlFree(c->listeners[i].bind_address);
|
||||
}
|
||||
@ -324,6 +330,7 @@ static void _set_defaults(ice_config_t *configuration)
|
||||
configuration->header_timeout = CONFIG_DEFAULT_HEADER_TIMEOUT;
|
||||
configuration->source_timeout = CONFIG_DEFAULT_SOURCE_TIMEOUT;
|
||||
configuration->source_password = CONFIG_DEFAULT_SOURCE_PASSWORD;
|
||||
configuration->shoutcast_mount = CONFIG_DEFAULT_SHOUTCAST_MOUNT;
|
||||
configuration->ice_login = CONFIG_DEFAULT_ICE_LOGIN;
|
||||
configuration->fileserve = CONFIG_DEFAULT_FILESERVE;
|
||||
configuration->touch_interval = CONFIG_DEFAULT_TOUCH_FREQ;
|
||||
@ -345,6 +352,7 @@ static void _set_defaults(ice_config_t *configuration)
|
||||
configuration->log_dir = CONFIG_DEFAULT_LOG_DIR;
|
||||
configuration->webroot_dir = CONFIG_DEFAULT_WEBROOT_DIR;
|
||||
configuration->adminroot_dir = CONFIG_DEFAULT_ADMINROOT_DIR;
|
||||
configuration->playlist_log = CONFIG_DEFAULT_PLAYLIST_LOG;
|
||||
configuration->access_log = CONFIG_DEFAULT_ACCESS_LOG;
|
||||
configuration->error_log = CONFIG_DEFAULT_ERROR_LOG;
|
||||
configuration->loglevel = CONFIG_DEFAULT_LOG_LEVEL;
|
||||
@ -439,6 +447,11 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node,
|
||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->master_relay_auth = atoi(tmp);
|
||||
xmlFree (tmp);
|
||||
} else if (strcmp(node->name, "shoutcast-mount") == 0) {
|
||||
if (configuration->shoutcast_mount &&
|
||||
configuration->shoutcast_mount != CONFIG_DEFAULT_SHOUTCAST_MOUNT)
|
||||
xmlFree(configuration->shoutcast_mount);
|
||||
configuration->shoutcast_mount = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "limits") == 0) {
|
||||
_parse_limits(doc, node->xmlChildrenNode, configuration);
|
||||
} else if (strcmp(node->name, "relay") == 0) {
|
||||
@ -919,6 +932,9 @@ static void _parse_logging(xmlDocPtr doc, xmlNodePtr node,
|
||||
} else if (strcmp(node->name, "errorlog") == 0) {
|
||||
if (configuration->error_log && configuration->error_log != CONFIG_DEFAULT_ERROR_LOG) xmlFree(configuration->error_log);
|
||||
configuration->error_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "playlistlog") == 0) {
|
||||
if (configuration->playlist_log && configuration->playlist_log != CONFIG_DEFAULT_PLAYLIST_LOG) xmlFree(configuration->playlist_log);
|
||||
configuration->playlist_log = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
} else if (strcmp(node->name, "loglevel") == 0) {
|
||||
char *tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||
configuration->loglevel = atoi(tmp);
|
||||
|
@ -107,6 +107,7 @@ typedef struct ice_config_tag
|
||||
int fileserve;
|
||||
int on_demand; /* global setting for all relays */
|
||||
|
||||
char *shoutcast_mount;
|
||||
char *source_password;
|
||||
char *admin_username;
|
||||
char *admin_password;
|
||||
@ -143,6 +144,7 @@ typedef struct ice_config_tag
|
||||
|
||||
char *access_log;
|
||||
char *error_log;
|
||||
char *playlist_log;
|
||||
int loglevel;
|
||||
|
||||
int chroot;
|
||||
|
@ -610,7 +610,7 @@ int connection_check_relay_pass(http_parser_t *parser)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int connection_check_source_pass(http_parser_t *parser, char *mount)
|
||||
int connection_check_source_pass(http_parser_t *parser, const char *mount)
|
||||
{
|
||||
ice_config_t *config = config_get_config();
|
||||
char *pass = config->source_password;
|
||||
|
@ -52,7 +52,7 @@ int connection_complete_source (struct source_tag *source);
|
||||
|
||||
void connection_inject_event(int eventnum, void *event_data);
|
||||
|
||||
int connection_check_source_pass(http_parser_t *parser, char *mount);
|
||||
int connection_check_source_pass(http_parser_t *parser, const char *mount);
|
||||
int connection_check_relay_pass(http_parser_t *parser);
|
||||
int connection_check_admin_pass(http_parser_t *parser);
|
||||
|
||||
|
46
src/format.c
46
src/format.c
@ -64,6 +64,10 @@ format_type_t format_get_type(char *contenttype)
|
||||
return FORMAT_TYPE_MP3;
|
||||
else if(strcmp(contenttype, "video/nsv") == 0)
|
||||
return FORMAT_TYPE_NSV;
|
||||
else if(strcmp(contenttype, "audio/aac") == 0)
|
||||
return FORMAT_TYPE_AAC;
|
||||
else if(strcmp(contenttype, "audio/aacp") == 0)
|
||||
return FORMAT_TYPE_AACPLUS;
|
||||
else
|
||||
return FORMAT_ERROR;
|
||||
}
|
||||
@ -80,6 +84,12 @@ const char *format_get_mimetype(format_type_t type)
|
||||
case FORMAT_TYPE_NSV:
|
||||
return "video/nsv";
|
||||
break;
|
||||
case FORMAT_TYPE_AAC:
|
||||
return "audio/aac";
|
||||
break;
|
||||
case FORMAT_TYPE_AACPLUS:
|
||||
return "audio/aacp";
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@ -91,19 +101,29 @@ int format_get_plugin(format_type_t type, source_t *source)
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case FORMAT_TYPE_OGG:
|
||||
ret = format_ogg_get_plugin (source);
|
||||
break;
|
||||
case FORMAT_TYPE_MP3:
|
||||
ret = format_mp3_get_plugin (source);
|
||||
break;
|
||||
case FORMAT_TYPE_NSV:
|
||||
ret = format_mp3_get_plugin (source);
|
||||
source->format->format_description = "NSV Video";
|
||||
source->format->type = FORMAT_TYPE_NSV;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case FORMAT_TYPE_OGG:
|
||||
ret = format_ogg_get_plugin (source);
|
||||
break;
|
||||
case FORMAT_TYPE_MP3:
|
||||
ret = format_mp3_get_plugin (source);
|
||||
break;
|
||||
case FORMAT_TYPE_NSV:
|
||||
ret = format_mp3_get_plugin (source);
|
||||
source->format->format_description = "NSV Video";
|
||||
source->format->type = FORMAT_TYPE_NSV;
|
||||
break;
|
||||
case FORMAT_TYPE_AAC:
|
||||
ret = format_mp3_get_plugin (source);
|
||||
source->format->format_description = "AAC Audio";
|
||||
source->format->type = FORMAT_TYPE_AAC;
|
||||
break;
|
||||
case FORMAT_TYPE_AACPLUS:
|
||||
ret = format_mp3_get_plugin (source);
|
||||
source->format->format_description = "AACPlus Audio";
|
||||
source->format->type = FORMAT_TYPE_AACPLUS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
stats_event (source->mount, "content-type",
|
||||
format_get_mimetype(source->format->type));
|
||||
|
@ -31,7 +31,9 @@ typedef enum _format_type_tag
|
||||
FORMAT_TYPE_OGG,
|
||||
FORMAT_TYPE_VORBIS,
|
||||
FORMAT_TYPE_MP3,
|
||||
FORMAT_TYPE_NSV
|
||||
FORMAT_TYPE_NSV,
|
||||
FORMAT_TYPE_AAC,
|
||||
FORMAT_TYPE_AACPLUS
|
||||
} format_type_t;
|
||||
|
||||
typedef struct _format_plugin_tag
|
||||
|
@ -95,8 +95,11 @@ int format_mp3_get_plugin (source_t *source)
|
||||
|
||||
plugin->_state = state;
|
||||
|
||||
meta = refbuf_new (1);
|
||||
memcpy (meta->data, "", 1);
|
||||
/* initial metadata needs to be blank for sending to clients and for
|
||||
comparing with new metadata */
|
||||
meta = refbuf_new (2);
|
||||
memcpy (meta->data, "\0\0", 2);
|
||||
meta->len = 1;
|
||||
state->metadata = meta;
|
||||
state->interval = -1;
|
||||
|
||||
@ -531,8 +534,9 @@ static refbuf_t *mp3_get_filter_meta (source_t *source)
|
||||
bytes -= metadata_remaining;
|
||||
memmove (src, src+metadata_remaining, bytes);
|
||||
|
||||
/* assign metadata if it's not 1 byte, as that indicates a change */
|
||||
if (source_mp3->build_metadata_len > 1)
|
||||
/* assign metadata if it's greater than 1 byte, and the text has changed */
|
||||
if (source_mp3->build_metadata_len > 1 &&
|
||||
strcmp (source_mp3->build_metadata+1, source_mp3->metadata->data+1) != 0)
|
||||
{
|
||||
refbuf_t *meta = refbuf_new (source_mp3->build_metadata_len);
|
||||
memcpy (meta->data, source_mp3->build_metadata,
|
||||
|
@ -691,21 +691,53 @@ static refbuf_t *ogg_get_buffer (source_t *source)
|
||||
|
||||
if (ogg_info->send_yp_info)
|
||||
{
|
||||
char *tag;
|
||||
tag = ogg_info->title;
|
||||
if (tag == NULL)
|
||||
tag = "unknown";
|
||||
stats_event (source->mount, "title", tag);
|
||||
INFO1("Updating title \"%s\"", tag);
|
||||
char *title;
|
||||
char *artist;
|
||||
char *metadata = NULL;
|
||||
unsigned int len = 0;
|
||||
|
||||
title = ogg_info->title;
|
||||
if (title)
|
||||
INFO1("Updating title \"%s\"", title);
|
||||
stats_event (source->mount, "title", title);
|
||||
|
||||
artist = ogg_info->artist;
|
||||
if (artist)
|
||||
INFO1("Updating artist \"%s\"", artist);
|
||||
stats_event (source->mount, "artist", artist);
|
||||
if (artist)
|
||||
{
|
||||
if (title)
|
||||
{
|
||||
len += strlen(artist) + strlen(title) + 3;
|
||||
metadata = calloc (1, len);
|
||||
snprintf (metadata, len, "%s - %s", artist, title);
|
||||
}
|
||||
else
|
||||
{
|
||||
len += strlen(artist);
|
||||
metadata = calloc (1, len);
|
||||
snprintf (metadata, len, "%s", artist);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (title)
|
||||
{
|
||||
len += strlen (title);
|
||||
metadata = calloc (1, len);
|
||||
snprintf (metadata, len, "%s", title);
|
||||
}
|
||||
}
|
||||
if (metadata)
|
||||
{
|
||||
logging_playlist (source->mount, metadata, source->listeners);
|
||||
free (metadata);
|
||||
}
|
||||
|
||||
tag = ogg_info->artist;
|
||||
if (tag == NULL)
|
||||
tag = "unknown";
|
||||
stats_event (source->mount, "artist", tag);
|
||||
if (ogg_info->bitrate)
|
||||
stats_event_args (source->mount, "ice-bitrate", "%u", ogg_info->bitrate/1000);
|
||||
|
||||
INFO1("Updating artist \"%s\"", tag);
|
||||
ogg_info->send_yp_info = 0;
|
||||
yp_touch (source->mount);
|
||||
}
|
||||
|
@ -410,23 +410,56 @@ static int process_vorbis_headers (source_t *source)
|
||||
|
||||
static void update_stats (source_t *source, vorbis_comment *vc)
|
||||
{
|
||||
char *tag;
|
||||
/* put known comments in the stats, this could be site specific */
|
||||
tag = vorbis_comment_query (vc, "TITLE", 0);
|
||||
if (tag == NULL)
|
||||
tag = "unknown";
|
||||
else
|
||||
INFO1 ("title set to \"%s\"", tag);
|
||||
stats_event (source->mount, "title", tag);
|
||||
char *artist;
|
||||
char *title;
|
||||
char *metadata = NULL;
|
||||
unsigned int len = 1;
|
||||
|
||||
tag = vorbis_comment_query (vc, "ARTIST", 0);
|
||||
if (tag)
|
||||
/* put known comments in the stats, this could be site specific */
|
||||
title = vorbis_comment_query (vc, "TITLE", 0);
|
||||
if (title)
|
||||
{
|
||||
INFO1 ("artist set to \"%s\"", tag);
|
||||
stats_event (source->mount, "artist", tag);
|
||||
INFO1 ("title set to \"%s\"", title);
|
||||
len += strlen (title);
|
||||
}
|
||||
stats_event (source->mount, "title", title);
|
||||
|
||||
artist = vorbis_comment_query (vc, "ARTIST", 0);
|
||||
if (artist)
|
||||
{
|
||||
INFO1 ("artist set to \"%s\"", artist);
|
||||
len += strlen (artist);
|
||||
}
|
||||
stats_event (source->mount, "artist", artist);
|
||||
if (artist)
|
||||
{
|
||||
if (title)
|
||||
{
|
||||
len += strlen(artist) + strlen(title) + 3;
|
||||
metadata = calloc (1, len);
|
||||
snprintf (metadata, len, "%s - %s", artist, title);
|
||||
}
|
||||
else
|
||||
{
|
||||
len += strlen(artist);
|
||||
metadata = calloc (1, len);
|
||||
snprintf (metadata, len, "%s", artist);
|
||||
}
|
||||
}
|
||||
else
|
||||
stats_event (source->mount, "artist", NULL);
|
||||
{
|
||||
if (title)
|
||||
{
|
||||
len += strlen (title);
|
||||
metadata = calloc (1, len);
|
||||
snprintf (metadata, len, "%s", title);
|
||||
}
|
||||
}
|
||||
if (metadata)
|
||||
{
|
||||
logging_playlist (source->mount, metadata, source->listeners);
|
||||
free (metadata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -466,7 +466,7 @@ int fserve_client_create(client_t *httpclient, char *path)
|
||||
bytes = sock_write(httpclient->con->sock,
|
||||
"HTTP/1.0 416 Request Range Not Satisfiable\r\n\r\n");
|
||||
if(bytes > 0) httpclient->con->sent_bytes = bytes;
|
||||
fserve_client_destroy (httpclient);
|
||||
fserve_client_destroy (client);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
/* the global log descriptors */
|
||||
int errorlog = 0;
|
||||
int accesslog = 0;
|
||||
int playlistlog = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Since strftime's %z option on win32 is different, we need
|
||||
@ -156,6 +157,39 @@ void logging_access(client_t *client)
|
||||
}
|
||||
|
||||
|
||||
/* This function will provide a log of metadata for each
|
||||
mountpoint. The metadata *must* be in UTF-8, and thus
|
||||
you can assume that the log itself is UTF-8 encoded */
|
||||
void logging_playlist(char *mount, char *metadata, long listeners)
|
||||
{
|
||||
char datebuf[128];
|
||||
struct tm thetime;
|
||||
time_t now;
|
||||
|
||||
if (playlistlog == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
localtime_r (&now, &thetime);
|
||||
/* build the data */
|
||||
#ifdef _WIN32
|
||||
memset(datebuf, '\000', sizeof(datebuf));
|
||||
get_clf_time(datebuf, sizeof(datebuf)-1, &thetime);
|
||||
#else
|
||||
strftime (datebuf, sizeof(datebuf), LOGGING_FORMAT_CLF, &thetime);
|
||||
#endif
|
||||
/* This format MAY CHANGE OVER TIME. We are looking into finding a good
|
||||
standard format for this, if you have any ideas, please let us know */
|
||||
log_write_direct (playlistlog, "%s|%s|%d|%s",
|
||||
datebuf,
|
||||
mount,
|
||||
listeners,
|
||||
metadata);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void restart_logging (ice_config_t *config)
|
||||
{
|
||||
@ -175,4 +209,12 @@ void restart_logging (ice_config_t *config)
|
||||
log_set_filename (accesslog, fn_error);
|
||||
log_reopen (accesslog);
|
||||
}
|
||||
|
||||
if (config->playlist_log)
|
||||
{
|
||||
char fn_error[FILENAME_MAX];
|
||||
snprintf (fn_error, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->playlist_log);
|
||||
log_set_filename (playlistlog, fn_error);
|
||||
log_reopen (playlistlog);
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
extern int errorlog;
|
||||
extern int accesslog;
|
||||
extern int playlistlog;
|
||||
|
||||
/* these are all ERRORx and WARNx where _x_ is the number of parameters
|
||||
** it takes. it turns out most other copmilers don't have support for
|
||||
@ -88,6 +89,7 @@ extern int accesslog;
|
||||
#define LOGGING_FORMAT_CLF "%d/%b/%Y:%H:%M:%S %z"
|
||||
|
||||
void logging_access(client_t *client);
|
||||
void logging_playlist(char *mount, char *metadata, long listeners);
|
||||
void restart_logging (ice_config_t *config);
|
||||
|
||||
#endif /* __LOGGING_H__ */
|
||||
|
19
src/main.c
19
src/main.c
@ -180,6 +180,7 @@ static int _start_logging(void)
|
||||
{
|
||||
char fn_error[FILENAME_MAX];
|
||||
char fn_access[FILENAME_MAX];
|
||||
char fn_playlist[FILENAME_MAX];
|
||||
char buf[1024];
|
||||
int log_to_stderr;
|
||||
|
||||
@ -202,6 +203,7 @@ static int _start_logging(void)
|
||||
strerror(errno));
|
||||
_fatal_error(buf);
|
||||
}
|
||||
|
||||
log_set_level(errorlog, config->loglevel);
|
||||
|
||||
if(strcmp(config->access_log, "-")) {
|
||||
@ -222,8 +224,25 @@ static int _start_logging(void)
|
||||
_fatal_error(buf);
|
||||
}
|
||||
|
||||
if(config->playlist_log) {
|
||||
snprintf(fn_playlist, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->playlist_log);
|
||||
playlistlog = log_open(fn_playlist);
|
||||
if (playlistlog < 0) {
|
||||
buf[sizeof(buf)-1] = 0;
|
||||
snprintf(buf, sizeof(buf)-1,
|
||||
"FATAL: could not open playlist logging (%s): %s",
|
||||
log_to_stderr?"standard error":fn_playlist,
|
||||
strerror(errno));
|
||||
_fatal_error(buf);
|
||||
}
|
||||
log_to_stderr = 0;
|
||||
} else {
|
||||
playlistlog = -1;
|
||||
}
|
||||
|
||||
log_set_level(errorlog, config->loglevel);
|
||||
log_set_level(accesslog, 4);
|
||||
log_set_level(playlistlog, 4);
|
||||
|
||||
if (errorlog >= 0 && accesslog >= 0) return 1;
|
||||
|
||||
|
14
src/yp.c
14
src/yp.c
@ -498,22 +498,12 @@ static ypdata_t *create_yp_entry (source_t *source)
|
||||
if (url == NULL)
|
||||
break;
|
||||
config = config_get_config();
|
||||
if (source->format->type == FORMAT_TYPE_NSV) {
|
||||
ret = snprintf (url, len, "http://%s:%d%s?stream.nsv", config->hostname, config->port, source->mount);
|
||||
}
|
||||
else {
|
||||
ret = snprintf (url, len, "http://%s:%d%s", config->hostname, config->port, source->mount);
|
||||
}
|
||||
ret = snprintf (url, len, "http://%s:%d%s", config->hostname, config->port, source->mount);
|
||||
if (ret >= (signed)len)
|
||||
{
|
||||
s = realloc (url, ++ret);
|
||||
if (s) url = s;
|
||||
if (source->format->type == FORMAT_TYPE_NSV) {
|
||||
snprintf (url, ret, "http://%s:%d%s?file=stream.nsv", config->hostname, config->port, source->mount);
|
||||
}
|
||||
else {
|
||||
snprintf (url, ret, "http://%s:%d%s", config->hostname, config->port, source->mount);
|
||||
}
|
||||
snprintf (url, ret, "http://%s:%d%s", config->hostname, config->port, source->mount);
|
||||
}
|
||||
config_release_config();
|
||||
yp->listen_url = util_url_escape (url);
|
||||
|
@ -54,14 +54,7 @@
|
||||
<a href="auth.xsl">Click to Listen</a>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:choose>
|
||||
<xsl:when test="content-type='video/nsv'">
|
||||
<a href="{@mount}%3Ffile%3Dstream.nsv.m3u">Click to Listen</a>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<a href="{@mount}.m3u">Click to Listen</a>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<a href="{@mount}.m3u">Click to Listen</a>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</td></tr>
|
||||
|
Loading…
Reference in New Issue
Block a user