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.
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
View File

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

View File

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

View File

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

View File

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