diff options
| -rw-r--r-- | polyp/Makefile.am | 10 | ||||
| -rw-r--r-- | polyp/module-zeroconf-publish.c | 61 | ||||
| -rw-r--r-- | polyp/parseaddr.c | 112 | ||||
| -rw-r--r-- | polyp/parseaddr.h | 42 | ||||
| -rw-r--r-- | polyp/polyplib-browser.c | 1 | ||||
| -rw-r--r-- | polyp/socket-client.c | 108 | ||||
| -rw-r--r-- | polyp/util.c | 2 | 
7 files changed, 242 insertions, 94 deletions
| diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 79accfe6..0c491ce5 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -87,6 +87,7 @@ modlib_LTLIBRARIES= \  		libiochannel.la \  		libsocket-server.la \  		libsocket-client.la \ +		libparseaddr.la \  		libpacket.la \  		libpstream.la \  		liboss-util.la \ @@ -228,7 +229,8 @@ polypaudio_SOURCES = idxset.c idxset.h \  polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)  polypaudio_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL)  polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) -polypaudio_LDFLAGS= $(AM_LDFLAGS) -export-dynamic -dlopen force #-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f)) +polypaudio_LDFLAGS= $(AM_LDFLAGS) -export-dynamic -dlopen force  +#q-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f))  libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h  libprotocol_simple_la_LDFLAGS = -avoid-version @@ -240,7 +242,10 @@ libsocket_server_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la $(LI  libsocket_client_la_SOURCES = socket-client.c socket-client.h  libsocket_client_la_LDFLAGS = -avoid-version -libsocket_client_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la +libsocket_client_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la libparseaddr.la + +libparseaddr_la_SOURCES = parseaddr.c parseaddr.h +libparseaddr_la_LDFLAGS = -avoid-version  libpstream_la_SOURCES = pstream.c pstream.h  libpstream_la_LDFLAGS = -avoid-version @@ -434,6 +439,7 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \  		util.c util.h \  		memblock.c memblock.h \  		socket-client.c socket-client.h \ +		parseaddr.c parseaddr.h \  		packet.c packet.h \  		queue.c queue.h \  		dynarray.c dynarray.h \ diff --git a/polyp/module-zeroconf-publish.c b/polyp/module-zeroconf-publish.c index c88ac766..511ceb47 100644 --- a/polyp/module-zeroconf-publish.c +++ b/polyp/module-zeroconf-publish.c @@ -41,15 +41,22 @@  #include "subscribe.h"  #include "dynarray.h"  #include "endianmacros.h" +#include "modargs.h"  PA_MODULE_AUTHOR("Lennart Poettering")  PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher")  PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("port=<IP port number>")  #define SERVICE_NAME_SINK "_polypaudio-sink._tcp"  #define SERVICE_NAME_SOURCE "_polypaudio-source._tcp"  #define SERVICE_NAME_SERVER "_polypaudio-server._tcp" +static const char* const valid_modargs[] = { +    "port", +    NULL +}; +  struct service {      sw_discovery_oid oid;      char *name; @@ -74,6 +81,9 @@ struct userdata {      struct pa_hashmap *services;      struct pa_dynarray *sink_dynarray, *source_dynarray, *autoload_dynarray;      struct pa_subscription *subscription; + +    uint16_t port; +    sw_discovery_oid server_oid;  };  static sw_result publish_reply(sw_discovery discovery, sw_discovery_publish_status status, sw_discovery_oid oid, sw_opaque extra) { @@ -127,7 +137,7 @@ static int publish_service(struct userdata *u, struct service *s) {          s->published = 0;      } -    snprintf(t, sizeof(t), "%s@%s", s->name, pa_get_host_name(hn, sizeof(hn)));    +    snprintf(t, sizeof(t), "Networked Audio device %s on %s", s->name, pa_get_host_name(hn, sizeof(hn)));      if (sw_text_record_init(&txt) != SW_OKAY) {          pa_log(__FILE__": sw_text_record_init() failed\n"); @@ -160,7 +170,7 @@ static int publish_service(struct userdata *u, struct service *s) {          if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t,                                   s->loaded.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, -                                 NULL, NULL, PA_NATIVE_DEFAULT_PORT, sw_text_record_bytes(txt), sw_text_record_len(txt), +                                 NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt),                                   publish_reply, s, &s->oid) != SW_OKAY) {              pa_log(__FILE__": failed to register sink on zeroconf.\n");              goto finish; @@ -171,7 +181,7 @@ static int publish_service(struct userdata *u, struct service *s) {          if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t,                                   s->autoload.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, -                                 NULL, NULL, PA_NATIVE_DEFAULT_PORT, sw_text_record_bytes(txt), sw_text_record_len(txt), +                                 NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt),                                   publish_reply, s, &s->oid) != SW_OKAY) {              pa_log(__FILE__": failed to register sink on zeroconf.\n");              goto finish; @@ -375,13 +385,28 @@ fail:  int pa__init(struct pa_core *c, struct pa_module*m) {      struct userdata *u; -    uint32_t index; +    uint32_t index, port = PA_NATIVE_DEFAULT_PORT;      struct pa_sink *sink;      struct pa_source *source;      struct pa_autoload_entry *autoload; +    struct pa_modargs *ma = NULL; +    char t[256], hn[256]; +    int free_txt = 0; +    sw_text_record txt; + +    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { +        pa_log(__FILE__": failed to parse module arguments.\n"); +        goto fail; +    } + +    if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port == 0 || port >= 0xFFFF) { +        pa_log(__FILE__": invalid port specified.\n"); +        goto fail; +    }      m->userdata = u = pa_xmalloc(sizeof(struct userdata));      u->core = c; +    u->port = (uint16_t) port;      if (!(u->howl_wrapper = pa_howl_wrapper_get(c)))          goto fail; @@ -409,10 +434,38 @@ int pa__init(struct pa_core *c, struct pa_module*m) {              if (publish_autoload(u, autoload) < 0)                  goto fail; +    snprintf(t, sizeof(t), "Networked Audio on %s", pa_get_host_name(hn, sizeof(hn)));    + +    if (sw_text_record_init(&txt) != SW_OKAY) { +        pa_log(__FILE__": sw_text_record_init() failed\n"); +        goto fail; +    } +    free_txt = 1; + +    txt_record_server_data(u->core, txt); +     +    if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t, +                             SERVICE_NAME_SERVER, +                             NULL, NULL, u->port, sw_text_record_bytes(txt), sw_text_record_len(txt), +                             publish_reply, u, &u->server_oid) != SW_OKAY) { +        pa_log(__FILE__": failed to register server on zeroconf.\n"); +        goto fail; +    } +     +    sw_text_record_fina(txt); +    pa_modargs_free(ma); +          return 0;  fail:      pa__done(c, m); + +    if (ma) +        pa_modargs_free(ma); + +    if (free_txt) +        sw_text_record_fina(txt); +          return -1;  } diff --git a/polyp/parseaddr.c b/polyp/parseaddr.c new file mode 100644 index 00000000..05ed508b --- /dev/null +++ b/polyp/parseaddr.c @@ -0,0 +1,112 @@ +/* $Id$ */ + +/*** +  This file is part of polypaudio. +  +  polypaudio is free software; you can redistribute it and/or modify +  it under the terms of the GNU Lesser General Public License as +  published by the Free Software Foundation; either version 2.1 of the +  License, or (at your option) any later version. +  +  polypaudio is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +  Lesser General Public License for more details. +  +  You should have received a copy of the GNU Lesser General Public +  License along with polypaudio; if not, write to the Free Software +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +  USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <assert.h> +#include <stdlib.h> + +#include "xmalloc.h" +#include "util.h" +#include "parseaddr.h" + +/* Parse addresses in one of the following forms: + *    HOSTNAME + *    HOSTNAME:PORT + *    [HOSTNAME] + *    [HOSTNAME]:PORT + * + *  Return a newly allocated string of the hostname and fill in *ret_port if specified  */ + +static char *parse_host(const char *s, uint16_t *ret_port) { +    assert(s && ret_port); +    if (*s == '[') { +        char *e; +        if (!(e = strchr(s+1, ']'))) +            return NULL; + +        if (e[1] == ':') +            *ret_port = atoi(e+2); +        else if (e[1] != 0) +            return NULL; +         +        return pa_xstrndup(s+1, e-s-1); +    } else { +        char *e; +         +        if (!(e = strrchr(s, ':'))) +            return pa_xstrdup(s); + +        *ret_port = atoi(e+1); +        return pa_xstrndup(s, e-s); +    } +} + +int pa_parse_address(const char *name, struct pa_parsed_address *ret_p) { +    const char *p; +    assert(name && ret_p); +    memset(ret_p, 0, sizeof(struct pa_parsed_address)); +    ret_p->type = PA_PARSED_ADDRESS_TCP_AUTO; + +    if (*name == '{') { +        char hn[256], *pfx; +        /* The URL starts with a host specification for detecting local connections */ +         +        if (!pa_get_host_name(hn, sizeof(hn))) +            return -1; +                 +        pfx = pa_sprintf_malloc("{%s}", hn); +        if (!pa_startswith(name, pfx)) { +            pa_xfree(pfx); +            /* Not local */ +            return -1; +        } +         +        p = name + strlen(pfx); +        pa_xfree(pfx); +    } else +        p = name; +     +    if (*p == '/') +        ret_p->type = PA_PARSED_ADDRESS_UNIX; +    else if (pa_startswith(p, "unix:")) { +        ret_p->type = PA_PARSED_ADDRESS_UNIX; +        p += sizeof("unix:")-1; +    } else if (pa_startswith(p, "tcp:") || pa_startswith(p, "tcp4:")) { +        ret_p->type = PA_PARSED_ADDRESS_TCP4; +        p += sizeof("tcp:")-1; +    } else if (pa_startswith(p, "tcp6:")) { +        ret_p->type = PA_PARSED_ADDRESS_TCP6; +        p += sizeof("tcp6:")-1; +    } + +    if (ret_p->type == PA_PARSED_ADDRESS_UNIX) +        ret_p->path_or_host = pa_xstrdup(p); +    else +        if (!(ret_p->path_or_host = parse_host(p, &ret_p->port))) +            return -1; +     +         +    return 0; +} diff --git a/polyp/parseaddr.h b/polyp/parseaddr.h new file mode 100644 index 00000000..5ddc0351 --- /dev/null +++ b/polyp/parseaddr.h @@ -0,0 +1,42 @@ +#ifndef fooparseaddrhfoo +#define fooparseaddrhfoo + +/* $Id$ */ + +/*** +  This file is part of polypaudio. +  +  polypaudio is free software; you can redistribute it and/or modify +  it under the terms of the GNU Lesser General Public License as +  published by the Free Software Foundation; either version 2.1 of the +  License, or (at your option) any later version. +  +  polypaudio is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +  Lesser General Public License for more details. +  +  You should have received a copy of the GNU Lesser General Public +  License along with polypaudio; if not, write to the Free Software +  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +  USA. +***/ + +#include <inttypes.h> + +enum pa_parsed_address_type { +    PA_PARSED_ADDRESS_UNIX, +    PA_PARSED_ADDRESS_TCP4, +    PA_PARSED_ADDRESS_TCP6, +    PA_PARSED_ADDRESS_TCP_AUTO +}; + +struct pa_parsed_address { +    enum pa_parsed_address_type type; +    char *path_or_host; +    uint16_t port; +}; + +int pa_parse_address(const char *a, struct pa_parsed_address *ret_p); + +#endif diff --git a/polyp/polyplib-browser.c b/polyp/polyplib-browser.c index a1bd3fb7..7e56e2ce 100644 --- a/polyp/polyplib-browser.c +++ b/polyp/polyplib-browser.c @@ -221,7 +221,6 @@ static sw_result browse_reply(      switch (status) {          case SW_DISCOVERY_BROWSE_ADD_SERVICE: {              sw_discovery_oid oid; -            fprintf(stderr, "debug: new service: %s\n", name);              if (sw_discovery_resolve(b->discovery, 0, name, type, domain, resolve_reply, b, &oid) != SW_OKAY)                  pa_log("sw_discovery_resolve() failed\n"); diff --git a/polyp/socket-client.c b/polyp/socket-client.c index c58c7bd4..0581e553 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -39,6 +39,7 @@  #include "util.h"  #include "xmalloc.h"  #include "log.h" +#include "parseaddr.h"  struct pa_socket_client {      int ref; @@ -254,121 +255,56 @@ struct pa_socket_client* pa_socket_client_new_ipv6(struct pa_mainloop_api *m, ui      return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));  } -/* Parse addresses in one of the following forms: - *    HOSTNAME - *    HOSTNAME:PORT - *    [HOSTNAME] - *    [HOSTNAME]:PORT - * - *  Return a newly allocated string of the hostname and fill in *port if specified  */ - -static char *parse_address(const char *s, uint16_t *port) { -    assert(s && port); -    if (*s == '[') { -        char *e; -        if (!(e = strchr(s+1, ']'))) -            return NULL; - -        if (e[1] == ':') -            *port = atoi(e+2); -        else if (e[1] != 0) -            return NULL; -         -        return pa_xstrndup(s+1, e-s-1); -    } else { -        char *e; -         -        if (!(e = strrchr(s, ':'))) -            return pa_xstrdup(s); - -        *port = atoi(e+1); -        return pa_xstrndup(s, e-s); -    } -} -  struct pa_socket_client* pa_socket_client_new_string(struct pa_mainloop_api *m, const char*name, uint16_t default_port) { -    const char *p;      struct pa_socket_client *c = NULL; -    enum { KIND_UNIX, KIND_TCP_AUTO, KIND_TCP4, KIND_TCP6 } kind = KIND_TCP_AUTO; +    struct pa_parsed_address a;      assert(m && name); -    if (*name == '{') { -        char hn[256], *pfx; -        /* The URL starts with a host specification for detecting local connections */ -         -        if (!pa_get_host_name(hn, sizeof(hn))) -            return NULL; -                 -        pfx = pa_sprintf_malloc("{%s}", hn); -        if (!pa_startswith(name, pfx)) -            /* Not local */ -            return NULL; -         -        p = name + strlen(pfx); -    } else -        p = name; -     -    if (*p == '/') -        kind = KIND_UNIX; -    else if (pa_startswith(p, "unix:")) { -        kind = KIND_UNIX; -        p += sizeof("unix:")-1; -    } else if (pa_startswith(p, "tcp:") || pa_startswith(p, "tcp4:")) { -        kind = KIND_TCP4; -        p += sizeof("tcp:")-1; -    } else if (pa_startswith(p, "tcp6:")) { -        kind = KIND_TCP6; -        p += sizeof("tcp6:")-1; -    } +    if (pa_parse_address(name, &a) < 0) +        return NULL; -    switch (kind) { -        case KIND_UNIX: -            return pa_socket_client_new_unix(m, p); +    switch (a.type) { +        case PA_PARSED_ADDRESS_UNIX: +            c = pa_socket_client_new_unix(m, a.path_or_host); +            break; -        case KIND_TCP_AUTO:  /* Fallthrough */ -        case KIND_TCP4:  -        case KIND_TCP6: { -            uint16_t port = default_port; -            char *h; +        case PA_PARSED_ADDRESS_TCP4:  /* Fallthrough */ +        case PA_PARSED_ADDRESS_TCP6:  /* Fallthrough */ +        case PA_PARSED_ADDRESS_TCP_AUTO:{              int ret;              struct addrinfo hints, *res; -            if (!(h = parse_address(p, &port))) -                return NULL; -              memset(&hints, 0, sizeof(hints)); -            hints.ai_family = kind == KIND_TCP4 ? AF_INET : (kind == KIND_TCP6 ? AF_INET6 : AF_UNSPEC); +            hints.ai_family = a.type == PA_PARSED_ADDRESS_TCP4 ? AF_INET : (a.type == PA_PARSED_ADDRESS_TCP6 ? AF_INET6 : AF_UNSPEC); -            ret = getaddrinfo(h, NULL, &hints, &res); -            pa_xfree(h); +            ret = getaddrinfo(a.path_or_host, NULL, &hints, &res);              if (ret < 0 || !res || !res->ai_addr) -                return NULL; +                goto finish;              if (res->ai_family == AF_INET) {                  if (res->ai_addrlen != sizeof(struct sockaddr_in)) -                    return NULL; +                    goto finish;                  assert(res->ai_addr->sa_family == res->ai_family); -                ((struct sockaddr_in*) res->ai_addr)->sin_port = htons(port); +                ((struct sockaddr_in*) res->ai_addr)->sin_port = htons(a.port);              } else if (res->ai_family == AF_INET6) {                  if (res->ai_addrlen != sizeof(struct sockaddr_in6)) -                    return NULL; +                    goto finish;                  assert(res->ai_addr->sa_family == res->ai_family); -                ((struct sockaddr_in6*) res->ai_addr)->sin6_port = htons(port); +                ((struct sockaddr_in6*) res->ai_addr)->sin6_port = htons(a.port);              } else -                return NULL; +                goto finish;              c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen);              freeaddrinfo(res); -            return c;          }      } -    /* Should never be reached */ -    assert(0); -    return NULL; +finish: +    pa_xfree(a.path_or_host); +    return c;  } diff --git a/polyp/util.c b/polyp/util.c index ff1aebf3..ee3fa87d 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -880,7 +880,7 @@ int pa_atoi(const char *s, int32_t *ret_i) {      l = strtol(s, &x, 0); -    if (x || *x) +    if (!x || *x)          return -1;      *ret_i = (int32_t) l; | 
