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 */
37 #ifdef HAVE_SYS_SOCKET_H
38 #include <sys/socket.h>
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
46 #ifdef HAVE_NETINET_IN_H
47 #include <netinet/in.h>
53 #ifdef HAVE_LIBASYNCNS
57 #include <pulse/timeval.h>
58 #include <pulse/xmalloc.h>
60 #include <pulsecore/winsock.h>
61 #include <pulsecore/core-error.h>
62 #include <pulsecore/socket-util.h>
63 #include <pulsecore/core-util.h>
64 #include <pulsecore/log.h>
65 #include <pulsecore/parseaddr.h>
66 #include <pulsecore/macro.h>
67 #include <pulsecore/refcnt.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_xnew(pa_socket_client
, 1);
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
;
139 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
140 pa_assert(c
->callback
);
142 pa_socket_client_ref(c
);
147 lerror
= sizeof(error
);
148 if (getsockopt(c
->fd
, SOL_SOCKET
, SO_ERROR
, (void*)&error
, &lerror
) < 0) {
149 pa_log("getsockopt(): %s", pa_cstrerror(errno
));
153 if (lerror
!= sizeof(error
)) {
154 pa_log("getsockopt() returned invalid size.");
159 pa_log_debug("connect(): %s", pa_cstrerror(error
));
164 io
= pa_iochannel_new(c
->mainloop
, c
->fd
, c
->fd
);
168 if (!io
&& c
->fd
>= 0)
174 pa_assert(c
->callback
);
175 c
->callback(c
, io
, c
->userdata
);
177 pa_socket_client_unref(c
);
180 static void connect_fixed_cb(pa_mainloop_api
*m
, pa_defer_event
*e
, void *userdata
) {
181 pa_socket_client
*c
= userdata
;
185 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
186 pa_assert(c
->defer_event
== e
);
191 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
) {
192 pa_socket_client
*c
= userdata
;
196 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
197 pa_assert(c
->io_event
== e
);
203 static int do_connect(pa_socket_client
*c
, const struct sockaddr
*sa
, socklen_t len
) {
207 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
211 pa_make_fd_nonblock(c
->fd
);
213 if ((r
= connect(c
->fd
, sa
, len
)) < 0) {
215 if (WSAGetLastError() != EWOULDBLOCK
) {
216 pa_log_debug("connect(): %d", WSAGetLastError());
218 if (errno
!= EINPROGRESS
) {
219 pa_log_debug("connect(): %s (%d)", pa_cstrerror(errno
), errno
);
224 pa_assert_se(c
->io_event
= c
->mainloop
->io_new(c
->mainloop
, c
->fd
, PA_IO_EVENT_OUTPUT
, connect_io_cb
, c
));
226 pa_assert_se(c
->defer_event
= c
->mainloop
->defer_new(c
->mainloop
, connect_fixed_cb
, c
));
231 pa_socket_client
* pa_socket_client_new_ipv4(pa_mainloop_api
*m
, uint32_t address
, uint16_t port
) {
232 struct sockaddr_in sa
;
237 memset(&sa
, 0, sizeof(sa
));
238 sa
.sin_family
= AF_INET
;
239 sa
.sin_port
= htons(port
);
240 sa
.sin_addr
.s_addr
= htonl(address
);
242 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
247 pa_socket_client
* pa_socket_client_new_unix(pa_mainloop_api
*m
, const char *filename
) {
248 struct sockaddr_un sa
;
253 memset(&sa
, 0, sizeof(sa
));
254 sa
.sun_family
= AF_UNIX
;
255 strncpy(sa
.sun_path
, filename
, sizeof(sa
.sun_path
)-1);
256 sa
.sun_path
[sizeof(sa
.sun_path
) - 1] = 0;
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 switch (sa
->sa_family
) {
280 c
->local
= ((const struct sockaddr_in
*) sa
)->sin_addr
.s_addr
== INADDR_LOOPBACK
;
284 c
->local
= memcmp(&((const struct sockaddr_in6
*) sa
)->sin6_addr
, &in6addr_loopback
, sizeof(struct in6_addr
)) == 0;
291 if ((c
->fd
= socket(sa
->sa_family
, SOCK_STREAM
, 0)) < 0) {
292 pa_log("socket(): %s", pa_cstrerror(errno
));
296 pa_make_fd_cloexec(c
->fd
);
297 if (sa
->sa_family
== AF_INET
|| sa
->sa_family
== AF_INET6
)
298 pa_make_tcp_socket_low_delay(c
->fd
);
300 pa_make_socket_low_delay(c
->fd
);
302 if (do_connect(c
, sa
, salen
) < 0)
308 pa_socket_client
* pa_socket_client_new_sockaddr(pa_mainloop_api
*m
, const struct sockaddr
*sa
, size_t salen
) {
313 pa_assert(salen
> 0);
315 pa_assert_se(c
= pa_socket_client_new(m
));
317 if (sockaddr_prepare(c
, sa
, salen
) < 0)
323 pa_socket_client_unref(c
);
327 static void socket_client_free(pa_socket_client
*c
) {
329 pa_assert(c
->mainloop
);
336 #ifdef HAVE_LIBASYNCNS
337 if (c
->asyncns_query
)
338 asyncns_cancel(c
->asyncns
, c
->asyncns_query
);
340 asyncns_free(c
->asyncns
);
341 if (c
->asyncns_io_event
)
342 c
->mainloop
->io_free(c
->asyncns_io_event
);
348 void pa_socket_client_unref(pa_socket_client
*c
) {
350 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
352 if (PA_REFCNT_DEC(c
) <= 0)
353 socket_client_free(c
);
356 pa_socket_client
* pa_socket_client_ref(pa_socket_client
*c
) {
358 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
364 void pa_socket_client_set_callback(pa_socket_client
*c
, void (*on_connection
)(pa_socket_client
*c
, pa_iochannel
*io
, void *userdata
), void *userdata
) {
366 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
368 c
->callback
= on_connection
;
369 c
->userdata
= userdata
;
372 pa_socket_client
* pa_socket_client_new_ipv6(pa_mainloop_api
*m
, uint8_t address
[16], uint16_t port
) {
373 struct sockaddr_in6 sa
;
379 memset(&sa
, 0, sizeof(sa
));
380 sa
.sin6_family
= AF_INET6
;
381 sa
.sin6_port
= htons(port
);
382 memcpy(&sa
.sin6_addr
, address
, sizeof(sa
.sin6_addr
));
384 return pa_socket_client_new_sockaddr(m
, (struct sockaddr
*) &sa
, sizeof(sa
));
387 #ifdef HAVE_LIBASYNCNS
389 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
) {
390 pa_socket_client
*c
= userdata
;
391 struct addrinfo
*res
= NULL
;
396 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
397 pa_assert(c
->asyncns_io_event
== e
);
400 if (asyncns_wait(c
->asyncns
, 0) < 0)
403 if (!asyncns_isdone(c
->asyncns
, c
->asyncns_query
))
406 ret
= asyncns_getaddrinfo_done(c
->asyncns
, c
->asyncns_query
, &res
);
407 c
->asyncns_query
= NULL
;
409 if (ret
!= 0 || !res
)
413 sockaddr_prepare(c
, res
->ai_addr
, res
->ai_addrlen
);
415 asyncns_freeaddrinfo(res
);
417 m
->io_free(c
->asyncns_io_event
);
418 c
->asyncns_io_event
= NULL
;
422 m
->io_free(c
->asyncns_io_event
);
423 c
->asyncns_io_event
= NULL
;
425 errno
= EHOSTUNREACH
;
433 static void timeout_cb(pa_mainloop_api
*m
, pa_time_event
*e
, const struct timeval
*tv
, void *userdata
) {
434 pa_socket_client
*c
= userdata
;
450 static void start_timeout(pa_socket_client
*c
) {
453 pa_assert(!c
->timeout_event
);
455 pa_gettimeofday(&tv
);
456 pa_timeval_add(&tv
, CONNECT_TIMEOUT
* 1000000);
457 c
->timeout_event
= c
->mainloop
->time_new(c
->mainloop
, &tv
, timeout_cb
, c
);
460 pa_socket_client
* pa_socket_client_new_string(pa_mainloop_api
*m
, const char*name
, uint16_t default_port
) {
461 pa_socket_client
*c
= NULL
;
467 if (pa_parse_address(name
, &a
) < 0)
471 a
.port
= default_port
;
474 case PA_PARSED_ADDRESS_UNIX
:
475 if ((c
= pa_socket_client_new_unix(m
, a
.path_or_host
)))
479 case PA_PARSED_ADDRESS_TCP4
: /* Fallthrough */
480 case PA_PARSED_ADDRESS_TCP6
: /* Fallthrough */
481 case PA_PARSED_ADDRESS_TCP_AUTO
:{
483 struct addrinfo hints
;
486 pa_snprintf(port
, sizeof(port
), "%u", (unsigned) a
.port
);
488 memset(&hints
, 0, sizeof(hints
));
489 hints
.ai_family
= a
.type
== PA_PARSED_ADDRESS_TCP4
? PF_INET
: (a
.type
== PA_PARSED_ADDRESS_TCP6
? PF_INET6
: PF_UNSPEC
);
490 hints
.ai_socktype
= SOCK_STREAM
;
492 #ifdef HAVE_LIBASYNCNS
496 if (!(asyncns
= asyncns_new(1)))
499 c
= pa_socket_client_new(m
);
500 c
->asyncns
= asyncns
;
501 c
->asyncns_io_event
= m
->io_new(m
, asyncns_fd(c
->asyncns
), PA_IO_EVENT_INPUT
, asyncns_cb
, c
);
502 c
->asyncns_query
= asyncns_getaddrinfo(c
->asyncns
, a
.path_or_host
, port
, &hints
);
503 pa_assert(c
->asyncns_query
);
506 #else /* HAVE_LIBASYNCNS */
508 #ifdef HAVE_GETADDRINFO
510 struct addrinfo
*res
= NULL
;
512 ret
= getaddrinfo(a
.path_or_host
, port
, &hints
, &res
);
518 if ((c
= pa_socket_client_new_sockaddr(m
, res
->ai_addr
, res
->ai_addrlen
)))
523 #else /* HAVE_GETADDRINFO */
524 struct hostent
*host
= NULL
;
525 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");
533 host
= gethostbyname(a
.path_or_host
);
535 unsigned int addr
= inet_addr(a
.path_or_host
);
536 if (addr
!= INADDR_NONE
)
537 host
= gethostbyaddr((char*)&addr
, 4, AF_INET
);
543 s
.sin_family
= AF_INET
;
544 memcpy(&s
.sin_addr
, host
->h_addr
, sizeof(struct in_addr
));
545 s
.sin_port
= htons(a
.port
);
547 if ((c
= pa_socket_client_new_sockaddr(m
, (struct sockaddr
*)&s
, sizeof(s
))))
549 #endif /* HAVE_GETADDRINFO */
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 int pa_socket_client_is_local(pa_socket_client
*c
) {
566 pa_assert(PA_REFCNT_VALUE(c
) >= 1);