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