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