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