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