]> code.delx.au - pulseaudio/blob - src/pulsecore/socket-server.c
dbus: first restart timer, then dispatch it
[pulseaudio] / src / pulsecore / socket-server.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 published
9 by the Free Software Foundation; either version 2.1 of the License,
10 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 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 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 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <sys/stat.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 #ifndef SUN_LEN
41 #define SUN_LEN(ptr) \
42 ((size_t)(((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path))
43 #endif
44 #endif
45 #ifdef HAVE_ARPA_INET_H
46 #include <arpa/inet.h>
47 #endif
48 #ifdef HAVE_NETINET_IN_H
49 #include <netinet/in.h>
50 #endif
51
52 #ifdef HAVE_LIBWRAP
53 #include <tcpd.h>
54 #endif
55
56 #ifndef HAVE_INET_NTOP
57 #include "inet_ntop.h"
58 #endif
59
60 #ifndef HAVE_INET_PTON
61 #include "inet_pton.h"
62 #endif
63
64 #include "winsock.h"
65
66 #include <pulse/xmalloc.h>
67 #include <pulse/util.h>
68
69 #include <pulsecore/socket-util.h>
70 #include <pulsecore/core-util.h>
71 #include <pulsecore/log.h>
72 #include <pulsecore/macro.h>
73 #include <pulsecore/core-error.h>
74 #include <pulsecore/refcnt.h>
75
76 #include "socket-server.h"
77
78 struct pa_socket_server {
79 PA_REFCNT_DECLARE;
80 int fd;
81 char *filename;
82 char *tcpwrap_service;
83
84 pa_socket_server_on_connection_cb_t on_connection;
85 void *userdata;
86
87 pa_io_event *io_event;
88 pa_mainloop_api *mainloop;
89 enum {
90 SOCKET_SERVER_GENERIC,
91 SOCKET_SERVER_IPV4,
92 SOCKET_SERVER_UNIX,
93 SOCKET_SERVER_IPV6
94 } type;
95 };
96
97 static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
98 pa_socket_server *s = userdata;
99 pa_iochannel *io;
100 int nfd;
101
102 pa_assert(s);
103 pa_assert(PA_REFCNT_VALUE(s) >= 1);
104 pa_assert(s->mainloop == mainloop);
105 pa_assert(s->io_event == e);
106 pa_assert(e);
107 pa_assert(fd >= 0);
108 pa_assert(fd == s->fd);
109
110 pa_socket_server_ref(s);
111
112 if ((nfd = pa_accept_cloexec(fd, NULL, NULL)) < 0) {
113 pa_log("accept(): %s", pa_cstrerror(errno));
114 goto finish;
115 }
116
117 if (!s->on_connection) {
118 pa_close(nfd);
119 goto finish;
120 }
121
122 #ifdef HAVE_LIBWRAP
123
124 if (s->tcpwrap_service) {
125 struct request_info req;
126
127 request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL);
128 fromhost(&req);
129 if (!hosts_access(&req)) {
130 pa_log_warn("TCP connection refused by tcpwrap.");
131 pa_close(nfd);
132 goto finish;
133 }
134
135 pa_log_info("TCP connection accepted by tcpwrap.");
136 }
137 #endif
138
139 /* There should be a check for socket type here */
140 if (s->type == SOCKET_SERVER_IPV4)
141 pa_make_tcp_socket_low_delay(fd);
142 else
143 pa_make_socket_low_delay(fd);
144
145 pa_assert_se(io = pa_iochannel_new(s->mainloop, nfd, nfd));
146 s->on_connection(s, io, s->userdata);
147
148 finish:
149 pa_socket_server_unref(s);
150 }
151
152 pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) {
153 pa_socket_server *s;
154
155 pa_assert(m);
156 pa_assert(fd >= 0);
157
158 s = pa_xnew0(pa_socket_server, 1);
159 PA_REFCNT_INIT(s);
160 s->fd = fd;
161 s->mainloop = m;
162
163 pa_assert_se(s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s));
164
165 s->type = SOCKET_SERVER_GENERIC;
166
167 return s;
168 }
169
170 pa_socket_server* pa_socket_server_ref(pa_socket_server *s) {
171 pa_assert(s);
172 pa_assert(PA_REFCNT_VALUE(s) >= 1);
173
174 PA_REFCNT_INC(s);
175 return s;
176 }
177
178 #ifdef HAVE_SYS_UN_H
179
180 pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) {
181 int fd = -1;
182 struct sockaddr_un sa;
183 pa_socket_server *s;
184
185 pa_assert(m);
186 pa_assert(filename);
187
188 if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) {
189 pa_log("socket(): %s", pa_cstrerror(errno));
190 goto fail;
191 }
192
193 memset(&sa, 0, sizeof(sa));
194 sa.sun_family = AF_UNIX;
195 pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path));
196
197 pa_make_socket_low_delay(fd);
198
199 if (bind(fd, (struct sockaddr*) &sa, (socklen_t) SUN_LEN(&sa)) < 0) {
200 pa_log("bind(): %s", pa_cstrerror(errno));
201 goto fail;
202 }
203
204 /* Allow access from all clients. Sockets like this one should
205 * always be put inside a directory with proper access rights,
206 * because not all OS check the access rights on the socket
207 * inodes. */
208 chmod(filename, 0777);
209
210 if (listen(fd, 5) < 0) {
211 pa_log("listen(): %s", pa_cstrerror(errno));
212 goto fail;
213 }
214
215 pa_assert_se(s = pa_socket_server_new(m, fd));
216
217 s->filename = pa_xstrdup(filename);
218 s->type = SOCKET_SERVER_UNIX;
219
220 return s;
221
222 fail:
223 if (fd >= 0)
224 pa_close(fd);
225
226 return NULL;
227 }
228
229 #else /* HAVE_SYS_UN_H */
230
231 pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) {
232 return NULL;
233 }
234
235 #endif /* HAVE_SYS_UN_H */
236
237 pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
238 pa_socket_server *ss;
239 int fd = -1;
240 struct sockaddr_in sa;
241 int on = 1;
242
243 pa_assert(m);
244 pa_assert(port);
245
246 if ((fd = pa_socket_cloexec(PF_INET, SOCK_STREAM, 0)) < 0) {
247 pa_log("socket(PF_INET): %s", pa_cstrerror(errno));
248 goto fail;
249 }
250
251 #ifdef SO_REUSEADDR
252 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
253 pa_log("setsockopt(): %s", pa_cstrerror(errno));
254 #endif
255
256 pa_make_tcp_socket_low_delay(fd);
257
258 memset(&sa, 0, sizeof(sa));
259 sa.sin_family = AF_INET;
260 sa.sin_port = htons(port);
261 sa.sin_addr.s_addr = htonl(address);
262
263 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
264
265 if (errno == EADDRINUSE && fallback) {
266 sa.sin_port = 0;
267
268 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
269 goto good;
270 }
271
272 pa_log("bind(): %s", pa_cstrerror(errno));
273 goto fail;
274
275 good:
276 ;
277 }
278
279 if (listen(fd, 5) < 0) {
280 pa_log("listen(): %s", pa_cstrerror(errno));
281 goto fail;
282 }
283
284 if ((ss = pa_socket_server_new(m, fd))) {
285 ss->type = SOCKET_SERVER_IPV4;
286 ss->tcpwrap_service = pa_xstrdup(tcpwrap_service);
287 }
288
289 return ss;
290
291 fail:
292 if (fd >= 0)
293 pa_close(fd);
294
295 return NULL;
296 }
297
298 #ifdef HAVE_IPV6
299 pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
300 pa_socket_server *ss;
301 int fd = -1;
302 struct sockaddr_in6 sa;
303 int on;
304
305 pa_assert(m);
306 pa_assert(port > 0);
307
308 if ((fd = pa_socket_cloexec(PF_INET6, SOCK_STREAM, 0)) < 0) {
309 pa_log("socket(PF_INET6): %s", pa_cstrerror(errno));
310 goto fail;
311 }
312
313 #ifdef IPV6_V6ONLY
314 on = 1;
315 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
316 pa_log("setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", pa_cstrerror(errno));
317 #endif
318
319 #ifdef SO_REUSEADDR
320 on = 1;
321 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
322 pa_log("setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", pa_cstrerror(errno));
323 #endif
324
325 pa_make_tcp_socket_low_delay(fd);
326
327 memset(&sa, 0, sizeof(sa));
328 sa.sin6_family = AF_INET6;
329 sa.sin6_port = htons(port);
330 memcpy(sa.sin6_addr.s6_addr, address, 16);
331
332 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
333
334 if (errno == EADDRINUSE && fallback) {
335 sa.sin6_port = 0;
336
337 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
338 goto good;
339 }
340
341 pa_log("bind(): %s", pa_cstrerror(errno));
342 goto fail;
343
344 good:
345 ;
346 }
347
348 if (listen(fd, 5) < 0) {
349 pa_log("listen(): %s", pa_cstrerror(errno));
350 goto fail;
351 }
352
353 if ((ss = pa_socket_server_new(m, fd))) {
354 ss->type = SOCKET_SERVER_IPV6;
355 ss->tcpwrap_service = pa_xstrdup(tcpwrap_service);
356 }
357
358 return ss;
359
360 fail:
361 if (fd >= 0)
362 pa_close(fd);
363
364 return NULL;
365 }
366 #endif
367
368 pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
369 pa_assert(m);
370 pa_assert(port > 0);
371
372 return pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, fallback, tcpwrap_service);
373 }
374
375 #ifdef HAVE_IPV6
376 pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
377 pa_assert(m);
378 pa_assert(port > 0);
379
380 return pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, fallback, tcpwrap_service);
381 }
382 #endif
383
384 pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
385 pa_assert(m);
386 pa_assert(port > 0);
387
388 return pa_socket_server_new_ipv4(m, INADDR_ANY, port, fallback, tcpwrap_service);
389 }
390
391 #ifdef HAVE_IPV6
392 pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
393 pa_assert(m);
394 pa_assert(port > 0);
395
396 return pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, fallback, tcpwrap_service);
397 }
398 #endif
399
400 pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
401 struct in_addr ipv4;
402
403 pa_assert(m);
404 pa_assert(name);
405 pa_assert(port > 0);
406
407 if (inet_pton(AF_INET, name, &ipv4) > 0)
408 return pa_socket_server_new_ipv4(m, ntohl(ipv4.s_addr), port, fallback, tcpwrap_service);
409
410 return NULL;
411 }
412
413 #ifdef HAVE_IPV6
414 pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
415 struct in6_addr ipv6;
416
417 pa_assert(m);
418 pa_assert(name);
419 pa_assert(port > 0);
420
421 if (inet_pton(AF_INET6, name, &ipv6) > 0)
422 return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, fallback, tcpwrap_service);
423
424 return NULL;
425 }
426 #endif
427
428 static void socket_server_free(pa_socket_server*s) {
429 pa_assert(s);
430
431 if (s->filename) {
432 unlink(s->filename);
433 pa_xfree(s->filename);
434 }
435
436 pa_close(s->fd);
437
438 pa_xfree(s->tcpwrap_service);
439
440 s->mainloop->io_free(s->io_event);
441 pa_xfree(s);
442 }
443
444 void pa_socket_server_unref(pa_socket_server *s) {
445 pa_assert(s);
446 pa_assert(PA_REFCNT_VALUE(s) >= 1);
447
448 if (PA_REFCNT_DEC(s) <= 0)
449 socket_server_free(s);
450 }
451
452 void pa_socket_server_set_callback(pa_socket_server*s, pa_socket_server_on_connection_cb_t on_connection, void *userdata) {
453 pa_assert(s);
454 pa_assert(PA_REFCNT_VALUE(s) >= 1);
455
456 s->on_connection = on_connection;
457 s->userdata = userdata;
458 }
459
460 char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
461 pa_assert(s);
462 pa_assert(PA_REFCNT_VALUE(s) >= 1);
463 pa_assert(c);
464 pa_assert(l > 0);
465
466 switch (s->type) {
467 #ifdef HAVE_IPV6
468 case SOCKET_SERVER_IPV6: {
469 struct sockaddr_in6 sa;
470 socklen_t sa_len = sizeof(sa);
471
472 if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
473 pa_log("getsockname(): %s", pa_cstrerror(errno));
474 return NULL;
475 }
476
477 if (memcmp(&in6addr_any, &sa.sin6_addr, sizeof(in6addr_any)) == 0) {
478 char fqdn[256];
479 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
480 return NULL;
481
482 pa_snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port));
483
484 } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) {
485 char *id;
486
487 if (!(id = pa_machine_id()))
488 return NULL;
489
490 pa_snprintf(c, l, "{%s}tcp6:localhost:%u", id, (unsigned) ntohs(sa.sin6_port));
491 pa_xfree(id);
492 } else {
493 char ip[INET6_ADDRSTRLEN];
494
495 if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) {
496 pa_log("inet_ntop(): %s", pa_cstrerror(errno));
497 return NULL;
498 }
499
500 pa_snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port));
501 }
502
503 return c;
504 }
505 #endif
506
507 case SOCKET_SERVER_IPV4: {
508 struct sockaddr_in sa;
509 socklen_t sa_len = sizeof(sa);
510
511 if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
512 pa_log("getsockname(): %s", pa_cstrerror(errno));
513 return NULL;
514 }
515
516 if (sa.sin_addr.s_addr == INADDR_ANY) {
517 char fqdn[256];
518 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
519 return NULL;
520
521 pa_snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port));
522 } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) {
523 char *id;
524
525 if (!(id = pa_machine_id()))
526 return NULL;
527
528 pa_snprintf(c, l, "{%s}tcp:localhost:%u", id, (unsigned) ntohs(sa.sin_port));
529 pa_xfree(id);
530 } else {
531 char ip[INET_ADDRSTRLEN];
532
533 if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) {
534 pa_log("inet_ntop(): %s", pa_cstrerror(errno));
535 return NULL;
536 }
537
538 pa_snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port));
539 }
540
541 return c;
542 }
543
544 case SOCKET_SERVER_UNIX: {
545 char *id;
546
547 if (!s->filename)
548 return NULL;
549
550 if (!(id = pa_machine_id()))
551 return NULL;
552
553 pa_snprintf(c, l, "{%s}unix:%s", id, s->filename);
554 pa_xfree(id);
555 return c;
556 }
557
558 default:
559 return NULL;
560 }
561 }