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