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