virtual-sink: Fix a crash when moving the sink to a new master right after setup.
[pulseaudio-raopUDP/pulseaudio-raop-alac.git] / src / pulsecore / socket-util.c
blob0b16e0f95ec5d916f652003c7315c19b8673ba7b
1 /***
2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2004 Joe Marcus Clarke
6 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
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 ***/
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
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>
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
61 #ifndef HAVE_INET_NTOP
62 #include <pulsecore/inet_ntop.h>
63 #endif
65 #include <pulse/xmalloc.h>
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>
73 #include "socket-util.h"
75 void pa_socket_peer_to_string(int fd, char *c, size_t l) {
76 struct stat st;
78 pa_assert(fd >= 0);
79 pa_assert(c);
80 pa_assert(l > 0);
82 #ifndef OS_IS_WIN32
83 pa_assert_se(fstat(fd, &st) == 0);
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);
100 if (getpeername(fd, &sa.sa, &sa_len) >= 0) {
102 if (sa.sa.sa_family == AF_INET) {
103 uint32_t ip = ntohl(sa.in.sin_addr.s_addr);
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;
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;
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
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;
138 #endif /* OS_IS_WIN32 */
140 pa_snprintf(c, l, "Unknown client");
143 void pa_make_socket_low_delay(int fd) {
145 #ifdef SO_PRIORITY
146 int priority;
147 pa_assert(fd >= 0);
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
155 void pa_make_tcp_socket_low_delay(int fd) {
156 pa_assert(fd >= 0);
158 pa_make_socket_low_delay(fd);
160 #if defined(SOL_TCP) || defined(IPPROTO_TCP)
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));
170 #endif
172 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
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));
182 #endif
185 void pa_make_udp_socket_low_delay(int fd) {
186 pa_assert(fd >= 0);
188 pa_make_socket_low_delay(fd);
190 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
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));
200 #endif
203 int pa_socket_set_rcvbuf(int fd, size_t l) {
204 int bufsz = (int) l;
206 pa_assert(fd >= 0);
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;
213 return 0;
216 int pa_socket_set_sndbuf(int fd, size_t l) {
217 int bufsz = (int) l;
219 pa_assert(fd >= 0);
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;
226 return 0;
229 #ifdef HAVE_SYS_UN_H
231 int pa_unix_socket_is_stale(const char *fn) {
232 struct sockaddr_un sa;
233 int fd = -1, ret = -1;
235 pa_assert(fn);
237 if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) {
238 pa_log("socket(): %s", pa_cstrerror(errno));
239 goto finish;
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;
246 if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) {
247 if (errno == ECONNREFUSED)
248 ret = 1;
249 } else
250 ret = 0;
252 finish:
253 if (fd >= 0)
254 pa_close(fd);
256 return ret;
259 int pa_unix_socket_remove_stale(const char *fn) {
260 int r;
262 pa_assert(fn);
264 if ((r = pa_unix_socket_is_stale(fn)) < 0)
265 return errno != ENOENT ? -1 : 0;
267 if (!r)
268 return 0;
270 /* Yes, here is a race condition. But who cares? */
271 if (unlink(fn) < 0)
272 return -1;
274 return 0;
277 #else /* HAVE_SYS_UN_H */
279 int pa_unix_socket_is_stale(const char *fn) {
280 return -1;
283 int pa_unix_socket_remove_stale(const char *fn) {
284 return -1;
287 #endif /* HAVE_SYS_UN_H */
290 pa_bool_t pa_socket_address_is_local(const struct sockaddr *sa) {
291 pa_assert(sa);
293 switch (sa->sa_family) {
294 case AF_UNIX:
295 return TRUE;
297 case AF_INET:
298 return ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK;
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
305 default:
306 return FALSE;
310 pa_bool_t pa_socket_is_local(int fd) {
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);
325 if (getpeername(fd, &sa.sa, &sa_len) < 0)
326 return FALSE;
328 return pa_socket_address_is_local(&sa.sa);