• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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