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