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