]> code.delx.au - pulseaudio/blob - src/pulsecore/socket-util.c
Merge remote branch 'phish3/master'
[pulseaudio] / 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
89 if (S_ISSOCK(st.st_mode)) {
90 #endif
91 union {
92 struct sockaddr_storage storage;
93 struct sockaddr sa;
94 struct sockaddr_in in;
95 #ifdef HAVE_IPV6
96 struct sockaddr_in6 in6;
97 #endif
98 #ifdef HAVE_SYS_UN_H
99 struct sockaddr_un un;
100 #endif
101 } sa;
102 socklen_t sa_len = sizeof(sa);
103
104 if (getpeername(fd, &sa.sa, &sa_len) >= 0) {
105
106 if (sa.sa.sa_family == AF_INET) {
107 uint32_t ip = ntohl(sa.in.sin_addr.s_addr);
108
109 pa_snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u",
110 ip >> 24,
111 (ip >> 16) & 0xFF,
112 (ip >> 8) & 0xFF,
113 ip & 0xFF,
114 ntohs(sa.in.sin_port));
115 return;
116 #ifdef HAVE_IPV6
117 } else if (sa.sa.sa_family == AF_INET6) {
118 char buf[INET6_ADDRSTRLEN];
119 const char *res;
120
121 res = inet_ntop(AF_INET6, &sa.in6.sin6_addr, buf, sizeof(buf));
122 if (res) {
123 pa_snprintf(c, l, "TCP/IP client from [%s]:%u", buf, ntohs(sa.in6.sin6_port));
124 return;
125 }
126 #endif
127 #ifdef HAVE_SYS_UN_H
128 } else if (sa.sa.sa_family == AF_UNIX) {
129 pa_snprintf(c, l, "UNIX socket client");
130 return;
131 #endif
132 }
133 }
134
135 #ifndef OS_IS_WIN32
136 pa_snprintf(c, l, "Unknown network client");
137 return;
138 } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) {
139 pa_snprintf(c, l, "STDIN/STDOUT client");
140 return;
141 }
142 #endif /* OS_IS_WIN32 */
143
144 pa_snprintf(c, l, "Unknown client");
145 }
146
147 void pa_make_socket_low_delay(int fd) {
148
149 #ifdef SO_PRIORITY
150 int priority;
151 pa_assert(fd >= 0);
152
153 priority = 6;
154 if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0)
155 pa_log_warn("SO_PRIORITY failed: %s", pa_cstrerror(errno));
156 #endif
157 }
158
159 void pa_make_tcp_socket_low_delay(int fd) {
160 pa_assert(fd >= 0);
161
162 pa_make_socket_low_delay(fd);
163
164 #if defined(SOL_TCP) || defined(IPPROTO_TCP)
165 {
166 int on = 1;
167 #if defined(SOL_TCP)
168 if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
169 #else
170 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
171 #endif
172 pa_log_warn("TCP_NODELAY failed: %s", pa_cstrerror(errno));
173 }
174 #endif
175
176 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
177 {
178 int tos = IPTOS_LOWDELAY;
179 #ifdef SOL_IP
180 if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0)
181 #else
182 if (setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0)
183 #endif
184 pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
185 }
186 #endif
187 }
188
189 void pa_make_udp_socket_low_delay(int fd) {
190 pa_assert(fd >= 0);
191
192 pa_make_socket_low_delay(fd);
193
194 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
195 {
196 int tos = IPTOS_LOWDELAY;
197 #ifdef SOL_IP
198 if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0)
199 #else
200 if (setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0)
201 #endif
202 pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
203 }
204 #endif
205 }
206
207 int pa_socket_set_rcvbuf(int fd, size_t l) {
208 int bufsz = (int) l;
209
210 pa_assert(fd >= 0);
211
212 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsz, sizeof(bufsz)) < 0) {
213 pa_log_warn("SO_RCVBUF: %s", pa_cstrerror(errno));
214 return -1;
215 }
216
217 return 0;
218 }
219
220 int pa_socket_set_sndbuf(int fd, size_t l) {
221 int bufsz = (int) l;
222
223 pa_assert(fd >= 0);
224
225 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bufsz, sizeof(bufsz)) < 0) {
226 pa_log_warn("SO_SNDBUF: %s", pa_cstrerror(errno));
227 return -1;
228 }
229
230 return 0;
231 }
232
233 #ifdef HAVE_SYS_UN_H
234
235 int pa_unix_socket_is_stale(const char *fn) {
236 struct sockaddr_un sa;
237 int fd = -1, ret = -1;
238
239 pa_assert(fn);
240
241 if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) {
242 pa_log("socket(): %s", pa_cstrerror(errno));
243 goto finish;
244 }
245
246 sa.sun_family = AF_UNIX;
247 strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1);
248 sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
249
250 if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) {
251 if (errno == ECONNREFUSED)
252 ret = 1;
253 } else
254 ret = 0;
255
256 finish:
257 if (fd >= 0)
258 pa_close(fd);
259
260 return ret;
261 }
262
263 int pa_unix_socket_remove_stale(const char *fn) {
264 int r;
265
266 pa_assert(fn);
267
268 if ((r = pa_unix_socket_is_stale(fn)) < 0)
269 return errno != ENOENT ? -1 : 0;
270
271 if (!r)
272 return 0;
273
274 /* Yes, here is a race condition. But who cares? */
275 if (unlink(fn) < 0)
276 return -1;
277
278 return 0;
279 }
280
281 #else /* HAVE_SYS_UN_H */
282
283 int pa_unix_socket_is_stale(const char *fn) {
284 return -1;
285 }
286
287 int pa_unix_socket_remove_stale(const char *fn) {
288 return -1;
289 }
290
291 #endif /* HAVE_SYS_UN_H */
292
293
294 pa_bool_t pa_socket_address_is_local(const struct sockaddr *sa) {
295 pa_assert(sa);
296
297 switch (sa->sa_family) {
298 case AF_UNIX:
299 return TRUE;
300
301 case AF_INET:
302 return ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK;
303
304 #ifdef HAVE_IPV6
305 case AF_INET6:
306 return memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0;
307 #endif
308
309 default:
310 return FALSE;
311 }
312 }
313
314 pa_bool_t pa_socket_is_local(int fd) {
315
316 union {
317 struct sockaddr_storage storage;
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 }