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