mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	* Publish server info in mDNS in addition to sinks/sources
* Split off address parser * Add port= argument to module-zeroconf-publish git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@324 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
		
							parent
							
								
									bc5b917f93
								
							
						
					
					
						commit
						99e0779b51
					
				
					 7 changed files with 242 additions and 94 deletions
				
			
		| 
						 | 
				
			
			@ -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 \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										112
									
								
								polyp/parseaddr.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								polyp/parseaddr.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								polyp/parseaddr.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								polyp/parseaddr.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)))
 | 
			
		||||
    if (pa_parse_address(name, &a) < 0)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
        pfx = pa_sprintf_malloc("{%s}", hn);
 | 
			
		||||
        if (!pa_startswith(name, pfx))
 | 
			
		||||
            /* Not local */
 | 
			
		||||
            return NULL;
 | 
			
		||||
    switch (a.type) {
 | 
			
		||||
        case PA_PARSED_ADDRESS_UNIX:
 | 
			
		||||
            c = pa_socket_client_new_unix(m, a.path_or_host);
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (kind) {
 | 
			
		||||
        case KIND_UNIX:
 | 
			
		||||
            return pa_socket_client_new_unix(m, p);
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue