4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as
11 published by the Free Software Foundation; either version 2.1 of the
12 License, or (at your option) any later version.
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public
20 License along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 /* #undef HAVE_LIBASYNCNS */
38 #ifdef HAVE_SYS_SOCKET_H
39 #include <sys/socket.h>
44 #ifdef HAVE_ARPA_INET_H
45 #include <arpa/inet.h>
47 #ifdef HAVE_NETINET_IN_H
48 #include <netinet/in.h>
54 #ifdef HAVE_LIBASYNCNS
60 #include <pulse/timeval.h>
61 #include <pulse/xmalloc.h>
63 #include <pulsecore/core-error.h>
64 #include <pulsecore/socket-util.h>
65 #include <pulsecore/core-util.h>
66 #include <pulsecore/log.h>
67 #include <pulsecore/parseaddr.h>
69 #include "socket-client.h"
71 #define CONNECT_TIMEOUT 5
73 struct pa_socket_client
{
75 pa_mainloop_api
*mainloop
;
77 pa_io_event
*io_event
;
78 pa_time_event
*timeout_event
;
79 pa_defer_event
*defer_event
;
80 void (*callback
)(pa_socket_client
*c
, pa_iochannel
*io
, void *userdata
);
83 #ifdef HAVE_LIBASYNCNS
85 asyncns_query_t
* asyncns_query
;
86 pa_io_event
*asyncns_io_event
;
90 static pa_socket_client
*pa_socket_client_new(pa_mainloop_api
*m
) {
94 c
= pa_xmalloc(sizeof(pa_socket_client
));
99 c
->defer_event
= NULL
;
100 c
->timeout_event
= NULL
;
105 #ifdef HAVE_LIBASYNCNS
107 c
->asyncns_io_event
= NULL
;
108 c
->asyncns_query
= NULL
;
114 static void free_events(pa_socket_client
*c
) {
118 c
->mainloop
->io_free(c
->io_event
);
122 if (c
->defer_event
) {
123 c
->mainloop
->defer_free(c
->defer_event
);
124 c
->defer_event
= NULL
;
127 if (c
->timeout_event
) {
128 c
->mainloop
->time_free(c
->timeout_event
);
129 c
->timeout_event
= NULL
;
133 static void do_call(pa_socket_client
*c
) {
134 pa_iochannel
*io
= NULL
;
137 assert(c
&& c
->callback
);
139 pa_socket_client_ref(c
);
144 lerror
= sizeof(error
);
145 if (getsockopt(c
->fd
, SOL_SOCKET
, SO_ERROR
, (void*)&error
, &lerror
) < 0) {
146 pa_log("getsockopt(): %s", pa_cstrerror(errno
));
150 if (lerror
!= sizeof(error
)) {
151 pa_log("getsockopt() returned invalid size.");
156 pa_log_debug("connect(): %s", pa_cstrerror(errno
));
161 io
= pa_iochannel_new(c
->mainloop
, c
->fd
, c
->fd
);
165 if (!io
&& c
->fd
>= 0)
172 c
->callback(c
, io
, c
->userdata
);
174 pa_socket_client_unref(c
);
177 static void connect_fixed_cb(pa_mainloop_api
*m
, pa_defer_event
*e
, void *userdata
) {
178 pa_socket_client
*c
= userdata
;
179 assert(m
&& c
&& c
->defer_event
== e
);
183 static void connect_io_cb(pa_mainloop_api
*m
, pa_io_event
*e
, int fd
, PA_GCC_UNUSED pa_io_event_flags_t f
, void *userdata
) {
184 pa_socket_client
*c
= userdata
;
185 assert(m
&& c
&& c
->io_event
== e
&& fd
>= 0);
189 static int do_connect(pa_socket_client
*c
, const struct sockaddr
*sa
, socklen_t len
) {
191 assert(c
&& sa
&& len
);
193 pa_make_nonblock_fd(c
->fd
);
195 if ((r
= connect(c
->fd
, sa
, len
)) < 0) {
197 if (WSAGetLastError() != EWOULDBLOCK
) {
198 pa_log_debug("connect(): %d", WSAGetLastError());
200 if (errno
!= EINPROGRESS
) {
201 pa_log_debug("connect(): %s (%d)", pa_cstrerror(errno
), errno
);
206 c
->io_event
= c
->mainloop
->io_new(c
->mainloop
, c
->fd
, PA_IO_EVENT_OUTPUT
, connect_io_cb
, c
);
209 c
->defer_event
= c
->mainloop
->defer_new(c
->mainloop
, connect_fixed_cb
, c
);
210 assert(c
->defer_event
);
216 pa_socket_client
* pa_socket_client_new_ipv4(pa_mainloop_api
*m
, uint32_t address
, uint16_t port
) {
217 struct sockaddr_in sa
;
218 assert(m
&& port
> 0);
220 memset(&sa
, 0, sizeof(sa
));
221 sa
.sin_family
= AF_INET
;
222 sa
.sin_port
= htons(port
);
223 sa
.sin_addr
.s_addr
= htonl(address
);
225 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
230 pa_socket_client
* pa_socket_client_new_unix(pa_mainloop_api
*m
, const char *filename
) {
231 struct sockaddr_un sa
;
232 assert(m
&& filename
);
234 memset(&sa
, 0, sizeof(sa
));
235 sa
.sun_family
= AF_UNIX
;
236 strncpy(sa
.sun_path
, filename
, sizeof(sa
.sun_path
)-1);
237 sa
.sun_path
[sizeof(sa
.sun_path
) - 1] = 0;
239 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
242 #else /* HAVE_SYS_UN_H */
244 pa_socket_client
* pa_socket_client_new_unix(pa_mainloop_api
*m
, const char *filename
) {
248 #endif /* HAVE_SYS_UN_H */
250 static int sockaddr_prepare(pa_socket_client
*c
, const struct sockaddr
*sa
, size_t salen
) {
255 switch (sa
->sa_family
) {
261 c
->local
= ((const struct sockaddr_in
*) sa
)->sin_addr
.s_addr
== INADDR_LOOPBACK
;
265 c
->local
= memcmp(&((const struct sockaddr_in6
*) sa
)->sin6_addr
, &in6addr_loopback
, sizeof(struct in6_addr
)) == 0;
272 if ((c
->fd
= socket(sa
->sa_family
, SOCK_STREAM
, 0)) < 0) {
273 pa_log("socket(): %s", pa_cstrerror(errno
));
277 pa_fd_set_cloexec(c
->fd
, 1);
278 if (sa
->sa_family
== AF_INET
|| sa
->sa_family
== AF_INET6
)
279 pa_socket_tcp_low_delay(c
->fd
);
281 pa_socket_low_delay(c
->fd
);
283 if (do_connect(c
, sa
, salen
) < 0)
289 pa_socket_client
* pa_socket_client_new_sockaddr(pa_mainloop_api
*m
, const struct sockaddr
*sa
, size_t salen
) {
292 c
= pa_socket_client_new(m
);
295 if (sockaddr_prepare(c
, sa
, salen
) < 0)
301 pa_socket_client_unref(c
);
306 static void socket_client_free(pa_socket_client
*c
) {
307 assert(c
&& c
->mainloop
);
315 #ifdef HAVE_LIBASYNCNS
316 if (c
->asyncns_query
)
317 asyncns_cancel(c
->asyncns
, c
->asyncns_query
);
319 asyncns_free(c
->asyncns
);
320 if (c
->asyncns_io_event
)
321 c
->mainloop
->io_free(c
->asyncns_io_event
);
327 void pa_socket_client_unref(pa_socket_client
*c
) {
328 assert(c
&& c
->ref
>= 1);
331 socket_client_free(c
);
334 pa_socket_client
* pa_socket_client_ref(pa_socket_client
*c
) {
335 assert(c
&& c
->ref
>= 1);
340 void pa_socket_client_set_callback(pa_socket_client
*c
, void (*on_connection
)(pa_socket_client
*c
, pa_iochannel
*io
, void *userdata
), void *userdata
) {
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
) {
347 struct sockaddr_in6 sa
;
349 memset(&sa
, 0, sizeof(sa
));
350 sa
.sin6_family
= AF_INET6
;
351 sa
.sin6_port
= htons(port
);
352 memcpy(&sa
.sin6_addr
, address
, sizeof(sa
.sin6_addr
));
354 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
357 #ifdef HAVE_LIBASYNCNS
359 static void asyncns_cb(pa_mainloop_api
*m
, pa_io_event
*e
, int fd
, PA_GCC_UNUSED pa_io_event_flags_t f
, void *userdata
) {
360 pa_socket_client
*c
= userdata
;
361 struct addrinfo
*res
= NULL
;
363 assert(m
&& c
&& c
->asyncns_io_event
== e
&& fd
>= 0);
365 if (asyncns_wait(c
->asyncns
, 0) < 0)
368 if (!asyncns_isdone(c
->asyncns
, c
->asyncns_query
))
371 ret
= asyncns_getaddrinfo_done(c
->asyncns
, c
->asyncns_query
, &res
);
372 c
->asyncns_query
= NULL
;
374 if (ret
!= 0 || !res
)
378 sockaddr_prepare(c
, res
->ai_addr
, res
->ai_addrlen
);
380 asyncns_freeaddrinfo(res
);
382 m
->io_free(c
->asyncns_io_event
);
383 c
->asyncns_io_event
= NULL
;
387 m
->io_free(c
->asyncns_io_event
);
388 c
->asyncns_io_event
= NULL
;
390 errno
= EHOSTUNREACH
;
398 static void timeout_cb(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*tv
, void *userdata
) {
399 pa_socket_client
*c
= userdata
;
414 static void start_timeout(pa_socket_client
*c
) {
417 assert(!c
->timeout_event
);
419 pa_gettimeofday(&tv
);
420 pa_timeval_add(&tv
, CONNECT_TIMEOUT
* 1000000);
421 c
->timeout_event
= c
->mainloop
->time_new(c
->mainloop
, &tv
, timeout_cb
, c
);
424 pa_socket_client
* pa_socket_client_new_string(pa_mainloop_api
*m
, const char*name
, uint16_t default_port
) {
425 pa_socket_client
*c
= NULL
;
429 if (pa_parse_address(name
, &a
) < 0)
433 a
.port
= default_port
;
436 case PA_PARSED_ADDRESS_UNIX
:
437 if ((c
= pa_socket_client_new_unix(m
, a
.path_or_host
)))
441 case PA_PARSED_ADDRESS_TCP4
: /* Fallthrough */
442 case PA_PARSED_ADDRESS_TCP6
: /* Fallthrough */
443 case PA_PARSED_ADDRESS_TCP_AUTO
:{
445 struct addrinfo hints
;
448 snprintf(port
, sizeof(port
), "%u", (unsigned) a
.port
);
450 memset(&hints
, 0, sizeof(hints
));
451 hints
.ai_family
= a
.type
== PA_PARSED_ADDRESS_TCP4
? PF_INET
: (a
.type
== PA_PARSED_ADDRESS_TCP6
? PF_INET6
: PF_UNSPEC
);
452 hints
.ai_socktype
= SOCK_STREAM
;
454 #ifdef HAVE_LIBASYNCNS
458 if (!(asyncns
= asyncns_new(1)))
461 c
= pa_socket_client_new(m
);
462 c
->asyncns
= asyncns
;
463 c
->asyncns_io_event
= m
->io_new(m
, asyncns_fd(c
->asyncns
), PA_IO_EVENT_INPUT
, asyncns_cb
, c
);
464 c
->asyncns_query
= asyncns_getaddrinfo(c
->asyncns
, a
.path_or_host
, port
, &hints
);
465 assert(c
->asyncns_query
);
468 #else /* HAVE_LIBASYNCNS */
470 #ifdef HAVE_GETADDRINFO
472 struct addrinfo
*res
= NULL
;
474 ret
= getaddrinfo(a
.path_or_host
, port
, &hints
, &res
);
480 if ((c
= pa_socket_client_new_sockaddr(m
, res
->ai_addr
, res
->ai_addrlen
)))
485 #else /* HAVE_GETADDRINFO */
486 struct hostent
*host
= NULL
;
487 struct sockaddr_in s
;
489 /* FIXME: PF_INET6 support */
490 if (hints
.ai_family
== PF_INET6
) {
491 pa_log_error("IPv6 is not supported on Windows");
495 host
= gethostbyname(a
.path_or_host
);
497 unsigned int addr
= inet_addr(a
.path_or_host
);
498 if (addr
!= INADDR_NONE
)
499 host
= gethostbyaddr((char*)&addr
, 4, AF_INET
);
505 s
.sin_family
= AF_INET
;
506 memcpy(&s
.sin_addr
, host
->h_addr
, sizeof(struct in_addr
));
507 s
.sin_port
= htons(a
.port
);
509 if ((c
= pa_socket_client_new_sockaddr(m
, (struct sockaddr
*)&s
, sizeof(s
))))
511 #endif /* HAVE_GETADDRINFO */
513 #endif /* HAVE_LIBASYNCNS */
518 pa_xfree(a
.path_or_host
);
523 /* Return non-zero when the target sockaddr is considered
524 local. "local" means UNIX socket or TCP socket on localhost. Other
525 local IP addresses are not considered local. */
526 int pa_socket_client_is_local(pa_socket_client
*c
) {