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