• 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 #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 
86 struct 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 
callback(pa_mainloop_api * mainloop,pa_io_event * e,int fd,pa_io_event_flags_t f,void * userdata)105 static 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 
156 finish:
157     pa_socket_server_unref(s);
158 }
159 
socket_server_new(pa_mainloop_api * m,int fd)160 static 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 
pa_socket_server_ref(pa_socket_server * s)176 pa_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 
pa_socket_server_new_unix(pa_mainloop_api * m,const char * filename)186 pa_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 
288 fail:
289     if (fd >= 0)
290         pa_close(fd);
291 
292     return NULL;
293 }
294 
295 #else /* HAVE_SYS_UN_H */
296 
pa_socket_server_new_unix(pa_mainloop_api * m,const char * filename)297 pa_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 
pa_socket_server_new_ipv4(pa_mainloop_api * m,uint32_t address,uint16_t port,bool fallback,const char * tcpwrap_service)303 pa_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 
376 fail:
377     if (fd >= 0)
378         pa_close(fd);
379 
380     return NULL;
381 }
382 
383 #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)384 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) {
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 
464 fail:
465     if (fd >= 0)
466         pa_close(fd);
467 
468     return NULL;
469 }
470 #endif
471 
pa_socket_server_new_ipv4_loopback(pa_mainloop_api * m,uint16_t port,bool fallback,const char * tcpwrap_service)472 pa_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
pa_socket_server_new_ipv6_loopback(pa_mainloop_api * m,uint16_t port,bool fallback,const char * tcpwrap_service)480 pa_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 
pa_socket_server_new_ipv4_any(pa_mainloop_api * m,uint16_t port,bool fallback,const char * tcpwrap_service)488 pa_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
pa_socket_server_new_ipv6_any(pa_mainloop_api * m,uint16_t port,bool fallback,const char * tcpwrap_service)496 pa_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 
pa_socket_server_new_ipv4_string(pa_mainloop_api * m,const char * name,uint16_t port,bool fallback,const char * tcpwrap_service)504 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) {
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
pa_socket_server_new_ipv6_string(pa_mainloop_api * m,const char * name,uint16_t port,bool fallback,const char * tcpwrap_service)518 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) {
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 
socket_server_free(pa_socket_server * s)532 static 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 
pa_socket_server_unref(pa_socket_server * s)547 void 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 
pa_socket_server_set_callback(pa_socket_server * s,pa_socket_server_on_connection_cb_t on_connection,void * userdata)555 void 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 
pa_socket_server_get_address(pa_socket_server * s,char * c,size_t l)563 char *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 
pa_unix_socket_is_stale(const char * fn)669 int 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 
695 finish:
696     if (fd >= 0)
697         pa_close(fd);
698 
699     return ret;
700 }
701 
pa_unix_socket_remove_stale(const char * fn)702 int 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 
pa_unix_socket_is_stale(const char * fn)737 int pa_unix_socket_is_stale(const char *fn) {
738     return -1;
739 }
740 
pa_unix_socket_remove_stale(const char * fn)741 int pa_unix_socket_remove_stale(const char *fn) {
742     return -1;
743 }
744 
745 #endif /* HAVE_SYS_UN_H */