Git init
[framework/multimedia/pulseaudio.git] / src / pulsecore / socket-util.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2006 Lennart Poettering
5   Copyright 2004 Joe Marcus Clarke
6   Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
7
8   PulseAudio is free software; you can redistribute it and/or modify
9   it under the terms of the GNU Lesser General Public License as published
10   by the Free Software Foundation; either version 2.1 of the License,
11   or (at your option) any later version.
12
13   PulseAudio is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with PulseAudio; if not, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21   USA.
22 ***/
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdarg.h>
29 #include <stdlib.h>
30 #include <signal.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <sys/stat.h>
38
39 #ifdef HAVE_SYS_SOCKET_H
40 #include <sys/socket.h>
41 #endif
42 #ifdef HAVE_SYS_UN_H
43 #include <sys/un.h>
44 #endif
45 #ifdef HAVE_NETINET_IN_H
46 #include <netinet/in.h>
47 #endif
48 #ifdef HAVE_NETINET_IN_SYSTM_H
49 #include <netinet/in_systm.h>
50 #endif
51 #ifdef HAVE_NETINET_IP_H
52 #include <netinet/ip.h>
53 #endif
54 #ifdef HAVE_NETINET_TCP_H
55 #include <netinet/tcp.h>
56 #endif
57 #ifdef HAVE_NETDB_H
58 #include <netdb.h>
59 #endif
60 #ifdef HAVE_ARPA_INET_H
61 #include <arpa/inet.h>
62 #endif
63
64 #ifndef HAVE_INET_NTOP
65 #include "inet_ntop.h"
66 #endif
67
68 #include "winsock.h"
69
70 #include <pulse/xmalloc.h>
71
72 #include <pulsecore/core-error.h>
73 #include <pulsecore/core-util.h>
74 #include <pulsecore/log.h>
75 #include <pulsecore/macro.h>
76
77 #include "socket-util.h"
78
79 void pa_socket_peer_to_string(int fd, char *c, size_t l) {
80     struct stat st;
81
82     pa_assert(fd >= 0);
83     pa_assert(c);
84     pa_assert(l > 0);
85
86 #ifndef OS_IS_WIN32
87     pa_assert_se(fstat(fd, &st) == 0);
88 #endif
89
90 #ifndef OS_IS_WIN32
91     if (S_ISSOCK(st.st_mode)) {
92 #endif
93         union {
94             struct sockaddr sa;
95             struct sockaddr_in in;
96 #ifdef HAVE_IPV6
97             struct sockaddr_in6 in6;
98 #endif
99 #ifdef HAVE_SYS_UN_H
100             struct sockaddr_un un;
101 #endif
102         } sa;
103         socklen_t sa_len = sizeof(sa);
104
105         if (getpeername(fd, &sa.sa, &sa_len) >= 0) {
106
107             if (sa.sa.sa_family == AF_INET) {
108                 uint32_t ip = ntohl(sa.in.sin_addr.s_addr);
109
110                 pa_snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u",
111                             ip >> 24,
112                             (ip >> 16) & 0xFF,
113                             (ip >> 8) & 0xFF,
114                             ip & 0xFF,
115                             ntohs(sa.in.sin_port));
116                 return;
117 #ifdef HAVE_IPV6
118             } else if (sa.sa.sa_family == AF_INET6) {
119                 char buf[INET6_ADDRSTRLEN];
120                 const char *res;
121
122                 res = inet_ntop(AF_INET6, &sa.in6.sin6_addr, buf, sizeof(buf));
123                 if (res) {
124                     pa_snprintf(c, l, "TCP/IP client from [%s]:%u", buf, ntohs(sa.in6.sin6_port));
125                     return;
126                 }
127 #endif
128 #ifdef HAVE_SYS_UN_H
129             } else if (sa.sa.sa_family == AF_UNIX) {
130                 pa_snprintf(c, l, "UNIX socket client");
131                 return;
132 #endif
133             }
134         }
135
136 #ifndef OS_IS_WIN32
137         pa_snprintf(c, l, "Unknown network client");
138         return;
139     } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) {
140         pa_snprintf(c, l, "STDIN/STDOUT client");
141         return;
142     }
143 #endif /* OS_IS_WIN32 */
144
145     pa_snprintf(c, l, "Unknown client");
146 }
147
148 void pa_make_socket_low_delay(int fd) {
149
150 #ifdef SO_PRIORITY
151     int priority;
152     pa_assert(fd >= 0);
153
154     priority = 6;
155     if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority, sizeof(priority)) < 0)
156         pa_log_warn("SO_PRIORITY failed: %s", pa_cstrerror(errno));
157 #endif
158 }
159
160 void pa_make_tcp_socket_low_delay(int fd) {
161     pa_assert(fd >= 0);
162
163     pa_make_socket_low_delay(fd);
164
165 #if defined(SOL_TCP) || defined(IPPROTO_TCP)
166     {
167         int on = 1;
168 #if defined(SOL_TCP)
169         if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0)
170 #else
171         if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0)
172 #endif
173             pa_log_warn("TCP_NODELAY failed: %s", pa_cstrerror(errno));
174     }
175 #endif
176
177 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
178     {
179         int tos = IPTOS_LOWDELAY;
180 #ifdef SOL_IP
181         if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
182 #else
183         if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
184 #endif
185             pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
186     }
187 #endif
188 }
189
190 void pa_make_udp_socket_low_delay(int fd) {
191     pa_assert(fd >= 0);
192
193     pa_make_socket_low_delay(fd);
194
195 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
196     {
197         int tos = IPTOS_LOWDELAY;
198 #ifdef SOL_IP
199         if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
200 #else
201         if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
202 #endif
203             pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
204     }
205 #endif
206 }
207
208 int pa_socket_set_rcvbuf(int fd, size_t l) {
209     int bufsz = (int)l;
210
211     pa_assert(fd >= 0);
212
213     if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsz, sizeof(bufsz)) < 0) {
214         pa_log_warn("SO_RCVBUF: %s", pa_cstrerror(errno));
215         return -1;
216     }
217
218     return 0;
219 }
220
221 int pa_socket_set_sndbuf(int fd, size_t l) {
222     int bufsz = (int)l;
223
224     pa_assert(fd >= 0);
225
226     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsz, sizeof(bufsz)) < 0) {
227         pa_log("SO_SNDBUF: %s", pa_cstrerror(errno));
228         return -1;
229     }
230
231     return 0;
232 }
233
234 #ifdef HAVE_SYS_UN_H
235
236 int pa_unix_socket_is_stale(const char *fn) {
237     struct sockaddr_un sa;
238     int fd = -1, ret = -1;
239
240     pa_assert(fn);
241
242     if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
243         pa_log("socket(): %s", pa_cstrerror(errno));
244         goto finish;
245     }
246
247     sa.sun_family = AF_UNIX;
248     strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1);
249     sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
250
251     if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) {
252         if (errno == ECONNREFUSED)
253             ret = 1;
254     } else
255         ret = 0;
256
257 finish:
258     if (fd >= 0)
259         pa_close(fd);
260
261     return ret;
262 }
263
264 int pa_unix_socket_remove_stale(const char *fn) {
265     int r;
266
267     pa_assert(fn);
268
269     if ((r = pa_unix_socket_is_stale(fn)) < 0)
270         return errno != ENOENT ? -1 : 0;
271
272     if (!r)
273         return 0;
274
275     /* Yes, here is a race condition. But who cares? */
276     if (unlink(fn) < 0)
277         return -1;
278
279     return 0;
280 }
281
282 #else /* HAVE_SYS_UN_H */
283
284 int pa_unix_socket_is_stale(const char *fn) {
285     return -1;
286 }
287
288 int pa_unix_socket_remove_stale(const char *fn) {
289     return -1;
290 }
291
292 #endif /* HAVE_SYS_UN_H */
293
294
295 pa_bool_t pa_socket_address_is_local(const struct sockaddr *sa) {
296     pa_assert(sa);
297
298     switch (sa->sa_family) {
299         case AF_UNIX:
300             return TRUE;
301
302         case AF_INET:
303             return ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK;
304
305 #ifdef HAVE_IPV6
306         case AF_INET6:
307             return memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0;
308 #endif
309
310         default:
311             return FALSE;
312     }
313 }
314
315 pa_bool_t pa_socket_is_local(int fd) {
316
317     union {
318         struct sockaddr sa;
319         struct sockaddr_in in;
320 #ifdef HAVE_IPV6
321         struct sockaddr_in6 in6;
322 #endif
323 #ifdef HAVE_SYS_UN_H
324         struct sockaddr_un un;
325 #endif
326     } sa;
327     socklen_t sa_len = sizeof(sa);
328
329     if (getpeername(fd, &sa.sa, &sa_len) < 0)
330         return FALSE;
331
332     return pa_socket_address_is_local(&sa.sa);
333 }