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