make use of the new pa_socket_address_is_local() function
[pulseaudio-mirror.git] / src / pulsecore / socket-client.c
blobf8f2ff2f0a69463ad1e8d72668c04d1b49963c7f
1 /* $Id$ */
3 /***
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
22 USA.
23 ***/
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
29 /* #undef HAVE_LIBASYNCNS */
31 #include <unistd.h>
32 #include <stdio.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <stdlib.h>
37 #ifdef HAVE_SYS_SOCKET_H
38 #include <sys/socket.h>
39 #endif
40 #ifdef HAVE_SYS_UN_H
41 #include <sys/un.h>
42 #endif
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
45 #endif
46 #ifdef HAVE_NETINET_IN_H
47 #include <netinet/in.h>
48 #endif
49 #ifdef HAVE_NETDB_H
50 #include <netdb.h>
51 #endif
53 #ifdef HAVE_LIBASYNCNS
54 #include <asyncns.h>
55 #endif
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/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 {
75 PA_REFCNT_DECLARE;
76 pa_mainloop_api *mainloop;
77 int fd;
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;
82 void *userdata;
83 pa_bool_t local;
84 #ifdef HAVE_LIBASYNCNS
85 asyncns_t *asyncns;
86 asyncns_query_t * asyncns_query;
87 pa_io_event *asyncns_io_event;
88 #endif
91 static pa_socket_client* socket_client_new(pa_mainloop_api *m) {
92 pa_socket_client *c;
93 pa_assert(m);
95 c = pa_xnew(pa_socket_client, 1);
96 PA_REFCNT_INIT(c);
97 c->mainloop = m;
98 c->fd = -1;
99 c->io_event = NULL;
100 c->timeout_event = NULL;
101 c->defer_event = NULL;
102 c->callback = NULL;
103 c->userdata = NULL;
104 c->local = FALSE;
106 #ifdef HAVE_LIBASYNCNS
107 c->asyncns = NULL;
108 c->asyncns_io_event = NULL;
109 c->asyncns_query = NULL;
110 #endif
112 return c;
115 static void free_events(pa_socket_client *c) {
116 pa_assert(c);
118 if (c->io_event) {
119 c->mainloop->io_free(c->io_event);
120 c->io_event = NULL;
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;
136 int error;
137 socklen_t lerror;
139 pa_assert(c);
140 pa_assert(PA_REFCNT_VALUE(c) >= 1);
141 pa_assert(c->callback);
143 pa_socket_client_ref(c);
145 if (c->fd < 0)
146 goto finish;
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));
151 goto finish;
154 if (lerror != sizeof(error)) {
155 pa_log("getsockopt() returned invalid size.");
156 goto finish;
159 if (error != 0) {
160 pa_log_debug("connect(): %s", pa_cstrerror(error));
161 errno = error;
162 goto finish;
165 io = pa_iochannel_new(c->mainloop, c->fd, c->fd);
166 pa_assert(io);
168 finish:
169 if (!io && c->fd >= 0)
170 pa_close(c->fd);
171 c->fd = -1;
173 free_events(c);
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;
184 pa_assert(m);
185 pa_assert(c);
186 pa_assert(PA_REFCNT_VALUE(c) >= 1);
187 pa_assert(c->defer_event == e);
189 do_call(c);
192 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) {
193 pa_socket_client *c = userdata;
195 pa_assert(m);
196 pa_assert(c);
197 pa_assert(PA_REFCNT_VALUE(c) >= 1);
198 pa_assert(c->io_event == e);
199 pa_assert(fd >= 0);
201 do_call(c);
204 static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t len) {
205 int r;
207 pa_assert(c);
208 pa_assert(PA_REFCNT_VALUE(c) >= 1);
209 pa_assert(sa);
210 pa_assert(len > 0);
212 pa_make_fd_nonblock(c->fd);
214 if ((r = connect(c->fd, sa, len)) < 0) {
215 #ifdef OS_IS_WIN32
216 if (WSAGetLastError() != EWOULDBLOCK) {
217 pa_log_debug("connect(): %d", WSAGetLastError());
218 #else
219 if (errno != EINPROGRESS) {
220 pa_log_debug("connect(): %s (%d)", pa_cstrerror(errno), errno);
221 #endif
222 return -1;
225 pa_assert_se(c->io_event = c->mainloop->io_new(c->mainloop, c->fd, PA_IO_EVENT_OUTPUT, connect_io_cb, c));
226 } else
227 pa_assert_se(c->defer_event = c->mainloop->defer_new(c->mainloop, connect_defer_cb, c));
229 return 0;
232 pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port) {
233 struct sockaddr_in sa;
235 pa_assert(m);
236 pa_assert(port > 0);
238 memset(&sa, 0, sizeof(sa));
239 sa.sin_family = AF_INET;
240 sa.sin_port = htons(port);
241 sa.sin_addr.s_addr = htonl(address);
243 return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
246 #ifdef HAVE_SYS_UN_H
248 pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) {
249 struct sockaddr_un sa;
251 pa_assert(m);
252 pa_assert(filename);
254 memset(&sa, 0, sizeof(sa));
255 sa.sun_family = AF_UNIX;
256 pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path));
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) {
264 return NULL;
267 #endif /* HAVE_SYS_UN_H */
269 static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size_t salen) {
270 pa_assert(c);
271 pa_assert(sa);
272 pa_assert(salen);
274 c->local = pa_socket_address_is_local(sa);
276 if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) {
277 pa_log("socket(): %s", pa_cstrerror(errno));
278 return -1;
281 pa_make_fd_cloexec(c->fd);
283 if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)
284 pa_make_tcp_socket_low_delay(c->fd);
285 else
286 pa_make_socket_low_delay(c->fd);
288 if (do_connect(c, sa, salen) < 0)
289 return -1;
291 return 0;
294 pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) {
295 pa_socket_client *c;
297 pa_assert(m);
298 pa_assert(sa);
299 pa_assert(salen > 0);
301 pa_assert_se(c = socket_client_new(m));
303 if (sockaddr_prepare(c, sa, salen) < 0)
304 goto fail;
306 return c;
308 fail:
309 pa_socket_client_unref(c);
310 return NULL;
313 static void socket_client_free(pa_socket_client *c) {
314 pa_assert(c);
315 pa_assert(c->mainloop);
317 free_events(c);
319 if (c->fd >= 0)
320 pa_close(c->fd);
322 #ifdef HAVE_LIBASYNCNS
323 if (c->asyncns_query)
324 asyncns_cancel(c->asyncns, c->asyncns_query);
325 if (c->asyncns)
326 asyncns_free(c->asyncns);
327 if (c->asyncns_io_event)
328 c->mainloop->io_free(c->asyncns_io_event);
329 #endif
331 pa_xfree(c);
334 void pa_socket_client_unref(pa_socket_client *c) {
335 pa_assert(c);
336 pa_assert(PA_REFCNT_VALUE(c) >= 1);
338 if (PA_REFCNT_DEC(c) <= 0)
339 socket_client_free(c);
342 pa_socket_client* pa_socket_client_ref(pa_socket_client *c) {
343 pa_assert(c);
344 pa_assert(PA_REFCNT_VALUE(c) >= 1);
346 PA_REFCNT_INC(c);
347 return c;
350 void pa_socket_client_set_callback(pa_socket_client *c, pa_socket_client_cb_t on_connection, void *userdata) {
351 pa_assert(c);
352 pa_assert(PA_REFCNT_VALUE(c) >= 1);
354 c->callback = on_connection;
355 c->userdata = userdata;
358 pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port) {
359 struct sockaddr_in6 sa;
361 pa_assert(m);
362 pa_assert(address);
363 pa_assert(port > 0);
365 memset(&sa, 0, sizeof(sa));
366 sa.sin6_family = AF_INET6;
367 sa.sin6_port = htons(port);
368 memcpy(&sa.sin6_addr, address, sizeof(sa.sin6_addr));
370 return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
373 #ifdef HAVE_LIBASYNCNS
375 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) {
376 pa_socket_client *c = userdata;
377 struct addrinfo *res = NULL;
378 int ret;
380 pa_assert(m);
381 pa_assert(c);
382 pa_assert(PA_REFCNT_VALUE(c) >= 1);
383 pa_assert(c->asyncns_io_event == e);
384 pa_assert(fd >= 0);
386 if (asyncns_wait(c->asyncns, 0) < 0)
387 goto fail;
389 if (!asyncns_isdone(c->asyncns, c->asyncns_query))
390 return;
392 ret = asyncns_getaddrinfo_done(c->asyncns, c->asyncns_query, &res);
393 c->asyncns_query = NULL;
395 if (ret != 0 || !res)
396 goto fail;
398 if (res->ai_addr)
399 sockaddr_prepare(c, res->ai_addr, res->ai_addrlen);
401 asyncns_freeaddrinfo(res);
403 m->io_free(c->asyncns_io_event);
404 c->asyncns_io_event = NULL;
405 return;
407 fail:
408 m->io_free(c->asyncns_io_event);
409 c->asyncns_io_event = NULL;
411 errno = EHOSTUNREACH;
412 do_call(c);
413 return;
417 #endif
419 static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *tv, void *userdata) {
420 pa_socket_client *c = userdata;
422 pa_assert(m);
423 pa_assert(e);
424 pa_assert(tv);
425 pa_assert(c);
427 if (c->fd >= 0) {
428 pa_close(c->fd);
429 c->fd = -1;
432 errno = ETIMEDOUT;
433 do_call(c);
436 static void start_timeout(pa_socket_client *c) {
437 struct timeval tv;
438 pa_assert(c);
439 pa_assert(!c->timeout_event);
441 pa_gettimeofday(&tv);
442 pa_timeval_add(&tv, CONNECT_TIMEOUT * 1000000);
443 c->timeout_event = c->mainloop->time_new(c->mainloop, &tv, timeout_cb, c);
446 pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*name, uint16_t default_port) {
447 pa_socket_client *c = NULL;
448 pa_parsed_address a;
450 pa_assert(m);
451 pa_assert(name);
453 if (pa_parse_address(name, &a) < 0)
454 return NULL;
456 if (!a.port)
457 a.port = default_port;
459 switch (a.type) {
460 case PA_PARSED_ADDRESS_UNIX:
461 if ((c = pa_socket_client_new_unix(m, a.path_or_host)))
462 start_timeout(c);
463 break;
465 case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */
466 case PA_PARSED_ADDRESS_TCP6: /* Fallthrough */
467 case PA_PARSED_ADDRESS_TCP_AUTO:{
469 struct addrinfo hints;
470 char port[12];
472 pa_snprintf(port, sizeof(port), "%u", (unsigned) a.port);
474 memset(&hints, 0, sizeof(hints));
475 hints.ai_family = a.type == PA_PARSED_ADDRESS_TCP4 ? PF_INET : (a.type == PA_PARSED_ADDRESS_TCP6 ? PF_INET6 : PF_UNSPEC);
476 hints.ai_socktype = SOCK_STREAM;
478 #if defined(HAVE_LIBASYNCNS)
480 asyncns_t *asyncns;
482 if (!(asyncns = asyncns_new(1)))
483 goto finish;
485 pa_assert_se(c = socket_client_new(m));
486 c->asyncns = asyncns;
487 c->asyncns_io_event = m->io_new(m, asyncns_fd(c->asyncns), PA_IO_EVENT_INPUT, asyncns_cb, c);
488 c->asyncns_query = asyncns_getaddrinfo(c->asyncns, a.path_or_host, port, &hints);
489 pa_assert(c->asyncns_query);
490 start_timeout(c);
492 #elif defined(HAVE_GETADDRINFO)
494 int ret;
495 struct addrinfo *res = NULL;
497 ret = getaddrinfo(a.path_or_host, port, &hints, &res);
499 if (ret < 0 || !res)
500 goto finish;
502 if (res->ai_addr) {
503 if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen)))
504 start_timeout(c);
507 freeaddrinfo(res);
509 #else
511 struct hostent *host = NULL;
512 struct sockaddr_in s;
514 /* FIXME: PF_INET6 support */
515 if (hints.ai_family == PF_INET6) {
516 pa_log_error("IPv6 is not supported on Windows");
517 goto finish;
520 host = gethostbyname(a.path_or_host);
521 if (!host) {
522 unsigned int addr = inet_addr(a.path_or_host);
523 if (addr != INADDR_NONE)
524 host = gethostbyaddr((char*)&addr, 4, AF_INET);
527 if (!host)
528 goto finish;
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);
537 #endif /* HAVE_LIBASYNCNS */
541 finish:
542 pa_xfree(a.path_or_host);
543 return c;
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) {
551 pa_assert(c);
552 pa_assert(PA_REFCNT_VALUE(c) >= 1);
554 return c->local;