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 */