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
{
78 pa_mainloop_api
*mainloop
;
79 pa_io_event
*io_event
;
80 pa_time_event
*timeout_event
;
81 pa_defer_event
*defer_event
;
83 pa_socket_client_cb_t callback
;
88 #ifdef HAVE_LIBASYNCNS
90 asyncns_query_t
* asyncns_query
;
91 pa_io_event
*asyncns_io_event
;
95 static pa_socket_client
* socket_client_new(pa_mainloop_api
*m
) {
99 c
= pa_xnew0(pa_socket_client
, 1);
107 static void free_events(pa_socket_client
*c
) {
111 c
->mainloop
->io_free(c
->io_event
);
115 if (c
->timeout_event
) {
116 c
->mainloop
->time_free(c
->timeout_event
);
117 c
->timeout_event
= NULL
;
120 if (c
->defer_event
) {
121 c
->mainloop
->defer_free(c
->defer_event
);
122 c
->defer_event
= NULL
;
126 static void do_call(pa_socket_client
*c
) {
127 pa_iochannel
*io
= NULL
;
132 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
133 pa_assert(c
->callback
);
135 pa_socket_client_ref(c
);
140 lerror
= sizeof(error
);
141 if (getsockopt(c
->fd
, SOL_SOCKET
, SO_ERROR
, (void*)&error
, &lerror
) < 0) {
142 pa_log("getsockopt(): %s", pa_cstrerror(errno
));
146 if (lerror
!= sizeof(error
)) {
147 pa_log("getsockopt() returned invalid size.");
152 pa_log_debug("connect(): %s", pa_cstrerror(error
));
157 io
= pa_iochannel_new(c
->mainloop
, c
->fd
, c
->fd
);
160 if (!io
&& c
->fd
>= 0)
166 c
->callback(c
, io
, c
->userdata
);
168 pa_socket_client_unref(c
);
171 static void connect_defer_cb(pa_mainloop_api
*m
, pa_defer_event
*e
, void *userdata
) {
172 pa_socket_client
*c
= userdata
;
176 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
177 pa_assert(c
->defer_event
== e
);
182 static void connect_io_cb(pa_mainloop_api
*m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
183 pa_socket_client
*c
= userdata
;
187 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
188 pa_assert(c
->io_event
== e
);
194 static int do_connect(pa_socket_client
*c
, const struct sockaddr
*sa
, socklen_t len
) {
196 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
200 pa_make_fd_nonblock(c
->fd
);
202 if (connect(c
->fd
, sa
, len
) < 0) {
204 if (WSAGetLastError() != EWOULDBLOCK
) {
205 pa_log_debug("connect(): %d", WSAGetLastError());
207 if (errno
!= EINPROGRESS
) {
208 pa_log_debug("connect(): %s (%d)", pa_cstrerror(errno
), errno
);
213 c
->io_event
= c
->mainloop
->io_new(c
->mainloop
, c
->fd
, PA_IO_EVENT_OUTPUT
, connect_io_cb
, c
);
215 c
->defer_event
= c
->mainloop
->defer_new(c
->mainloop
, connect_defer_cb
, c
);
220 pa_socket_client
* pa_socket_client_new_ipv4(pa_mainloop_api
*m
, uint32_t address
, uint16_t port
) {
221 struct sockaddr_in sa
;
227 sa
.sin_family
= AF_INET
;
228 sa
.sin_port
= htons(port
);
229 sa
.sin_addr
.s_addr
= htonl(address
);
231 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
235 pa_socket_client
* pa_socket_client_new_unix(pa_mainloop_api
*m
, const char *filename
) {
237 struct sockaddr_un sa
;
243 sa
.sun_family
= AF_UNIX
;
244 pa_strlcpy(sa
.sun_path
, filename
, sizeof(sa
.sun_path
));
246 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
247 #else /* HAVE_SYS_UN_H */
250 #endif /* HAVE_SYS_UN_H */
253 static int sockaddr_prepare(pa_socket_client
*c
, const struct sockaddr
*sa
, size_t salen
) {
258 c
->local
= pa_socket_address_is_local(sa
);
260 if ((c
->fd
= socket(sa
->sa_family
, SOCK_STREAM
, 0)) < 0) {
261 pa_log("socket(): %s", pa_cstrerror(errno
));
265 pa_make_fd_cloexec(c
->fd
);
268 if (sa
->sa_family
== AF_INET
|| sa
->sa_family
== AF_INET6
)
270 if (sa
->sa_family
== AF_INET
)
272 pa_make_tcp_socket_low_delay(c
->fd
);
274 pa_make_socket_low_delay(c
->fd
);
276 if (do_connect(c
, sa
, (socklen_t
) salen
) < 0)
282 pa_socket_client
* pa_socket_client_new_sockaddr(pa_mainloop_api
*m
, const struct sockaddr
*sa
, size_t salen
) {
287 pa_assert(salen
> 0);
289 c
= socket_client_new(m
);
291 if (sockaddr_prepare(c
, sa
, salen
) < 0)
297 pa_socket_client_unref(c
);
301 static void socket_client_free(pa_socket_client
*c
) {
303 pa_assert(c
->mainloop
);
310 #ifdef HAVE_LIBASYNCNS
311 if (c
->asyncns_query
)
312 asyncns_cancel(c
->asyncns
, c
->asyncns_query
);
314 asyncns_free(c
->asyncns
);
315 if (c
->asyncns_io_event
)
316 c
->mainloop
->io_free(c
->asyncns_io_event
);
322 void pa_socket_client_unref(pa_socket_client
*c
) {
324 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
326 if (PA_REFCNT_DEC(c
) <= 0)
327 socket_client_free(c
);
330 pa_socket_client
* pa_socket_client_ref(pa_socket_client
*c
) {
332 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
338 void pa_socket_client_set_callback(pa_socket_client
*c
, pa_socket_client_cb_t on_connection
, void *userdata
) {
340 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
342 c
->callback
= on_connection
;
343 c
->userdata
= userdata
;
346 pa_socket_client
* pa_socket_client_new_ipv6(pa_mainloop_api
*m
, uint8_t address
[16], uint16_t port
) {
348 struct sockaddr_in6 sa
;
355 sa
.sin6_family
= AF_INET6
;
356 sa
.sin6_port
= htons(port
);
357 memcpy(&sa
.sin6_addr
, address
, sizeof(sa
.sin6_addr
));
359 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
366 #ifdef HAVE_LIBASYNCNS
368 static void asyncns_cb(pa_mainloop_api
*m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
369 pa_socket_client
*c
= userdata
;
370 struct addrinfo
*res
= NULL
;
375 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
376 pa_assert(c
->asyncns_io_event
== e
);
379 if (asyncns_wait(c
->asyncns
, 0) < 0)
382 if (!asyncns_isdone(c
->asyncns
, c
->asyncns_query
))
385 ret
= asyncns_getaddrinfo_done(c
->asyncns
, c
->asyncns_query
, &res
);
386 c
->asyncns_query
= NULL
;
388 if (ret
!= 0 || !res
)
392 sockaddr_prepare(c
, res
->ai_addr
, res
->ai_addrlen
);
394 asyncns_freeaddrinfo(res
);
396 m
->io_free(c
->asyncns_io_event
);
397 c
->asyncns_io_event
= NULL
;
401 m
->io_free(c
->asyncns_io_event
);
402 c
->asyncns_io_event
= NULL
;
404 errno
= EHOSTUNREACH
;
412 static void timeout_cb(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
413 pa_socket_client
*c
= userdata
;
428 static void start_timeout(pa_socket_client
*c
, pa_bool_t use_rtclock
) {
432 pa_assert(!c
->timeout_event
);
434 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
);
437 pa_socket_client
* pa_socket_client_new_string(pa_mainloop_api
*m
, pa_bool_t use_rtclock
, const char*name
, uint16_t default_port
) {
438 pa_socket_client
*c
= NULL
;
444 if (pa_parse_address(name
, &a
) < 0)
448 a
.port
= default_port
;
451 case PA_PARSED_ADDRESS_UNIX
:
452 if ((c
= pa_socket_client_new_unix(m
, a
.path_or_host
)))
453 start_timeout(c
, use_rtclock
);
456 case PA_PARSED_ADDRESS_TCP4
: /* Fallthrough */
457 case PA_PARSED_ADDRESS_TCP6
: /* Fallthrough */
458 case PA_PARSED_ADDRESS_TCP_AUTO
: {
459 struct addrinfo hints
;
462 pa_snprintf(port
, sizeof(port
), "%u", (unsigned) a
.port
);
465 if (a
.type
== PA_PARSED_ADDRESS_TCP4
)
466 hints
.ai_family
= PF_INET
;
468 else if (a
.type
== PA_PARSED_ADDRESS_TCP6
)
469 hints
.ai_family
= PF_INET6
;
472 hints
.ai_family
= PF_UNSPEC
;
474 hints
.ai_socktype
= SOCK_STREAM
;
476 #if defined(HAVE_LIBASYNCNS)
480 if (!(asyncns
= asyncns_new(1)))
483 c
= socket_client_new(m
);
484 c
->asyncns
= asyncns
;
485 c
->asyncns_io_event
= m
->io_new(m
, asyncns_fd(c
->asyncns
), PA_IO_EVENT_INPUT
, asyncns_cb
, c
);
486 pa_assert_se(c
->asyncns_query
= asyncns_getaddrinfo(c
->asyncns
, a
.path_or_host
, port
, &hints
));
487 start_timeout(c
, use_rtclock
);
489 #elif defined(HAVE_GETADDRINFO)
492 struct addrinfo
*res
= NULL
;
494 ret
= getaddrinfo(a
.path_or_host
, port
, &hints
, &res
);
500 if ((c
= pa_socket_client_new_sockaddr(m
, res
->ai_addr
, res
->ai_addrlen
)))
501 start_timeout(c
, use_rtclock
);
508 struct hostent
*host
= NULL
;
509 struct sockaddr_in s
;
512 /* FIXME: PF_INET6 support */
513 if (hints
.ai_family
== PF_INET6
) {
514 pa_log_error("IPv6 is not supported on Windows");
519 host
= gethostbyname(a
.path_or_host
);
521 unsigned int addr
= inet_addr(a
.path_or_host
);
522 if (addr
!= INADDR_NONE
)
523 host
= gethostbyaddr((char*)&addr
, 4, AF_INET
);
530 s
.sin_family
= AF_INET
;
531 memcpy(&s
.sin_addr
, host
->h_addr
, sizeof(struct in_addr
));
532 s
.sin_port
= htons(a
.port
);
534 if ((c
= pa_socket_client_new_sockaddr(m
, (struct sockaddr
*)&s
, sizeof(s
))))
535 start_timeout(c
, use_rtclock
);
537 #endif /* HAVE_LIBASYNCNS */
542 pa_xfree(a
.path_or_host
);
547 /* Return non-zero when the target sockaddr is considered
548 local. "local" means UNIX socket or TCP socket on localhost. Other
549 local IP addresses are not considered local. */
550 pa_bool_t
pa_socket_client_is_local(pa_socket_client
*c
) {
552 pa_assert(PA_REFCNT_VALUE(c
) >= 1);