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