]> code.delx.au - pulseaudio/blob - src/pulsecore/socket-util.c
namereg: choose default sink/source as soon as one becomes available
[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 #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 }