+
+struct pa_socket_client* pa_socket_client_new_ipv6(struct pa_mainloop_api *m, uint8_t address[16], uint16_t port) {
+ struct sockaddr_in6 sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sin6_family = AF_INET6;
+ sa.sin6_port = htons(port);
+ memcpy(&sa.sin6_addr, address, sizeof(sa.sin6_addr));
+
+ 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;
+ 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;
+ }
+
+ 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;
+ 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);
+
+ if (getaddrinfo(h, NULL, &hints, &res) < 0 || !res)
+ return NULL;
+
+ if (res->ai_addr->sa_family == AF_INET)
+ ((struct sockaddr_in*) res->ai_addr)->sin_port = htons(port);
+ else if (res->ai_addr->sa_family == AF_INET6)
+ ((struct sockaddr_in6*) res->ai_addr)->sin6_port = htons(port);
+ else
+ return NULL;
+
+ 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;
+
+}
+
+int pa_socket_client_is_local(struct pa_socket_client *c) {
+ assert(c);
+ return c->local;
+}