From 945287358b6e935d994a3411da097aba107e592d Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Thu, 5 Nov 2009 23:47:29 +0100
Subject: [PATCH] output/httpd: bind port when output is enabled

Implement the methods enable() and disable().  Bind the HTTP port in
the enable() method, but reject all incoming connections until the
output is opened.
---
 NEWS                             |  3 +-
 src/output/httpd_internal.h      |  7 ++++
 src/output/httpd_output_plugin.c | 55 ++++++++++++++++++++++++--------
 3 files changed, 51 insertions(+), 14 deletions(-)

diff --git a/NEWS b/NEWS
index 653105f54..776278ff0 100644
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,7 @@ ver 0.16 (20??/??/??)
   - twolame: new encoder plugin based on libtwolame
 * output:
   - recorder: new output plugin for recording radio streams
+  - alsa: don't recover on CANCEL
   - openal: new output plugin
   - pulse: announce "media.role=music"
   - pulse: renamed context to "Music Player Daemon"
@@ -38,8 +39,8 @@ ver 0.16 (20??/??/??)
   - jack: added option "client_name"
   - jack: clear ring buffers before activating
   - jack: support mono input
+  - httpd: bind port when output is enabled
   - wildcards allowed in audio_format configuration
-  - alsa: don't recover on CANCEL
   - consistently lock audio output objects
 * mixers:
   - removed support for legacy mixer configuration
diff --git a/src/output/httpd_internal.h b/src/output/httpd_internal.h
index 83e9498c6..22155b7ba 100644
--- a/src/output/httpd_internal.h
+++ b/src/output/httpd_internal.h
@@ -30,10 +30,17 @@
 #include <glib.h>
 
 #include <sys/socket.h>
+#include <stdbool.h>
 
 struct httpd_client;
 
 struct httpd_output {
+	/**
+	 * True if the audio output is open and accepts client
+	 * connections.
+	 */
+	bool open;
+
 	/**
 	 * The configured encoder plugin.
 	 */
diff --git a/src/output/httpd_output_plugin.c b/src/output/httpd_output_plugin.c
index 675297cd3..9e82489ca 100644
--- a/src/output/httpd_output_plugin.c
+++ b/src/output/httpd_output_plugin.c
@@ -151,8 +151,9 @@ httpd_listen_in_event(G_GNUC_UNUSED GIOChannel *source,
 	fd = accept(httpd->fd, (struct sockaddr*)&sa, &sa_length);
 	if (fd >= 0) {
 		/* can we allow additional client */
-		if (!httpd->clients_max ||
-		     httpd->clients_cnt < httpd->clients_max)
+		if (httpd->open &&
+		    (httpd->clients_max == 0 ||
+		     httpd->clients_cnt < httpd->clients_max))
 			httpd_client_add(httpd, fd);
 		else
 			close(fd);
@@ -208,31 +209,56 @@ httpd_output_encoder_open(struct httpd_output *httpd,
 }
 
 static bool
-httpd_output_open(void *data, struct audio_format *audio_format,
-		  GError **error)
+httpd_output_enable(void *data, GError **error_r)
 {
 	struct httpd_output *httpd = data;
-	bool success;
 	GIOChannel *channel;
 
-	g_mutex_lock(httpd->mutex);
+	httpd->open = false;
 
 	/* create and set up listener socket */
 
 	httpd->fd = socket_bind_listen(PF_INET, SOCK_STREAM, 0,
 				       (struct sockaddr *)&httpd->address,
 				       httpd->address_size,
-				       16, error);
-	if (httpd->fd < 0) {
-		g_mutex_unlock(httpd->mutex);
+				       16, error_r);
+	if (httpd->fd < 0)
 		return false;
-	}
+
+	g_mutex_lock(httpd->mutex);
 
 	channel = g_io_channel_unix_new(httpd->fd);
 	httpd->source_id = g_io_add_watch(channel, G_IO_IN,
 					  httpd_listen_in_event, httpd);
 	g_io_channel_unref(channel);
 
+	g_mutex_unlock(httpd->mutex);
+
+	return true;
+}
+
+static void
+httpd_output_disable(void *data)
+{
+	struct httpd_output *httpd = data;
+
+	g_mutex_lock(httpd->mutex);
+
+	g_source_remove(httpd->source_id);
+	close(httpd->fd);
+
+	g_mutex_unlock(httpd->mutex);
+}
+
+static bool
+httpd_output_open(void *data, struct audio_format *audio_format,
+		  GError **error)
+{
+	struct httpd_output *httpd = data;
+	bool success;
+
+	g_mutex_lock(httpd->mutex);
+
 	/* open the encoder */
 
 	success = httpd_output_encoder_open(httpd, audio_format, error);
@@ -249,6 +275,8 @@ httpd_output_open(void *data, struct audio_format *audio_format,
 	httpd->clients_cnt = 0;
 	httpd->timer = timer_new(audio_format);
 
+	httpd->open = true;
+
 	g_mutex_unlock(httpd->mutex);
 	return true;
 }
@@ -267,6 +295,8 @@ static void httpd_output_close(void *data)
 
 	g_mutex_lock(httpd->mutex);
 
+	httpd->open = false;
+
 	timer_free(httpd->timer);
 
 	g_list_foreach(httpd->clients, httpd_client_delete, NULL);
@@ -277,9 +307,6 @@ static void httpd_output_close(void *data)
 
 	encoder_close(httpd->encoder);
 
-	g_source_remove(httpd->source_id);
-	close(httpd->fd);
-
 	g_mutex_unlock(httpd->mutex);
 }
 
@@ -478,6 +505,8 @@ const struct audio_output_plugin httpd_output_plugin = {
 	.name = "httpd",
 	.init = httpd_output_init,
 	.finish = httpd_output_finish,
+	.enable = httpd_output_enable,
+	.disable = httpd_output_disable,
 	.open = httpd_output_open,
 	.close = httpd_output_close,
 	.send_tag = httpd_output_tag,