diff --git a/NEWS b/NEWS index f40befed9..a1c9feeb1 100644 --- a/NEWS +++ b/NEWS @@ -60,6 +60,7 @@ ver 0.16 (20??/??/??) - httpd: bind port when output is enabled - httpd: added name/genre/website configuration - httpd: implement "pause" + - httpd: bind_to_address support (including IPv6) - oss: 24 bit support via OSS4 - win32: new output plugin for Windows Wave - wildcards allowed in audio_format configuration diff --git a/doc/mpdconf.example b/doc/mpdconf.example index 3b69e9bb3..b14337c76 100644 --- a/doc/mpdconf.example +++ b/doc/mpdconf.example @@ -260,6 +260,7 @@ input { # name "My HTTP Stream" # encoder "vorbis" # optional, vorbis or lame # port "8000" +# bind_to_address "0.0.0.0" # optional, IPv4 or IPv6 ## quality "5.0" # do not define if bitrate is defined # bitrate "128" # do not define if quality is defined # format "44100:16:1" diff --git a/doc/user.xml b/doc/user.xml index e1e62eb92..c783a981b 100644 --- a/doc/user.xml +++ b/doc/user.xml @@ -914,8 +914,17 @@ cd mpd-version P - Binds the HTTP server to the specified port (on all - interfaces). + Binds the HTTP server to the specified port. + + + + + bind_to_address + ADDR + + + Binds the HTTP server to the specified address (IPv4 or + IPv6). Multiple addresses in parallel are not supported. 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;