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
= pa_socket_cloexec(sa
->sa_family
, SOCK_STREAM
, 0)) < 0) {
261 pa_log("socket(): %s", pa_cstrerror(errno
));
266 if (sa
->sa_family
== AF_INET
|| sa
->sa_family
== AF_INET6
)
268 if (sa
->sa_family
== AF_INET
)
270 pa_make_tcp_socket_low_delay(c
->fd
);
272 pa_make_socket_low_delay(c
->fd
);
274 if (do_connect(c
, sa
, (socklen_t
) salen
) < 0)
280 pa_socket_client
* pa_socket_client_new_sockaddr(pa_mainloop_api
*m
, const struct sockaddr
*sa
, size_t salen
) {
285 pa_assert(salen
> 0);
287 c
= socket_client_new(m
);
289 if (sockaddr_prepare(c
, sa
, salen
) < 0)
295 pa_socket_client_unref(c
);
299 static void socket_client_free(pa_socket_client
*c
) {
301 pa_assert(c
->mainloop
);
308 #ifdef HAVE_LIBASYNCNS
309 if (c
->asyncns_query
)
310 asyncns_cancel(c
->asyncns
, c
->asyncns_query
);
312 asyncns_free(c
->asyncns
);
313 if (c
->asyncns_io_event
)
314 c
->mainloop
->io_free(c
->asyncns_io_event
);
320 void pa_socket_client_unref(pa_socket_client
*c
) {
322 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
324 if (PA_REFCNT_DEC(c
) <= 0)
325 socket_client_free(c
);
328 pa_socket_client
* pa_socket_client_ref(pa_socket_client
*c
) {
330 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
336 void pa_socket_client_set_callback(pa_socket_client
*c
, pa_socket_client_cb_t on_connection
, void *userdata
) {
338 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
340 c
->callback
= on_connection
;
341 c
->userdata
= userdata
;
344 pa_socket_client
* pa_socket_client_new_ipv6(pa_mainloop_api
*m
, uint8_t address
[16], uint16_t port
) {
346 struct sockaddr_in6 sa
;
353 sa
.sin6_family
= AF_INET6
;
354 sa
.sin6_port
= htons(port
);
355 memcpy(&sa
.sin6_addr
, address
, sizeof(sa
.sin6_addr
));
357 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
364 #ifdef HAVE_LIBASYNCNS
366 static void asyncns_cb(pa_mainloop_api
*m
, pa_io_event
*e
, int fd
, pa_io_event_flags_t f
, void *userdata
) {
367 pa_socket_client
*c
= userdata
;
368 struct addrinfo
*res
= NULL
;
373 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
374 pa_assert(c
->asyncns_io_event
== e
);
377 if (asyncns_wait(c
->asyncns
, 0) < 0)
380 if (!asyncns_isdone(c
->asyncns
, c
->asyncns_query
))
383 ret
= asyncns_getaddrinfo_done(c
->asyncns
, c
->asyncns_query
, &res
);
384 c
->asyncns_query
= NULL
;
386 if (ret
!= 0 || !res
)
390 if (sockaddr_prepare(c
, res
->ai_addr
, res
->ai_addrlen
) < 0)
393 asyncns_freeaddrinfo(res
);
395 m
->io_free(c
->asyncns_io_event
);
396 c
->asyncns_io_event
= NULL
;
400 m
->io_free(c
->asyncns_io_event
);
401 c
->asyncns_io_event
= NULL
;
403 errno
= EHOSTUNREACH
;
411 static void timeout_cb(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*t
, void *userdata
) {
412 pa_socket_client
*c
= userdata
;
427 static void start_timeout(pa_socket_client
*c
, pa_bool_t use_rtclock
) {
431 pa_assert(!c
->timeout_event
);
433 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
);
436 pa_socket_client
* pa_socket_client_new_string(pa_mainloop_api
*m
, pa_bool_t use_rtclock
, const char*name
, uint16_t default_port
) {
437 pa_socket_client
*c
= NULL
;
443 if (pa_parse_address(name
, &a
) < 0)
447 a
.port
= default_port
;
450 case PA_PARSED_ADDRESS_UNIX
:
451 if ((c
= pa_socket_client_new_unix(m
, a
.path_or_host
)))
452 start_timeout(c
, use_rtclock
);
455 case PA_PARSED_ADDRESS_TCP4
: /* Fallthrough */
456 case PA_PARSED_ADDRESS_TCP6
: /* Fallthrough */
457 case PA_PARSED_ADDRESS_TCP_AUTO
: {
458 struct addrinfo hints
;
461 pa_snprintf(port
, sizeof(port
), "%u", (unsigned) a
.port
);
464 if (a
.type
== PA_PARSED_ADDRESS_TCP4
)
465 hints
.ai_family
= PF_INET
;
467 else if (a
.type
== PA_PARSED_ADDRESS_TCP6
)
468 hints
.ai_family
= PF_INET6
;
471 hints
.ai_family
= PF_UNSPEC
;
473 hints
.ai_socktype
= SOCK_STREAM
;
475 #if defined(HAVE_LIBASYNCNS)
479 if (!(asyncns
= asyncns_new(1)))
482 c
= socket_client_new(m
);
483 c
->asyncns
= asyncns
;
484 c
->asyncns_io_event
= m
->io_new(m
, asyncns_fd(c
->asyncns
), PA_IO_EVENT_INPUT
, asyncns_cb
, c
);
485 pa_assert_se(c
->asyncns_query
= asyncns_getaddrinfo(c
->asyncns
, a
.path_or_host
, port
, &hints
));
486 start_timeout(c
, use_rtclock
);
488 #elif defined(HAVE_GETADDRINFO)
491 struct addrinfo
*res
= NULL
;
493 ret
= getaddrinfo(a
.path_or_host
, port
, &hints
, &res
);
499 if ((c
= pa_socket_client_new_sockaddr(m
, res
->ai_addr
, res
->ai_addrlen
)))
500 start_timeout(c
, use_rtclock
);
507 struct hostent
*host
= NULL
;
508 struct sockaddr_in s
;
511 /* FIXME: PF_INET6 support */
512 if (hints
.ai_family
== PF_INET6
) {
513 pa_log_error("IPv6 is not supported on Windows");
518 host
= gethostbyname(a
.path_or_host
);
520 unsigned int addr
= inet_addr(a
.path_or_host
);
521 if (addr
!= INADDR_NONE
)
522 host
= gethostbyaddr((char*)&addr
, 4, AF_INET
);
529 s
.sin_family
= AF_INET
;
530 memcpy(&s
.sin_addr
, host
->h_addr
, sizeof(struct in_addr
));
531 s
.sin_port
= htons(a
.port
);
533 if ((c
= pa_socket_client_new_sockaddr(m
, (struct sockaddr
*)&s
, sizeof(s
))))
534 start_timeout(c
, use_rtclock
);
536 #endif /* HAVE_LIBASYNCNS */
541 pa_xfree(a
.path_or_host
);
546 /* Return non-zero when the target sockaddr is considered
547 local. "local" means UNIX socket or TCP socket on localhost. Other
548 local IP addresses are not considered local. */
549 pa_bool_t
pa_socket_client_is_local(pa_socket_client
*c
) {
551 pa_assert(PA_REFCNT_VALUE(c
) >= 1);