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
30 #include <sys/types.h>
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
41 #define SUN_LEN(ptr) \
42 ((size_t)(((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path))
45 #ifdef HAVE_ARPA_INET_H
46 #include <arpa/inet.h>
48 #ifdef HAVE_NETINET_IN_H
49 #include <netinet/in.h>
56 #ifndef HAVE_INET_NTOP
57 #include "inet_ntop.h"
60 #ifndef HAVE_INET_PTON
61 #include "inet_pton.h"
66 #include <pulse/xmalloc.h>
67 #include <pulse/util.h>
69 #include <pulsecore/socket-util.h>
70 #include <pulsecore/core-util.h>
71 #include <pulsecore/log.h>
72 #include <pulsecore/macro.h>
73 #include <pulsecore/core-error.h>
74 #include <pulsecore/refcnt.h>
76 #include "socket-server.h"
78 struct pa_socket_server {
82 char *tcpwrap_service;
84 pa_socket_server_on_connection_cb_t on_connection;
87 pa_io_event *io_event;
88 pa_mainloop_api *mainloop;
89 enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX, SOCKET_SERVER_IPV6 } type;
92 static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
93 pa_socket_server *s = userdata;
98 pa_assert(PA_REFCNT_VALUE(s) >= 1);
99 pa_assert(s->mainloop == mainloop);
100 pa_assert(s->io_event == e);
103 pa_assert(fd == s->fd);
105 pa_socket_server_ref(s);
107 if ((nfd = accept(fd, NULL, NULL)) < 0) {
108 pa_log("accept(): %s", pa_cstrerror(errno));
112 pa_make_fd_cloexec(nfd);
114 if (!s->on_connection) {
121 if (s->tcpwrap_service) {
122 struct request_info req;
124 request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL);
126 if (!hosts_access(&req)) {
127 pa_log_warn("TCP connection refused by tcpwrap.");
132 pa_log_info("TCP connection accepted by tcpwrap.");
136 /* There should be a check for socket type here */
137 if (s->type == SOCKET_SERVER_IPV4)
138 pa_make_tcp_socket_low_delay(fd);
140 pa_make_socket_low_delay(fd);
142 pa_assert_se(io = pa_iochannel_new(s->mainloop, nfd, nfd));
143 s->on_connection(s, io, s->userdata);
146 pa_socket_server_unref(s);
149 pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) {
155 s = pa_xnew(pa_socket_server, 1);
159 s->on_connection = NULL;
161 s->tcpwrap_service = NULL;
164 pa_assert_se(s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s));
166 s->type = SOCKET_SERVER_GENERIC;
171 pa_socket_server* pa_socket_server_ref(pa_socket_server *s) {
173 pa_assert(PA_REFCNT_VALUE(s) >= 1);
181 pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) {
183 struct sockaddr_un sa;
189 if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
190 pa_log("socket(): %s", pa_cstrerror(errno));
194 pa_make_fd_cloexec(fd);
196 memset(&sa, 0, sizeof(sa));
197 sa.sun_family = AF_UNIX;
198 pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path));
200 pa_make_socket_low_delay(fd);
202 if (bind(fd, (struct sockaddr*) &sa, (socklen_t) SUN_LEN(&sa)) < 0) {
203 pa_log("bind(): %s", pa_cstrerror(errno));
207 /* Allow access from all clients. Sockets like this one should
208 * always be put inside a directory with proper access rights,
209 * because not all OS check the access rights on the socket
211 chmod(filename, 0777);
213 if (listen(fd, 5) < 0) {
214 pa_log("listen(): %s", pa_cstrerror(errno));
218 pa_assert_se(s = pa_socket_server_new(m, fd));
220 s->filename = pa_xstrdup(filename);
221 s->type = SOCKET_SERVER_UNIX;
232 #else /* HAVE_SYS_UN_H */
234 pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) {
238 #endif /* HAVE_SYS_UN_H */
240 pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service) {
241 pa_socket_server *ss;
243 struct sockaddr_in sa;
249 if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
250 pa_log("socket(PF_INET): %s", pa_cstrerror(errno));
254 pa_make_fd_cloexec(fd);
257 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
258 pa_log("setsockopt(): %s", pa_cstrerror(errno));
261 pa_make_tcp_socket_low_delay(fd);
263 memset(&sa, 0, sizeof(sa));
264 sa.sin_family = AF_INET;
265 sa.sin_port = htons(port);
266 sa.sin_addr.s_addr = htonl(address);
268 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
269 pa_log("bind(): %s", pa_cstrerror(errno));
273 if (listen(fd, 5) < 0) {
274 pa_log("listen(): %s", pa_cstrerror(errno));
278 if ((ss = pa_socket_server_new(m, fd))) {
279 ss->type = SOCKET_SERVER_IPV4;
280 ss->tcpwrap_service = pa_xstrdup(tcpwrap_service);
293 pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, const char *tcpwrap_service) {
294 pa_socket_server *ss;
296 struct sockaddr_in6 sa;
302 if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) {
303 pa_log("socket(PF_INET6): %s", pa_cstrerror(errno));
307 pa_make_fd_cloexec(fd);
311 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
312 pa_log("setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", pa_cstrerror(errno));
317 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
318 pa_log("setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", pa_cstrerror(errno));
321 pa_make_tcp_socket_low_delay(fd);
323 memset(&sa, 0, sizeof(sa));
324 sa.sin6_family = AF_INET6;
325 sa.sin6_port = htons(port);
326 memcpy(sa.sin6_addr.s6_addr, address, 16);
328 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
329 pa_log("bind(): %s", pa_cstrerror(errno));
333 if (listen(fd, 5) < 0) {
334 pa_log("listen(): %s", pa_cstrerror(errno));
338 if ((ss = pa_socket_server_new(m, fd))) {
339 ss->type = SOCKET_SERVER_IPV6;
340 ss->tcpwrap_service = pa_xstrdup(tcpwrap_service);
353 pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
357 return pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, tcpwrap_service);
361 pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
365 return pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, tcpwrap_service);
369 pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
373 return pa_socket_server_new_ipv4(m, INADDR_ANY, port, tcpwrap_service);
377 pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
381 return pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, tcpwrap_service);
385 pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) {
392 if (inet_pton(AF_INET, name, &ipv4) > 0)
393 return pa_socket_server_new_ipv4(m, ntohl(ipv4.s_addr), port, tcpwrap_service);
399 pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) {
400 struct in6_addr ipv6;
406 if (inet_pton(AF_INET6, name, &ipv6) > 0)
407 return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, tcpwrap_service);
413 static void socket_server_free(pa_socket_server*s) {
418 pa_xfree(s->filename);
423 pa_xfree(s->tcpwrap_service);
425 s->mainloop->io_free(s->io_event);
429 void pa_socket_server_unref(pa_socket_server *s) {
431 pa_assert(PA_REFCNT_VALUE(s) >= 1);
433 if (PA_REFCNT_DEC(s) <= 0)
434 socket_server_free(s);
437 void pa_socket_server_set_callback(pa_socket_server*s, pa_socket_server_on_connection_cb_t on_connection, void *userdata) {
439 pa_assert(PA_REFCNT_VALUE(s) >= 1);
441 s->on_connection = on_connection;
442 s->userdata = userdata;
445 char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
447 pa_assert(PA_REFCNT_VALUE(s) >= 1);
453 case SOCKET_SERVER_IPV6: {
454 struct sockaddr_in6 sa;
455 socklen_t sa_len = sizeof(sa);
457 if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
458 pa_log("getsockname(): %s", pa_cstrerror(errno));
462 if (memcmp(&in6addr_any, &sa.sin6_addr, sizeof(in6addr_any)) == 0) {
464 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
467 pa_snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port));
469 } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) {
472 if (!(id = pa_machine_id()))
475 pa_snprintf(c, l, "{%s}tcp6:localhost:%u", id, (unsigned) ntohs(sa.sin6_port));
478 char ip[INET6_ADDRSTRLEN];
480 if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) {
481 pa_log("inet_ntop(): %s", pa_cstrerror(errno));
485 pa_snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port));
492 case SOCKET_SERVER_IPV4: {
493 struct sockaddr_in sa;
494 socklen_t sa_len = sizeof(sa);
496 if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
497 pa_log("getsockname(): %s", pa_cstrerror(errno));
501 if (sa.sin_addr.s_addr == INADDR_ANY) {
503 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
506 pa_snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port));
507 } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) {
510 if (!(id = pa_machine_id()))
513 pa_snprintf(c, l, "{%s}tcp:localhost:%u", id, (unsigned) ntohs(sa.sin_port));
516 char ip[INET_ADDRSTRLEN];
518 if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) {
519 pa_log("inet_ntop(): %s", pa_cstrerror(errno));
523 pa_snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port));
529 case SOCKET_SERVER_UNIX: {
535 if (!(id = pa_machine_id()))
538 pa_snprintf(c, l, "{%s}unix:%s", id, s->filename);