core: always allow volume setting with single-channel pa_cvolume
[platform/upstream/pulseaudio.git] / src / pulsecore / parseaddr.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2006 Lennart Poettering
5
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with PulseAudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27 #include <stdlib.h>
28 #include <arpa/inet.h>
29 #include <sys/socket.h>
30
31 #include <pulse/xmalloc.h>
32 #include <pulse/util.h>
33
34 #include <pulsecore/core-util.h>
35 #include <pulsecore/macro.h>
36
37 #include "parseaddr.h"
38
39 /* Parse addresses in one of the following forms:
40  *    HOSTNAME
41  *    HOSTNAME:PORT
42  *    [HOSTNAME]
43  *    [HOSTNAME]:PORT
44  *
45  *  Return a newly allocated string of the hostname and fill in *ret_port if specified  */
46
47 static char *parse_host(const char *s, uint16_t *ret_port) {
48     pa_assert(s);
49     pa_assert(ret_port);
50
51     if (*s == '[') {
52         char *e;
53         if (!(e = strchr(s+1, ']')))
54             return NULL;
55
56         if (e[1] == ':') {
57             uint32_t p;
58
59             if (pa_atou(e+2, &p) < 0)
60                 return NULL;
61
62             *ret_port = (uint16_t) p;
63         } else if (e[1] != 0)
64             return NULL;
65
66         return pa_xstrndup(s+1, (size_t) (e-s-1));
67     } else {
68         char *e;
69         uint32_t p;
70
71         if (!(e = strrchr(s, ':')))
72             return pa_xstrdup(s);
73
74         if (pa_atou(e+1, &p) < 0)
75             return NULL;
76
77         *ret_port = (uint16_t) p;
78         return pa_xstrndup(s, (size_t) (e-s));
79     }
80 }
81
82 int pa_parse_address(const char *name, pa_parsed_address *ret_p) {
83     const char *p;
84
85     pa_assert(name);
86     pa_assert(ret_p);
87
88     memset(ret_p, 0, sizeof(pa_parsed_address));
89     ret_p->type = PA_PARSED_ADDRESS_TCP_AUTO;
90
91     if (*name == '{') {
92         char *id, *pfx;
93
94         /* The URL starts with a host id for detecting local connections */
95         if (!(id = pa_machine_id()))
96             return -1;
97
98         pfx = pa_sprintf_malloc("{%s}", id);
99         pa_xfree(id);
100
101         if (!pa_startswith(name, pfx)) {
102             pa_xfree(pfx);
103             /* Not local */
104             return -1;
105         }
106
107         p = name + strlen(pfx);
108         pa_xfree(pfx);
109     } else
110         p = name;
111
112     if (*p == '/')
113         ret_p->type = PA_PARSED_ADDRESS_UNIX;
114     else if (pa_startswith(p, "unix:")) {
115         ret_p->type = PA_PARSED_ADDRESS_UNIX;
116         p += sizeof("unix:")-1;
117     } else if (pa_startswith(p, "tcp:")) {
118         ret_p->type = PA_PARSED_ADDRESS_TCP4;
119         p += sizeof("tcp:")-1;
120     } else if (pa_startswith(p, "tcp4:")) {
121         ret_p->type = PA_PARSED_ADDRESS_TCP4;
122         p += sizeof("tcp4:")-1;
123     } else if (pa_startswith(p, "tcp6:")) {
124         ret_p->type = PA_PARSED_ADDRESS_TCP6;
125         p += sizeof("tcp6:")-1;
126     }
127
128     if (ret_p->type == PA_PARSED_ADDRESS_UNIX)
129         ret_p->path_or_host = pa_xstrdup(p);
130     else
131         if (!(ret_p->path_or_host = parse_host(p, &ret_p->port)))
132             return -1;
133
134     return 0;
135 }
136
137 pa_bool_t pa_is_ip_address(const char *a) {
138     char buf[INET6_ADDRSTRLEN];
139
140     pa_assert(a);
141
142     if (inet_pton(AF_INET6, a, buf) >= 1)
143         return TRUE;
144
145     if (inet_pton(AF_INET, a, buf) >= 1)
146         return TRUE;
147
148     return FALSE;
149 }