2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
25 /* #undef HAVE_LIBASYNCNS */
36 #ifdef HAVE_NETINET_IN_H
37 #include <netinet/in.h>
43 #ifdef HAVE_LIBASYNCNS
47 #include <pulse/rtclock.h>
48 #include <pulse/timeval.h>
49 #include <pulse/xmalloc.h>
51 #include <pulsecore/socket.h>
52 #include <pulsecore/socket-util.h>
53 #include <pulsecore/core-error.h>
54 #include <pulsecore/core-rtclock.h>
55 #include <pulsecore/core-util.h>
56 #include <pulsecore/socket-util.h>
57 #include <pulsecore/log.h>
58 #include <pulsecore/parseaddr.h>
59 #include <pulsecore/macro.h>
60 #include <pulsecore/refcnt.h>
61 #include <pulsecore/arpa-inet.h>
63 #include "socket-client.h"
65 #define CONNECT_TIMEOUT 5
67 struct pa_socket_client {
71 pa_mainloop_api *mainloop;
72 pa_io_event *io_event;
73 pa_time_event *timeout_event;
74 pa_defer_event *defer_event;
76 pa_socket_client_cb_t callback;
81 #ifdef HAVE_LIBASYNCNS
83 asyncns_query_t * asyncns_query;
84 pa_io_event *asyncns_io_event;
88 static pa_socket_client* socket_client_new(pa_mainloop_api *m) {
92 c = pa_xnew0(pa_socket_client, 1);
100 static void free_events(pa_socket_client *c) {
104 c->mainloop->io_free(c->io_event);
108 if (c->timeout_event) {
109 c->mainloop->time_free(c->timeout_event);
110 c->timeout_event = NULL;
113 if (c->defer_event) {
114 c->mainloop->defer_free(c->defer_event);
115 c->defer_event = NULL;
119 static void do_call(pa_socket_client *c) {
120 pa_iochannel *io = NULL;
125 pa_assert(PA_REFCNT_VALUE(c) >= 1);
126 pa_assert(c->callback);
128 pa_socket_client_ref(c);
133 lerror = sizeof(error);
134 if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &lerror) < 0) {
135 pa_log("getsockopt(): %s", pa_cstrerror(errno));
139 if (lerror != sizeof(error)) {
140 pa_log("getsockopt() returned invalid size.");
145 pa_log_debug("connect(): %s", pa_cstrerror(error));
150 io = pa_iochannel_new(c->mainloop, c->fd, c->fd);
153 if (!io && c->fd >= 0)
159 c->callback(c, io, c->userdata);
161 pa_socket_client_unref(c);
164 static void connect_defer_cb(pa_mainloop_api *m, pa_defer_event *e, void *userdata) {
165 pa_socket_client *c = userdata;
169 pa_assert(PA_REFCNT_VALUE(c) >= 1);
170 pa_assert(c->defer_event == e);
175 static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
176 pa_socket_client *c = userdata;
180 pa_assert(PA_REFCNT_VALUE(c) >= 1);
181 pa_assert(c->io_event == e);
187 static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t len) {
189 pa_assert(PA_REFCNT_VALUE(c) >= 1);
193 pa_make_fd_nonblock(c->fd);
195 if (connect(c->fd, sa, len) < 0) {
197 if (WSAGetLastError() != EWOULDBLOCK) {
198 pa_log_debug("connect(): %d", WSAGetLastError());
200 if (errno != EINPROGRESS) {
201 pa_log_debug("connect(): %s (%d)", pa_cstrerror(errno), errno);
206 c->io_event = c->mainloop->io_new(c->mainloop, c->fd, PA_IO_EVENT_OUTPUT, connect_io_cb, c);
208 c->defer_event = c->mainloop->defer_new(c->mainloop, connect_defer_cb, c);
213 pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port) {
214 struct sockaddr_in sa;
220 sa.sin_family = AF_INET;
221 sa.sin_port = htons(port);
222 sa.sin_addr.s_addr = htonl(address);
224 return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
227 pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) {
229 struct sockaddr_un sa;
235 sa.sun_family = AF_UNIX;
236 pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path));
238 return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
239 #else /* HAVE_SYS_UN_H */
242 #endif /* HAVE_SYS_UN_H */
245 static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size_t salen) {
250 c->local = pa_socket_address_is_local(sa);
252 if ((c->fd = pa_socket_cloexec(sa->sa_family, SOCK_STREAM, 0)) < 0) {
253 pa_log("socket(): %s", pa_cstrerror(errno));
258 if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)
260 if (sa->sa_family == AF_INET)
262 pa_make_tcp_socket_low_delay(c->fd);
264 pa_make_socket_low_delay(c->fd);
266 if (do_connect(c, sa, (socklen_t) salen) < 0)
272 pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) {
277 pa_assert(salen > 0);
279 c = socket_client_new(m);
281 if (sockaddr_prepare(c, sa, salen) < 0)
287 pa_socket_client_unref(c);
291 static void socket_client_free(pa_socket_client *c) {
293 pa_assert(c->mainloop);
300 #ifdef HAVE_LIBASYNCNS
301 if (c->asyncns_query)
302 asyncns_cancel(c->asyncns, c->asyncns_query);
304 asyncns_free(c->asyncns);
305 if (c->asyncns_io_event)
306 c->mainloop->io_free(c->asyncns_io_event);
312 void pa_socket_client_unref(pa_socket_client *c) {
314 pa_assert(PA_REFCNT_VALUE(c) >= 1);
316 if (PA_REFCNT_DEC(c) <= 0)
317 socket_client_free(c);
320 pa_socket_client* pa_socket_client_ref(pa_socket_client *c) {
322 pa_assert(PA_REFCNT_VALUE(c) >= 1);
328 void pa_socket_client_set_callback(pa_socket_client *c, pa_socket_client_cb_t on_connection, void *userdata) {
330 pa_assert(PA_REFCNT_VALUE(c) >= 1);
332 c->callback = on_connection;
333 c->userdata = userdata;
336 pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port) {
338 struct sockaddr_in6 sa;
345 sa.sin6_family = AF_INET6;
346 sa.sin6_port = htons(port);
347 memcpy(&sa.sin6_addr, address, sizeof(sa.sin6_addr));
349 return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
356 #ifdef HAVE_LIBASYNCNS
358 static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
359 pa_socket_client *c = userdata;
360 struct addrinfo *res = NULL;
365 pa_assert(PA_REFCNT_VALUE(c) >= 1);
366 pa_assert(c->asyncns_io_event == e);
369 if (asyncns_wait(c->asyncns, 0) < 0)
372 if (!asyncns_isdone(c->asyncns, c->asyncns_query))
375 ret = asyncns_getaddrinfo_done(c->asyncns, c->asyncns_query, &res);
376 c->asyncns_query = NULL;
378 if (ret != 0 || !res)
382 if (sockaddr_prepare(c, res->ai_addr, res->ai_addrlen) < 0)
385 asyncns_freeaddrinfo(res);
387 m->io_free(c->asyncns_io_event);
388 c->asyncns_io_event = NULL;
392 m->io_free(c->asyncns_io_event);
393 c->asyncns_io_event = NULL;
395 errno = EHOSTUNREACH;
403 static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
404 pa_socket_client *c = userdata;
419 static void start_timeout(pa_socket_client *c, bool use_rtclock) {
423 pa_assert(!c->timeout_event);
425 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);
428 pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, bool use_rtclock, const char*name, uint16_t default_port) {
429 pa_socket_client *c = NULL;
436 a.path_or_host = NULL;
438 if (pa_is_ip6_address(name)) {
439 size_t len = strlen(name);
440 name_buf = pa_xmalloc(len + 3);
441 memcpy(name_buf + 1, name, len);
443 name_buf[len + 1] = ']';
444 name_buf[len + 2] = '\0';
446 name_buf = pa_xstrdup(name);
449 if (pa_parse_address(name_buf, &a) < 0) {
450 pa_log_warn("parsing address failed: %s", name_buf);
455 a.port = default_port;
458 case PA_PARSED_ADDRESS_UNIX:
459 if ((c = pa_socket_client_new_unix(m, a.path_or_host)))
460 start_timeout(c, use_rtclock);
463 case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */
464 case PA_PARSED_ADDRESS_TCP6: /* Fallthrough */
465 case PA_PARSED_ADDRESS_TCP_AUTO: {
466 struct addrinfo hints;
469 pa_snprintf(port, sizeof(port), "%u", (unsigned) a.port);
472 if (a.type == PA_PARSED_ADDRESS_TCP4)
473 hints.ai_family = PF_INET;
475 else if (a.type == PA_PARSED_ADDRESS_TCP6)
476 hints.ai_family = PF_INET6;
479 hints.ai_family = PF_UNSPEC;
481 hints.ai_socktype = SOCK_STREAM;
483 #if defined(HAVE_LIBASYNCNS)
487 if (!(asyncns = asyncns_new(1)))
490 c = socket_client_new(m);
491 c->asyncns = asyncns;
492 c->asyncns_io_event = m->io_new(m, asyncns_fd(c->asyncns), PA_IO_EVENT_INPUT, asyncns_cb, c);
493 pa_assert_se(c->asyncns_query = asyncns_getaddrinfo(c->asyncns, a.path_or_host, port, &hints));
494 start_timeout(c, use_rtclock);
496 #elif defined(HAVE_GETADDRINFO)
499 struct addrinfo *res = NULL;
501 ret = getaddrinfo(a.path_or_host, port, &hints, &res);
507 if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen)))
508 start_timeout(c, use_rtclock);
515 struct hostent *host = NULL;
516 struct sockaddr_in s;
519 /* FIXME: PF_INET6 support */
520 if (hints.ai_family == PF_INET6) {
521 pa_log_error("IPv6 is not supported on Windows");
526 host = gethostbyname(a.path_or_host);
528 unsigned int addr = inet_addr(a.path_or_host);
529 if (addr != INADDR_NONE)
530 host = gethostbyaddr((char*)&addr, 4, AF_INET);
537 s.sin_family = AF_INET;
538 memcpy(&s.sin_addr, host->h_addr, sizeof(struct in_addr));
539 s.sin_port = htons(a.port);
541 if ((c = pa_socket_client_new_sockaddr(m, (struct sockaddr*)&s, sizeof(s))))
542 start_timeout(c, use_rtclock);
544 #endif /* HAVE_LIBASYNCNS */
550 pa_xfree(a.path_or_host);
555 /* Return non-zero when the target sockaddr is considered
556 local. "local" means UNIX socket or TCP socket on localhost. Other
557 local IP addresses are not considered local. */
558 bool pa_socket_client_is_local(pa_socket_client *c) {
560 pa_assert(PA_REFCNT_VALUE(c) >= 1);