153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2004-2006 Lennart Poettering
553a5a1b3Sopenharmony_ci
653a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
753a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as
853a5a1b3Sopenharmony_ci  published by the Free Software Foundation; either version 2.1 of the
953a5a1b3Sopenharmony_ci  License, or (at your option) any later version.
1053a5a1b3Sopenharmony_ci
1153a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1253a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1353a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1453a5a1b3Sopenharmony_ci  Lesser General Public License for more details.
1553a5a1b3Sopenharmony_ci
1653a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public
1753a5a1b3Sopenharmony_ci  License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1853a5a1b3Sopenharmony_ci***/
1953a5a1b3Sopenharmony_ci
2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2153a5a1b3Sopenharmony_ci#include <config.h>
2253a5a1b3Sopenharmony_ci#endif
2353a5a1b3Sopenharmony_ci
2453a5a1b3Sopenharmony_ci#include <string.h>
2553a5a1b3Sopenharmony_ci#include <stdlib.h>
2653a5a1b3Sopenharmony_ci
2753a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
2853a5a1b3Sopenharmony_ci
2953a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
3053a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
3153a5a1b3Sopenharmony_ci#include <pulsecore/arpa-inet.h>
3253a5a1b3Sopenharmony_ci
3353a5a1b3Sopenharmony_ci#include "parseaddr.h"
3453a5a1b3Sopenharmony_ci
3553a5a1b3Sopenharmony_ci/* Parse addresses in one of the following forms:
3653a5a1b3Sopenharmony_ci *    HOSTNAME
3753a5a1b3Sopenharmony_ci *    HOSTNAME:PORT
3853a5a1b3Sopenharmony_ci *    [HOSTNAME]
3953a5a1b3Sopenharmony_ci *    [HOSTNAME]:PORT
4053a5a1b3Sopenharmony_ci *
4153a5a1b3Sopenharmony_ci *  Return a newly allocated string of the hostname and fill in *ret_port if specified  */
4253a5a1b3Sopenharmony_ci
4353a5a1b3Sopenharmony_cistatic char *parse_host(const char *s, uint16_t *ret_port) {
4453a5a1b3Sopenharmony_ci    pa_assert(s);
4553a5a1b3Sopenharmony_ci    pa_assert(ret_port);
4653a5a1b3Sopenharmony_ci
4753a5a1b3Sopenharmony_ci    if (*s == '[') {
4853a5a1b3Sopenharmony_ci        char *e;
4953a5a1b3Sopenharmony_ci        if (!(e = strchr(s+1, ']')))
5053a5a1b3Sopenharmony_ci            return NULL;
5153a5a1b3Sopenharmony_ci
5253a5a1b3Sopenharmony_ci        if (e[1] == ':') {
5353a5a1b3Sopenharmony_ci            uint32_t p;
5453a5a1b3Sopenharmony_ci
5553a5a1b3Sopenharmony_ci            if (pa_atou(e+2, &p) < 0)
5653a5a1b3Sopenharmony_ci                return NULL;
5753a5a1b3Sopenharmony_ci
5853a5a1b3Sopenharmony_ci            *ret_port = (uint16_t) p;
5953a5a1b3Sopenharmony_ci        } else if (e[1] != 0)
6053a5a1b3Sopenharmony_ci            return NULL;
6153a5a1b3Sopenharmony_ci
6253a5a1b3Sopenharmony_ci        return pa_xstrndup(s+1, (size_t) (e-s-1));
6353a5a1b3Sopenharmony_ci    } else {
6453a5a1b3Sopenharmony_ci        char *e;
6553a5a1b3Sopenharmony_ci        uint32_t p;
6653a5a1b3Sopenharmony_ci
6753a5a1b3Sopenharmony_ci        if (!(e = strrchr(s, ':')))
6853a5a1b3Sopenharmony_ci            return pa_xstrdup(s);
6953a5a1b3Sopenharmony_ci
7053a5a1b3Sopenharmony_ci        if (pa_atou(e+1, &p) < 0)
7153a5a1b3Sopenharmony_ci            return NULL;
7253a5a1b3Sopenharmony_ci
7353a5a1b3Sopenharmony_ci        *ret_port = (uint16_t) p;
7453a5a1b3Sopenharmony_ci        return pa_xstrndup(s, (size_t) (e-s));
7553a5a1b3Sopenharmony_ci    }
7653a5a1b3Sopenharmony_ci}
7753a5a1b3Sopenharmony_ci
7853a5a1b3Sopenharmony_ciint pa_parse_address(const char *name, pa_parsed_address *ret_p) {
7953a5a1b3Sopenharmony_ci    const char *p;
8053a5a1b3Sopenharmony_ci
8153a5a1b3Sopenharmony_ci    pa_assert(name);
8253a5a1b3Sopenharmony_ci    pa_assert(ret_p);
8353a5a1b3Sopenharmony_ci
8453a5a1b3Sopenharmony_ci    memset(ret_p, 0, sizeof(pa_parsed_address));
8553a5a1b3Sopenharmony_ci    ret_p->type = PA_PARSED_ADDRESS_TCP_AUTO;
8653a5a1b3Sopenharmony_ci
8753a5a1b3Sopenharmony_ci    if (*name == '{') {
8853a5a1b3Sopenharmony_ci        char *id, *pfx;
8953a5a1b3Sopenharmony_ci
9053a5a1b3Sopenharmony_ci        /* The URL starts with a host id for detecting local connections */
9153a5a1b3Sopenharmony_ci        if (!(id = pa_machine_id()))
9253a5a1b3Sopenharmony_ci            return -1;
9353a5a1b3Sopenharmony_ci
9453a5a1b3Sopenharmony_ci        pfx = pa_sprintf_malloc("{%s}", id);
9553a5a1b3Sopenharmony_ci        pa_xfree(id);
9653a5a1b3Sopenharmony_ci
9753a5a1b3Sopenharmony_ci        if (!pa_startswith(name, pfx)) {
9853a5a1b3Sopenharmony_ci            pa_xfree(pfx);
9953a5a1b3Sopenharmony_ci            /* Not local */
10053a5a1b3Sopenharmony_ci            return -1;
10153a5a1b3Sopenharmony_ci        }
10253a5a1b3Sopenharmony_ci
10353a5a1b3Sopenharmony_ci        p = name + strlen(pfx);
10453a5a1b3Sopenharmony_ci        pa_xfree(pfx);
10553a5a1b3Sopenharmony_ci    } else
10653a5a1b3Sopenharmony_ci        p = name;
10753a5a1b3Sopenharmony_ci
10853a5a1b3Sopenharmony_ci#ifndef OS_IS_WIN32
10953a5a1b3Sopenharmony_ci    if (*p == '/')
11053a5a1b3Sopenharmony_ci        ret_p->type = PA_PARSED_ADDRESS_UNIX;
11153a5a1b3Sopenharmony_ci#else
11253a5a1b3Sopenharmony_ci    if (strlen(p) >= 3 && p[1] == ':' && p[2] == '\\' && ((p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z')))
11353a5a1b3Sopenharmony_ci        ret_p->type = PA_PARSED_ADDRESS_UNIX;
11453a5a1b3Sopenharmony_ci#endif
11553a5a1b3Sopenharmony_ci    else if (pa_startswith(p, "unix:")) {
11653a5a1b3Sopenharmony_ci        ret_p->type = PA_PARSED_ADDRESS_UNIX;
11753a5a1b3Sopenharmony_ci        p += sizeof("unix:")-1;
11853a5a1b3Sopenharmony_ci    } else if (pa_startswith(p, "tcp:")) {
11953a5a1b3Sopenharmony_ci        ret_p->type = PA_PARSED_ADDRESS_TCP4;
12053a5a1b3Sopenharmony_ci        p += sizeof("tcp:")-1;
12153a5a1b3Sopenharmony_ci    } else if (pa_startswith(p, "tcp4:")) {
12253a5a1b3Sopenharmony_ci        ret_p->type = PA_PARSED_ADDRESS_TCP4;
12353a5a1b3Sopenharmony_ci        p += sizeof("tcp4:")-1;
12453a5a1b3Sopenharmony_ci    } else if (pa_startswith(p, "tcp6:")) {
12553a5a1b3Sopenharmony_ci        ret_p->type = PA_PARSED_ADDRESS_TCP6;
12653a5a1b3Sopenharmony_ci        p += sizeof("tcp6:")-1;
12753a5a1b3Sopenharmony_ci    }
12853a5a1b3Sopenharmony_ci
12953a5a1b3Sopenharmony_ci    if (ret_p->type == PA_PARSED_ADDRESS_UNIX)
13053a5a1b3Sopenharmony_ci        ret_p->path_or_host = pa_xstrdup(p);
13153a5a1b3Sopenharmony_ci    else
13253a5a1b3Sopenharmony_ci        if (!(ret_p->path_or_host = parse_host(p, &ret_p->port)))
13353a5a1b3Sopenharmony_ci            return -1;
13453a5a1b3Sopenharmony_ci
13553a5a1b3Sopenharmony_ci    return 0;
13653a5a1b3Sopenharmony_ci}
13753a5a1b3Sopenharmony_ci
13853a5a1b3Sopenharmony_cibool pa_is_ip_address(const char *a) {
13953a5a1b3Sopenharmony_ci    char buf[INET6_ADDRSTRLEN];
14053a5a1b3Sopenharmony_ci
14153a5a1b3Sopenharmony_ci    pa_assert(a);
14253a5a1b3Sopenharmony_ci
14353a5a1b3Sopenharmony_ci    if (inet_pton(AF_INET6, a, buf) >= 1)
14453a5a1b3Sopenharmony_ci        return true;
14553a5a1b3Sopenharmony_ci
14653a5a1b3Sopenharmony_ci    if (inet_pton(AF_INET, a, buf) >= 1)
14753a5a1b3Sopenharmony_ci        return true;
14853a5a1b3Sopenharmony_ci
14953a5a1b3Sopenharmony_ci    return false;
15053a5a1b3Sopenharmony_ci}
15153a5a1b3Sopenharmony_ci
15253a5a1b3Sopenharmony_cibool pa_is_ip6_address(const char *a) {
15353a5a1b3Sopenharmony_ci    char buf[INET6_ADDRSTRLEN];
15453a5a1b3Sopenharmony_ci
15553a5a1b3Sopenharmony_ci    pa_assert(a);
15653a5a1b3Sopenharmony_ci
15753a5a1b3Sopenharmony_ci    if (inet_pton(AF_INET6, a, buf) >= 1)
15853a5a1b3Sopenharmony_ci        return true;
15953a5a1b3Sopenharmony_ci
16053a5a1b3Sopenharmony_ci    return false;
16153a5a1b3Sopenharmony_ci}
162