]> code.delx.au - pulseaudio/blob - src/pulsecore/socket-server.c
e660700cbe2ab249e2b6c97aa94f79374dfe1452
[pulseaudio] / src / pulsecore / socket-server.c
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, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
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>
34
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
37 #endif
38 #ifdef HAVE_SYS_UN_H
39 #include <sys/un.h>
40 #ifndef SUN_LEN
41 #define SUN_LEN(ptr) \
42 ((size_t)(((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path))
43 #endif
44 #endif
45 #ifdef HAVE_ARPA_INET_H
46 #include <arpa/inet.h>
47 #endif
48 #ifdef HAVE_NETINET_IN_H
49 #include <netinet/in.h>
50 #endif
51
52 #ifdef HAVE_LIBWRAP
53 #include <tcpd.h>
54 #endif
55
56 #ifndef HAVE_INET_NTOP
57 #include "inet_ntop.h"
58 #endif
59
60 #ifndef HAVE_INET_PTON
61 #include "inet_pton.h"
62 #endif
63
64 #include "winsock.h"
65
66 #include <pulse/xmalloc.h>
67 #include <pulse/util.h>
68
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>
75
76 #include "socket-server.h"
77
78 struct pa_socket_server {
79 PA_REFCNT_DECLARE;
80 int fd;
81 char *filename;
82 char *tcpwrap_service;
83
84 pa_socket_server_on_connection_cb_t on_connection;
85 void *userdata;
86
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;
90 };
91
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;
94 pa_iochannel *io;
95 int nfd;
96
97 pa_assert(s);
98 pa_assert(PA_REFCNT_VALUE(s) >= 1);
99 pa_assert(s->mainloop == mainloop);
100 pa_assert(s->io_event == e);
101 pa_assert(e);
102 pa_assert(fd >= 0);
103 pa_assert(fd == s->fd);
104
105 pa_socket_server_ref(s);
106
107 if ((nfd = accept(fd, NULL, NULL)) < 0) {
108 pa_log("accept(): %s", pa_cstrerror(errno));
109 goto finish;
110 }
111
112 pa_make_fd_cloexec(nfd);
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(fd);
139 else
140 pa_make_socket_low_delay(fd);
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
149 pa_socket_server* pa_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_xnew(pa_socket_server, 1);
156 PA_REFCNT_INIT(s);
157 s->fd = fd;
158 s->filename = NULL;
159 s->on_connection = NULL;
160 s->userdata = NULL;
161 s->tcpwrap_service = NULL;
162
163 s->mainloop = m;
164 pa_assert_se(s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s));
165
166 s->type = SOCKET_SERVER_GENERIC;
167
168 return s;
169 }
170
171 pa_socket_server* pa_socket_server_ref(pa_socket_server *s) {
172 pa_assert(s);
173 pa_assert(PA_REFCNT_VALUE(s) >= 1);
174
175 PA_REFCNT_INC(s);
176 return s;
177 }
178
179 #ifdef HAVE_SYS_UN_H
180
181 pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) {
182 int fd = -1;
183 struct sockaddr_un sa;
184 pa_socket_server *s;
185
186 pa_assert(m);
187 pa_assert(filename);
188
189 if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
190 pa_log("socket(): %s", pa_cstrerror(errno));
191 goto fail;
192 }
193
194 pa_make_fd_cloexec(fd);
195
196 memset(&sa, 0, sizeof(sa));
197 sa.sun_family = AF_UNIX;
198 pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path));
199
200 pa_make_socket_low_delay(fd);
201
202 if (bind(fd, (struct sockaddr*) &sa, (socklen_t) SUN_LEN(&sa)) < 0) {
203 pa_log("bind(): %s", pa_cstrerror(errno));
204 goto fail;
205 }
206
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
210 * inodes. */
211 chmod(filename, 0777);
212
213 if (listen(fd, 5) < 0) {
214 pa_log("listen(): %s", pa_cstrerror(errno));
215 goto fail;
216 }
217
218 pa_assert_se(s = pa_socket_server_new(m, fd));
219
220 s->filename = pa_xstrdup(filename);
221 s->type = SOCKET_SERVER_UNIX;
222
223 return s;
224
225 fail:
226 if (fd >= 0)
227 pa_close(fd);
228
229 return NULL;
230 }
231
232 #else /* HAVE_SYS_UN_H */
233
234 pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) {
235 return NULL;
236 }
237
238 #endif /* HAVE_SYS_UN_H */
239
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;
242 int fd = -1;
243 struct sockaddr_in sa;
244 int on = 1;
245
246 pa_assert(m);
247 pa_assert(port);
248
249 if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
250 pa_log("socket(PF_INET): %s", pa_cstrerror(errno));
251 goto fail;
252 }
253
254 pa_make_fd_cloexec(fd);
255
256 #ifdef SO_REUSEADDR
257 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
258 pa_log("setsockopt(): %s", pa_cstrerror(errno));
259 #endif
260
261 pa_make_tcp_socket_low_delay(fd);
262
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);
267
268 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
269 pa_log("bind(): %s", pa_cstrerror(errno));
270 goto fail;
271 }
272
273 if (listen(fd, 5) < 0) {
274 pa_log("listen(): %s", pa_cstrerror(errno));
275 goto fail;
276 }
277
278 if ((ss = pa_socket_server_new(m, fd))) {
279 ss->type = SOCKET_SERVER_IPV4;
280 ss->tcpwrap_service = pa_xstrdup(tcpwrap_service);
281 }
282
283 return ss;
284
285 fail:
286 if (fd >= 0)
287 pa_close(fd);
288
289 return NULL;
290 }
291
292 #ifdef HAVE_IPV6
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;
295 int fd = -1;
296 struct sockaddr_in6 sa;
297 int on;
298
299 pa_assert(m);
300 pa_assert(port > 0);
301
302 if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) {
303 pa_log("socket(PF_INET6): %s", pa_cstrerror(errno));
304 goto fail;
305 }
306
307 pa_make_fd_cloexec(fd);
308
309 #ifdef IPV6_V6ONLY
310 on = 1;
311 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
312 pa_log("setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", pa_cstrerror(errno));
313 #endif
314
315 #ifdef SO_REUSEADDR
316 on = 1;
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));
319 #endif
320
321 pa_make_tcp_socket_low_delay(fd);
322
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);
327
328 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
329 pa_log("bind(): %s", pa_cstrerror(errno));
330 goto fail;
331 }
332
333 if (listen(fd, 5) < 0) {
334 pa_log("listen(): %s", pa_cstrerror(errno));
335 goto fail;
336 }
337
338 if ((ss = pa_socket_server_new(m, fd))) {
339 ss->type = SOCKET_SERVER_IPV6;
340 ss->tcpwrap_service = pa_xstrdup(tcpwrap_service);
341 }
342
343 return ss;
344
345 fail:
346 if (fd >= 0)
347 pa_close(fd);
348
349 return NULL;
350 }
351 #endif
352
353 pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
354 pa_assert(m);
355 pa_assert(port > 0);
356
357 return pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, tcpwrap_service);
358 }
359
360 #ifdef HAVE_IPV6
361 pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
362 pa_assert(m);
363 pa_assert(port > 0);
364
365 return pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, tcpwrap_service);
366 }
367 #endif
368
369 pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
370 pa_assert(m);
371 pa_assert(port > 0);
372
373 return pa_socket_server_new_ipv4(m, INADDR_ANY, port, tcpwrap_service);
374 }
375
376 #ifdef HAVE_IPV6
377 pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
378 pa_assert(m);
379 pa_assert(port > 0);
380
381 return pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, tcpwrap_service);
382 }
383 #endif
384
385 pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) {
386 struct in_addr ipv4;
387
388 pa_assert(m);
389 pa_assert(name);
390 pa_assert(port > 0);
391
392 if (inet_pton(AF_INET, name, &ipv4) > 0)
393 return pa_socket_server_new_ipv4(m, ntohl(ipv4.s_addr), port, tcpwrap_service);
394
395 return NULL;
396 }
397
398 #ifdef HAVE_IPV6
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;
401
402 pa_assert(m);
403 pa_assert(name);
404 pa_assert(port > 0);
405
406 if (inet_pton(AF_INET6, name, &ipv6) > 0)
407 return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, tcpwrap_service);
408
409 return NULL;
410 }
411 #endif
412
413 static void socket_server_free(pa_socket_server*s) {
414 pa_assert(s);
415
416 if (s->filename) {
417 unlink(s->filename);
418 pa_xfree(s->filename);
419 }
420
421 pa_close(s->fd);
422
423 pa_xfree(s->tcpwrap_service);
424
425 s->mainloop->io_free(s->io_event);
426 pa_xfree(s);
427 }
428
429 void pa_socket_server_unref(pa_socket_server *s) {
430 pa_assert(s);
431 pa_assert(PA_REFCNT_VALUE(s) >= 1);
432
433 if (PA_REFCNT_DEC(s) <= 0)
434 socket_server_free(s);
435 }
436
437 void pa_socket_server_set_callback(pa_socket_server*s, pa_socket_server_on_connection_cb_t on_connection, void *userdata) {
438 pa_assert(s);
439 pa_assert(PA_REFCNT_VALUE(s) >= 1);
440
441 s->on_connection = on_connection;
442 s->userdata = userdata;
443 }
444
445 char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
446 pa_assert(s);
447 pa_assert(PA_REFCNT_VALUE(s) >= 1);
448 pa_assert(c);
449 pa_assert(l > 0);
450
451 switch (s->type) {
452 #ifdef HAVE_IPV6
453 case SOCKET_SERVER_IPV6: {
454 struct sockaddr_in6 sa;
455 socklen_t sa_len = sizeof(sa);
456
457 if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
458 pa_log("getsockname(): %s", pa_cstrerror(errno));
459 return NULL;
460 }
461
462 if (memcmp(&in6addr_any, &sa.sin6_addr, sizeof(in6addr_any)) == 0) {
463 char fqdn[256];
464 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
465 return NULL;
466
467 pa_snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port));
468
469 } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) {
470 char *id;
471
472 if (!(id = pa_machine_id()))
473 return NULL;
474
475 pa_snprintf(c, l, "{%s}tcp6:localhost:%u", id, (unsigned) ntohs(sa.sin6_port));
476 pa_xfree(id);
477 } else {
478 char ip[INET6_ADDRSTRLEN];
479
480 if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) {
481 pa_log("inet_ntop(): %s", pa_cstrerror(errno));
482 return NULL;
483 }
484
485 pa_snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port));
486 }
487
488 return c;
489 }
490 #endif
491
492 case SOCKET_SERVER_IPV4: {
493 struct sockaddr_in sa;
494 socklen_t sa_len = sizeof(sa);
495
496 if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
497 pa_log("getsockname(): %s", pa_cstrerror(errno));
498 return NULL;
499 }
500
501 if (sa.sin_addr.s_addr == INADDR_ANY) {
502 char fqdn[256];
503 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
504 return NULL;
505
506 pa_snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port));
507 } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) {
508 char *id;
509
510 if (!(id = pa_machine_id()))
511 return NULL;
512
513 pa_snprintf(c, l, "{%s}tcp:localhost:%u", id, (unsigned) ntohs(sa.sin_port));
514 pa_xfree(id);
515 } else {
516 char ip[INET_ADDRSTRLEN];
517
518 if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) {
519 pa_log("inet_ntop(): %s", pa_cstrerror(errno));
520 return NULL;
521 }
522
523 pa_snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port));
524 }
525
526 return c;
527 }
528
529 case SOCKET_SERVER_UNIX: {
530 char *id;
531
532 if (!s->filename)
533 return NULL;
534
535 if (!(id = pa_machine_id()))
536 return NULL;
537
538 pa_snprintf(c, l, "{%s}unix:%s", id, s->filename);
539 pa_xfree(id);
540 return c;
541 }
542
543 default:
544 return NULL;
545 }
546 }