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  and .
This commit is contained in:
Thomas Jansen
2010-09-25 15:00:43 +02:00
parent 0c80bd5fc0
commit 9af9fd1400
4 changed files with 65 additions and 14 deletions

1
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

@ -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"

@ -914,8 +914,17 @@ cd mpd-version</programlisting>
<parameter>P</parameter>
</entry>
<entry>
Binds the HTTP server to the specified port (on all
interfaces).
Binds the HTTP server to the specified port.
</entry>
</row>
<row>
<entry>
<varname>bind_to_address</varname>
<parameter>ADDR</parameter>
</entry>
<entry>
Binds the HTTP server to the specified address (IPv4 or
IPv6). Multiple addresses in parallel are not supported.
</entry>
</row>
<row>

@ -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;