]> code.delx.au - pulseaudio/blob - src/pulsecore/socket-client.c
socket-client: properly handle asyncns failures
[pulseaudio] / src / pulsecore / socket-client.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
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.
11
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.
16
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
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 /* #undef HAVE_LIBASYNCNS */
28
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <stdlib.h>
34
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
37 #endif
38 #ifdef HAVE_SYS_UN_H
39 #include <sys/un.h>
40 #endif
41 #ifdef HAVE_ARPA_INET_H
42 #include <arpa/inet.h>
43 #endif
44 #ifdef HAVE_NETINET_IN_H
45 #include <netinet/in.h>
46 #endif
47 #ifdef HAVE_NETDB_H
48 #include <netdb.h>
49 #endif
50
51 #ifdef HAVE_LIBASYNCNS
52 #include <asyncns.h>
53 #endif
54
55 #include <pulse/rtclock.h>
56 #include <pulse/timeval.h>
57 #include <pulse/xmalloc.h>
58
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>
69
70 #include "socket-client.h"
71
72 #define CONNECT_TIMEOUT 5
73
74 struct pa_socket_client {
75 PA_REFCNT_DECLARE;
76 int fd;
77
78 pa_mainloop_api *mainloop;
79 pa_io_event *io_event;
80 pa_time_event *timeout_event;
81 pa_defer_event *defer_event;
82
83 pa_socket_client_cb_t callback;
84 void *userdata;
85
86 pa_bool_t local;
87
88 #ifdef HAVE_LIBASYNCNS
89 asyncns_t *asyncns;
90 asyncns_query_t * asyncns_query;
91 pa_io_event *asyncns_io_event;
92 #endif
93 };
94
95 static pa_socket_client* socket_client_new(pa_mainloop_api *m) {
96 pa_socket_client *c;
97 pa_assert(m);
98
99 c = pa_xnew0(pa_socket_client, 1);
100 PA_REFCNT_INIT(c);
101 c->mainloop = m;
102 c->fd = -1;
103
104 return c;
105 }
106
107 static void free_events(pa_socket_client *c) {
108 pa_assert(c);
109
110 if (c->io_event) {
111 c->mainloop->io_free(c->io_event);
112 c->io_event = NULL;
113 }
114
115 if (c->timeout_event) {
116 c->mainloop->time_free(c->timeout_event);
117 c->timeout_event = NULL;
118 }
119
120 if (c->defer_event) {
121 c->mainloop->defer_free(c->defer_event);
122 c->defer_event = NULL;
123 }
124 }
125
126 static void do_call(pa_socket_client *c) {
127 pa_iochannel *io = NULL;
128 int error;
129 socklen_t lerror;
130
131 pa_assert(c);
132 pa_assert(PA_REFCNT_VALUE(c) >= 1);
133 pa_assert(c->callback);
134
135 pa_socket_client_ref(c);
136
137 if (c->fd < 0)
138 goto finish;
139
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));
143 goto finish;
144 }
145
146 if (lerror != sizeof(error)) {
147 pa_log("getsockopt() returned invalid size.");
148 goto finish;
149 }
150
151 if (error != 0) {
152 pa_log_debug("connect(): %s", pa_cstrerror(error));
153 errno = error;
154 goto finish;
155 }
156
157 io = pa_iochannel_new(c->mainloop, c->fd, c->fd);
158
159 finish:
160 if (!io && c->fd >= 0)
161 pa_close(c->fd);
162 c->fd = -1;
163
164 free_events(c);
165
166 c->callback(c, io, c->userdata);
167
168 pa_socket_client_unref(c);
169 }
170
171 static void connect_defer_cb(pa_mainloop_api *m, pa_defer_event *e, void *userdata) {
172 pa_socket_client *c = userdata;
173
174 pa_assert(m);
175 pa_assert(c);
176 pa_assert(PA_REFCNT_VALUE(c) >= 1);
177 pa_assert(c->defer_event == e);
178
179 do_call(c);
180 }
181
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;
184
185 pa_assert(m);
186 pa_assert(c);
187 pa_assert(PA_REFCNT_VALUE(c) >= 1);
188 pa_assert(c->io_event == e);
189 pa_assert(fd >= 0);
190
191 do_call(c);
192 }
193
194 static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t len) {
195 pa_assert(c);
196 pa_assert(PA_REFCNT_VALUE(c) >= 1);
197 pa_assert(sa);
198 pa_assert(len > 0);
199
200 pa_make_fd_nonblock(c->fd);
201
202 if (connect(c->fd, sa, len) < 0) {
203 #ifdef OS_IS_WIN32
204 if (WSAGetLastError() != EWOULDBLOCK) {
205 pa_log_debug("connect(): %d", WSAGetLastError());
206 #else
207 if (errno != EINPROGRESS) {
208 pa_log_debug("connect(): %s (%d)", pa_cstrerror(errno), errno);
209 #endif
210 return -1;
211 }
212
213 c->io_event = c->mainloop->io_new(c->mainloop, c->fd, PA_IO_EVENT_OUTPUT, connect_io_cb, c);
214 } else
215 c->defer_event = c->mainloop->defer_new(c->mainloop, connect_defer_cb, c);
216
217 return 0;
218 }
219
220 pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port) {
221 struct sockaddr_in sa;
222
223 pa_assert(m);
224 pa_assert(port > 0);
225
226 pa_zero(sa);
227 sa.sin_family = AF_INET;
228 sa.sin_port = htons(port);
229 sa.sin_addr.s_addr = htonl(address);
230
231 return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
232 }
233
234
235 pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) {
236 #ifdef HAVE_SYS_UN_H
237 struct sockaddr_un sa;
238
239 pa_assert(m);
240 pa_assert(filename);
241
242 pa_zero(sa);
243 sa.sun_family = AF_UNIX;
244 pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path));
245
246 return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
247 #else /* HAVE_SYS_UN_H */
248
249 return NULL;
250 #endif /* HAVE_SYS_UN_H */
251 }
252
253 static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size_t salen) {
254 pa_assert(c);
255 pa_assert(sa);
256 pa_assert(salen);
257
258 c->local = pa_socket_address_is_local(sa);
259
260 if ((c->fd = pa_socket_cloexec(sa->sa_family, SOCK_STREAM, 0)) < 0) {
261 pa_log("socket(): %s", pa_cstrerror(errno));
262 return -1;
263 }
264
265 #ifdef HAVE_IPV6
266 if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)
267 #else
268 if (sa->sa_family == AF_INET)
269 #endif
270 pa_make_tcp_socket_low_delay(c->fd);
271 else
272 pa_make_socket_low_delay(c->fd);
273
274 if (do_connect(c, sa, (socklen_t) salen) < 0)
275 return -1;
276
277 return 0;
278 }
279
280 pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) {
281 pa_socket_client *c;
282
283 pa_assert(m);
284 pa_assert(sa);
285 pa_assert(salen > 0);
286
287 c = socket_client_new(m);
288
289 if (sockaddr_prepare(c, sa, salen) < 0)
290 goto fail;
291
292 return c;
293
294 fail:
295 pa_socket_client_unref(c);
296 return NULL;
297 }
298
299 static void socket_client_free(pa_socket_client *c) {
300 pa_assert(c);
301 pa_assert(c->mainloop);
302
303 free_events(c);
304
305 if (c->fd >= 0)
306 pa_close(c->fd);
307
308 #ifdef HAVE_LIBASYNCNS
309 if (c->asyncns_query)
310 asyncns_cancel(c->asyncns, c->asyncns_query);
311 if (c->asyncns)
312 asyncns_free(c->asyncns);
313 if (c->asyncns_io_event)
314 c->mainloop->io_free(c->asyncns_io_event);
315 #endif
316
317 pa_xfree(c);
318 }
319
320 void pa_socket_client_unref(pa_socket_client *c) {
321 pa_assert(c);
322 pa_assert(PA_REFCNT_VALUE(c) >= 1);
323
324 if (PA_REFCNT_DEC(c) <= 0)
325 socket_client_free(c);
326 }
327
328 pa_socket_client* pa_socket_client_ref(pa_socket_client *c) {
329 pa_assert(c);
330 pa_assert(PA_REFCNT_VALUE(c) >= 1);
331
332 PA_REFCNT_INC(c);
333 return c;
334 }
335
336 void pa_socket_client_set_callback(pa_socket_client *c, pa_socket_client_cb_t on_connection, void *userdata) {
337 pa_assert(c);
338 pa_assert(PA_REFCNT_VALUE(c) >= 1);
339
340 c->callback = on_connection;
341 c->userdata = userdata;
342 }
343
344 pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port) {
345 #ifdef HAVE_IPV6
346 struct sockaddr_in6 sa;
347
348 pa_assert(m);
349 pa_assert(address);
350 pa_assert(port > 0);
351
352 pa_zero(sa);
353 sa.sin6_family = AF_INET6;
354 sa.sin6_port = htons(port);
355 memcpy(&sa.sin6_addr, address, sizeof(sa.sin6_addr));
356
357 return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
358
359 #else
360 return NULL;
361 #endif
362 }
363
364 #ifdef HAVE_LIBASYNCNS
365
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;
369 int ret;
370
371 pa_assert(m);
372 pa_assert(c);
373 pa_assert(PA_REFCNT_VALUE(c) >= 1);
374 pa_assert(c->asyncns_io_event == e);
375 pa_assert(fd >= 0);
376
377 if (asyncns_wait(c->asyncns, 0) < 0)
378 goto fail;
379
380 if (!asyncns_isdone(c->asyncns, c->asyncns_query))
381 return;
382
383 ret = asyncns_getaddrinfo_done(c->asyncns, c->asyncns_query, &res);
384 c->asyncns_query = NULL;
385
386 if (ret != 0 || !res)
387 goto fail;
388
389 if (res->ai_addr)
390 if (sockaddr_prepare(c, res->ai_addr, res->ai_addrlen) < 0)
391 goto fail;
392
393 asyncns_freeaddrinfo(res);
394
395 m->io_free(c->asyncns_io_event);
396 c->asyncns_io_event = NULL;
397 return;
398
399 fail:
400 m->io_free(c->asyncns_io_event);
401 c->asyncns_io_event = NULL;
402
403 errno = EHOSTUNREACH;
404 do_call(c);
405 return;
406
407 }
408
409 #endif
410
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;
413
414 pa_assert(m);
415 pa_assert(e);
416 pa_assert(c);
417
418 if (c->fd >= 0) {
419 pa_close(c->fd);
420 c->fd = -1;
421 }
422
423 errno = ETIMEDOUT;
424 do_call(c);
425 }
426
427 static void start_timeout(pa_socket_client *c, pa_bool_t use_rtclock) {
428 struct timeval tv;
429
430 pa_assert(c);
431 pa_assert(!c->timeout_event);
432
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);
434 }
435
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;
438 pa_parsed_address a;
439
440 pa_assert(m);
441 pa_assert(name);
442
443 if (pa_parse_address(name, &a) < 0)
444 return NULL;
445
446 if (!a.port)
447 a.port = default_port;
448
449 switch (a.type) {
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);
453 break;
454
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;
459 char port[12];
460
461 pa_snprintf(port, sizeof(port), "%u", (unsigned) a.port);
462
463 pa_zero(hints);
464 if (a.type == PA_PARSED_ADDRESS_TCP4)
465 hints.ai_family = PF_INET;
466 #ifdef HAVE_IPV6
467 else if (a.type == PA_PARSED_ADDRESS_TCP6)
468 hints.ai_family = PF_INET6;
469 #endif
470 else
471 hints.ai_family = PF_UNSPEC;
472
473 hints.ai_socktype = SOCK_STREAM;
474
475 #if defined(HAVE_LIBASYNCNS)
476 {
477 asyncns_t *asyncns;
478
479 if (!(asyncns = asyncns_new(1)))
480 goto finish;
481
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);
487 }
488 #elif defined(HAVE_GETADDRINFO)
489 {
490 int ret;
491 struct addrinfo *res = NULL;
492
493 ret = getaddrinfo(a.path_or_host, port, &hints, &res);
494
495 if (ret < 0 || !res)
496 goto finish;
497
498 if (res->ai_addr) {
499 if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen)))
500 start_timeout(c, use_rtclock);
501 }
502
503 freeaddrinfo(res);
504 }
505 #else
506 {
507 struct hostent *host = NULL;
508 struct sockaddr_in s;
509
510 #ifdef HAVE_IPV6
511 /* FIXME: PF_INET6 support */
512 if (hints.ai_family == PF_INET6) {
513 pa_log_error("IPv6 is not supported on Windows");
514 goto finish;
515 }
516 #endif
517
518 host = gethostbyname(a.path_or_host);
519 if (!host) {
520 unsigned int addr = inet_addr(a.path_or_host);
521 if (addr != INADDR_NONE)
522 host = gethostbyaddr((char*)&addr, 4, AF_INET);
523 }
524
525 if (!host)
526 goto finish;
527
528 pa_zero(sa);
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);
532
533 if ((c = pa_socket_client_new_sockaddr(m, (struct sockaddr*)&s, sizeof(s))))
534 start_timeout(c, use_rtclock);
535 }
536 #endif /* HAVE_LIBASYNCNS */
537 }
538 }
539
540 finish:
541 pa_xfree(a.path_or_host);
542 return c;
543
544 }
545
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) {
550 pa_assert(c);
551 pa_assert(PA_REFCNT_VALUE(c) >= 1);
552
553 return c->local;
554 }