]> code.delx.au - pulseaudio/blob - polyp/socket-client.c
add simple hardware auto detection module
[pulseaudio] / polyp / socket-client.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
10
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 /* #undef HAVE_LIBASYNCNS */
27
28 #include <unistd.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <assert.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 "winsock.h"
56
57 #include "socket-client.h"
58 #include "socket-util.h"
59 #include "util.h"
60 #include "xmalloc.h"
61 #include "log.h"
62 #include "parseaddr.h"
63
64 #define CONNECT_TIMEOUT 5
65
66 struct pa_socket_client {
67 int ref;
68 pa_mainloop_api *mainloop;
69 int fd;
70 pa_io_event *io_event;
71 pa_time_event *timeout_event;
72 pa_defer_event *defer_event;
73 void (*callback)(pa_socket_client*c, pa_iochannel *io, void *userdata);
74 void *userdata;
75 int local;
76 #ifdef HAVE_LIBASYNCNS
77 asyncns_t *asyncns;
78 asyncns_query_t * asyncns_query;
79 pa_io_event *asyncns_io_event;
80 #endif
81 };
82
83 static pa_socket_client*pa_socket_client_new(pa_mainloop_api *m) {
84 pa_socket_client *c;
85 assert(m);
86
87 c = pa_xmalloc(sizeof(pa_socket_client));
88 c->ref = 1;
89 c->mainloop = m;
90 c->fd = -1;
91 c->io_event = NULL;
92 c->defer_event = NULL;
93 c->timeout_event = NULL;
94 c->callback = NULL;
95 c->userdata = NULL;
96 c->local = 0;
97
98 #ifdef HAVE_LIBASYNCNS
99 c->asyncns = NULL;
100 c->asyncns_io_event = NULL;
101 c->asyncns_query = NULL;
102 #endif
103
104 return c;
105 }
106
107 static void free_events(pa_socket_client *c) {
108 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->defer_event) {
116 c->mainloop->defer_free(c->defer_event);
117 c->defer_event = NULL;
118 }
119
120 if (c->timeout_event) {
121 c->mainloop->time_free(c->timeout_event);
122 c->timeout_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 assert(c && c->callback);
131
132 pa_socket_client_ref(c);
133
134 if (c->fd < 0)
135 goto finish;
136
137 lerror = sizeof(error);
138 if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &lerror) < 0) {
139 pa_log(__FILE__": getsockopt(): %s\n", strerror(errno));
140 goto finish;
141 }
142
143 if (lerror != sizeof(error)) {
144 pa_log(__FILE__": getsockopt() returned invalid size.\n");
145 goto finish;
146 }
147
148 if (error != 0) {
149 pa_log_debug(__FILE__": connect(): %s\n", strerror(error));
150 errno = error;
151 goto finish;
152 }
153
154 io = pa_iochannel_new(c->mainloop, c->fd, c->fd);
155 assert(io);
156
157 finish:
158 if (!io && c->fd >= 0)
159 close(c->fd);
160 c->fd = -1;
161
162 free_events(c);
163
164 assert(c->callback);
165 c->callback(c, io, c->userdata);
166
167 pa_socket_client_unref(c);
168 }
169
170 static void connect_fixed_cb(pa_mainloop_api *m, pa_defer_event *e, void *userdata) {
171 pa_socket_client *c = userdata;
172 assert(m && c && c->defer_event == e);
173 do_call(c);
174 }
175
176 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) {
177 pa_socket_client *c = userdata;
178 assert(m && c && c->io_event == e && fd >= 0);
179 do_call(c);
180 }
181
182 static int do_connect(pa_socket_client *c, const struct sockaddr *sa, socklen_t len) {
183 int r;
184 assert(c && sa && len);
185
186 pa_make_nonblock_fd(c->fd);
187
188 if ((r = connect(c->fd, sa, len)) < 0) {
189 if (errno != EINPROGRESS) {
190 /*pa_log(__FILE__": connect(): %s\n", strerror(errno));*/
191 return -1;
192 }
193
194 c->io_event = c->mainloop->io_new(c->mainloop, c->fd, PA_IO_EVENT_OUTPUT, connect_io_cb, c);
195 assert(c->io_event);
196 } else {
197 c->defer_event = c->mainloop->defer_new(c->mainloop, connect_fixed_cb, c);
198 assert(c->defer_event);
199 }
200
201 return 0;
202 }
203
204 pa_socket_client* pa_socket_client_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port) {
205 struct sockaddr_in sa;
206 assert(m && port > 0);
207
208 memset(&sa, 0, sizeof(sa));
209 sa.sin_family = AF_INET;
210 sa.sin_port = htons(port);
211 sa.sin_addr.s_addr = htonl(address);
212
213 return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
214 }
215
216 #ifdef HAVE_SYS_UN_H
217
218 pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) {
219 struct sockaddr_un sa;
220 assert(m && filename);
221
222 memset(&sa, 0, sizeof(sa));
223 sa.sun_family = AF_UNIX;
224 strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1);
225 sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
226
227 return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
228 }
229
230 #else /* HAVE_SYS_UN_H */
231
232 pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename) {
233 return NULL;
234 }
235
236 #endif /* HAVE_SYS_UN_H */
237
238 static int sockaddr_prepare(pa_socket_client *c, const struct sockaddr *sa, size_t salen) {
239 assert(c);
240 assert(sa);
241 assert(salen);
242
243 switch (sa->sa_family) {
244 case AF_UNIX:
245 c->local = 1;
246 break;
247
248 case AF_INET:
249 c->local = ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK;
250 break;
251
252 case AF_INET6:
253 c->local = memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0;
254 break;
255
256 default:
257 c->local = 0;
258 }
259
260 if ((c->fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) {
261 pa_log(__FILE__": socket(): %s\n", strerror(errno));
262 return -1;
263 }
264
265 pa_fd_set_cloexec(c->fd, 1);
266 if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6)
267 pa_socket_tcp_low_delay(c->fd);
268 else
269 pa_socket_low_delay(c->fd);
270
271 if (do_connect(c, sa, salen) < 0)
272 return -1;
273
274 return 0;
275 }
276
277 pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen) {
278 pa_socket_client *c;
279 assert(m && sa);
280 c = pa_socket_client_new(m);
281 assert(c);
282
283 if (sockaddr_prepare(c, sa, salen) < 0)
284 goto fail;
285
286 return c;
287
288 fail:
289 pa_socket_client_unref(c);
290 return NULL;
291
292 }
293
294 static void socket_client_free(pa_socket_client *c) {
295 assert(c && c->mainloop);
296
297
298 free_events(c);
299
300 if (c->fd >= 0)
301 close(c->fd);
302
303 #ifdef HAVE_LIBASYNCNS
304 if (c->asyncns_query)
305 asyncns_cancel(c->asyncns, c->asyncns_query);
306 if (c->asyncns)
307 asyncns_free(c->asyncns);
308 if (c->asyncns_io_event)
309 c->mainloop->io_free(c->asyncns_io_event);
310 #endif
311
312 pa_xfree(c);
313 }
314
315 void pa_socket_client_unref(pa_socket_client *c) {
316 assert(c && c->ref >= 1);
317
318 if (!(--(c->ref)))
319 socket_client_free(c);
320 }
321
322 pa_socket_client* pa_socket_client_ref(pa_socket_client *c) {
323 assert(c && c->ref >= 1);
324 c->ref++;
325 return c;
326 }
327
328 void pa_socket_client_set_callback(pa_socket_client *c, void (*on_connection)(pa_socket_client *c, pa_iochannel*io, void *userdata), void *userdata) {
329 assert(c);
330 c->callback = on_connection;
331 c->userdata = userdata;
332 }
333
334 pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[16], uint16_t port) {
335 struct sockaddr_in6 sa;
336
337 memset(&sa, 0, sizeof(sa));
338 sa.sin6_family = AF_INET6;
339 sa.sin6_port = htons(port);
340 memcpy(&sa.sin6_addr, address, sizeof(sa.sin6_addr));
341
342 return pa_socket_client_new_sockaddr(m, (struct sockaddr*) &sa, sizeof(sa));
343 }
344
345 #ifdef HAVE_LIBASYNCNS
346
347 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) {
348 pa_socket_client *c = userdata;
349 struct addrinfo *res = NULL;
350 int ret;
351 assert(m && c && c->asyncns_io_event == e && fd >= 0);
352
353 if (asyncns_wait(c->asyncns, 0) < 0)
354 goto fail;
355
356 if (!asyncns_isdone(c->asyncns, c->asyncns_query))
357 return;
358
359 ret = asyncns_getaddrinfo_done(c->asyncns, c->asyncns_query, &res);
360 c->asyncns_query = NULL;
361
362 if (ret != 0 || !res)
363 goto fail;
364
365 if (res->ai_addr)
366 sockaddr_prepare(c, res->ai_addr, res->ai_addrlen);
367
368 asyncns_freeaddrinfo(res);
369
370 goto finish;
371
372 fail:
373 errno == EHOSTUNREACH;
374 do_call(c);
375
376 finish:
377
378 m->io_free(c->asyncns_io_event);
379 c->asyncns_io_event = NULL;
380 }
381
382 #endif
383
384 static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *tv, void *userdata) {
385 pa_socket_client *c = userdata;
386 assert(m);
387 assert(e);
388 assert(tv);
389 assert(c);
390
391 if (c->fd >= 0) {
392 close(c->fd);
393 c->fd = -1;
394 }
395
396 errno = ETIMEDOUT;
397 do_call(c);
398 }
399
400 static void start_timeout(pa_socket_client *c) {
401 struct timeval tv;
402 assert(c);
403 assert(!c->timeout_event);
404
405 pa_gettimeofday(&tv);
406 pa_timeval_add(&tv, CONNECT_TIMEOUT * 1000000);
407 c->timeout_event = c->mainloop->time_new(c->mainloop, &tv, timeout_cb, c);
408 }
409
410 pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*name, uint16_t default_port) {
411 pa_socket_client *c = NULL;
412 pa_parsed_address a;
413 assert(m && name);
414
415 if (pa_parse_address(name, &a) < 0)
416 return NULL;
417
418 if (!a.port)
419 a.port = default_port;
420
421 switch (a.type) {
422 case PA_PARSED_ADDRESS_UNIX:
423 if ((c = pa_socket_client_new_unix(m, a.path_or_host)))
424 start_timeout(c);
425 break;
426
427 case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */
428 case PA_PARSED_ADDRESS_TCP6: /* Fallthrough */
429 case PA_PARSED_ADDRESS_TCP_AUTO:{
430
431 struct addrinfo hints;
432 char port[12];
433
434 snprintf(port, sizeof(port), "%u", (unsigned) a.port);
435
436 memset(&hints, 0, sizeof(hints));
437 hints.ai_family = a.type == PA_PARSED_ADDRESS_TCP4 ? PF_INET : (a.type == PA_PARSED_ADDRESS_TCP6 ? PF_INET6 : PF_UNSPEC);
438 hints.ai_socktype = SOCK_STREAM;
439
440 #ifdef HAVE_LIBASYNCNS
441 {
442 asyncns_t *asyncns;
443
444 if (!(asyncns = asyncns_new(1)))
445 goto finish;
446
447 c = pa_socket_client_new(m);
448 c->asyncns = asyncns;
449 c->asyncns_io_event = m->io_new(m, asyncns_fd(c->asyncns), PA_IO_EVENT_INPUT, asyncns_cb, c);
450 c->asyncns_query = asyncns_getaddrinfo(c->asyncns, a.path_or_host, port, &hints);
451 assert(c->asyncns_query);
452 start_timeout(c);
453 }
454 #else /* HAVE_LIBASYNCNS */
455 {
456 #ifdef HAVE_GETADDRINFO
457 int ret;
458 struct addrinfo *res = NULL;
459
460 ret = getaddrinfo(a.path_or_host, port, &hints, &res);
461
462 if (ret < 0 || !res)
463 goto finish;
464
465 if (res->ai_addr) {
466 if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen)))
467 start_timeout(c);
468 }
469
470 freeaddrinfo(res);
471 #else /* HAVE_GETADDRINFO */
472 struct hostent *host = NULL;
473 struct sockaddr_in s;
474
475 /* FIXME: PF_INET6 support */
476 if (hints.ai_family != PF_INET)
477 goto finish;
478
479 host = gethostbyname(a.path_or_host);
480 if (!host) {
481 unsigned int addr = inet_addr(a.path_or_host);
482 if (addr != INADDR_NONE)
483 host = gethostbyaddr((char*)&addr, 4, AF_INET);
484 }
485
486 if (!host)
487 goto finish;
488
489 s.sin_family = AF_INET;
490 memcpy(&s.sin_addr, host->h_addr, sizeof(struct in_addr));
491 s.sin_port = port;
492
493 if ((c = pa_socket_client_new_sockaddr(m, &s, sizeof(s))))
494 start_timeout(c);
495 #endif /* HAVE_GETADDRINFO */
496 }
497 #endif /* HAVE_LIBASYNCNS */
498 }
499 }
500
501 finish:
502 pa_xfree(a.path_or_host);
503 return c;
504
505 }
506
507 /* Return non-zero when the target sockaddr is considered
508 local. "local" means UNIX socket or TCP socket on localhost. Other
509 local IP addresses are not considered local. */
510 int pa_socket_client_is_local(pa_socket_client *c) {
511 assert(c);
512 return c->local;
513 }