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, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 /* #undef HAVE_LIBASYNCNS */
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
45 #ifdef HAVE_LIBASYNCNS
49 #include <pulse/rtclock.h>
50 #include <pulse/timeval.h>
51 #include <pulse/xmalloc.h>
53 #include <pulsecore/socket.h>
54 #include <pulsecore/socket-util.h>
55 #include <pulsecore/core-error.h>
56 #include <pulsecore/core-rtclock.h>
57 #include <pulsecore/core-util.h>
58 #include <pulsecore/socket-util.h>
59 #include <pulsecore/log.h>
60 #include <pulsecore/parseaddr.h>
61 #include <pulsecore/macro.h>
62 #include <pulsecore/refcnt.h>
63 #include <pulsecore/arpa-inet.h>
65 #include "socket-client.h"
67 #define CONNECT_TIMEOUT 5
69 struct pa_socket_client
{
73 pa_mainloop_api
*mainloop
;
74 pa_io_event
*io_event
;
75 pa_time_event
*timeout_event
;
76 pa_defer_event
*defer_event
;
78 pa_socket_client_cb_t callback
;
83 #ifdef HAVE_LIBASYNCNS
85 asyncns_query_t
* asyncns_query
;
86 pa_io_event
*asyncns_io_event
;
90 static pa_socket_client
* socket_client_new(pa_mainloop_api
*m
) {
94 c
= pa_xnew0(pa_socket_client
, 1);
102 static void free_events(pa_socket_client
*c
) {
106 c
->mainloop
->io_free(c
->io_event
);
110 if (c
->timeout_event
) {
111 c
->mainloop
->time_free(c
->timeout_event
);
112 c
->timeout_event
= NULL
;
115 if (c
->defer_event
) {
116 c
->mainloop
->defer_free(c
->defer_event
);
117 c
->defer_event
= NULL
;
121 static void do_call(pa_socket_client
*c
) {
122 pa_iochannel
*io
= NULL
;
127 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
128 pa_assert(c
->callback
);
130 pa_socket_client_ref(c
);
135 lerror
= sizeof(error
);
136 if (getsockopt(c
->fd
, SOL_SOCKET
, SO_ERROR
, (void*)&error
, &lerror
) < 0) {
137 pa_log("getsockopt(): %s", pa_cstrerror(errno
));
141 if (lerror
!= sizeof(error
)) {
142 pa_log("getsockopt() returned invalid size.");
147 pa_log_debug("connect(): %s", pa_cstrerror(error
));
152 io
= pa_iochannel_new(c
->mainloop
, c
->fd
, c
->fd
);
155 if (!io
&& c
->fd
>= 0)
161 c
->callback(c
, io
, c
->userdata
);
163 pa_socket_client_unref(c
);
166 static void connect_defer_cb(pa_mainloop_api
*m
, pa_defer_event
*e
, void *userdata
) {
167 pa_socket_client
*c
= userdata
;
171 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
172 pa_assert(c
->defer_event
== e
);
177 static void connect_io_cb(pa_mainloop_api
*m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
178 pa_socket_client
*c
= userdata
;
182 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
183 pa_assert(c
->io_event
== e
);
189 static int do_connect(pa_socket_client
*c
, const struct sockaddr
*sa
, socklen_t len
) {
191 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
195 pa_make_fd_nonblock(c
->fd
);
197 if (connect(c
->fd
, sa
, len
) < 0) {
199 if (WSAGetLastError() != EWOULDBLOCK
) {
200 pa_log_debug("connect(): %d", WSAGetLastError());
202 if (errno
!= EINPROGRESS
) {
203 pa_log_debug("connect(): %s (%d)", pa_cstrerror(errno
), errno
);
208 c
->io_event
= c
->mainloop
->io_new(c
->mainloop
, c
->fd
, PA_IO_EVENT_OUTPUT
, connect_io_cb
, c
);
210 c
->defer_event
= c
->mainloop
->defer_new(c
->mainloop
, connect_defer_cb
, c
);
215 pa_socket_client
* pa_socket_client_new_ipv4(pa_mainloop_api
*m
, uint32_t address
, uint16_t port
) {
216 struct sockaddr_in sa
;
222 sa
.sin_family
= AF_INET
;
223 sa
.sin_port
= htons(port
);
224 sa
.sin_addr
.s_addr
= htonl(address
);
226 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
229 pa_socket_client
* pa_socket_client_new_unix(pa_mainloop_api
*m
, const char *filename
) {
231 struct sockaddr_un sa
;
237 sa
.sun_family
= AF_UNIX
;
238 pa_strlcpy(sa
.sun_path
, filename
, sizeof(sa
.sun_path
));
240 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
241 #else /* HAVE_SYS_UN_H */
244 #endif /* HAVE_SYS_UN_H */
247 static int sockaddr_prepare(pa_socket_client
*c
, const struct sockaddr
*sa
, size_t salen
) {
252 c
->local
= pa_socket_address_is_local(sa
);
254 if ((c
->fd
= pa_socket_cloexec(sa
->sa_family
, SOCK_STREAM
, 0)) < 0) {
255 pa_log("socket(): %s", pa_cstrerror(errno
));
260 if (sa
->sa_family
== AF_INET
|| sa
->sa_family
== AF_INET6
)
262 if (sa
->sa_family
== AF_INET
)
264 pa_make_tcp_socket_low_delay(c
->fd
);
266 pa_make_socket_low_delay(c
->fd
);
268 if (do_connect(c
, sa
, (socklen_t
) salen
) < 0)
274 pa_socket_client
* pa_socket_client_new_sockaddr(pa_mainloop_api
*m
, const struct sockaddr
*sa
, size_t salen
) {
279 pa_assert(salen
> 0);
281 c
= socket_client_new(m
);
283 if (sockaddr_prepare(c
, sa
, salen
) < 0)
289 pa_socket_client_unref(c
);
293 static void socket_client_free(pa_socket_client
*c
) {
295 pa_assert(c
->mainloop
);
302 #ifdef HAVE_LIBASYNCNS
303 if (c
->asyncns_query
)
304 asyncns_cancel(c
->asyncns
, c
->asyncns_query
);
306 asyncns_free(c
->asyncns
);
307 if (c
->asyncns_io_event
)
308 c
->mainloop
->io_free(c
->asyncns_io_event
);
314 void pa_socket_client_unref(pa_socket_client
*c
) {
316 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
318 if (PA_REFCNT_DEC(c
) <= 0)
319 socket_client_free(c
);
322 pa_socket_client
* pa_socket_client_ref(pa_socket_client
*c
) {
324 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
330 void pa_socket_client_set_callback(pa_socket_client
*c
, pa_socket_client_cb_t on_connection
, void *userdata
) {
332 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
334 c
->callback
= on_connection
;
335 c
->userdata
= userdata
;
338 pa_socket_client
* pa_socket_client_new_ipv6(pa_mainloop_api
*m
, uint8_t address
[16], uint16_t port
) {
340 struct sockaddr_in6 sa
;
347 sa
.sin6_family
= AF_INET6
;
348 sa
.sin6_port
= htons(port
);
349 memcpy(&sa
.sin6_addr
, address
, sizeof(sa
.sin6_addr
));
351 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
358 #ifdef HAVE_LIBASYNCNS
360 static void asyncns_cb(pa_mainloop_api
*m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
361 pa_socket_client
*c
= userdata
;
362 struct addrinfo
*res
= NULL
;
367 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
368 pa_assert(c
->asyncns_io_event
== e
);
371 if (asyncns_wait(c
->asyncns
, 0) < 0)
374 if (!asyncns_isdone(c
->asyncns
, c
->asyncns_query
))
377 ret
= asyncns_getaddrinfo_done(c
->asyncns
, c
->asyncns_query
, &res
);
378 c
->asyncns_query
= NULL
;
380 if (ret
!= 0 || !res
)
384 if (sockaddr_prepare(c
, res
->ai_addr
, res
->ai_addrlen
) < 0)
387 asyncns_freeaddrinfo(res
);
389 m
->io_free(c
->asyncns_io_event
);
390 c
->asyncns_io_event
= NULL
;
394 m
->io_free(c
->asyncns_io_event
);
395 c
->asyncns_io_event
= NULL
;
397 errno
= EHOSTUNREACH
;
405 static void timeout_cb(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
406 pa_socket_client
*c
= userdata
;
421 static void start_timeout(pa_socket_client
*c
, bool use_rtclock
) {
425 pa_assert(!c
->timeout_event
);
427 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
);
430 pa_socket_client
* pa_socket_client_new_string(pa_mainloop_api
*m
, bool use_rtclock
, const char*name
, uint16_t default_port
) {
431 pa_socket_client
*c
= NULL
;
437 if (pa_parse_address(name
, &a
) < 0)
441 a
.port
= default_port
;
444 case PA_PARSED_ADDRESS_UNIX
:
445 if ((c
= pa_socket_client_new_unix(m
, a
.path_or_host
)))
446 start_timeout(c
, use_rtclock
);
449 case PA_PARSED_ADDRESS_TCP4
: /* Fallthrough */
450 case PA_PARSED_ADDRESS_TCP6
: /* Fallthrough */
451 case PA_PARSED_ADDRESS_TCP_AUTO
: {
452 struct addrinfo hints
;
455 pa_snprintf(port
, sizeof(port
), "%u", (unsigned) a
.port
);
458 if (a
.type
== PA_PARSED_ADDRESS_TCP4
)
459 hints
.ai_family
= PF_INET
;
461 else if (a
.type
== PA_PARSED_ADDRESS_TCP6
)
462 hints
.ai_family
= PF_INET6
;
465 hints
.ai_family
= PF_UNSPEC
;
467 hints
.ai_socktype
= SOCK_STREAM
;
469 #if defined(HAVE_LIBASYNCNS)
473 if (!(asyncns
= asyncns_new(1)))
476 c
= socket_client_new(m
);
477 c
->asyncns
= asyncns
;
478 c
->asyncns_io_event
= m
->io_new(m
, asyncns_fd(c
->asyncns
), PA_IO_EVENT_INPUT
, asyncns_cb
, c
);
479 pa_assert_se(c
->asyncns_query
= asyncns_getaddrinfo(c
->asyncns
, a
.path_or_host
, port
, &hints
));
480 start_timeout(c
, use_rtclock
);
482 #elif defined(HAVE_GETADDRINFO)
485 struct addrinfo
*res
= NULL
;
487 ret
= getaddrinfo(a
.path_or_host
, port
, &hints
, &res
);
493 if ((c
= pa_socket_client_new_sockaddr(m
, res
->ai_addr
, res
->ai_addrlen
)))
494 start_timeout(c
, use_rtclock
);
501 struct hostent
*host
= NULL
;
502 struct sockaddr_in s
;
505 /* FIXME: PF_INET6 support */
506 if (hints
.ai_family
== PF_INET6
) {
507 pa_log_error("IPv6 is not supported on Windows");
512 host
= gethostbyname(a
.path_or_host
);
514 unsigned int addr
= inet_addr(a
.path_or_host
);
515 if (addr
!= INADDR_NONE
)
516 host
= gethostbyaddr((char*)&addr
, 4, AF_INET
);
523 s
.sin_family
= AF_INET
;
524 memcpy(&s
.sin_addr
, host
->h_addr
, sizeof(struct in_addr
));
525 s
.sin_port
= htons(a
.port
);
527 if ((c
= pa_socket_client_new_sockaddr(m
, (struct sockaddr
*)&s
, sizeof(s
))))
528 start_timeout(c
, use_rtclock
);
530 #endif /* HAVE_LIBASYNCNS */
535 pa_xfree(a
.path_or_host
);
540 /* Return non-zero when the target sockaddr is considered
541 local. "local" means UNIX socket or TCP socket on localhost. Other
542 local IP addresses are not considered local. */
543 bool pa_socket_client_is_local(pa_socket_client
*c
) {
545 pa_assert(PA_REFCNT_VALUE(c
) >= 1);