aboutsummaryrefslogtreecommitdiffstats
path: root/src/output
diff options
context:
space:
mode:
authorThomas Jansen <mithi@mithi.net>2010-09-25 15:00:43 +0200
committerThomas Jansen <mithi@mithi.net>2010-09-25 15:00:43 +0200
commit9af9fd140032138894e4781caabee8a5a96edab8 (patch)
treee8afa3fcc319b9a8f9b810c32ae398edeee2372f /src/output
parent0c80bd5fc09fad536424b139331b0f8f43437d1b (diff)
downloadmpd-9af9fd140032138894e4781caabee8a5a96edab8.tar.gz
mpd-9af9fd140032138894e4781caabee8a5a96edab8.tar.xz
mpd-9af9fd140032138894e4781caabee8a5a96edab8.zip
output/httpd: bind_to_address support (including IPv6)
Added support for a new optional configuration setting for the httpd output named "bind_to_address". Setting it to a specific IP address (v4 or v6) will cause the httpd output to bind to that address exclusively. Supporting multiple addresses in parallel is future work. This implements the feature requests #2998 and #2646.
Diffstat (limited to 'src/output')
-rw-r--r--src/output/httpd_output_plugin.c64
1 files changed, 52 insertions, 12 deletions
diff --git a/src/output/httpd_output_plugin.c b/src/output/httpd_output_plugin.c
index bff56bf6b..43b635472 100644
--- a/src/output/httpd_output_plugin.c
+++ b/src/output/httpd_output_plugin.c
@@ -71,8 +71,8 @@ httpd_output_bind(struct httpd_output *httpd, GError **error_r)
/* create and set up listener socket */
- httpd->fd = socket_bind_listen(PF_INET, SOCK_STREAM, 0,
- (struct sockaddr *)&httpd->address,
+ httpd->fd = socket_bind_listen(httpd->address.ss_family, SOCK_STREAM,
+ 0, (struct sockaddr *)&httpd->address,
httpd->address_size,
16, error_r);
if (httpd->fd < 0)
@@ -103,16 +103,52 @@ httpd_output_unbind(struct httpd_output *httpd)
g_mutex_unlock(httpd->mutex);
}
+static void
+httpd_output_parse_bind_to_address(struct httpd_output *httpd,
+ const char *bind_to_address,
+ guint port, GError **error)
+{
+ struct addrinfo hints, *ai;
+ char service[20];
+ int ret;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_PASSIVE;
+#ifdef AI_ADDRCONFIG
+ hints.ai_flags |= AI_ADDRCONFIG;
+#endif
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ g_snprintf(service, sizeof(service), "%u", port);
+ ret = getaddrinfo(bind_to_address, service, &hints, &ai);
+ if (ret != 0) {
+ g_set_error(error, httpd_output_quark(), ret,
+ "Failed to look up host \"%s\": %s",
+ bind_to_address, gai_strerror(ret));
+ return;
+ }
+
+ assert(ai);
+
+ /* Choose the first address, even if multiple are available. We do
+ * not support multiple addresses yet. */
+ memcpy(&httpd->address, ai->ai_addr, ai->ai_addrlen);
+ httpd->address_size = ai->ai_addrlen;
+
+ freeaddrinfo(ai);
+}
+
static void *
httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
const struct config_param *param,
GError **error)
{
struct httpd_output *httpd = g_new(struct httpd_output, 1);
- const char *encoder_name;
+ const char *encoder_name, *bind_to_address;
const struct encoder_plugin *encoder_plugin;
guint port;
- struct sockaddr_in *sin;
/* read configuration */
httpd->name =
@@ -134,14 +170,18 @@ httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
httpd->clients_max = config_get_block_unsigned(param,"max_clients", 0);
- /* initialize listen address */
-
- sin = (struct sockaddr_in *)&httpd->address;
- memset(sin, 0, sizeof(sin));
- sin->sin_port = htons(port);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = INADDR_ANY;
- httpd->address_size = sizeof(*sin);
+ /* set up bind_to_address */
+ bind_to_address =
+ config_get_block_string(param, "bind_to_address",
+#ifdef HAVE_IPV6
+ "::"
+#else
+ "0.0.0.0"
+#endif
+ );
+ httpd_output_parse_bind_to_address(httpd, bind_to_address, port, error);
+ if (*error)
+ return NULL;
/* initialize metadata */
httpd->metadata = NULL;