• 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 #include <pulse/xmalloc.h>
62 #include <pulse/util.h>
63 
64 #include <pulsecore/socket.h>
65 #include <pulsecore/socket-util.h>
66 #include <pulsecore/core-util.h>
67 #include <pulsecore/log.h>
68 #include <pulsecore/macro.h>
69 #include <pulsecore/core-error.h>
70 #include <pulsecore/refcnt.h>
71 #include <pulsecore/arpa-inet.h>
72 
73 #include "socket-server.h"
74 
75 struct pa_socket_server {
76     PA_REFCNT_DECLARE;
77     int fd;
78     char *filename;
79     bool activated;
80     char *tcpwrap_service;
81 
82     pa_socket_server_on_connection_cb_t on_connection;
83     void *userdata;
84 
85     pa_io_event *io_event;
86     pa_mainloop_api *mainloop;
87     enum {
88         SOCKET_SERVER_IPV4,
89         SOCKET_SERVER_UNIX,
90         SOCKET_SERVER_IPV6
91     } type;
92 };
93 
callback(pa_mainloop_api * mainloop,pa_io_event * e,int fd,pa_io_event_flags_t f,void * userdata)94 static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
95     pa_socket_server *s = userdata;
96     pa_iochannel *io;
97     int nfd;
98 
99     pa_assert(s);
100     pa_assert(PA_REFCNT_VALUE(s) >= 1);
101     pa_assert(s->mainloop == mainloop);
102     pa_assert(s->io_event == e);
103     pa_assert(e);
104     pa_assert(fd >= 0);
105     pa_assert(fd == s->fd);
106 
107     pa_socket_server_ref(s);
108 
109     if ((nfd = pa_accept_cloexec(fd, NULL, NULL)) < 0) {
110         pa_log("accept(): %s", pa_cstrerror(errno));
111         goto finish;
112     }
113 
114     if (!s->on_connection) {
115         pa_close(nfd);
116         goto finish;
117     }
118 
119 #ifdef HAVE_LIBWRAP
120 
121     if (s->tcpwrap_service) {
122         struct request_info req;
123 
124         request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL);
125         fromhost(&req);
126         if (!hosts_access(&req)) {
127             pa_log_warn("TCP connection refused by tcpwrap.");
128             pa_close(nfd);
129             goto finish;
130         }
131 
132         pa_log_info("TCP connection accepted by tcpwrap.");
133     }
134 #endif
135 
136     /* There should be a check for socket type here */
137     if (s->type == SOCKET_SERVER_IPV4)
138         pa_make_tcp_socket_low_delay(nfd);
139     else
140         pa_make_socket_low_delay(nfd);
141 
142     pa_assert_se(io = pa_iochannel_new(s->mainloop, nfd, nfd));
143     s->on_connection(s, io, s->userdata);
144 
145 finish:
146     pa_socket_server_unref(s);
147 }
148 
socket_server_new(pa_mainloop_api * m,int fd)149 static pa_socket_server* socket_server_new(pa_mainloop_api *m, int fd) {
150     pa_socket_server *s;
151 
152     pa_assert(m);
153     pa_assert(fd >= 0);
154 
155     s = pa_xnew0(pa_socket_server, 1);
156     PA_REFCNT_INIT(s);
157     s->fd = fd;
158     s->mainloop = m;
159 
160     pa_assert_se(s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s));
161 
162     return s;
163 }
164 
pa_socket_server_ref(pa_socket_server * s)165 pa_socket_server* pa_socket_server_ref(pa_socket_server *s) {
166     pa_assert(s);
167     pa_assert(PA_REFCNT_VALUE(s) >= 1);
168 
169     PA_REFCNT_INC(s);
170     return s;
171 }
172 
173 #ifdef HAVE_SYS_UN_H
174 
pa_socket_server_new_unix(pa_mainloop_api * m,const char * filename)175 pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) {
176     int fd = -1;
177     bool activated = false;
178     struct sockaddr_un sa;
179     pa_socket_server *s;
180 
181     pa_assert(m);
182     pa_assert(filename);
183 
184 #ifdef HAVE_SYSTEMD_DAEMON
185     {
186         int n = sd_listen_fds(0);
187         if (n > 0) {
188             for (int i = 0; i < n; ++i) {
189                 if (sd_is_socket_unix(SD_LISTEN_FDS_START + i, SOCK_STREAM, 1, filename, 0) > 0) {
190                     fd = SD_LISTEN_FDS_START + i;
191                     activated = true;
192                     pa_log_info("Found socket activation socket for '%s' \\o/", filename);
193                     break;
194                 }
195             }
196         }
197     }
198 #endif
199 
200     if (fd < 0) {
201         if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) {
202             pa_log("socket(PF_UNIX): %s", pa_cstrerror(errno));
203             goto fail;
204         }
205 
206         memset(&sa, 0, sizeof(sa));
207         sa.sun_family = AF_UNIX;
208         pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path));
209 
210         pa_make_socket_low_delay(fd);
211 
212         if (bind(fd, (struct sockaddr*) &sa, (socklen_t) SUN_LEN(&sa)) < 0) {
213             pa_log("bind(): %s", pa_cstrerror(errno));
214             goto fail;
215         }
216 
217         /* Allow access from all clients. Sockets like this one should
218         * always be put inside a directory with proper access rights,
219         * because not all OS check the access rights on the socket
220         * inodes. */
221         chmod(filename, 0777);
222 
223         if (listen(fd, 5) < 0) {
224             pa_log("listen(): %s", pa_cstrerror(errno));
225             goto fail;
226         }
227     }
228 
229     pa_assert_se(s = socket_server_new(m, fd));
230 
231     s->filename = pa_xstrdup(filename);
232     s->type = SOCKET_SERVER_UNIX;
233     s->activated = activated;
234 
235     return s;
236 
237 fail:
238     if (fd >= 0)
239         pa_close(fd);
240 
241     return NULL;
242 }
243 
244 #else /* HAVE_SYS_UN_H */
245 
pa_socket_server_new_unix(pa_mainloop_api * m,const char * filename)246 pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) {
247     return NULL;
248 }
249 
250 #endif /* HAVE_SYS_UN_H */
251 
pa_socket_server_new_ipv4(pa_mainloop_api * m,uint32_t address,uint16_t port,bool fallback,const char * tcpwrap_service)252 pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, bool fallback, const char *tcpwrap_service) {
253     pa_socket_server *ss;
254     int fd = -1;
255     bool activated = false;
256     struct sockaddr_in sa;
257     int on = 1;
258 
259     pa_assert(m);
260     pa_assert(port);
261 
262 #ifdef HAVE_SYSTEMD_DAEMON
263     {
264         int n = sd_listen_fds(0);
265         if (n > 0) {
266             for (int i = 0; i < n; ++i) {
267                 if (sd_is_socket_inet(SD_LISTEN_FDS_START + i, AF_INET, SOCK_STREAM, 1, port) > 0) {
268                     fd = SD_LISTEN_FDS_START + i;
269                     activated = true;
270                     pa_log_info("Found socket activation socket for ipv4 in port '%d' \\o/", port);
271                     break;
272                 }
273             }
274         }
275     }
276 #endif
277 
278     if (fd < 0) {
279         if ((fd = pa_socket_cloexec(PF_INET, SOCK_STREAM, 0)) < 0) {
280             pa_log("socket(PF_INET): %s", pa_cstrerror(errno));
281             goto fail;
282         }
283 
284 #ifdef SO_REUSEADDR
285         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &on, sizeof(on)) < 0)
286             pa_log("setsockopt(): %s", pa_cstrerror(errno));
287 #endif
288 
289         pa_make_tcp_socket_low_delay(fd);
290 
291         memset(&sa, 0, sizeof(sa));
292         sa.sin_family = AF_INET;
293         sa.sin_port = htons(port);
294         sa.sin_addr.s_addr = htonl(address);
295 
296         if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
297 
298             if (errno == EADDRINUSE && fallback) {
299                 sa.sin_port = 0;
300 
301                 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
302                     pa_log("bind(): %s", pa_cstrerror(errno));
303                     goto fail;
304                 }
305             } else {
306                 pa_log("bind(): %s", pa_cstrerror(errno));
307                 goto fail;
308             }
309         }
310 
311         if (listen(fd, 5) < 0) {
312             pa_log("listen(): %s", pa_cstrerror(errno));
313             goto fail;
314         }
315     }
316 
317     pa_assert_se(ss = socket_server_new(m, fd));
318 
319     ss->type = SOCKET_SERVER_IPV4;
320     ss->tcpwrap_service = pa_xstrdup(tcpwrap_service);
321     ss->activated = activated;
322 
323     return ss;
324 
325 fail:
326     if (fd >= 0)
327         pa_close(fd);
328 
329     return NULL;
330 }
331 
332 #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)333 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) {
334     pa_socket_server *ss;
335     int fd = -1;
336     bool activated = false;
337     struct sockaddr_in6 sa;
338     int on;
339 
340     pa_assert(m);
341     pa_assert(port > 0);
342 
343 #ifdef HAVE_SYSTEMD_DAEMON
344     {
345         int n = sd_listen_fds(0);
346         if (n > 0) {
347             for (int i = 0; i < n; ++i) {
348                 if (sd_is_socket_inet(SD_LISTEN_FDS_START + i, AF_INET6, SOCK_STREAM, 1, port) > 0) {
349                     fd = SD_LISTEN_FDS_START + i;
350                     activated = true;
351                     pa_log_info("Found socket activation socket for ipv6 in port '%d' \\o/", port);
352                     break;
353                 }
354             }
355         }
356     }
357 #endif
358 
359     if (fd < 0) {
360         if ((fd = pa_socket_cloexec(PF_INET6, SOCK_STREAM, 0)) < 0) {
361             pa_log("socket(PF_INET6): %s", pa_cstrerror(errno));
362             goto fail;
363         }
364 
365 #ifdef IPV6_V6ONLY
366         on = 1;
367         if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void *) &on, sizeof(on)) < 0)
368             pa_log("setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", pa_cstrerror(errno));
369 #endif
370 
371 #ifdef SO_REUSEADDR
372         on = 1;
373         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &on, sizeof(on)) < 0)
374             pa_log("setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", pa_cstrerror(errno));
375 #endif
376 
377         pa_make_tcp_socket_low_delay(fd);
378 
379         memset(&sa, 0, sizeof(sa));
380         sa.sin6_family = AF_INET6;
381         sa.sin6_port = htons(port);
382         memcpy(sa.sin6_addr.s6_addr, address, 16);
383 
384         if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
385 
386             if (errno == EADDRINUSE && fallback) {
387                 sa.sin6_port = 0;
388 
389                 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
390                     pa_log("bind(): %s", pa_cstrerror(errno));
391                     goto fail;
392                 }
393             } else {
394                 pa_log("bind(): %s", pa_cstrerror(errno));
395                 goto fail;
396             }
397         }
398 
399         if (listen(fd, 5) < 0) {
400             pa_log("listen(): %s", pa_cstrerror(errno));
401             goto fail;
402         }
403     }
404 
405     pa_assert_se(ss = socket_server_new(m, fd));
406 
407     ss->type = SOCKET_SERVER_IPV6;
408     ss->tcpwrap_service = pa_xstrdup(tcpwrap_service);
409     ss->activated = activated;
410 
411     return ss;
412 
413 fail:
414     if (fd >= 0)
415         pa_close(fd);
416 
417     return NULL;
418 }
419 #endif
420 
pa_socket_server_new_ipv4_loopback(pa_mainloop_api * m,uint16_t port,bool fallback,const char * tcpwrap_service)421 pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, bool fallback, const char *tcpwrap_service) {
422     pa_assert(m);
423     pa_assert(port > 0);
424 
425     return pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, fallback, tcpwrap_service);
426 }
427 
428 #ifdef HAVE_IPV6
pa_socket_server_new_ipv6_loopback(pa_mainloop_api * m,uint16_t port,bool fallback,const char * tcpwrap_service)429 pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, bool fallback, const char *tcpwrap_service) {
430     pa_assert(m);
431     pa_assert(port > 0);
432 
433     return pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, fallback, tcpwrap_service);
434 }
435 #endif
436 
pa_socket_server_new_ipv4_any(pa_mainloop_api * m,uint16_t port,bool fallback,const char * tcpwrap_service)437 pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, bool fallback, const char *tcpwrap_service) {
438     pa_assert(m);
439     pa_assert(port > 0);
440 
441     return pa_socket_server_new_ipv4(m, INADDR_ANY, port, fallback, tcpwrap_service);
442 }
443 
444 #ifdef HAVE_IPV6
pa_socket_server_new_ipv6_any(pa_mainloop_api * m,uint16_t port,bool fallback,const char * tcpwrap_service)445 pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, bool fallback, const char *tcpwrap_service) {
446     pa_assert(m);
447     pa_assert(port > 0);
448 
449     return pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, fallback, tcpwrap_service);
450 }
451 #endif
452 
pa_socket_server_new_ipv4_string(pa_mainloop_api * m,const char * name,uint16_t port,bool fallback,const char * tcpwrap_service)453 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) {
454     struct in_addr ipv4;
455 
456     pa_assert(m);
457     pa_assert(name);
458     pa_assert(port > 0);
459 
460     if (inet_pton(AF_INET, name, &ipv4) > 0)
461         return pa_socket_server_new_ipv4(m, ntohl(ipv4.s_addr), port, fallback, tcpwrap_service);
462 
463     return NULL;
464 }
465 
466 #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)467 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) {
468     struct in6_addr ipv6;
469 
470     pa_assert(m);
471     pa_assert(name);
472     pa_assert(port > 0);
473 
474     if (inet_pton(AF_INET6, name, &ipv6) > 0)
475         return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, fallback, tcpwrap_service);
476 
477     return NULL;
478 }
479 #endif
480 
socket_server_free(pa_socket_server * s)481 static void socket_server_free(pa_socket_server*s) {
482     pa_assert(s);
483 
484     if (!s->activated && s->filename)
485         unlink(s->filename);
486     pa_xfree(s->filename);
487 
488     pa_close(s->fd);
489 
490     pa_xfree(s->tcpwrap_service);
491 
492     s->mainloop->io_free(s->io_event);
493     pa_xfree(s);
494 }
495 
pa_socket_server_unref(pa_socket_server * s)496 void pa_socket_server_unref(pa_socket_server *s) {
497     pa_assert(s);
498     pa_assert(PA_REFCNT_VALUE(s) >= 1);
499 
500     if (PA_REFCNT_DEC(s) <= 0)
501         socket_server_free(s);
502 }
503 
pa_socket_server_set_callback(pa_socket_server * s,pa_socket_server_on_connection_cb_t on_connection,void * userdata)504 void pa_socket_server_set_callback(pa_socket_server*s, pa_socket_server_on_connection_cb_t on_connection, void *userdata) {
505     pa_assert(s);
506     pa_assert(PA_REFCNT_VALUE(s) >= 1);
507 
508     s->on_connection = on_connection;
509     s->userdata = userdata;
510 }
511 
pa_socket_server_get_address(pa_socket_server * s,char * c,size_t l)512 char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
513     pa_assert(s);
514     pa_assert(PA_REFCNT_VALUE(s) >= 1);
515     pa_assert(c);
516     pa_assert(l > 0);
517 
518     switch (s->type) {
519 #ifdef HAVE_IPV6
520         case SOCKET_SERVER_IPV6: {
521             struct sockaddr_in6 sa;
522             socklen_t sa_len = sizeof(sa);
523 
524             if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
525                 pa_log("getsockname(): %s", pa_cstrerror(errno));
526                 return NULL;
527             }
528 
529             if (memcmp(&in6addr_any, &sa.sin6_addr, sizeof(in6addr_any)) == 0) {
530                 char fqdn[256];
531                 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
532                     return NULL;
533 
534                 pa_snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port));
535 
536             } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) {
537                 char *id;
538 
539                 if (!(id = pa_machine_id()))
540                     return NULL;
541 
542                 pa_snprintf(c, l, "{%s}tcp6:localhost:%u", id, (unsigned) ntohs(sa.sin6_port));
543                 pa_xfree(id);
544             } else {
545                 char ip[INET6_ADDRSTRLEN];
546 
547                 if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) {
548                     pa_log("inet_ntop(): %s", pa_cstrerror(errno));
549                     return NULL;
550                 }
551 
552                 pa_snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port));
553             }
554 
555             return c;
556         }
557 #endif
558 
559         case SOCKET_SERVER_IPV4: {
560             struct sockaddr_in sa;
561             socklen_t sa_len = sizeof(sa);
562 
563             if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
564                 pa_log("getsockname(): %s", pa_cstrerror(errno));
565                 return NULL;
566             }
567 
568             if (sa.sin_addr.s_addr == INADDR_ANY) {
569                 char fqdn[256];
570                 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
571                     return NULL;
572 
573                 pa_snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port));
574             } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) {
575                 char *id;
576 
577                 if (!(id = pa_machine_id()))
578                     return NULL;
579 
580                 pa_snprintf(c, l, "{%s}tcp:localhost:%u", id, (unsigned) ntohs(sa.sin_port));
581                 pa_xfree(id);
582             } else {
583                 char ip[INET_ADDRSTRLEN];
584 
585                 if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) {
586                     pa_log("inet_ntop(): %s", pa_cstrerror(errno));
587                     return NULL;
588                 }
589 
590                 pa_snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port));
591             }
592 
593             return c;
594         }
595 
596         case SOCKET_SERVER_UNIX: {
597             char *id;
598 
599             if (!s->filename)
600                 return NULL;
601 
602             if (!(id = pa_machine_id()))
603                 return NULL;
604 
605             pa_snprintf(c, l, "{%s}unix:%s", id, s->filename);
606             pa_xfree(id);
607             return c;
608         }
609 
610         default:
611             return NULL;
612     }
613 }
614