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