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 */
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
41 #ifdef HAVE_ARPA_INET_H
42 #include <arpa/inet.h>
44 #ifdef HAVE_NETINET_IN_H
45 #include <netinet/in.h>
51 #ifdef HAVE_LIBASYNCNS
55 #include <pulse/rtclock.h>
56 #include <pulse/timeval.h>
57 #include <pulse/xmalloc.h>
59 #include <pulsecore/winsock.h>
60 #include <pulsecore/core-error.h>
61 #include <pulsecore/socket-util.h>
62 #include <pulsecore/core-rtclock.h>
63 #include <pulsecore/core-util.h>
64 #include <pulsecore/socket-util.h>
65 #include <pulsecore/log.h>
66 #include <pulsecore/parseaddr.h>
67 #include <pulsecore/macro.h>
68 #include <pulsecore/refcnt.h>
70 #include "socket-client.h"
72 #define CONNECT_TIMEOUT 5
74 struct pa_socket_client
{
76 pa_mainloop_api
*mainloop
;
78 pa_io_event
*io_event
;
79 pa_time_event
*timeout_event
;
80 pa_defer_event
*defer_event
;
81 pa_socket_client_cb_t callback
;
84 #ifdef HAVE_LIBASYNCNS
86 asyncns_query_t
* asyncns_query
;
87 pa_io_event
*asyncns_io_event
;
91 static pa_socket_client
* socket_client_new(pa_mainloop_api
*m
) {
95 c
= pa_xnew(pa_socket_client
, 1);
100 c
->timeout_event
= NULL
;
101 c
->defer_event
= NULL
;
106 #ifdef HAVE_LIBASYNCNS
108 c
->asyncns_io_event
= NULL
;
109 c
->asyncns_query
= NULL
;
115 static void free_events(pa_socket_client
*c
) {
119 c
->mainloop
->io_free(c
->io_event
);
123 if (c
->timeout_event
) {
124 c
->mainloop
->time_free(c
->timeout_event
);
125 c
->timeout_event
= NULL
;
128 if (c
->defer_event
) {
129 c
->mainloop
->defer_free(c
->defer_event
);
130 c
->defer_event
= NULL
;
134 static void do_call(pa_socket_client
*c
) {
135 pa_iochannel
*io
= NULL
;
140 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
141 pa_assert(c
->callback
);
143 pa_socket_client_ref(c
);
148 lerror
= sizeof(error
);
149 if (getsockopt(c
->fd
, SOL_SOCKET
, SO_ERROR
, (void*)&error
, &lerror
) < 0) {
150 pa_log("getsockopt(): %s", pa_cstrerror(errno
));
154 if (lerror
!= sizeof(error
)) {
155 pa_log("getsockopt() returned invalid size.");
160 pa_log_debug("connect(): %s", pa_cstrerror(error
));
165 io
= pa_iochannel_new(c
->mainloop
, c
->fd
, c
->fd
);
169 if (!io
&& c
->fd
>= 0)
175 pa_assert(c
->callback
);
176 c
->callback(c
, io
, c
->userdata
);
178 pa_socket_client_unref(c
);
181 static void connect_defer_cb(pa_mainloop_api
*m
, pa_defer_event
*e
, void *userdata
) {
182 pa_socket_client
*c
= userdata
;
186 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
187 pa_assert(c
->defer_event
== e
);
192 static void connect_io_cb(pa_mainloop_api
*m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
193 pa_socket_client
*c
= userdata
;
197 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
198 pa_assert(c
->io_event
== e
);
204 static int do_connect(pa_socket_client
*c
, const struct sockaddr
*sa
, socklen_t len
) {
208 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
212 pa_make_fd_nonblock(c
->fd
);
214 if ((r
= connect(c
->fd
, sa
, len
)) < 0) {
216 if (WSAGetLastError() != EWOULDBLOCK
) {
217 pa_log_debug("connect(): %d", WSAGetLastError());
219 if (errno
!= EINPROGRESS
) {
220 pa_log_debug("connect(): %s (%d)", pa_cstrerror(errno
), errno
);
225 pa_assert_se(c
->io_event
= c
->mainloop
->io_new(c
->mainloop
, c
->fd
, PA_IO_EVENT_OUTPUT
, connect_io_cb
, c
));
227 pa_assert_se(c
->defer_event
= c
->mainloop
->defer_new(c
->mainloop
, connect_defer_cb
, c
));
232 pa_socket_client
* pa_socket_client_new_ipv4(pa_mainloop_api
*m
, uint32_t address
, uint16_t port
) {
233 struct sockaddr_in sa
;
238 memset(&sa
, 0, sizeof(sa
));
239 sa
.sin_family
= AF_INET
;
240 sa
.sin_port
= htons(port
);
241 sa
.sin_addr
.s_addr
= htonl(address
);
243 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
248 pa_socket_client
* pa_socket_client_new_unix(pa_mainloop_api
*m
, const char *filename
) {
249 struct sockaddr_un sa
;
254 memset(&sa
, 0, sizeof(sa
));
255 sa
.sun_family
= AF_UNIX
;
256 pa_strlcpy(sa
.sun_path
, filename
, sizeof(sa
.sun_path
));
258 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
261 #else /* HAVE_SYS_UN_H */
263 pa_socket_client
* pa_socket_client_new_unix(pa_mainloop_api
*m
, const char *filename
) {
267 #endif /* HAVE_SYS_UN_H */
269 static int sockaddr_prepare(pa_socket_client
*c
, const struct sockaddr
*sa
, size_t salen
) {
274 c
->local
= pa_socket_address_is_local(sa
);
276 if ((c
->fd
= socket(sa
->sa_family
, SOCK_STREAM
, 0)) < 0) {
277 pa_log("socket(): %s", pa_cstrerror(errno
));
281 pa_make_fd_cloexec(c
->fd
);
284 if (sa
->sa_family
== AF_INET
|| sa
->sa_family
== AF_INET6
)
286 if (sa
->sa_family
== AF_INET
)
288 pa_make_tcp_socket_low_delay(c
->fd
);
290 pa_make_socket_low_delay(c
->fd
);
292 if (do_connect(c
, sa
, (socklen_t
) salen
) < 0)
298 pa_socket_client
* pa_socket_client_new_sockaddr(pa_mainloop_api
*m
, const struct sockaddr
*sa
, size_t salen
) {
303 pa_assert(salen
> 0);
305 pa_assert_se(c
= socket_client_new(m
));
307 if (sockaddr_prepare(c
, sa
, salen
) < 0)
313 pa_socket_client_unref(c
);
317 static void socket_client_free(pa_socket_client
*c
) {
319 pa_assert(c
->mainloop
);
326 #ifdef HAVE_LIBASYNCNS
327 if (c
->asyncns_query
)
328 asyncns_cancel(c
->asyncns
, c
->asyncns_query
);
330 asyncns_free(c
->asyncns
);
331 if (c
->asyncns_io_event
)
332 c
->mainloop
->io_free(c
->asyncns_io_event
);
338 void pa_socket_client_unref(pa_socket_client
*c
) {
340 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
342 if (PA_REFCNT_DEC(c
) <= 0)
343 socket_client_free(c
);
346 pa_socket_client
* pa_socket_client_ref(pa_socket_client
*c
) {
348 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
354 void pa_socket_client_set_callback(pa_socket_client
*c
, pa_socket_client_cb_t on_connection
, void *userdata
) {
356 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
358 c
->callback
= on_connection
;
359 c
->userdata
= userdata
;
363 pa_socket_client
* pa_socket_client_new_ipv6(pa_mainloop_api
*m
, uint8_t address
[16], uint16_t port
) {
364 struct sockaddr_in6 sa
;
370 memset(&sa
, 0, sizeof(sa
));
371 sa
.sin6_family
= AF_INET6
;
372 sa
.sin6_port
= htons(port
);
373 memcpy(&sa
.sin6_addr
, address
, sizeof(sa
.sin6_addr
));
375 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
379 #ifdef HAVE_LIBASYNCNS
381 static void asyncns_cb(pa_mainloop_api
*m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
382 pa_socket_client
*c
= userdata
;
383 struct addrinfo
*res
= NULL
;
388 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
389 pa_assert(c
->asyncns_io_event
== e
);
392 if (asyncns_wait(c
->asyncns
, 0) < 0)
395 if (!asyncns_isdone(c
->asyncns
, c
->asyncns_query
))
398 ret
= asyncns_getaddrinfo_done(c
->asyncns
, c
->asyncns_query
, &res
);
399 c
->asyncns_query
= NULL
;
401 if (ret
!= 0 || !res
)
405 sockaddr_prepare(c
, res
->ai_addr
, res
->ai_addrlen
);
407 asyncns_freeaddrinfo(res
);
409 m
->io_free(c
->asyncns_io_event
);
410 c
->asyncns_io_event
= NULL
;
414 m
->io_free(c
->asyncns_io_event
);
415 c
->asyncns_io_event
= NULL
;
417 errno
= EHOSTUNREACH
;
425 static void timeout_cb(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
426 pa_socket_client
*c
= userdata
;
441 static void start_timeout(pa_socket_client
*c
, pa_bool_t use_rtclock
) {
445 pa_assert(!c
->timeout_event
);
447 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
);
450 pa_socket_client
* pa_socket_client_new_string(pa_mainloop_api
*m
, pa_bool_t use_rtclock
, const char*name
, uint16_t default_port
) {
451 pa_socket_client
*c
= NULL
;
457 if (pa_parse_address(name
, &a
) < 0)
461 a
.port
= default_port
;
464 case PA_PARSED_ADDRESS_UNIX
:
465 if ((c
= pa_socket_client_new_unix(m
, a
.path_or_host
)))
466 start_timeout(c
, use_rtclock
);
469 case PA_PARSED_ADDRESS_TCP4
: /* Fallthrough */
470 case PA_PARSED_ADDRESS_TCP6
: /* Fallthrough */
471 case PA_PARSED_ADDRESS_TCP_AUTO
:{
473 struct addrinfo hints
;
476 pa_snprintf(port
, sizeof(port
), "%u", (unsigned) a
.port
);
478 memset(&hints
, 0, sizeof(hints
));
479 if (a
.type
== PA_PARSED_ADDRESS_TCP4
)
480 hints
.ai_family
= PF_INET
;
482 else if (a
.type
== PA_PARSED_ADDRESS_TCP6
)
483 hints
.ai_family
= PF_INET6
;
486 hints
.ai_family
= PF_UNSPEC
;
488 hints
.ai_socktype
= SOCK_STREAM
;
490 #if defined(HAVE_LIBASYNCNS)
494 if (!(asyncns
= asyncns_new(1)))
497 pa_assert_se(c
= socket_client_new(m
));
498 c
->asyncns
= asyncns
;
499 c
->asyncns_io_event
= m
->io_new(m
, asyncns_fd(c
->asyncns
), PA_IO_EVENT_INPUT
, asyncns_cb
, c
);
500 c
->asyncns_query
= asyncns_getaddrinfo(c
->asyncns
, a
.path_or_host
, port
, &hints
);
501 pa_assert(c
->asyncns_query
);
502 start_timeout(c
, use_rtclock
);
504 #elif defined(HAVE_GETADDRINFO)
507 struct addrinfo
*res
= NULL
;
509 ret
= getaddrinfo(a
.path_or_host
, port
, &hints
, &res
);
515 if ((c
= pa_socket_client_new_sockaddr(m
, res
->ai_addr
, res
->ai_addrlen
)))
516 start_timeout(c
, use_rtclock
);
523 struct hostent
*host
= NULL
;
524 struct sockaddr_in s
;
527 /* FIXME: PF_INET6 support */
528 if (hints
.ai_family
== PF_INET6
) {
529 pa_log_error("IPv6 is not supported on Windows");
534 host
= gethostbyname(a
.path_or_host
);
536 unsigned int addr
= inet_addr(a
.path_or_host
);
537 if (addr
!= INADDR_NONE
)
538 host
= gethostbyaddr((char*)&addr
, 4, AF_INET
);
544 s
.sin_family
= AF_INET
;
545 memcpy(&s
.sin_addr
, host
->h_addr
, sizeof(struct in_addr
));
546 s
.sin_port
= htons(a
.port
);
548 if ((c
= pa_socket_client_new_sockaddr(m
, (struct sockaddr
*)&s
, sizeof(s
))))
549 start_timeout(c
, use_rtclock
);
551 #endif /* HAVE_LIBASYNCNS */
556 pa_xfree(a
.path_or_host
);
561 /* Return non-zero when the target sockaddr is considered
562 local. "local" means UNIX socket or TCP socket on localhost. Other
563 local IP addresses are not considered local. */
564 pa_bool_t
pa_socket_client_is_local(pa_socket_client
*c
) {
566 pa_assert(PA_REFCNT_VALUE(c
) >= 1);