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: bind port when output is enabled
- httpd: added name/genre/website configuration - httpd: added name/genre/website configuration
- httpd: implement "pause" - httpd: implement "pause"
- httpd: bind_to_address support (including IPv6)
- oss: 24 bit support via OSS4 - oss: 24 bit support via OSS4
- win32: new output plugin for Windows Wave - win32: new output plugin for Windows Wave
- wildcards allowed in audio_format configuration - wildcards allowed in audio_format configuration

@ -260,6 +260,7 @@ input {
# name "My HTTP Stream" # name "My HTTP Stream"
# encoder "vorbis" # optional, vorbis or lame # encoder "vorbis" # optional, vorbis or lame
# port "8000" # port "8000"
# bind_to_address "0.0.0.0" # optional, IPv4 or IPv6
## quality "5.0" # do not define if bitrate is defined ## quality "5.0" # do not define if bitrate is defined
# bitrate "128" # do not define if quality is defined # bitrate "128" # do not define if quality is defined
# format "44100:16:1" # format "44100:16:1"

@ -914,8 +914,17 @@ cd mpd-version</programlisting>
<parameter>P</parameter> <parameter>P</parameter>
</entry> </entry>
<entry> <entry>
Binds the HTTP server to the specified port (on all Binds the HTTP server to the specified port.
interfaces). </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> </entry>
</row> </row>
<row> <row>

@ -71,8 +71,8 @@ httpd_output_bind(struct httpd_output *httpd, GError **error_r)
/* create and set up listener socket */ /* create and set up listener socket */
httpd->fd = socket_bind_listen(PF_INET, SOCK_STREAM, 0, httpd->fd = socket_bind_listen(httpd->address.ss_family, SOCK_STREAM,
(struct sockaddr *)&httpd->address, 0, (struct sockaddr *)&httpd->address,
httpd->address_size, httpd->address_size,
16, error_r); 16, error_r);
if (httpd->fd < 0) if (httpd->fd < 0)
@ -103,16 +103,52 @@ httpd_output_unbind(struct httpd_output *httpd)
g_mutex_unlock(httpd->mutex); 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 * static void *
httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
const struct config_param *param, const struct config_param *param,
GError **error) GError **error)
{ {
struct httpd_output *httpd = g_new(struct httpd_output, 1); 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; const struct encoder_plugin *encoder_plugin;
guint port; guint port;
struct sockaddr_in *sin;
/* read configuration */ /* read configuration */
httpd->name = 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); httpd->clients_max = config_get_block_unsigned(param,"max_clients", 0);
/* initialize listen address */ /* set up bind_to_address */
bind_to_address =
sin = (struct sockaddr_in *)&httpd->address; config_get_block_string(param, "bind_to_address",
memset(sin, 0, sizeof(sin)); #ifdef HAVE_IPV6
sin->sin_port = htons(port); "::"
sin->sin_family = AF_INET; #else
sin->sin_addr.s_addr = INADDR_ANY; "0.0.0.0"
httpd->address_size = sizeof(*sin); #endif
);
httpd_output_parse_bind_to_address(httpd, bind_to_address, port, error);
if (*error)
return NULL;
/* initialize metadata */ /* initialize metadata */
httpd->metadata = NULL; httpd->metadata = NULL;