Add copyright notices to all relevant files. (based on svn log)
[profile/ivi/pulseaudio.git] / src / pulsecore / socket-server.c
1 /* $Id$ */
2
3 /***
4   This file is part of PulseAudio.
5
6   Copyright 2004-2006 Lennart Poettering
7   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
8
9   PulseAudio is free software; you can redistribute it and/or modify
10   it under the terms of the GNU Lesser General Public License as published
11   by the Free Software Foundation; either version 2 of the License,
12   or (at your option) any later version.
13
14   PulseAudio is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with PulseAudio; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22   USA.
23 ***/
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdlib.h>
30 #include <assert.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #include <stdio.h>
35 #include <unistd.h>
36 #include <sys/stat.h>
37
38 #ifdef HAVE_SYS_SOCKET_H
39 #include <sys/socket.h>
40 #endif
41 #ifdef HAVE_SYS_UN_H
42 #include <sys/un.h>
43 #ifndef SUN_LEN
44 #define SUN_LEN(ptr) \
45     ((size_t)(((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path))
46 #endif
47 #endif
48 #ifdef HAVE_ARPA_INET_H
49 #include <arpa/inet.h>
50 #endif
51 #ifdef HAVE_NETINET_IN_H
52 #include <netinet/in.h>
53 #endif
54
55 #ifdef HAVE_LIBWRAP
56 #include <tcpd.h>
57 #endif
58
59 #ifndef HAVE_INET_NTOP
60 #include "inet_ntop.h"
61 #endif
62
63 #ifndef HAVE_INET_PTON
64 #include "inet_pton.h"
65 #endif
66
67 #include "winsock.h"
68
69 #include <pulse/xmalloc.h>
70 #include <pulse/util.h>
71
72 #include <pulsecore/socket-util.h>
73 #include <pulsecore/core-util.h>
74 #include <pulsecore/log.h>
75 #include <pulsecore/core-error.h>
76
77 #include "socket-server.h"
78
79 struct pa_socket_server {
80     int ref;
81     int fd;
82     char *filename;
83     char *tcpwrap_service;
84
85     void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata);
86     void *userdata;
87
88     pa_io_event *io_event;
89     pa_mainloop_api *mainloop;
90     enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX, SOCKET_SERVER_IPV6 } type;
91 };
92
93 static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) {
94     pa_socket_server *s = userdata;
95     pa_iochannel *io;
96     int nfd;
97     assert(s && s->mainloop == mainloop && s->io_event == e && e && fd >= 0 && fd == s->fd);
98
99     pa_socket_server_ref(s);
100
101     if ((nfd = accept(fd, NULL, NULL)) < 0) {
102         pa_log("accept(): %s", pa_cstrerror(errno));
103         goto finish;
104     }
105
106     pa_fd_set_cloexec(nfd, 1);
107
108     if (!s->on_connection) {
109         close(nfd);
110         goto finish;
111     }
112
113 #ifdef HAVE_LIBWRAP
114
115     if (s->tcpwrap_service) {
116         struct request_info req;
117
118         request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL);
119         fromhost(&req);
120         if (!hosts_access(&req)) {
121             pa_log_warn("TCP connection refused by tcpwrap.");
122             close(nfd);
123             goto finish;
124         }
125
126         pa_log_info("TCP connection accepted by tcpwrap.");
127     }
128 #endif
129
130     /* There should be a check for socket type here */
131     if (s->type == SOCKET_SERVER_IPV4)
132         pa_socket_tcp_low_delay(fd);
133     else
134         pa_socket_low_delay(fd);
135
136     io = pa_iochannel_new(s->mainloop, nfd, nfd);
137     assert(io);
138     s->on_connection(s, io, s->userdata);
139
140 finish:
141     pa_socket_server_unref(s);
142 }
143
144 pa_socket_server* pa_socket_server_new(pa_mainloop_api *m, int fd) {
145     pa_socket_server *s;
146     assert(m && fd >= 0);
147
148     s = pa_xmalloc(sizeof(pa_socket_server));
149     s->ref = 1;
150     s->fd = fd;
151     s->filename = NULL;
152     s->on_connection = NULL;
153     s->userdata = NULL;
154     s->tcpwrap_service = NULL;
155
156     s->mainloop = m;
157     s->io_event = m->io_new(m, fd, PA_IO_EVENT_INPUT, callback, s);
158     assert(s->io_event);
159
160     s->type = SOCKET_SERVER_GENERIC;
161
162     return s;
163 }
164
165 pa_socket_server* pa_socket_server_ref(pa_socket_server *s) {
166     assert(s && s->ref >= 1);
167     s->ref++;
168     return s;
169 }
170
171 #ifdef HAVE_SYS_UN_H
172
173 pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) {
174     int fd = -1;
175     struct sockaddr_un sa;
176     pa_socket_server *s;
177
178     assert(m && filename);
179
180     if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
181         pa_log("socket(): %s", pa_cstrerror(errno));
182         goto fail;
183     }
184
185     pa_fd_set_cloexec(fd, 1);
186
187     sa.sun_family = AF_UNIX;
188     strncpy(sa.sun_path, filename, sizeof(sa.sun_path)-1);
189     sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
190
191     pa_socket_low_delay(fd);
192
193     if (bind(fd, (struct sockaddr*) &sa, SUN_LEN(&sa)) < 0) {
194         pa_log("bind(): %s", pa_cstrerror(errno));
195         goto fail;
196     }
197
198     /* Allow access from all clients. Sockets like this one should
199      * always be put inside a directory with proper access rights,
200      * because not all OS check the access rights on the socket
201      * inodes. */
202     chmod(filename, 0777);
203
204     if (listen(fd, 5) < 0) {
205         pa_log("listen(): %s", pa_cstrerror(errno));
206         goto fail;
207     }
208
209     s = pa_socket_server_new(m, fd);
210     assert(s);
211
212     s->filename = pa_xstrdup(filename);
213     s->type = SOCKET_SERVER_UNIX;
214
215     return s;
216
217 fail:
218     if (fd >= 0)
219         close(fd);
220
221     return NULL;
222 }
223
224 #else /* HAVE_SYS_UN_H */
225
226 pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) {
227     return NULL;
228 }
229
230 #endif /* HAVE_SYS_UN_H */
231
232 pa_socket_server* pa_socket_server_new_ipv4(pa_mainloop_api *m, uint32_t address, uint16_t port, const char *tcpwrap_service) {
233     pa_socket_server *ss;
234     int fd = -1;
235     struct sockaddr_in sa;
236     int on = 1;
237
238     assert(m && port);
239
240     if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
241         pa_log("socket(PF_INET): %s", pa_cstrerror(errno));
242         goto fail;
243     }
244
245     pa_fd_set_cloexec(fd, 1);
246
247 #ifdef SO_REUSEADDR
248     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
249         pa_log("setsockopt(): %s", pa_cstrerror(errno));
250 #endif
251
252     pa_socket_tcp_low_delay(fd);
253
254     memset(&sa, 0, sizeof(sa));
255     sa.sin_family = AF_INET;
256     sa.sin_port = htons(port);
257     sa.sin_addr.s_addr = htonl(address);
258
259     if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
260         pa_log("bind(): %s", pa_cstrerror(errno));
261         goto fail;
262     }
263
264     if (listen(fd, 5) < 0) {
265         pa_log("listen(): %s", pa_cstrerror(errno));
266         goto fail;
267     }
268
269     if ((ss = pa_socket_server_new(m, fd))) {
270         ss->type = SOCKET_SERVER_IPV4;
271         ss->tcpwrap_service = pa_xstrdup(tcpwrap_service);
272     }
273
274     return ss;
275
276 fail:
277     if (fd >= 0)
278         close(fd);
279
280     return NULL;
281 }
282
283 pa_socket_server* pa_socket_server_new_ipv6(pa_mainloop_api *m, const uint8_t address[16], uint16_t port, const char *tcpwrap_service) {
284     pa_socket_server *ss;
285     int fd = -1;
286     struct sockaddr_in6 sa;
287     int on = 1;
288
289     assert(m && port);
290
291     if ((fd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) {
292         pa_log("socket(PF_INET6): %s", pa_cstrerror(errno));
293         goto fail;
294     }
295
296     pa_fd_set_cloexec(fd, 1);
297
298 #ifdef IPV6_V6ONLY
299     if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
300         pa_log("setsockopt(IPPROTO_IPV6, IPV6_V6ONLY): %s", pa_cstrerror(errno));
301 #endif
302
303 #ifdef SO_REUSEADDR
304     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
305         pa_log("setsockopt(SOL_SOCKET, SO_REUSEADDR, 1): %s", pa_cstrerror(errno));
306 #endif
307
308     pa_socket_tcp_low_delay(fd);
309
310     memset(&sa, 0, sizeof(sa));
311     sa.sin6_family = AF_INET6;
312     sa.sin6_port = htons(port);
313     memcpy(sa.sin6_addr.s6_addr, address, 16);
314
315     if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
316         pa_log("bind(): %s", pa_cstrerror(errno));
317         goto fail;
318     }
319
320     if (listen(fd, 5) < 0) {
321         pa_log("listen(): %s", pa_cstrerror(errno));
322         goto fail;
323     }
324
325     if ((ss = pa_socket_server_new(m, fd))) {
326         ss->type = SOCKET_SERVER_IPV6;
327         ss->tcpwrap_service = pa_xstrdup(tcpwrap_service);
328     }
329
330     return ss;
331
332 fail:
333     if (fd >= 0)
334         close(fd);
335
336     return NULL;
337 }
338
339 pa_socket_server* pa_socket_server_new_ipv4_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
340     assert(m);
341     assert(port > 0);
342
343     return pa_socket_server_new_ipv4(m, INADDR_LOOPBACK, port, tcpwrap_service);
344 }
345
346 pa_socket_server* pa_socket_server_new_ipv6_loopback(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
347     assert(m);
348     assert(port > 0);
349
350     return pa_socket_server_new_ipv6(m, in6addr_loopback.s6_addr, port, tcpwrap_service);
351 }
352
353 pa_socket_server* pa_socket_server_new_ipv4_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
354     assert(m);
355     assert(port > 0);
356
357     return pa_socket_server_new_ipv4(m, INADDR_ANY, port, tcpwrap_service);
358 }
359
360 pa_socket_server* pa_socket_server_new_ipv6_any(pa_mainloop_api *m, uint16_t port, const char *tcpwrap_service) {
361     assert(m);
362     assert(port > 0);
363
364     return pa_socket_server_new_ipv6(m, in6addr_any.s6_addr, port, tcpwrap_service);
365 }
366
367 pa_socket_server* pa_socket_server_new_ipv4_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) {
368     struct in_addr ipv4;
369
370     assert(m);
371     assert(name);
372     assert(port > 0);
373
374     if (inet_pton(AF_INET, name, &ipv4) > 0)
375         return pa_socket_server_new_ipv4(m, ntohl(ipv4.s_addr), port, tcpwrap_service);
376
377     return NULL;
378 }
379
380 pa_socket_server* pa_socket_server_new_ipv6_string(pa_mainloop_api *m, const char *name, uint16_t port, const char *tcpwrap_service) {
381     struct in6_addr ipv6;
382
383     assert(m);
384     assert(name);
385     assert(port > 0);
386
387     if (inet_pton(AF_INET6, name, &ipv6) > 0)
388         return pa_socket_server_new_ipv6(m, ipv6.s6_addr, port, tcpwrap_service);
389
390     return NULL;
391 }
392
393 static void socket_server_free(pa_socket_server*s) {
394     assert(s);
395
396     if (s->filename) {
397         unlink(s->filename);
398         pa_xfree(s->filename);
399     }
400
401     close(s->fd);
402
403     pa_xfree(s->tcpwrap_service);
404
405     s->mainloop->io_free(s->io_event);
406     pa_xfree(s);
407 }
408
409 void pa_socket_server_unref(pa_socket_server *s) {
410     assert(s && s->ref >= 1);
411
412     if (!(--(s->ref)))
413         socket_server_free(s);
414 }
415
416 void pa_socket_server_set_callback(pa_socket_server*s, void (*on_connection)(pa_socket_server*s, pa_iochannel *io, void *userdata), void *userdata) {
417     assert(s && s->ref >= 1);
418
419     s->on_connection = on_connection;
420     s->userdata = userdata;
421 }
422
423 char *pa_socket_server_get_address(pa_socket_server *s, char *c, size_t l) {
424     assert(s && c && l > 0);
425
426     switch (s->type) {
427         case SOCKET_SERVER_IPV6: {
428             struct sockaddr_in6 sa;
429             socklen_t sa_len = sizeof(sa);
430
431             if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
432                 pa_log("getsockname(): %s", pa_cstrerror(errno));
433                 return NULL;
434             }
435
436             if (memcmp(&in6addr_any, &sa.sin6_addr, sizeof(in6addr_any)) == 0) {
437                 char fqdn[256];
438                 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
439                     return NULL;
440
441                 snprintf(c, l, "tcp6:%s:%u", fqdn, (unsigned) ntohs(sa.sin6_port));
442
443             } else if (memcmp(&in6addr_loopback, &sa.sin6_addr, sizeof(in6addr_loopback)) == 0) {
444                 char hn[256];
445                 if (!pa_get_host_name(hn, sizeof(hn)))
446                     return NULL;
447
448                 snprintf(c, l, "{%s}tcp6:localhost:%u", hn, (unsigned) ntohs(sa.sin6_port));
449             } else {
450                 char ip[INET6_ADDRSTRLEN];
451
452                 if (!inet_ntop(AF_INET6, &sa.sin6_addr, ip, sizeof(ip))) {
453                     pa_log("inet_ntop(): %s", pa_cstrerror(errno));
454                     return NULL;
455                 }
456
457                 snprintf(c, l, "tcp6:[%s]:%u", ip, (unsigned) ntohs(sa.sin6_port));
458             }
459
460             return c;
461         }
462
463         case SOCKET_SERVER_IPV4: {
464             struct sockaddr_in sa;
465             socklen_t sa_len = sizeof(sa);
466
467             if (getsockname(s->fd, (struct sockaddr*) &sa, &sa_len) < 0) {
468                 pa_log("getsockname(): %s", pa_cstrerror(errno));
469                 return NULL;
470             }
471
472             if (sa.sin_addr.s_addr == INADDR_ANY) {
473                 char fqdn[256];
474                 if (!pa_get_fqdn(fqdn, sizeof(fqdn)))
475                     return NULL;
476
477                 snprintf(c, l, "tcp:%s:%u", fqdn, (unsigned) ntohs(sa.sin_port));
478             } else if (sa.sin_addr.s_addr == INADDR_LOOPBACK) {
479                 char hn[256];
480                 if (!pa_get_host_name(hn, sizeof(hn)))
481                     return NULL;
482
483                 snprintf(c, l, "{%s}tcp:localhost:%u", hn, (unsigned) ntohs(sa.sin_port));
484             } else {
485                 char ip[INET_ADDRSTRLEN];
486
487                 if (!inet_ntop(AF_INET, &sa.sin_addr, ip, sizeof(ip))) {
488                     pa_log("inet_ntop(): %s", pa_cstrerror(errno));
489                     return NULL;
490                 }
491
492                 snprintf(c, l, "tcp:[%s]:%u", ip, (unsigned) ntohs(sa.sin_port));
493
494             }
495
496             return c;
497         }
498
499         case SOCKET_SERVER_UNIX: {
500             char hn[256];
501
502             if (!s->filename)
503                 return NULL;
504
505             if (!pa_get_host_name(hn, sizeof(hn)))
506                 return NULL;
507
508             snprintf(c, l, "{%s}unix:%s", hn, s->filename);
509             return c;
510         }
511
512         default:
513             return NULL;
514     }
515 }