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
) {
206 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
210 pa_make_fd_nonblock(c
->fd
);
212 if (connect(c
->fd
, sa
, len
) < 0) {
214 if (WSAGetLastError() != EWOULDBLOCK
) {
215 pa_log_debug("connect(): %d", WSAGetLastError());
217 if (errno
!= EINPROGRESS
) {
218 pa_log_debug("connect(): %s (%d)", pa_cstrerror(errno
), errno
);
223 pa_assert_se(c
->io_event
= c
->mainloop
->io_new(c
->mainloop
, c
->fd
, PA_IO_EVENT_OUTPUT
, connect_io_cb
, c
));
225 pa_assert_se(c
->defer_event
= c
->mainloop
->defer_new(c
->mainloop
, connect_defer_cb
, c
));
230 pa_socket_client
* pa_socket_client_new_ipv4(pa_mainloop_api
*m
, uint32_t address
, uint16_t port
) {
231 struct sockaddr_in sa
;
236 memset(&sa
, 0, sizeof(sa
));
237 sa
.sin_family
= AF_INET
;
238 sa
.sin_port
= htons(port
);
239 sa
.sin_addr
.s_addr
= htonl(address
);
241 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
246 pa_socket_client
* pa_socket_client_new_unix(pa_mainloop_api
*m
, const char *filename
) {
247 struct sockaddr_un sa
;
252 memset(&sa
, 0, sizeof(sa
));
253 sa
.sun_family
= AF_UNIX
;
254 pa_strlcpy(sa
.sun_path
, filename
, sizeof(sa
.sun_path
));
256 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
259 #else /* HAVE_SYS_UN_H */
261 pa_socket_client
* pa_socket_client_new_unix(pa_mainloop_api
*m
, const char *filename
) {
265 #endif /* HAVE_SYS_UN_H */
267 static int sockaddr_prepare(pa_socket_client
*c
, const struct sockaddr
*sa
, size_t salen
) {
272 c
->local
= pa_socket_address_is_local(sa
);
274 if ((c
->fd
= socket(sa
->sa_family
, SOCK_STREAM
, 0)) < 0) {
275 pa_log("socket(): %s", pa_cstrerror(errno
));
279 pa_make_fd_cloexec(c
->fd
);
282 if (sa
->sa_family
== AF_INET
|| sa
->sa_family
== AF_INET6
)
284 if (sa
->sa_family
== AF_INET
)
286 pa_make_tcp_socket_low_delay(c
->fd
);
288 pa_make_socket_low_delay(c
->fd
);
290 if (do_connect(c
, sa
, (socklen_t
) salen
) < 0)
296 pa_socket_client
* pa_socket_client_new_sockaddr(pa_mainloop_api
*m
, const struct sockaddr
*sa
, size_t salen
) {
301 pa_assert(salen
> 0);
303 pa_assert_se(c
= socket_client_new(m
));
305 if (sockaddr_prepare(c
, sa
, salen
) < 0)
311 pa_socket_client_unref(c
);
315 static void socket_client_free(pa_socket_client
*c
) {
317 pa_assert(c
->mainloop
);
324 #ifdef HAVE_LIBASYNCNS
325 if (c
->asyncns_query
)
326 asyncns_cancel(c
->asyncns
, c
->asyncns_query
);
328 asyncns_free(c
->asyncns
);
329 if (c
->asyncns_io_event
)
330 c
->mainloop
->io_free(c
->asyncns_io_event
);
336 void pa_socket_client_unref(pa_socket_client
*c
) {
338 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
340 if (PA_REFCNT_DEC(c
) <= 0)
341 socket_client_free(c
);
344 pa_socket_client
* pa_socket_client_ref(pa_socket_client
*c
) {
346 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
352 void pa_socket_client_set_callback(pa_socket_client
*c
, pa_socket_client_cb_t on_connection
, void *userdata
) {
354 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
356 c
->callback
= on_connection
;
357 c
->userdata
= userdata
;
361 pa_socket_client
* pa_socket_client_new_ipv6(pa_mainloop_api
*m
, uint8_t address
[16], uint16_t port
) {
362 struct sockaddr_in6 sa
;
368 memset(&sa
, 0, sizeof(sa
));
369 sa
.sin6_family
= AF_INET6
;
370 sa
.sin6_port
= htons(port
);
371 memcpy(&sa
.sin6_addr
, address
, sizeof(sa
.sin6_addr
));
373 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
377 #ifdef HAVE_LIBASYNCNS
379 static void asyncns_cb(pa_mainloop_api
*m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
380 pa_socket_client
*c
= userdata
;
381 struct addrinfo
*res
= NULL
;
386 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
387 pa_assert(c
->asyncns_io_event
== e
);
390 if (asyncns_wait(c
->asyncns
, 0) < 0)
393 if (!asyncns_isdone(c
->asyncns
, c
->asyncns_query
))
396 ret
= asyncns_getaddrinfo_done(c
->asyncns
, c
->asyncns_query
, &res
);
397 c
->asyncns_query
= NULL
;
399 if (ret
!= 0 || !res
)
403 sockaddr_prepare(c
, res
->ai_addr
, res
->ai_addrlen
);
405 asyncns_freeaddrinfo(res
);
407 m
->io_free(c
->asyncns_io_event
);
408 c
->asyncns_io_event
= NULL
;
412 m
->io_free(c
->asyncns_io_event
);
413 c
->asyncns_io_event
= NULL
;
415 errno
= EHOSTUNREACH
;
423 static void timeout_cb(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
424 pa_socket_client
*c
= userdata
;
439 static void start_timeout(pa_socket_client
*c
, pa_bool_t use_rtclock
) {
443 pa_assert(!c
->timeout_event
);
445 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
);
448 pa_socket_client
* pa_socket_client_new_string(pa_mainloop_api
*m
, pa_bool_t use_rtclock
, const char*name
, uint16_t default_port
) {
449 pa_socket_client
*c
= NULL
;
455 if (pa_parse_address(name
, &a
) < 0)
459 a
.port
= default_port
;
462 case PA_PARSED_ADDRESS_UNIX
:
463 if ((c
= pa_socket_client_new_unix(m
, a
.path_or_host
)))
464 start_timeout(c
, use_rtclock
);
467 case PA_PARSED_ADDRESS_TCP4
: /* Fallthrough */
468 case PA_PARSED_ADDRESS_TCP6
: /* Fallthrough */
469 case PA_PARSED_ADDRESS_TCP_AUTO
:{
471 struct addrinfo hints
;
474 pa_snprintf(port
, sizeof(port
), "%u", (unsigned) a
.port
);
476 memset(&hints
, 0, sizeof(hints
));
477 if (a
.type
== PA_PARSED_ADDRESS_TCP4
)
478 hints
.ai_family
= PF_INET
;
480 else if (a
.type
== PA_PARSED_ADDRESS_TCP6
)
481 hints
.ai_family
= PF_INET6
;
484 hints
.ai_family
= PF_UNSPEC
;
486 hints
.ai_socktype
= SOCK_STREAM
;
488 #if defined(HAVE_LIBASYNCNS)
492 if (!(asyncns
= asyncns_new(1)))
495 pa_assert_se(c
= socket_client_new(m
));
496 c
->asyncns
= asyncns
;
497 c
->asyncns_io_event
= m
->io_new(m
, asyncns_fd(c
->asyncns
), PA_IO_EVENT_INPUT
, asyncns_cb
, c
);
498 c
->asyncns_query
= asyncns_getaddrinfo(c
->asyncns
, a
.path_or_host
, port
, &hints
);
499 pa_assert(c
->asyncns_query
);
500 start_timeout(c
, use_rtclock
);
502 #elif defined(HAVE_GETADDRINFO)
505 struct addrinfo
*res
= NULL
;
507 ret
= getaddrinfo(a
.path_or_host
, port
, &hints
, &res
);
513 if ((c
= pa_socket_client_new_sockaddr(m
, res
->ai_addr
, res
->ai_addrlen
)))
514 start_timeout(c
, use_rtclock
);
521 struct hostent
*host
= NULL
;
522 struct sockaddr_in s
;
525 /* FIXME: PF_INET6 support */
526 if (hints
.ai_family
== PF_INET6
) {
527 pa_log_error("IPv6 is not supported on Windows");
532 host
= gethostbyname(a
.path_or_host
);
534 unsigned int addr
= inet_addr(a
.path_or_host
);
535 if (addr
!= INADDR_NONE
)
536 host
= gethostbyaddr((char*)&addr
, 4, AF_INET
);
542 s
.sin_family
= AF_INET
;
543 memcpy(&s
.sin_addr
, host
->h_addr
, sizeof(struct in_addr
));
544 s
.sin_port
= htons(a
.port
);
546 if ((c
= pa_socket_client_new_sockaddr(m
, (struct sockaddr
*)&s
, sizeof(s
))))
547 start_timeout(c
, use_rtclock
);
549 #endif /* HAVE_LIBASYNCNS */
554 pa_xfree(a
.path_or_host
);
559 /* Return non-zero when the target sockaddr is considered
560 local. "local" means UNIX socket or TCP socket on localhost. Other
561 local IP addresses are not considered local. */
562 pa_bool_t
pa_socket_client_is_local(pa_socket_client
*c
) {
564 pa_assert(PA_REFCNT_VALUE(c
) >= 1);