153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2006 Lennart Poettering 553a5a1b3Sopenharmony_ci Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 853a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as 953a5a1b3Sopenharmony_ci published by the Free Software Foundation; either version 2.1 of the 1053a5a1b3Sopenharmony_ci License, or (at your option) any later version. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1353a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1453a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553a5a1b3Sopenharmony_ci Lesser General Public License for more details. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public 1853a5a1b3Sopenharmony_ci License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1953a5a1b3Sopenharmony_ci***/ 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2253a5a1b3Sopenharmony_ci#include <config.h> 2353a5a1b3Sopenharmony_ci#endif 2453a5a1b3Sopenharmony_ci 2553a5a1b3Sopenharmony_ci/* #undef HAVE_LIBASYNCNS */ 2653a5a1b3Sopenharmony_ci 2753a5a1b3Sopenharmony_ci#include <unistd.h> 2853a5a1b3Sopenharmony_ci#include <stdio.h> 2953a5a1b3Sopenharmony_ci#include <errno.h> 3053a5a1b3Sopenharmony_ci#include <string.h> 3153a5a1b3Sopenharmony_ci#include <stdlib.h> 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_UN_H 3453a5a1b3Sopenharmony_ci#include <sys/un.h> 3553a5a1b3Sopenharmony_ci#endif 3653a5a1b3Sopenharmony_ci#ifdef HAVE_NETINET_IN_H 3753a5a1b3Sopenharmony_ci#include <netinet/in.h> 3853a5a1b3Sopenharmony_ci#endif 3953a5a1b3Sopenharmony_ci#ifdef HAVE_NETDB_H 4053a5a1b3Sopenharmony_ci#include <netdb.h> 4153a5a1b3Sopenharmony_ci#endif 4253a5a1b3Sopenharmony_ci 4353a5a1b3Sopenharmony_ci#ifdef HAVE_LIBASYNCNS 4453a5a1b3Sopenharmony_ci#include <asyncns.h> 4553a5a1b3Sopenharmony_ci#endif 4653a5a1b3Sopenharmony_ci 4753a5a1b3Sopenharmony_ci#include <pulse/rtclock.h> 4853a5a1b3Sopenharmony_ci#include <pulse/timeval.h> 4953a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 5053a5a1b3Sopenharmony_ci 5153a5a1b3Sopenharmony_ci#include <pulsecore/socket.h> 5253a5a1b3Sopenharmony_ci#include <pulsecore/socket-util.h> 5353a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h> 5453a5a1b3Sopenharmony_ci#include <pulsecore/core-rtclock.h> 5553a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 5653a5a1b3Sopenharmony_ci#include <pulsecore/socket-util.h> 5753a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 5853a5a1b3Sopenharmony_ci#include <pulsecore/parseaddr.h> 5953a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 6053a5a1b3Sopenharmony_ci#include <pulsecore/refcnt.h> 6153a5a1b3Sopenharmony_ci#include <pulsecore/arpa-inet.h> 6253a5a1b3Sopenharmony_ci 6353a5a1b3Sopenharmony_ci#include "socket-client.h" 6453a5a1b3Sopenharmony_ci 6553a5a1b3Sopenharmony_ci#define CONNECT_TIMEOUT 5 6653a5a1b3Sopenharmony_ci 6753a5a1b3Sopenharmony_cistruct pa_socket_client { 6853a5a1b3Sopenharmony_ci PA_REFCNT_DECLARE; 6953a5a1b3Sopenharmony_ci int fd; 7053a5a1b3Sopenharmony_ci 7153a5a1b3Sopenharmony_ci pa_mainloop_api *mainloop; 7253a5a1b3Sopenharmony_ci pa_io_event *io_event; 7353a5a1b3Sopenharmony_ci pa_time_event *timeout_event; 7453a5a1b3Sopenharmony_ci pa_defer_event *defer_event; 7553a5a1b3Sopenharmony_ci 7653a5a1b3Sopenharmony_ci pa_socket_client_cb_t callback; 7753a5a1b3Sopenharmony_ci void *userdata; 7853a5a1b3Sopenharmony_ci 7953a5a1b3Sopenharmony_ci bool local; 8053a5a1b3Sopenharmony_ci 8153a5a1b3Sopenharmony_ci#ifdef HAVE_LIBASYNCNS 8253a5a1b3Sopenharmony_ci asyncns_t *asyncns; 8353a5a1b3Sopenharmony_ci asyncns_query_t * asyncns_query; 8453a5a1b3Sopenharmony_ci pa_io_event *asyncns_io_event; 8553a5a1b3Sopenharmony_ci#endif 8653a5a1b3Sopenharmony_ci}; 8753a5a1b3Sopenharmony_ci 8853a5a1b3Sopenharmony_cistatic pa_socket_client* socket_client_new(pa_mainloop_api *m) { 8953a5a1b3Sopenharmony_ci pa_socket_client *c; 9053a5a1b3Sopenharmony_ci pa_assert(m); 9153a5a1b3Sopenharmony_ci 9253a5a1b3Sopenharmony_ci c = pa_xnew0(pa_socket_client, 1); 9353a5a1b3Sopenharmony_ci PA_REFCNT_INIT(c); 9453a5a1b3Sopenharmony_ci c->mainloop = m; 9553a5a1b3Sopenharmony_ci c->fd = -1; 9653a5a1b3Sopenharmony_ci 9753a5a1b3Sopenharmony_ci return c; 9853a5a1b3Sopenharmony_ci} 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_cistatic void free_events(pa_socket_client *c) { 10153a5a1b3Sopenharmony_ci pa_assert(c); 10253a5a1b3Sopenharmony_ci 10353a5a1b3Sopenharmony_ci if (c->io_event) { 10453a5a1b3Sopenharmony_ci c->mainloop->io_free(c->io_event); 10553a5a1b3Sopenharmony_ci c->io_event = NULL; 10653a5a1b3Sopenharmony_ci } 10753a5a1b3Sopenharmony_ci 10853a5a1b3Sopenharmony_ci if (c->timeout_event) { 10953a5a1b3Sopenharmony_ci c->mainloop->time_free(c->timeout_event); 11053a5a1b3Sopenharmony_ci c->timeout_event = NULL; 11153a5a1b3Sopenharmony_ci } 11253a5a1b3Sopenharmony_ci 11353a5a1b3Sopenharmony_ci if (c->defer_event) { 11453a5a1b3Sopenharmony_ci c->mainloop->defer_free(c->defer_event); 11553a5a1b3Sopenharmony_ci c->defer_event = NULL; 11653a5a1b3Sopenharmony_ci } 11753a5a1b3Sopenharmony_ci} 11853a5a1b3Sopenharmony_ci 11953a5a1b3Sopenharmony_cistatic void do_call(pa_socket_client *c) { 12053a5a1b3Sopenharmony_ci pa_iochannel *io = NULL; 12153a5a1b3Sopenharmony_ci int error; 12253a5a1b3Sopenharmony_ci socklen_t lerror; 12353a5a1b3Sopenharmony_ci 12453a5a1b3Sopenharmony_ci pa_assert(c); 12553a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 12653a5a1b3Sopenharmony_ci pa_assert(c->callback); 12753a5a1b3Sopenharmony_ci 12853a5a1b3Sopenharmony_ci pa_socket_client_ref(c); 12953a5a1b3Sopenharmony_ci 13053a5a1b3Sopenharmony_ci if (c->fd < 0) 13153a5a1b3Sopenharmony_ci goto finish; 13253a5a1b3Sopenharmony_ci 13353a5a1b3Sopenharmony_ci lerror = sizeof(error); 13453a5a1b3Sopenharmony_ci if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &lerror) < 0) { 13553a5a1b3Sopenharmony_ci pa_log("getsockopt(): %s", pa_cstrerror(errno)); 13653a5a1b3Sopenharmony_ci goto finish; 13753a5a1b3Sopenharmony_ci } 13853a5a1b3Sopenharmony_ci 13953a5a1b3Sopenharmony_ci if (lerror != sizeof(error)) { 14053a5a1b3Sopenharmony_ci pa_log("getsockopt() returned invalid size."); 14153a5a1b3Sopenharmony_ci goto finish; 14253a5a1b3Sopenharmony_ci } 14353a5a1b3Sopenharmony_ci 14453a5a1b3Sopenharmony_ci if (error != 0) { 14553a5a1b3Sopenharmony_ci pa_log_debug("connect(): %s", pa_cstrerror(error)); 14653a5a1b3Sopenharmony_ci errno = error; 14753a5a1b3Sopenharmony_ci goto finish; 14853a5a1b3Sopenharmony_ci } 14953a5a1b3Sopenharmony_ci 15053a5a1b3Sopenharmony_ci io = pa_iochannel_new(c->mainloop, c->fd, c->fd); 15153a5a1b3Sopenharmony_ci 15253a5a1b3Sopenharmony_cifinish: 15353a5a1b3Sopenharmony_ci if (!io && c->fd >= 0) 15453a5a1b3Sopenharmony_ci pa_close(c->fd); 15553a5a1b3Sopenharmony_ci c->fd = -1; 15653a5a1b3Sopenharmony_ci 15753a5a1b3Sopenharmony_ci free_events(c); 15853a5a1b3Sopenharmony_ci 15953a5a1b3Sopenharmony_ci c->callback(c, io, c->userdata); 16053a5a1b3Sopenharmony_ci 16153a5a1b3Sopenharmony_ci pa_socket_client_unref(c); 16253a5a1b3Sopenharmony_ci} 16353a5a1b3Sopenharmony_ci 16453a5a1b3Sopenharmony_cistatic void connect_defer_cb(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { 16553a5a1b3Sopenharmony_ci pa_socket_client *c = userdata; 16653a5a1b3Sopenharmony_ci 16753a5a1b3Sopenharmony_ci pa_assert(m); 16853a5a1b3Sopenharmony_ci pa_assert(c); 16953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 17053a5a1b3Sopenharmony_ci pa_assert(c->defer_event == e); 17153a5a1b3Sopenharmony_ci 17253a5a1b3Sopenharmony_ci do_call(c); 17353a5a1b3Sopenharmony_ci} 17453a5a1b3Sopenharmony_ci 17553a5a1b3Sopenharmony_cistatic void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { 17653a5a1b3Sopenharmony_ci pa_socket_client *c = userdata; 17753a5a1b3Sopenharmony_ci 17853a5a1b3Sopenharmony_ci pa_assert(m); 17953a5a1b3Sopenharmony_ci pa_assert(c); 18053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 18153a5a1b3Sopenharmony_ci pa_assert(c->io_event == e); 18253a5a1b3Sopenharmony_ci pa_assert(fd >= 0); 18353a5a1b3Sopenharmony_ci 18453a5a1b3Sopenharmony_ci do_call(c); 18553a5a1b3Sopenharmony_ci} 18653a5a1b3Sopenharmony_ci 18753a5a1b3Sopenharmony_cistatic int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t len) { 18853a5a1b3Sopenharmony_ci pa_assert(c); 18953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 19053a5a1b3Sopenharmony_ci pa_assert(sa); 19153a5a1b3Sopenharmony_ci pa_assert(len > 0); 19253a5a1b3Sopenharmony_ci 19353a5a1b3Sopenharmony_ci pa_make_fd_nonblock(c->fd); 19453a5a1b3Sopenharmony_ci 19553a5a1b3Sopenharmony_ci if (connect(c->fd, sa, len) < 0) { 19653a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 19753a5a1b3Sopenharmony_ci if (WSAGetLastError() != EWOULDBLOCK) { 19853a5a1b3Sopenharmony_ci pa_log_debug("connect(): %d", WSAGetLastError()); 19953a5a1b3Sopenharmony_ci#else 20053a5a1b3Sopenharmony_ci if (errno != EINPROGRESS) { 20153a5a1b3Sopenharmony_ci pa_log_debug("connect(): %s (%d)", pa_cstrerror(errno), errno); 20253a5a1b3Sopenharmony_ci#endif 20353a5a1b3Sopenharmony_ci return -1; 20453a5a1b3Sopenharmony_ci } 20553a5a1b3Sopenharmony_ci 20653a5a1b3Sopenharmony_ci c->io_event = c->mainloop->io_new(c->mainloop, c->fd, PA_IO_EVENT_OUTPUT, connect_io_cb, c); 20753a5a1b3Sopenharmony_ci } else 20853a5a1b3Sopenharmony_ci c->defer_event = c->mainloop->defer_new(c->mainloop, connect_defer_cb, c); 20953a5a1b3Sopenharmony_ci 21053a5a1b3Sopenharmony_ci return 0; 21153a5a1b3Sopenharmony_ci} 21253a5a1b3Sopenharmony_ci 21353a5a1b3Sopenharmony_cipa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port) { 21453a5a1b3Sopenharmony_ci struct sockaddr_in sa; 21553a5a1b3Sopenharmony_ci 21653a5a1b3Sopenharmony_ci pa_assert(m); 21753a5a1b3Sopenharmony_ci pa_assert(port > 0); 21853a5a1b3Sopenharmony_ci 21953a5a1b3Sopenharmony_ci pa_zero(sa); 22053a5a1b3Sopenharmony_ci sa.sin_family = AF_INET; 22153a5a1b3Sopenharmony_ci sa.sin_port = htons(port); 22253a5a1b3Sopenharmony_ci sa.sin_addr.s_addr = htonl(address); 22353a5a1b3Sopenharmony_ci 22453a5a1b3Sopenharmony_ci return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); 22553a5a1b3Sopenharmony_ci} 22653a5a1b3Sopenharmony_ci 22753a5a1b3Sopenharmony_cipa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) { 22853a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_UN_H 22953a5a1b3Sopenharmony_ci struct sockaddr_un sa; 23053a5a1b3Sopenharmony_ci 23153a5a1b3Sopenharmony_ci pa_assert(m); 23253a5a1b3Sopenharmony_ci pa_assert(filename); 23353a5a1b3Sopenharmony_ci 23453a5a1b3Sopenharmony_ci pa_zero(sa); 23553a5a1b3Sopenharmony_ci sa.sun_family = AF_UNIX; 23653a5a1b3Sopenharmony_ci pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path)); 23753a5a1b3Sopenharmony_ci 23853a5a1b3Sopenharmony_ci return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); 23953a5a1b3Sopenharmony_ci#else /* HAVE_SYS_UN_H */ 24053a5a1b3Sopenharmony_ci 24153a5a1b3Sopenharmony_ci return NULL; 24253a5a1b3Sopenharmony_ci#endif /* HAVE_SYS_UN_H */ 24353a5a1b3Sopenharmony_ci} 24453a5a1b3Sopenharmony_ci 24553a5a1b3Sopenharmony_cistatic int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size_t salen) { 24653a5a1b3Sopenharmony_ci pa_assert(c); 24753a5a1b3Sopenharmony_ci pa_assert(sa); 24853a5a1b3Sopenharmony_ci pa_assert(salen); 24953a5a1b3Sopenharmony_ci 25053a5a1b3Sopenharmony_ci c->local = pa_socket_address_is_local(sa); 25153a5a1b3Sopenharmony_ci 25253a5a1b3Sopenharmony_ci if ((c->fd = pa_socket_cloexec(sa->sa_family, SOCK_STREAM, 0)) < 0) { 25353a5a1b3Sopenharmony_ci pa_log("socket(): %s", pa_cstrerror(errno)); 25453a5a1b3Sopenharmony_ci return -1; 25553a5a1b3Sopenharmony_ci } 25653a5a1b3Sopenharmony_ci 25753a5a1b3Sopenharmony_ci#ifdef HAVE_IPV6 25853a5a1b3Sopenharmony_ci if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) 25953a5a1b3Sopenharmony_ci#else 26053a5a1b3Sopenharmony_ci if (sa->sa_family == AF_INET) 26153a5a1b3Sopenharmony_ci#endif 26253a5a1b3Sopenharmony_ci pa_make_tcp_socket_low_delay(c->fd); 26353a5a1b3Sopenharmony_ci else 26453a5a1b3Sopenharmony_ci pa_make_socket_low_delay(c->fd); 26553a5a1b3Sopenharmony_ci 26653a5a1b3Sopenharmony_ci if (do_connect(c, sa, (socklen_t) salen) < 0) 26753a5a1b3Sopenharmony_ci return -1; 26853a5a1b3Sopenharmony_ci 26953a5a1b3Sopenharmony_ci return 0; 27053a5a1b3Sopenharmony_ci} 27153a5a1b3Sopenharmony_ci 27253a5a1b3Sopenharmony_cipa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) { 27353a5a1b3Sopenharmony_ci pa_socket_client *c; 27453a5a1b3Sopenharmony_ci 27553a5a1b3Sopenharmony_ci pa_assert(m); 27653a5a1b3Sopenharmony_ci pa_assert(sa); 27753a5a1b3Sopenharmony_ci pa_assert(salen > 0); 27853a5a1b3Sopenharmony_ci 27953a5a1b3Sopenharmony_ci c = socket_client_new(m); 28053a5a1b3Sopenharmony_ci 28153a5a1b3Sopenharmony_ci if (sockaddr_prepare(c, sa, salen) < 0) 28253a5a1b3Sopenharmony_ci goto fail; 28353a5a1b3Sopenharmony_ci 28453a5a1b3Sopenharmony_ci return c; 28553a5a1b3Sopenharmony_ci 28653a5a1b3Sopenharmony_cifail: 28753a5a1b3Sopenharmony_ci pa_socket_client_unref(c); 28853a5a1b3Sopenharmony_ci return NULL; 28953a5a1b3Sopenharmony_ci} 29053a5a1b3Sopenharmony_ci 29153a5a1b3Sopenharmony_cistatic void socket_client_free(pa_socket_client *c) { 29253a5a1b3Sopenharmony_ci pa_assert(c); 29353a5a1b3Sopenharmony_ci pa_assert(c->mainloop); 29453a5a1b3Sopenharmony_ci 29553a5a1b3Sopenharmony_ci free_events(c); 29653a5a1b3Sopenharmony_ci 29753a5a1b3Sopenharmony_ci if (c->fd >= 0) 29853a5a1b3Sopenharmony_ci pa_close(c->fd); 29953a5a1b3Sopenharmony_ci 30053a5a1b3Sopenharmony_ci#ifdef HAVE_LIBASYNCNS 30153a5a1b3Sopenharmony_ci if (c->asyncns_query) 30253a5a1b3Sopenharmony_ci asyncns_cancel(c->asyncns, c->asyncns_query); 30353a5a1b3Sopenharmony_ci if (c->asyncns) 30453a5a1b3Sopenharmony_ci asyncns_free(c->asyncns); 30553a5a1b3Sopenharmony_ci if (c->asyncns_io_event) 30653a5a1b3Sopenharmony_ci c->mainloop->io_free(c->asyncns_io_event); 30753a5a1b3Sopenharmony_ci#endif 30853a5a1b3Sopenharmony_ci 30953a5a1b3Sopenharmony_ci pa_xfree(c); 31053a5a1b3Sopenharmony_ci} 31153a5a1b3Sopenharmony_ci 31253a5a1b3Sopenharmony_civoid pa_socket_client_unref(pa_socket_client *c) { 31353a5a1b3Sopenharmony_ci pa_assert(c); 31453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 31553a5a1b3Sopenharmony_ci 31653a5a1b3Sopenharmony_ci if (PA_REFCNT_DEC(c) <= 0) 31753a5a1b3Sopenharmony_ci socket_client_free(c); 31853a5a1b3Sopenharmony_ci} 31953a5a1b3Sopenharmony_ci 32053a5a1b3Sopenharmony_cipa_socket_client* pa_socket_client_ref(pa_socket_client *c) { 32153a5a1b3Sopenharmony_ci pa_assert(c); 32253a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 32353a5a1b3Sopenharmony_ci 32453a5a1b3Sopenharmony_ci PA_REFCNT_INC(c); 32553a5a1b3Sopenharmony_ci return c; 32653a5a1b3Sopenharmony_ci} 32753a5a1b3Sopenharmony_ci 32853a5a1b3Sopenharmony_civoid pa_socket_client_set_callback(pa_socket_client *c, pa_socket_client_cb_t on_connection, void *userdata) { 32953a5a1b3Sopenharmony_ci pa_assert(c); 33053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 33153a5a1b3Sopenharmony_ci 33253a5a1b3Sopenharmony_ci c->callback = on_connection; 33353a5a1b3Sopenharmony_ci c->userdata = userdata; 33453a5a1b3Sopenharmony_ci} 33553a5a1b3Sopenharmony_ci 33653a5a1b3Sopenharmony_cipa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port) { 33753a5a1b3Sopenharmony_ci#ifdef HAVE_IPV6 33853a5a1b3Sopenharmony_ci struct sockaddr_in6 sa; 33953a5a1b3Sopenharmony_ci 34053a5a1b3Sopenharmony_ci pa_assert(m); 34153a5a1b3Sopenharmony_ci pa_assert(address); 34253a5a1b3Sopenharmony_ci pa_assert(port > 0); 34353a5a1b3Sopenharmony_ci 34453a5a1b3Sopenharmony_ci pa_zero(sa); 34553a5a1b3Sopenharmony_ci sa.sin6_family = AF_INET6; 34653a5a1b3Sopenharmony_ci sa.sin6_port = htons(port); 34753a5a1b3Sopenharmony_ci memcpy(&sa.sin6_addr, address, sizeof(sa.sin6_addr)); 34853a5a1b3Sopenharmony_ci 34953a5a1b3Sopenharmony_ci return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa)); 35053a5a1b3Sopenharmony_ci 35153a5a1b3Sopenharmony_ci#else 35253a5a1b3Sopenharmony_ci return NULL; 35353a5a1b3Sopenharmony_ci#endif 35453a5a1b3Sopenharmony_ci} 35553a5a1b3Sopenharmony_ci 35653a5a1b3Sopenharmony_ci#ifdef HAVE_LIBASYNCNS 35753a5a1b3Sopenharmony_ci 35853a5a1b3Sopenharmony_cistatic void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { 35953a5a1b3Sopenharmony_ci pa_socket_client *c = userdata; 36053a5a1b3Sopenharmony_ci struct addrinfo *res = NULL; 36153a5a1b3Sopenharmony_ci int ret; 36253a5a1b3Sopenharmony_ci 36353a5a1b3Sopenharmony_ci pa_assert(m); 36453a5a1b3Sopenharmony_ci pa_assert(c); 36553a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 36653a5a1b3Sopenharmony_ci pa_assert(c->asyncns_io_event == e); 36753a5a1b3Sopenharmony_ci pa_assert(fd >= 0); 36853a5a1b3Sopenharmony_ci 36953a5a1b3Sopenharmony_ci if (asyncns_wait(c->asyncns, 0) < 0) 37053a5a1b3Sopenharmony_ci goto fail; 37153a5a1b3Sopenharmony_ci 37253a5a1b3Sopenharmony_ci if (!asyncns_isdone(c->asyncns, c->asyncns_query)) 37353a5a1b3Sopenharmony_ci return; 37453a5a1b3Sopenharmony_ci 37553a5a1b3Sopenharmony_ci ret = asyncns_getaddrinfo_done(c->asyncns, c->asyncns_query, &res); 37653a5a1b3Sopenharmony_ci c->asyncns_query = NULL; 37753a5a1b3Sopenharmony_ci 37853a5a1b3Sopenharmony_ci if (ret != 0 || !res) 37953a5a1b3Sopenharmony_ci goto fail; 38053a5a1b3Sopenharmony_ci 38153a5a1b3Sopenharmony_ci if (res->ai_addr) 38253a5a1b3Sopenharmony_ci if (sockaddr_prepare(c, res->ai_addr, res->ai_addrlen) < 0) 38353a5a1b3Sopenharmony_ci goto fail; 38453a5a1b3Sopenharmony_ci 38553a5a1b3Sopenharmony_ci asyncns_freeaddrinfo(res); 38653a5a1b3Sopenharmony_ci 38753a5a1b3Sopenharmony_ci m->io_free(c->asyncns_io_event); 38853a5a1b3Sopenharmony_ci c->asyncns_io_event = NULL; 38953a5a1b3Sopenharmony_ci return; 39053a5a1b3Sopenharmony_ci 39153a5a1b3Sopenharmony_cifail: 39253a5a1b3Sopenharmony_ci m->io_free(c->asyncns_io_event); 39353a5a1b3Sopenharmony_ci c->asyncns_io_event = NULL; 39453a5a1b3Sopenharmony_ci 39553a5a1b3Sopenharmony_ci errno = EHOSTUNREACH; 39653a5a1b3Sopenharmony_ci do_call(c); 39753a5a1b3Sopenharmony_ci return; 39853a5a1b3Sopenharmony_ci 39953a5a1b3Sopenharmony_ci} 40053a5a1b3Sopenharmony_ci 40153a5a1b3Sopenharmony_ci#endif 40253a5a1b3Sopenharmony_ci 40353a5a1b3Sopenharmony_cistatic void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) { 40453a5a1b3Sopenharmony_ci pa_socket_client *c = userdata; 40553a5a1b3Sopenharmony_ci 40653a5a1b3Sopenharmony_ci pa_assert(m); 40753a5a1b3Sopenharmony_ci pa_assert(e); 40853a5a1b3Sopenharmony_ci pa_assert(c); 40953a5a1b3Sopenharmony_ci 41053a5a1b3Sopenharmony_ci if (c->fd >= 0) { 41153a5a1b3Sopenharmony_ci pa_close(c->fd); 41253a5a1b3Sopenharmony_ci c->fd = -1; 41353a5a1b3Sopenharmony_ci } 41453a5a1b3Sopenharmony_ci 41553a5a1b3Sopenharmony_ci errno = ETIMEDOUT; 41653a5a1b3Sopenharmony_ci do_call(c); 41753a5a1b3Sopenharmony_ci} 41853a5a1b3Sopenharmony_ci 41953a5a1b3Sopenharmony_cistatic void start_timeout(pa_socket_client *c, bool use_rtclock) { 42053a5a1b3Sopenharmony_ci struct timeval tv; 42153a5a1b3Sopenharmony_ci 42253a5a1b3Sopenharmony_ci pa_assert(c); 42353a5a1b3Sopenharmony_ci pa_assert(!c->timeout_event); 42453a5a1b3Sopenharmony_ci 42553a5a1b3Sopenharmony_ci c->timeout_event = c->mainloop->time_new(c->mainloop, pa_timeval_rtstore(&tv, pa_rtclock_now() + CONNECT_TIMEOUT * PA_USEC_PER_SEC, use_rtclock), timeout_cb, c); 42653a5a1b3Sopenharmony_ci} 42753a5a1b3Sopenharmony_ci 42853a5a1b3Sopenharmony_cipa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, bool use_rtclock, const char*name, uint16_t default_port) { 42953a5a1b3Sopenharmony_ci pa_socket_client *c = NULL; 43053a5a1b3Sopenharmony_ci pa_parsed_address a; 43153a5a1b3Sopenharmony_ci char *name_buf; 43253a5a1b3Sopenharmony_ci 43353a5a1b3Sopenharmony_ci pa_assert(m); 43453a5a1b3Sopenharmony_ci pa_assert(name); 43553a5a1b3Sopenharmony_ci 43653a5a1b3Sopenharmony_ci a.path_or_host = NULL; 43753a5a1b3Sopenharmony_ci 43853a5a1b3Sopenharmony_ci if (pa_is_ip6_address(name)) { 43953a5a1b3Sopenharmony_ci size_t len = strlen(name); 44053a5a1b3Sopenharmony_ci name_buf = pa_xmalloc(len + 3); 44153a5a1b3Sopenharmony_ci memcpy(name_buf + 1, name, len); 44253a5a1b3Sopenharmony_ci name_buf[0] = '['; 44353a5a1b3Sopenharmony_ci name_buf[len + 1] = ']'; 44453a5a1b3Sopenharmony_ci name_buf[len + 2] = '\0'; 44553a5a1b3Sopenharmony_ci } else { 44653a5a1b3Sopenharmony_ci name_buf = pa_xstrdup(name); 44753a5a1b3Sopenharmony_ci } 44853a5a1b3Sopenharmony_ci 44953a5a1b3Sopenharmony_ci if (pa_parse_address(name_buf, &a) < 0) { 45053a5a1b3Sopenharmony_ci pa_log_warn("parsing address failed: %s", name_buf); 45153a5a1b3Sopenharmony_ci goto finish; 45253a5a1b3Sopenharmony_ci } 45353a5a1b3Sopenharmony_ci 45453a5a1b3Sopenharmony_ci if (!a.port) 45553a5a1b3Sopenharmony_ci a.port = default_port; 45653a5a1b3Sopenharmony_ci 45753a5a1b3Sopenharmony_ci switch (a.type) { 45853a5a1b3Sopenharmony_ci case PA_PARSED_ADDRESS_UNIX: 45953a5a1b3Sopenharmony_ci if ((c = pa_socket_client_new_unix(m, a.path_or_host))) 46053a5a1b3Sopenharmony_ci start_timeout(c, use_rtclock); 46153a5a1b3Sopenharmony_ci break; 46253a5a1b3Sopenharmony_ci 46353a5a1b3Sopenharmony_ci case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */ 46453a5a1b3Sopenharmony_ci case PA_PARSED_ADDRESS_TCP6: /* Fallthrough */ 46553a5a1b3Sopenharmony_ci case PA_PARSED_ADDRESS_TCP_AUTO: { 46653a5a1b3Sopenharmony_ci struct addrinfo hints; 46753a5a1b3Sopenharmony_ci char port[12]; 46853a5a1b3Sopenharmony_ci 46953a5a1b3Sopenharmony_ci pa_snprintf(port, sizeof(port), "%u", (unsigned) a.port); 47053a5a1b3Sopenharmony_ci 47153a5a1b3Sopenharmony_ci pa_zero(hints); 47253a5a1b3Sopenharmony_ci if (a.type == PA_PARSED_ADDRESS_TCP4) 47353a5a1b3Sopenharmony_ci hints.ai_family = PF_INET; 47453a5a1b3Sopenharmony_ci#ifdef HAVE_IPV6 47553a5a1b3Sopenharmony_ci else if (a.type == PA_PARSED_ADDRESS_TCP6) 47653a5a1b3Sopenharmony_ci hints.ai_family = PF_INET6; 47753a5a1b3Sopenharmony_ci#endif 47853a5a1b3Sopenharmony_ci else 47953a5a1b3Sopenharmony_ci hints.ai_family = PF_UNSPEC; 48053a5a1b3Sopenharmony_ci 48153a5a1b3Sopenharmony_ci hints.ai_socktype = SOCK_STREAM; 48253a5a1b3Sopenharmony_ci 48353a5a1b3Sopenharmony_ci#if defined(HAVE_LIBASYNCNS) 48453a5a1b3Sopenharmony_ci { 48553a5a1b3Sopenharmony_ci asyncns_t *asyncns; 48653a5a1b3Sopenharmony_ci 48753a5a1b3Sopenharmony_ci if (!(asyncns = asyncns_new(1))) 48853a5a1b3Sopenharmony_ci goto finish; 48953a5a1b3Sopenharmony_ci 49053a5a1b3Sopenharmony_ci c = socket_client_new(m); 49153a5a1b3Sopenharmony_ci c->asyncns = asyncns; 49253a5a1b3Sopenharmony_ci c->asyncns_io_event = m->io_new(m, asyncns_fd(c->asyncns), PA_IO_EVENT_INPUT, asyncns_cb, c); 49353a5a1b3Sopenharmony_ci pa_assert_se(c->asyncns_query = asyncns_getaddrinfo(c->asyncns, a.path_or_host, port, &hints)); 49453a5a1b3Sopenharmony_ci start_timeout(c, use_rtclock); 49553a5a1b3Sopenharmony_ci } 49653a5a1b3Sopenharmony_ci#elif defined(HAVE_GETADDRINFO) 49753a5a1b3Sopenharmony_ci { 49853a5a1b3Sopenharmony_ci int ret; 49953a5a1b3Sopenharmony_ci struct addrinfo *res = NULL; 50053a5a1b3Sopenharmony_ci 50153a5a1b3Sopenharmony_ci ret = getaddrinfo(a.path_or_host, port, &hints, &res); 50253a5a1b3Sopenharmony_ci 50353a5a1b3Sopenharmony_ci if (ret < 0 || !res) 50453a5a1b3Sopenharmony_ci goto finish; 50553a5a1b3Sopenharmony_ci 50653a5a1b3Sopenharmony_ci if (res->ai_addr) { 50753a5a1b3Sopenharmony_ci if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen))) 50853a5a1b3Sopenharmony_ci start_timeout(c, use_rtclock); 50953a5a1b3Sopenharmony_ci } 51053a5a1b3Sopenharmony_ci 51153a5a1b3Sopenharmony_ci freeaddrinfo(res); 51253a5a1b3Sopenharmony_ci } 51353a5a1b3Sopenharmony_ci#else 51453a5a1b3Sopenharmony_ci { 51553a5a1b3Sopenharmony_ci struct hostent *host = NULL; 51653a5a1b3Sopenharmony_ci struct sockaddr_in s; 51753a5a1b3Sopenharmony_ci 51853a5a1b3Sopenharmony_ci#ifdef HAVE_IPV6 51953a5a1b3Sopenharmony_ci /* FIXME: PF_INET6 support */ 52053a5a1b3Sopenharmony_ci if (hints.ai_family == PF_INET6) { 52153a5a1b3Sopenharmony_ci pa_log_error("IPv6 is not supported on Windows"); 52253a5a1b3Sopenharmony_ci goto finish; 52353a5a1b3Sopenharmony_ci } 52453a5a1b3Sopenharmony_ci#endif 52553a5a1b3Sopenharmony_ci 52653a5a1b3Sopenharmony_ci host = gethostbyname(a.path_or_host); 52753a5a1b3Sopenharmony_ci if (!host) { 52853a5a1b3Sopenharmony_ci unsigned int addr = inet_addr(a.path_or_host); 52953a5a1b3Sopenharmony_ci if (addr != INADDR_NONE) 53053a5a1b3Sopenharmony_ci host = gethostbyaddr((char*)&addr, 4, AF_INET); 53153a5a1b3Sopenharmony_ci } 53253a5a1b3Sopenharmony_ci 53353a5a1b3Sopenharmony_ci if (!host) 53453a5a1b3Sopenharmony_ci goto finish; 53553a5a1b3Sopenharmony_ci 53653a5a1b3Sopenharmony_ci pa_zero(s); 53753a5a1b3Sopenharmony_ci s.sin_family = AF_INET; 53853a5a1b3Sopenharmony_ci memcpy(&s.sin_addr, host->h_addr, sizeof(struct in_addr)); 53953a5a1b3Sopenharmony_ci s.sin_port = htons(a.port); 54053a5a1b3Sopenharmony_ci 54153a5a1b3Sopenharmony_ci if ((c = pa_socket_client_new_sockaddr(m, (struct sockaddr*)&s, sizeof(s)))) 54253a5a1b3Sopenharmony_ci start_timeout(c, use_rtclock); 54353a5a1b3Sopenharmony_ci } 54453a5a1b3Sopenharmony_ci#endif /* HAVE_LIBASYNCNS */ 54553a5a1b3Sopenharmony_ci } 54653a5a1b3Sopenharmony_ci } 54753a5a1b3Sopenharmony_ci 54853a5a1b3Sopenharmony_cifinish: 54953a5a1b3Sopenharmony_ci pa_xfree(name_buf); 55053a5a1b3Sopenharmony_ci pa_xfree(a.path_or_host); 55153a5a1b3Sopenharmony_ci return c; 55253a5a1b3Sopenharmony_ci 55353a5a1b3Sopenharmony_ci} 55453a5a1b3Sopenharmony_ci 55553a5a1b3Sopenharmony_ci/* Return non-zero when the target sockaddr is considered 55653a5a1b3Sopenharmony_ci local. "local" means UNIX socket or TCP socket on localhost. Other 55753a5a1b3Sopenharmony_ci local IP addresses are not considered local. */ 55853a5a1b3Sopenharmony_cibool pa_socket_client_is_local(pa_socket_client *c) { 55953a5a1b3Sopenharmony_ci pa_assert(c); 56053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 56153a5a1b3Sopenharmony_ci 56253a5a1b3Sopenharmony_ci return c->local; 56353a5a1b3Sopenharmony_ci} 564