]> code.delx.au - pulseaudio/blob - src/pulsecore/socket-client.c
merge 'lennart' branch back into trunk.
[pulseaudio] / src / pulsecore / socket-client.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
8
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.
13
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.
18
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 ***/
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 /* #undef HAVE_LIBASYNCNS */
30
31 #include <unistd.h>
32 #include <stdio.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <stdlib.h>
36
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
52
53 #ifdef HAVE_LIBASYNCNS
54 #include <asyncns.h>
55 #endif
56
57 #include <pulse/timeval.h>
58 #include <pulse/xmalloc.h>
59
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>
68
69 #include "socket-client.h"
70
71 #define CONNECT_TIMEOUT 5
72
73 struct pa_socket_client {
74 PA_REFCNT_DECLARE;
75 pa_mainloop_api *mainloop;
76 int fd;
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);
81 void *userdata;
82 int local;
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 static pa_socket_client*pa_socket_client_new(pa_mainloop_api *m) {
91 pa_socket_client *c;
92 pa_assert(m);
93
94 c = pa_xnew(pa_socket_client, 1);
95 PA_REFCNT_INIT(c);
96 c->mainloop = m;
97 c->fd = -1;
98 c->io_event = NULL;
99 c->defer_event = NULL;
100 c->timeout_event = NULL;
101 c->callback = NULL;
102 c->userdata = NULL;
103 c->local = 0;
104
105 #ifdef HAVE_LIBASYNCNS
106 c->asyncns = NULL;
107 c->asyncns_io_event = NULL;
108 c->asyncns_query = NULL;
109 #endif
110
111 return c;
112 }
113
114 static void free_events(pa_socket_client *c) {
115 pa_assert(c);
116
117 if (c->io_event) {
118 c->mainloop->io_free(c->io_event);
119 c->io_event = NULL;
120 }
121
122 if (c->defer_event) {
123 c->mainloop->defer_free(c->defer_event);
124 c->defer_event = NULL;
125 }
126
127 if (c->timeout_event) {
128 c->mainloop->time_free(c->timeout_event);
129 c->timeout_event = NULL;
130 }
131 }
132
133 static void do_call(pa_socket_client *c) {
134 pa_iochannel *io = NULL;
135 int error;
136 socklen_t lerror;
137
138 pa_assert(c);
139 pa_assert(PA_REFCNT_VALUE(c) >= 1);
140 pa_assert(c->callback);
141
142 pa_socket_client_ref(c);
143
144 if (c->fd < 0)
145 goto finish;
146
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));
150 goto finish;
151 }
152
153 if (lerror != sizeof(error)) {
154 pa_log("getsockopt() returned invalid size.");
155 goto finish;
156 }
157
158 if (error != 0) {
159 pa_log_debug("connect(): %s", pa_cstrerror(error));
160 errno = error;
161 goto finish;
162 }
163
164 io = pa_iochannel_new(c->mainloop, c->fd, c->fd);
165 pa_assert(io);
166
167 finish:
168 if (!io && c->fd >= 0)
169 pa_close(c->fd);
170 c->fd = -1;
171
172 free_events(c);
173
174 pa_assert(c->callback);
175 c->callback(c, io, c->userdata);
176
177 pa_socket_client_unref(c);
178 }
179
180 static void connect_fixed_cb(pa_mainloop_api *m, pa_defer_event *e, void *userdata) {
181 pa_socket_client *c = userdata;
182
183 pa_assert(m);
184 pa_assert(c);
185 pa_assert(PA_REFCNT_VALUE(c) >= 1);
186 pa_assert(c->defer_event == e);
187
188 do_call(c);
189 }
190
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;
193
194 pa_assert(m);
195 pa_assert(c);
196 pa_assert(PA_REFCNT_VALUE(c) >= 1);
197 pa_assert(c->io_event == e);
198 pa_assert(fd >= 0);
199
200 do_call(c);
201 }
202
203 static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t len) {
204 int r;
205
206 pa_assert(c);
207 pa_assert(PA_REFCNT_VALUE(c) >= 1);
208 pa_assert(sa);
209 pa_assert(len > 0);
210
211 pa_make_fd_nonblock(c->fd);
212
213 if ((r = connect(c->fd, sa, len)) < 0) {
214 #ifdef OS_IS_WIN32
215 if (WSAGetLastError() != EWOULDBLOCK) {
216 pa_log_debug("connect(): %d", WSAGetLastError());
217 #else
218 if (errno != EINPROGRESS) {
219 pa_log_debug("connect(): %s (%d)", pa_cstrerror(errno), errno);
220 #endif
221 return -1;
222 }
223
224 pa_assert_se(c->io_event = c->mainloop->io_new(c->mainloop, c->fd, PA_IO_EVENT_OUTPUT, connect_io_cb, c));
225 } else
226 pa_assert_se(c->defer_event = c->mainloop->defer_new(c->mainloop, connect_fixed_cb, c));
227
228 return 0;
229 }
230
231 pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port) {
232 struct sockaddr_in sa;
233
234 pa_assert(m);
235 pa_assert(port > 0);
236
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);
241
242 return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
243 }
244
245 #ifdef HAVE_SYS_UN_H
246
247 pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) {
248 struct sockaddr_un sa;
249
250 pa_assert(m);
251 pa_assert(filename);
252
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;
257
258 return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
259 }
260
261 #else /* HAVE_SYS_UN_H */
262
263 pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) {
264 return NULL;
265 }
266
267 #endif /* HAVE_SYS_UN_H */
268
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);
273
274 switch (sa->sa_family) {
275 case AF_UNIX:
276 c->local = 1;
277 break;
278
279 case AF_INET:
280 c->local = ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK;
281 break;
282
283 case AF_INET6:
284 c->local = memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0;
285 break;
286
287 default:
288 c->local = 0;
289 }
290
291 if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) {
292 pa_log("socket(): %s", pa_cstrerror(errno));
293 return -1;
294 }
295
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);
299 else
300 pa_make_socket_low_delay(c->fd);
301
302 if (do_connect(c, sa, salen) < 0)
303 return -1;
304
305 return 0;
306 }
307
308 pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) {
309 pa_socket_client *c;
310
311 pa_assert(m);
312 pa_assert(sa);
313 pa_assert(salen > 0);
314
315 pa_assert_se(c = pa_socket_client_new(m));
316
317 if (sockaddr_prepare(c, sa, salen) < 0)
318 goto fail;
319
320 return c;
321
322 fail:
323 pa_socket_client_unref(c);
324 return NULL;
325 }
326
327 static void socket_client_free(pa_socket_client *c) {
328 pa_assert(c);
329 pa_assert(c->mainloop);
330
331 free_events(c);
332
333 if (c->fd >= 0)
334 pa_close(c->fd);
335
336 #ifdef HAVE_LIBASYNCNS
337 if (c->asyncns_query)
338 asyncns_cancel(c->asyncns, c->asyncns_query);
339 if (c->asyncns)
340 asyncns_free(c->asyncns);
341 if (c->asyncns_io_event)
342 c->mainloop->io_free(c->asyncns_io_event);
343 #endif
344
345 pa_xfree(c);
346 }
347
348 void pa_socket_client_unref(pa_socket_client *c) {
349 pa_assert(c);
350 pa_assert(PA_REFCNT_VALUE(c) >= 1);
351
352 if (PA_REFCNT_DEC(c) <= 0)
353 socket_client_free(c);
354 }
355
356 pa_socket_client* pa_socket_client_ref(pa_socket_client *c) {
357 pa_assert(c);
358 pa_assert(PA_REFCNT_VALUE(c) >= 1);
359
360 PA_REFCNT_INC(c);
361 return c;
362 }
363
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) {
365 pa_assert(c);
366 pa_assert(PA_REFCNT_VALUE(c) >= 1);
367
368 c->callback = on_connection;
369 c->userdata = userdata;
370 }
371
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;
374
375 pa_assert(m);
376 pa_assert(address);
377 pa_assert(port > 0);
378
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));
383
384 return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
385 }
386
387 #ifdef HAVE_LIBASYNCNS
388
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;
392 int ret;
393
394 pa_assert(m);
395 pa_assert(c);
396 pa_assert(PA_REFCNT_VALUE(c) >= 1);
397 pa_assert(c->asyncns_io_event == e);
398 pa_assert(fd >= 0);
399
400 if (asyncns_wait(c->asyncns, 0) < 0)
401 goto fail;
402
403 if (!asyncns_isdone(c->asyncns, c->asyncns_query))
404 return;
405
406 ret = asyncns_getaddrinfo_done(c->asyncns, c->asyncns_query, &res);
407 c->asyncns_query = NULL;
408
409 if (ret != 0 || !res)
410 goto fail;
411
412 if (res->ai_addr)
413 sockaddr_prepare(c, res->ai_addr, res->ai_addrlen);
414
415 asyncns_freeaddrinfo(res);
416
417 m->io_free(c->asyncns_io_event);
418 c->asyncns_io_event = NULL;
419 return;
420
421 fail:
422 m->io_free(c->asyncns_io_event);
423 c->asyncns_io_event = NULL;
424
425 errno = EHOSTUNREACH;
426 do_call(c);
427 return;
428
429 }
430
431 #endif
432
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;
435
436 pa_assert(m);
437 pa_assert(e);
438 pa_assert(tv);
439 pa_assert(c);
440
441 if (c->fd >= 0) {
442 pa_close(c->fd);
443 c->fd = -1;
444 }
445
446 errno = ETIMEDOUT;
447 do_call(c);
448 }
449
450 static void start_timeout(pa_socket_client *c) {
451 struct timeval tv;
452 pa_assert(c);
453 pa_assert(!c->timeout_event);
454
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);
458 }
459
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;
462 pa_parsed_address a;
463
464 pa_assert(m);
465 pa_assert(name);
466
467 if (pa_parse_address(name, &a) < 0)
468 return NULL;
469
470 if (!a.port)
471 a.port = default_port;
472
473 switch (a.type) {
474 case PA_PARSED_ADDRESS_UNIX:
475 if ((c = pa_socket_client_new_unix(m, a.path_or_host)))
476 start_timeout(c);
477 break;
478
479 case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */
480 case PA_PARSED_ADDRESS_TCP6: /* Fallthrough */
481 case PA_PARSED_ADDRESS_TCP_AUTO:{
482
483 struct addrinfo hints;
484 char port[12];
485
486 pa_snprintf(port, sizeof(port), "%u", (unsigned) a.port);
487
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;
491
492 #ifdef HAVE_LIBASYNCNS
493 {
494 asyncns_t *asyncns;
495
496 if (!(asyncns = asyncns_new(1)))
497 goto finish;
498
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);
504 start_timeout(c);
505 }
506 #else /* HAVE_LIBASYNCNS */
507 {
508 #ifdef HAVE_GETADDRINFO
509 int ret;
510 struct addrinfo *res = NULL;
511
512 ret = getaddrinfo(a.path_or_host, port, &hints, &res);
513
514 if (ret < 0 || !res)
515 goto finish;
516
517 if (res->ai_addr) {
518 if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen)))
519 start_timeout(c);
520 }
521
522 freeaddrinfo(res);
523 #else /* HAVE_GETADDRINFO */
524 struct hostent *host = NULL;
525 struct sockaddr_in s;
526
527 /* FIXME: PF_INET6 support */
528 if (hints.ai_family == PF_INET6) {
529 pa_log_error("IPv6 is not supported on Windows");
530 goto finish;
531 }
532
533 host = gethostbyname(a.path_or_host);
534 if (!host) {
535 unsigned int addr = inet_addr(a.path_or_host);
536 if (addr != INADDR_NONE)
537 host = gethostbyaddr((char*)&addr, 4, AF_INET);
538 }
539
540 if (!host)
541 goto finish;
542
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);
546
547 if ((c = pa_socket_client_new_sockaddr(m, (struct sockaddr*)&s, sizeof(s))))
548 start_timeout(c);
549 #endif /* HAVE_GETADDRINFO */
550 }
551 #endif /* HAVE_LIBASYNCNS */
552 }
553 }
554
555 finish:
556 pa_xfree(a.path_or_host);
557 return c;
558
559 }
560
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) {
565 pa_assert(c);
566 pa_assert(PA_REFCNT_VALUE(c) >= 1);
567
568 return c->local;
569 }