default: esd is obsolete, hence don't load it anymore by default
[pulseaudio-mirror.git] / src / pulsecore / socket-server.c
blob23096a0d5072fbd91c32551ffb39ec49395f9070
1 /***
2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
35 #ifdef HAVE_SYS_UN_H
36 #include <sys/un.h>
37 #ifndef SUN_LEN
38 #define SUN_LEN(ptr) \
39 ((size_t)(((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path))
40 #endif
41 #endif
42 #ifdef HAVE_NETINET_IN_H
43 #include <netinet/in.h>
44 #endif
46 #ifdef HAVE_LIBWRAP
47 #include <tcpd.h>
48 #endif
50 #include <pulse/xmalloc.h>
51 #include <pulse/util.h>
53 #include <pulsecore/socket.h>
54 #include <pulsecore/socket-util.h>
55 #include <pulsecore/core-util.h>
56 #include <pulsecore/log.h>
57 #include <pulsecore/macro.h>
58 #include <pulsecore/core-error.h>
59 #include <pulsecore/refcnt.h>
60 #include <pulsecore/arpa-inet.h>
62 #include "socket-server.h"
64 struct pa_socket_server {
65 PA_REFCNT_DECLARE;
66 int fd;
67 char *filename;
68 char *tcpwrap_service;
70 pa_socket_server_on_connection_cb_t on_connection;
71 void *userdata;
73 pa_io_event *io_event;
74 pa_mainloop_api *mainloop;
75 enum {
76 SOCKET_SERVER_GENERIC,
77 SOCKET_SERVER_IPV4,
78 SOCKET_SERVER_UNIX,
79 SOCKET_SERVER_IPV6
80 } type;
83 static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
84 pa_socket_server *s = userdata;
85 pa_iochannel *io;
86 int nfd;
88 pa_assert(s);
89 pa_assert(PA_REFCNT_VALUE(s) >= 1);
90 pa_assert(s->mainloop == mainloop);
91 pa_assert(s->io_event == e);
92 pa_assert(e);
93 pa_assert(fd >= 0);
94 pa_assert(fd == s->fd);
96 pa_socket_server_ref(s);
98 if ((nfd = pa_accept_cloexec(fd, NULL, NULL)) < 0) {
99 pa_log("accept(): %s", pa_cstrerror(errno));
100 goto finish;
103 if (!s->on_connection) {
104 pa_close(nfd);
105 goto finish;
108 #ifdef HAVE_LIBWRAP
110 if (s->tcpwrap_service) {
111 struct request_info req;
113 request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL);
114 fromhost(&req);
115 if (!hosts_access(&req)) {
116 pa_log_warn("TCP connection refused by tcpwrap.");
117 pa_close(nfd);
118 goto finish;
121 pa_log_info("TCP connection accepted by tcpwrap.");
123 #endif
125 /* There should be a check for socket type here */
126 if (s->type == SOCKET_SERVER_IPV4)
127 pa_make_tcp_socket_low_delay(fd);
128 else
129 pa_make_socket_low_delay(fd);
131 pa_assert_se(io = pa_iochannel_new(s->mainloop, nfd, nfd));
132 s->on_connection(s, io, s->userdata);
134 finish:
135 pa_socket_server_unref(s);
138 pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) {
139 pa_socket_server *s;
141 pa_assert(m);
142 pa_assert(fd >= 0);
144 s = pa_xnew0(pa_socket_server, 1);
145 PA_REFCNT_INIT(s);
146 s->fd = fd;
147 s->mainloop = m;
149 pa_assert_se(s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s));
151 s->type = SOCKET_SERVER_GENERIC;
153 return s;
156 pa_socket_server* pa_socket_server_ref(pa_socket_server *s) {
157 pa_assert(s);
158 pa_assert(PA_REFCNT_VALUE(s) >= 1);
160 PA_REFCNT_INC(s);
161 return s;
164 #ifdef HAVE_SYS_UN_H
166 pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) {
167 int fd = -1;
168 struct sockaddr_un sa;
169 pa_socket_server *s;
171 pa_assert(m);
172 pa_assert(filename);
174 if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) {
175 pa_log("socket(): %s", pa_cstrerror(errno));
176 goto fail;
179 memset(&sa, 0, sizeof(sa));
180 sa.sun_family = AF_UNIX;
181 pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path));
183 pa_make_socket_low_delay(fd);
185 if (bind(fd, (struct sockaddr*) &sa, (socklen_t) SUN_LEN(&sa)) < 0) {
186 pa_log("bind(): %s", pa_cstrerror(errno));
187 goto fail;
190 /* Allow access from all clients. Sockets like this one should
191 * always be put inside a directory with proper access rights,
192 * because not all OS check the access rights on the socket
193 * inodes. */
194 chmod(filename, 0777);
196 if (listen(fd, 5) < 0) {
197 pa_log("listen(): %s", pa_cstrerror(errno));
198 goto fail;
201 pa_assert_se(s = pa_socket_server_new(m, fd));
203 s->filename = pa_xstrdup(filename);
204 s->type = SOCKET_SERVER_UNIX;
206 return s;
208 fail:
209 if (fd >= 0)
210 pa_close(fd);
212 return NULL;
215 #else /* HAVE_SYS_UN_H */
217 pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) {
218 return NULL;
221 #endif /* HAVE_SYS_UN_H */
223 pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
224 pa_socket_server *ss;
225 int fd = -1;
226 struct sockaddr_in sa;
227 int on = 1;
229 pa_assert(m);
230 pa_assert(port);
232 if ((fd = pa_socket_cloexec(PF_INET, SOCK_STREAM, 0)) < 0) {
233 pa_log("socket(PF_INET): %s", pa_cstrerror(errno));
234 goto fail;
237 #ifdef SO_REUSEADDR
238 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
239 pa_log("setsockopt(): %s", pa_cstrerror(errno));
240 #endif
242 pa_make_tcp_socket_low_delay(fd);
244 memset(&sa, 0, sizeof(sa));
245 sa.sin_family = AF_INET;
246 sa.sin_port = htons(port);
247 sa.sin_addr.s_addr = htonl(address);
249 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
251 if (errno == EADDRINUSE && fallback) {
252 sa.sin_port = 0;
254 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
255 goto good;
258 pa_log("bind(): %s", pa_cstrerror(errno));
259 goto fail;
261 good:
265 if (listen(fd, 5) < 0) {
266 pa_log("listen(): %s", pa_cstrerror(errno));
267 goto fail;
270 if ((ss = pa_socket_server_new(m, fd))) {
271 ss->type = SOCKET_SERVER_IPV4;
272 ss->tcpwrap_service = pa_xstrdup(tcpwrap_service);
275 return ss;
277 fail:
278 if (fd >= 0)
279 pa_close(fd);
281 return NULL;
284 #ifdef HAVE_IPV6
285 pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
286 pa_socket_server *ss;
287 int fd = -1;
288 struct sockaddr_in6 sa;
289 int on;
291 pa_assert(m);
292 pa_assert(port > 0);
294 if ((fd = pa_socket_cloexec(PF_INET6, SOCK_STREAM, 0)) < 0) {
295 pa_log("socket(PF_INET6): %s", pa_cstrerror(errno));
296 goto fail;
299 #ifdef IPV6_V6ONLY
300 on = 1;
301 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
302 pa_log("setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", pa_cstrerror(errno));
303 #endif
305 #ifdef SO_REUSEADDR
306 on = 1;
307 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
308 pa_log("setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", pa_cstrerror(errno));
309 #endif
311 pa_make_tcp_socket_low_delay(fd);
313 memset(&sa, 0, sizeof(sa));
314 sa.sin6_family = AF_INET6;
315 sa.sin6_port = htons(port);
316 memcpy(sa.sin6_addr.s6_addr, address, 16);
318 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
320 if (errno == EADDRINUSE && fallback) {
321 sa.sin6_port = 0;
323 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
324 goto good;
327 pa_log("bind(): %s", pa_cstrerror(errno));
328 goto fail;
330 good:
334 if (listen(fd, 5) < 0) {
335 pa_log("listen(): %s", pa_cstrerror(errno));
336 goto fail;
339 if ((ss = pa_socket_server_new(m, fd))) {
340 ss->type = SOCKET_SERVER_IPV6;
341 ss->tcpwrap_service = pa_xstrdup(tcpwrap_service);
344 return ss;
346 fail:
347 if (fd >= 0)
348 pa_close(fd);
350 return NULL;
352 #endif
354 pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
355 pa_assert(m);
356 pa_assert(port > 0);
358 return pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, fallback, tcpwrap_service);
361 #ifdef HAVE_IPV6
362 pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
363 pa_assert(m);
364 pa_assert(port > 0);
366 return pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, fallback, tcpwrap_service);
368 #endif
370 pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
371 pa_assert(m);
372 pa_assert(port > 0);
374 return pa_socket_server_new_ipv4(m, INADDR_ANY, port, fallback, tcpwrap_service);
377 #ifdef HAVE_IPV6
378 pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
379 pa_assert(m);
380 pa_assert(port > 0);
382 return pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, fallback, tcpwrap_service);
384 #endif
386 pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
387 struct in_addr ipv4;
389 pa_assert(m);
390 pa_assert(name);
391 pa_assert(port > 0);
393 if (inet_pton(AF_INET, name, &ipv4) > 0)
394 return pa_socket_server_new_ipv4(m, ntohl(ipv4.s_addr), port, fallback, tcpwrap_service);
396 return NULL;
399 #ifdef HAVE_IPV6
400 pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, pa_bool_t fallback, const char *tcpwrap_service) {
401 struct in6_addr ipv6;
403 pa_assert(m);
404 pa_assert(name);
405 pa_assert(port > 0);
407 if (inet_pton(AF_INET6, name, &ipv6) > 0)
408 return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, fallback, tcpwrap_service);
410 return NULL;
412 #endif
414 static void socket_server_free(pa_socket_server*s) {
415 pa_assert(s);
417 if (s->filename) {
418 unlink(s->filename);
419 pa_xfree(s->filename);
422 pa_close(s->fd);
424 pa_xfree(s->tcpwrap_service);
426 s->mainloop->io_free(s->io_event);
427 pa_xfree(s);
430 void pa_socket_server_unref(pa_socket_server *s) {
431 pa_assert(s);
432 pa_assert(PA_REFCNT_VALUE(s) >= 1);
434 if (PA_REFCNT_DEC(s) <= 0)
435 socket_server_free(s);
438 void pa_socket_server_set_callback(pa_socket_server*s, pa_socket_server_on_connection_cb_t on_connection, void *userdata) {
439 pa_assert(s);
440 pa_assert(PA_REFCNT_VALUE(s) >= 1);
442 s->on_connection = on_connection;
443 s->userdata = userdata;
446 char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
447 pa_assert(s);
448 pa_assert(PA_REFCNT_VALUE(s) >= 1);
449 pa_assert(c);
450 pa_assert(l > 0);
452 switch (s->type) {
453 #ifdef HAVE_IPV6
454 case SOCKET_SERVER_IPV6: {
455 struct sockaddr_in6 sa;
456 socklen_t sa_len = sizeof(sa);
458 if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
459 pa_log("getsockname(): %s", pa_cstrerror(errno));
460 return NULL;
463 if (memcmp(&in6addr_any, &sa.sin6_addr, sizeof(in6addr_any)) == 0) {
464 char fqdn[256];
465 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
466 return NULL;
468 pa_snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port));
470 } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) {
471 char *id;
473 if (!(id = pa_machine_id()))
474 return NULL;
476 pa_snprintf(c, l, "{%s}tcp6:localhost:%u", id, (unsigned) ntohs(sa.sin6_port));
477 pa_xfree(id);
478 } else {
479 char ip[INET6_ADDRSTRLEN];
481 if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) {
482 pa_log("inet_ntop(): %s", pa_cstrerror(errno));
483 return NULL;
486 pa_snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port));
489 return c;
491 #endif
493 case SOCKET_SERVER_IPV4: {
494 struct sockaddr_in sa;
495 socklen_t sa_len = sizeof(sa);
497 if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
498 pa_log("getsockname(): %s", pa_cstrerror(errno));
499 return NULL;
502 if (sa.sin_addr.s_addr == INADDR_ANY) {
503 char fqdn[256];
504 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
505 return NULL;
507 pa_snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port));
508 } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) {
509 char *id;
511 if (!(id = pa_machine_id()))
512 return NULL;
514 pa_snprintf(c, l, "{%s}tcp:localhost:%u", id, (unsigned) ntohs(sa.sin_port));
515 pa_xfree(id);
516 } else {
517 char ip[INET_ADDRSTRLEN];
519 if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) {
520 pa_log("inet_ntop(): %s", pa_cstrerror(errno));
521 return NULL;
524 pa_snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port));
527 return c;
530 case SOCKET_SERVER_UNIX: {
531 char *id;
533 if (!s->filename)
534 return NULL;
536 if (!(id = pa_machine_id()))
537 return NULL;
539 pa_snprintf(c, l, "{%s}unix:%s", id, s->filename);
540 pa_xfree(id);
541 return c;
544 default:
545 return NULL;