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