]> code.delx.au - pulseaudio/blob - src/pulsecore/socket-server.c
Use pulsecore/arpa-inet.h to make arpa/inet.h functionality available
[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_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
45
46 #ifdef HAVE_LIBWRAP
47 #include <tcpd.h>
48 #endif
49
50 #include <pulse/xmalloc.h>
51 #include <pulse/util.h>
52
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>
61
62 #include "socket-server.h"
63
64 struct pa_socket_server {
65 PA_REFCNT_DECLARE;
66 int fd;
67 char *filename;
68 char *tcpwrap_service;
69
70 pa_socket_server_on_connection_cb_t on_connection;
71 void *userdata;
72
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;
81 };
82
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;
87
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);
95
96 pa_socket_server_ref(s);
97
98 if ((nfd = pa_accept_cloexec(fd, NULL, NULL)) < 0) {
99 pa_log("accept(): %s", pa_cstrerror(errno));
100 goto finish;
101 }
102
103 if (!s->on_connection) {
104 pa_close(nfd);
105 goto finish;
106 }
107
108 #ifdef HAVE_LIBWRAP
109
110 if (s->tcpwrap_service) {
111 struct request_info req;
112
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;
119 }
120
121 pa_log_info("TCP connection accepted by tcpwrap.");
122 }
123 #endif
124
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);
130
131 pa_assert_se(io = pa_iochannel_new(s->mainloop, nfd, nfd));
132 s->on_connection(s, io, s->userdata);
133
134 finish:
135 pa_socket_server_unref(s);
136 }
137
138 pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) {
139 pa_socket_server *s;
140
141 pa_assert(m);
142 pa_assert(fd >= 0);
143
144 s = pa_xnew0(pa_socket_server, 1);
145 PA_REFCNT_INIT(s);
146 s->fd = fd;
147 s->mainloop = m;
148
149 pa_assert_se(s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s));
150
151 s->type = SOCKET_SERVER_GENERIC;
152
153 return s;
154 }
155
156 pa_socket_server* pa_socket_server_ref(pa_socket_server *s) {
157 pa_assert(s);
158 pa_assert(PA_REFCNT_VALUE(s) >= 1);
159
160 PA_REFCNT_INC(s);
161 return s;
162 }
163
164 #ifdef HAVE_SYS_UN_H
165
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;
170
171 pa_assert(m);
172 pa_assert(filename);
173
174 if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) {
175 pa_log("socket(): %s", pa_cstrerror(errno));
176 goto fail;
177 }
178
179 memset(&sa, 0, sizeof(sa));
180 sa.sun_family = AF_UNIX;
181 pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path));
182
183 pa_make_socket_low_delay(fd);
184
185 if (bind(fd, (struct sockaddr*) &sa, (socklen_t) SUN_LEN(&sa)) < 0) {
186 pa_log("bind(): %s", pa_cstrerror(errno));
187 goto fail;
188 }
189
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);
195
196 if (listen(fd, 5) < 0) {
197 pa_log("listen(): %s", pa_cstrerror(errno));
198 goto fail;
199 }
200
201 pa_assert_se(s = pa_socket_server_new(m, fd));
202
203 s->filename = pa_xstrdup(filename);
204 s->type = SOCKET_SERVER_UNIX;
205
206 return s;
207
208 fail:
209 if (fd >= 0)
210 pa_close(fd);
211
212 return NULL;
213 }
214
215 #else /* HAVE_SYS_UN_H */
216
217 pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) {
218 return NULL;
219 }
220
221 #endif /* HAVE_SYS_UN_H */
222
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;
228
229 pa_assert(m);
230 pa_assert(port);
231
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;
235 }
236
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
241
242 pa_make_tcp_socket_low_delay(fd);
243
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);
248
249 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
250
251 if (errno == EADDRINUSE && fallback) {
252 sa.sin_port = 0;
253
254 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
255 goto good;
256 }
257
258 pa_log("bind(): %s", pa_cstrerror(errno));
259 goto fail;
260
261 good:
262 ;
263 }
264
265 if (listen(fd, 5) < 0) {
266 pa_log("listen(): %s", pa_cstrerror(errno));
267 goto fail;
268 }
269
270 if ((ss = pa_socket_server_new(m, fd))) {
271 ss->type = SOCKET_SERVER_IPV4;
272 ss->tcpwrap_service = pa_xstrdup(tcpwrap_service);
273 }
274
275 return ss;
276
277 fail:
278 if (fd >= 0)
279 pa_close(fd);
280
281 return NULL;
282 }
283
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;
290
291 pa_assert(m);
292 pa_assert(port > 0);
293
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;
297 }
298
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
304
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
310
311 pa_make_tcp_socket_low_delay(fd);
312
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);
317
318 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
319
320 if (errno == EADDRINUSE && fallback) {
321 sa.sin6_port = 0;
322
323 if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
324 goto good;
325 }
326
327 pa_log("bind(): %s", pa_cstrerror(errno));
328 goto fail;
329
330 good:
331 ;
332 }
333
334 if (listen(fd, 5) < 0) {
335 pa_log("listen(): %s", pa_cstrerror(errno));
336 goto fail;
337 }
338
339 if ((ss = pa_socket_server_new(m, fd))) {
340 ss->type = SOCKET_SERVER_IPV6;
341 ss->tcpwrap_service = pa_xstrdup(tcpwrap_service);
342 }
343
344 return ss;
345
346 fail:
347 if (fd >= 0)
348 pa_close(fd);
349
350 return NULL;
351 }
352 #endif
353
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);
357
358 return pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, fallback, tcpwrap_service);
359 }
360
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);
365
366 return pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, fallback, tcpwrap_service);
367 }
368 #endif
369
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);
373
374 return pa_socket_server_new_ipv4(m, INADDR_ANY, port, fallback, tcpwrap_service);
375 }
376
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);
381
382 return pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, fallback, tcpwrap_service);
383 }
384 #endif
385
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;
388
389 pa_assert(m);
390 pa_assert(name);
391 pa_assert(port > 0);
392
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);
395
396 return NULL;
397 }
398
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;
402
403 pa_assert(m);
404 pa_assert(name);
405 pa_assert(port > 0);
406
407 if (inet_pton(AF_INET6, name, &ipv6) > 0)
408 return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, fallback, tcpwrap_service);
409
410 return NULL;
411 }
412 #endif
413
414 static void socket_server_free(pa_socket_server*s) {
415 pa_assert(s);
416
417 if (s->filename) {
418 unlink(s->filename);
419 pa_xfree(s->filename);
420 }
421
422 pa_close(s->fd);
423
424 pa_xfree(s->tcpwrap_service);
425
426 s->mainloop->io_free(s->io_event);
427 pa_xfree(s);
428 }
429
430 void pa_socket_server_unref(pa_socket_server *s) {
431 pa_assert(s);
432 pa_assert(PA_REFCNT_VALUE(s) >= 1);
433
434 if (PA_REFCNT_DEC(s) <= 0)
435 socket_server_free(s);
436 }
437
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);
441
442 s->on_connection = on_connection;
443 s->userdata = userdata;
444 }
445
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);
451
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);
457
458 if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
459 pa_log("getsockname(): %s", pa_cstrerror(errno));
460 return NULL;
461 }
462
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;
467
468 pa_snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port));
469
470 } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) {
471 char *id;
472
473 if (!(id = pa_machine_id()))
474 return NULL;
475
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];
480
481 if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) {
482 pa_log("inet_ntop(): %s", pa_cstrerror(errno));
483 return NULL;
484 }
485
486 pa_snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port));
487 }
488
489 return c;
490 }
491 #endif
492
493 case SOCKET_SERVER_IPV4: {
494 struct sockaddr_in sa;
495 socklen_t sa_len = sizeof(sa);
496
497 if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
498 pa_log("getsockname(): %s", pa_cstrerror(errno));
499 return NULL;
500 }
501
502 if (sa.sin_addr.s_addr == INADDR_ANY) {
503 char fqdn[256];
504 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
505 return NULL;
506
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;
510
511 if (!(id = pa_machine_id()))
512 return NULL;
513
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];
518
519 if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) {
520 pa_log("inet_ntop(): %s", pa_cstrerror(errno));
521 return NULL;
522 }
523
524 pa_snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port));
525 }
526
527 return c;
528 }
529
530 case SOCKET_SERVER_UNIX: {
531 char *id;
532
533 if (!s->filename)
534 return NULL;
535
536 if (!(id = pa_machine_id()))
537 return NULL;
538
539 pa_snprintf(c, l, "{%s}unix:%s", id, s->filename);
540 pa_xfree(id);
541 return c;
542 }
543
544 default:
545 return NULL;
546 }
547 }