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
callback(pa_mainloop_api * mainloop,pa_io_event * e,int fd,pa_io_event_flags_t f,void * userdata)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
socket_server_new(pa_mainloop_api * m,int fd)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
pa_socket_server_ref(pa_socket_server * s)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
pa_socket_server_new_unix(pa_mainloop_api * m,const char * filename)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
pa_socket_server_new_unix(pa_mainloop_api * m,const char * filename)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
pa_socket_server_new_ipv4(pa_mainloop_api * m,uint32_t address,uint16_t port,bool fallback,const char * tcpwrap_service)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
pa_socket_server_new_ipv6(pa_mainloop_api * m,const uint8_t address[16],uint16_t port,bool fallback,const char * tcpwrap_service)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
pa_socket_server_new_ipv4_loopback(pa_mainloop_api * m,uint16_t port,bool fallback,const char * tcpwrap_service)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
pa_socket_server_new_ipv6_loopback(pa_mainloop_api * m,uint16_t port,bool fallback,const char * tcpwrap_service)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
pa_socket_server_new_ipv4_any(pa_mainloop_api * m,uint16_t port,bool fallback,const char * tcpwrap_service)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
pa_socket_server_new_ipv6_any(pa_mainloop_api * m,uint16_t port,bool fallback,const char * tcpwrap_service)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
pa_socket_server_new_ipv4_string(pa_mainloop_api * m,const char * name,uint16_t port,bool fallback,const char * tcpwrap_service)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
pa_socket_server_new_ipv6_string(pa_mainloop_api * m,const char * name,uint16_t port,bool fallback,const char * tcpwrap_service)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
socket_server_free(pa_socket_server * s)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
pa_socket_server_unref(pa_socket_server * s)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
pa_socket_server_set_callback(pa_socket_server * s,pa_socket_server_on_connection_cb_t on_connection,void * userdata)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
pa_socket_server_get_address(pa_socket_server * s,char * c,size_t l)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 }
645
646 #ifdef HAVE_SYS_UN_H
647
pa_unix_socket_is_stale(const char * fn)648 int pa_unix_socket_is_stale(const char *fn) {
649 struct sockaddr_un sa;
650 int fd = -1, ret = -1;
651
652 pa_assert(fn);
653
654 if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) {
655 pa_log("socket(): %s", pa_cstrerror(errno));
656 goto finish;
657 }
658
659 sa.sun_family = AF_UNIX;
660 strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1);
661 sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
662
663 if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) {
664 #if !defined(OS_IS_WIN32)
665 if (errno == ECONNREFUSED)
666 ret = 1;
667 #else
668 if (WSAGetLastError() == WSAECONNREFUSED || WSAGetLastError() == WSAEINVAL)
669 ret = 1;
670 #endif
671 } else
672 ret = 0;
673
674 finish:
675 if (fd >= 0)
676 pa_close(fd);
677
678 return ret;
679 }
680
pa_unix_socket_remove_stale(const char * fn)681 int pa_unix_socket_remove_stale(const char *fn) {
682 int r;
683
684 pa_assert(fn);
685
686 #ifdef HAVE_SYSTEMD_DAEMON
687 {
688 int n = sd_listen_fds(0);
689 if (n > 0) {
690 for (int i = 0; i < n; ++i) {
691 if (sd_is_socket_unix(SD_LISTEN_FDS_START + i, SOCK_STREAM, 1, fn, 0) > 0) {
692 /* This is a socket activated socket, therefore do not consider
693 * it stale. */
694 return 0;
695 }
696 }
697 }
698 }
699 #endif
700
701 if ((r = pa_unix_socket_is_stale(fn)) < 0)
702 return errno != ENOENT ? -1 : 0;
703
704 if (!r)
705 return 0;
706
707 /* Yes, here is a race condition. But who cares? */
708 if (unlink(fn) < 0)
709 return -1;
710
711 return 0;
712 }
713
714 #else /* HAVE_SYS_UN_H */
715
pa_unix_socket_is_stale(const char * fn)716 int pa_unix_socket_is_stale(const char *fn) {
717 return -1;
718 }
719
pa_unix_socket_remove_stale(const char * fn)720 int pa_unix_socket_remove_stale(const char *fn) {
721 return -1;
722 }
723
724 #endif /* HAVE_SYS_UN_H */
725