diff --git a/conf/icecast.xml.in b/conf/icecast.xml.in
index ff70d065..59dabaf3 100644
--- a/conf/icecast.xml.in
+++ b/conf/icecast.xml.in
@@ -105,6 +105,8 @@
+ /home/icecast/bin/stream-start
+ /home/icecast/bin/stream-stop
-->
diff --git a/doc/icecast2_config_file.html b/doc/icecast2_config_file.html
index d552ef27..a62bf82e 100644
--- a/doc/icecast2_config_file.html
+++ b/doc/icecast2_config_file.html
@@ -380,7 +380,8 @@ If you are relaying a Shoutcast stream, you need to specify this indicator to al
<option name="filename" value="myauth"/>
<option name="allow_duplicate_users" value="0"/>
</authentication>
-
+ <on-connect>/home/icecast/bin/source-start</on-connect>
+ <on-disconnect>/home/icecast/bin/source-end</on-disconnect>
</mount>
This section contains the settings which apply only to a specific mountpoint and applies to
@@ -524,6 +525,20 @@ relay to be shown
This specifies that the named mount point will require listener authentication. Currently, we only support a file-based authentication scheme (type=htpasswd). Users and encrypted password are placed in this file (separated by a :) and all requests for this mountpoint will require that a user and password be supplied for authentication purposes. These values are passed in via normal HTTP Basic Authentication means (i.e. http://user:password@stream:port/mountpoint.ogg). Users and Passwords are maintained via the web admin interface. A mountpoint configured with an authenticator will display a red key next to the mount point name on the admin screens. You can read more about listener authentication here.
+
on-connect
+
+
State a program that is run when the source is started. It is passed a parameter which
+ is the name of the mountpoint that is starting. The processing of the stream does not wait
+ for the script to end. This option is not available on win32
+
+
+
on-disconnect
+
+
State a program that is run when the source ends. It is passed a parameter which is the
+ name of the mountpoint that has ended. The processing of the stream does not wait for the
+ script to end. This option is not available on win32
+
+
diff --git a/src/cfgfile.c b/src/cfgfile.c
index b0c0ada5..0620f0de 100644
--- a/src/cfgfile.c
+++ b/src/cfgfile.c
@@ -191,6 +191,8 @@ void config_clear(ice_config_t *c)
xmlFree(mount->password);
xmlFree(mount->dumpfile);
xmlFree(mount->intro_filename);
+ xmlFree(mount->on_connect);
+ xmlFree(mount->on_disconnect);
xmlFree(mount->fallback_mount);
xmlFree(mount->stream_name);
xmlFree(mount->stream_description);
@@ -633,6 +635,14 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node,
option = option->next;
}
}
+ else if (strcmp(node->name, "on-connect") == 0) {
+ mount->on_connect = (char *)xmlNodeListGetString(
+ doc, node->xmlChildrenNode, 1);
+ }
+ else if (strcmp(node->name, "on-disconnect") == 0) {
+ mount->on_disconnect = (char *)xmlNodeListGetString(
+ doc, node->xmlChildrenNode, 1);
+ }
else if (strcmp(node->name, "queue-size") == 0) {
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
mount->queue_size_limit = atoi (tmp);
diff --git a/src/cfgfile.h b/src/cfgfile.h
index 8676e121..6b53d34a 100644
--- a/src/cfgfile.h
+++ b/src/cfgfile.h
@@ -65,6 +65,8 @@ typedef struct _mount_proxy {
char *auth_type; /* Authentication type */
char *cluster_password;
config_options_t *auth_options; /* Options for this type */
+ char *on_connect;
+ char *on_disconnect;
char *stream_name;
char *stream_description;
diff --git a/src/sighandler.c b/src/sighandler.c
index 23e750a1..a7c1cd76 100644
--- a/src/sighandler.c
+++ b/src/sighandler.c
@@ -41,6 +41,7 @@ void sighandler_initialize(void)
signal(SIGINT, _sig_die);
signal(SIGTERM, _sig_die);
signal(SIGPIPE, SIG_IGN);
+ signal(SIGCHLD, SIG_IGN);
#endif
}
diff --git a/src/source.c b/src/source.c
index 89d75bd6..673f818d 100644
--- a/src/source.c
+++ b/src/source.c
@@ -26,6 +26,7 @@
#include
#include
#include
+#include
#else
#include
#include
@@ -62,6 +63,11 @@ static int _compare_clients(void *compare_arg, void *a, void *b);
static int _free_client(void *key);
static void _parse_audio_info (source_t *source, const char *s);
static void source_shutdown (source_t *source);
+#ifdef _WIN32
+#define source_run_script(x,y) WARN0("on [dis]connect scripts disabled");
+#else
+static void source_run_script (char *command, char *mountpoint);
+#endif
/* Allocate a new source with the stated mountpoint, if one already
* exists with that mountpoint in the global source tree then return
@@ -534,6 +540,7 @@ static void source_init (source_t *source)
ice_config_t *config = config_get_config();
char *listenurl, *str;
int listen_url_size;
+ mount_proxy *mountinfo;
/* 6 for max size of port */
listen_url_size = strlen("http://") + strlen(config->hostname) +
@@ -584,6 +591,11 @@ static void source_init (source_t *source)
source->last_read = time (NULL);
source->running = 1;
+ mountinfo = config_find_mount (config_get_config(), source->mount);
+ if (mountinfo && mountinfo->on_connect)
+ source_run_script (mountinfo->on_connect, source->mount);
+ config_release_config();
+
/*
** Now, if we have a fallback source and override is on, we want
** to steal its clients, because it means we've come back online
@@ -769,9 +781,16 @@ void source_main (source_t *source)
static void source_shutdown (source_t *source)
{
+ mount_proxy *mountinfo;
+
source->running = 0;
INFO1("Source \"%s\" exiting", source->mount);
+ mountinfo = config_find_mount (config_get_config(), source->mount);
+ if (mountinfo && mountinfo->on_disconnect)
+ source_run_script (mountinfo->on_disconnect, source->mount);
+ config_release_config();
+
/* we have de-activated the source now, so no more clients will be
* added, now move the listeners we have to the fallback (if any)
*/
@@ -1089,6 +1108,10 @@ void source_update_settings (ice_config_t *config, source_t *source, mount_proxy
DEBUG1 ("intro file is %s", mountinfo->intro_filename);
if (source->dumpfilename)
DEBUG1 ("Dumping stream to %s", source->dumpfilename);
+ if (mountinfo && mountinfo->on_connect)
+ DEBUG1 ("connect script \"%s\"", mountinfo->on_connect);
+ if (mountinfo && mountinfo->on_disconnect)
+ DEBUG1 ("disconnect script \"%s\"", mountinfo->on_disconnect);
if (source->on_demand)
{
DEBUG0 ("on_demand set");
@@ -1156,6 +1179,41 @@ void *source_client_thread (void *arg)
}
+#ifndef _WIN32
+static void source_run_script (char *command, char *mountpoint)
+{
+ pid_t pid, external_pid;
+
+ /* do a fork twice so that the command has init as parent */
+ external_pid = fork();
+ switch (external_pid)
+ {
+ case 0:
+ switch (pid = fork ())
+ {
+ case -1:
+ ERROR2 ("Unable to fork %s (%s)", command, strerror (errno));
+ break;
+ case 0: /* child */
+ DEBUG1 ("Starting command %s", command);
+ execl (command, command, mountpoint, NULL);
+ ERROR2 ("Unable to run command %s (%s)", command, strerror (errno));
+ exit(0);
+ default: /* parent */
+ break;
+ }
+ exit (0);
+ case -1:
+ ERROR1 ("Unable to fork %s", strerror (errno));
+ break;
+ default: /* parent */
+ waitpid (external_pid, NULL, 0);
+ break;
+ }
+}
+#endif
+
+
/* rescan the mount list, so that xsl files are updated to show
* unconnected but active fallback mountpoints
*/