]> code.delx.au - pulseaudio/blob - src/pulsecore/socket-client.c
b9d695055c2a56a9f5c8f2e6e1c787b5afa836ef
[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 = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) {
261 pa_log("socket(): %s", pa_cstrerror(errno));
262 return -1;
263 }
264
265 pa_make_fd_cloexec(c->fd);
266
267 #ifdef HAVE_IPV6
268 if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)
269 #else
270 if (sa->sa_family == AF_INET)
271 #endif
272 pa_make_tcp_socket_low_delay(c->fd);
273 else
274 pa_make_socket_low_delay(c->fd);
275
276 if (do_connect(c, sa, (socklen_t) salen) < 0)
277 return -1;
278
279 return 0;
280 }
281
282 pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) {
283 pa_socket_client *c;
284
285 pa_assert(m);
286 pa_assert(sa);
287 pa_assert(salen > 0);
288
289 c = socket_client_new(m);
290
291 if (sockaddr_prepare(c, sa, salen) < 0)
292 goto fail;
293
294 return c;
295
296 fail:
297 pa_socket_client_unref(c);
298 return NULL;
299 }
300
301 static void socket_client_free(pa_socket_client *c) {
302 pa_assert(c);
303 pa_assert(c->mainloop);
304
305 free_events(c);
306
307 if (c->fd >= 0)
308 pa_close(c->fd);
309
310 #ifdef HAVE_LIBASYNCNS
311 if (c->asyncns_query)
312 asyncns_cancel(c->asyncns, c->asyncns_query);
313 if (c->asyncns)
314 asyncns_free(c->asyncns);
315 if (c->asyncns_io_event)
316 c->mainloop->io_free(c->asyncns_io_event);
317 #endif
318
319 pa_xfree(c);
320 }
321
322 void pa_socket_client_unref(pa_socket_client *c) {
323 pa_assert(c);
324 pa_assert(PA_REFCNT_VALUE(c) >= 1);
325
326 if (PA_REFCNT_DEC(c) <= 0)
327 socket_client_free(c);
328 }
329
330 pa_socket_client* pa_socket_client_ref(pa_socket_client *c) {
331 pa_assert(c);
332 pa_assert(PA_REFCNT_VALUE(c) >= 1);
333
334 PA_REFCNT_INC(c);
335 return c;
336 }
337
338 void pa_socket_client_set_callback(pa_socket_client *c, pa_socket_client_cb_t on_connection, void *userdata) {
339 pa_assert(c);
340 pa_assert(PA_REFCNT_VALUE(c) >= 1);
341
342 c->callback = on_connection;
343 c->userdata = userdata;
344 }
345
346 pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port) {
347 #ifdef HAVE_IPV6
348 struct sockaddr_in6 sa;
349
350 pa_assert(m);
351 pa_assert(address);
352 pa_assert(port > 0);
353
354 pa_zero(sa);
355 sa.sin6_family = AF_INET6;
356 sa.sin6_port = htons(port);
357 memcpy(&sa.sin6_addr, address, sizeof(sa.sin6_addr));
358
359 return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
360
361 #else
362 return NULL;
363 #endif
364 }
365
366 #ifdef HAVE_LIBASYNCNS
367
368 static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
369 pa_socket_client *c = userdata;
370 struct addrinfo *res = NULL;
371 int ret;
372
373 pa_assert(m);
374 pa_assert(c);
375 pa_assert(PA_REFCNT_VALUE(c) >= 1);
376 pa_assert(c->asyncns_io_event == e);
377 pa_assert(fd >= 0);
378
379 if (asyncns_wait(c->asyncns, 0) < 0)
380 goto fail;
381
382 if (!asyncns_isdone(c->asyncns, c->asyncns_query))
383 return;
384
385 ret = asyncns_getaddrinfo_done(c->asyncns, c->asyncns_query, &res);
386 c->asyncns_query = NULL;
387
388 if (ret != 0 || !res)
389 goto fail;
390
391 if (res->ai_addr)
392 sockaddr_prepare(c, res->ai_addr, res->ai_addrlen);
393
394 asyncns_freeaddrinfo(res);
395
396 m->io_free(c->asyncns_io_event);
397 c->asyncns_io_event = NULL;
398 return;
399
400 fail:
401 m->io_free(c->asyncns_io_event);
402 c->asyncns_io_event = NULL;
403
404 errno = EHOSTUNREACH;
405 do_call(c);
406 return;
407
408 }
409
410 #endif
411
412 static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
413 pa_socket_client *c = userdata;
414
415 pa_assert(m);
416 pa_assert(e);
417 pa_assert(c);
418
419 if (c->fd >= 0) {
420 pa_close(c->fd);
421 c->fd = -1;
422 }
423
424 errno = ETIMEDOUT;
425 do_call(c);
426 }
427
428 static void start_timeout(pa_socket_client *c, pa_bool_t use_rtclock) {
429 struct timeval tv;
430
431 pa_assert(c);
432 pa_assert(!c->timeout_event);
433
434 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);
435 }
436
437 pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, pa_bool_t use_rtclock, const char*name, uint16_t default_port) {
438 pa_socket_client *c = NULL;
439 pa_parsed_address a;
440
441 pa_assert(m);
442 pa_assert(name);
443
444 if (pa_parse_address(name, &a) < 0)
445 return NULL;
446
447 if (!a.port)
448 a.port = default_port;
449
450 switch (a.type) {
451 case PA_PARSED_ADDRESS_UNIX:
452 if ((c = pa_socket_client_new_unix(m, a.path_or_host)))
453 start_timeout(c, use_rtclock);
454 break;
455
456 case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */
457 case PA_PARSED_ADDRESS_TCP6: /* Fallthrough */
458 case PA_PARSED_ADDRESS_TCP_AUTO: {
459 struct addrinfo hints;
460 char port[12];
461
462 pa_snprintf(port, sizeof(port), "%u", (unsigned) a.port);
463
464 pa_zero(hints);
465 if (a.type == PA_PARSED_ADDRESS_TCP4)
466 hints.ai_family = PF_INET;
467 #ifdef HAVE_IPV6
468 else if (a.type == PA_PARSED_ADDRESS_TCP6)
469 hints.ai_family = PF_INET6;
470 #endif
471 else
472 hints.ai_family = PF_UNSPEC;
473
474 hints.ai_socktype = SOCK_STREAM;
475
476 #if defined(HAVE_LIBASYNCNS)
477 {
478 asyncns_t *asyncns;
479
480 if (!(asyncns = asyncns_new(1)))
481 goto finish;
482
483 c = socket_client_new(m);
484 c->asyncns = asyncns;
485 c->asyncns_io_event = m->io_new(m, asyncns_fd(c->asyncns), PA_IO_EVENT_INPUT, asyncns_cb, c);
486 pa_assert_se(c->asyncns_query = asyncns_getaddrinfo(c->asyncns, a.path_or_host, port, &hints));
487 start_timeout(c, use_rtclock);
488 }
489 #elif defined(HAVE_GETADDRINFO)
490 {
491 int ret;
492 struct addrinfo *res = NULL;
493
494 ret = getaddrinfo(a.path_or_host, port, &hints, &res);
495
496 if (ret < 0 || !res)
497 goto finish;
498
499 if (res->ai_addr) {
500 if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen)))
501 start_timeout(c, use_rtclock);
502 }
503
504 freeaddrinfo(res);
505 }
506 #else
507 {
508 struct hostent *host = NULL;
509 struct sockaddr_in s;
510
511 #ifdef HAVE_IPV6
512 /* FIXME: PF_INET6 support */
513 if (hints.ai_family == PF_INET6) {
514 pa_log_error("IPv6 is not supported on Windows");
515 goto finish;
516 }
517 #endif
518
519 host = gethostbyname(a.path_or_host);
520 if (!host) {
521 unsigned int addr = inet_addr(a.path_or_host);
522 if (addr != INADDR_NONE)
523 host = gethostbyaddr((char*)&addr, 4, AF_INET);
524 }
525
526 if (!host)
527 goto finish;
528
529 pa_zero(sa);
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);
533
534 if ((c = pa_socket_client_new_sockaddr(m, (struct sockaddr*)&s, sizeof(s))))
535 start_timeout(c, use_rtclock);
536 }
537 #endif /* HAVE_LIBASYNCNS */
538 }
539 }
540
541 finish:
542 pa_xfree(a.path_or_host);
543 return c;
544
545 }
546
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);
553
554 return c->local;
555 }