• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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