Git init
[framework/multimedia/pulseaudio.git] / 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 }