Add default-monitor-time-sec
[platform/upstream/pulseaudio.git] / 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, 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
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
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
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
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
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
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
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 !defined(OS_IS_WIN32)
243         if (errno == ECONNREFUSED)
244             ret = 1;
245 #else
246         if (WSAGetLastError() == WSAECONNREFUSED || WSAGetLastError() == WSAEINVAL)
247             ret = 1;
248 #endif
249     } else
250         ret = 0;
251
252 finish:
253     if (fd >= 0)
254         pa_close(fd);
255
256     return ret;
257 }
258
259 int pa_unix_socket_remove_stale(const char *fn) {
260     int r;
261
262     pa_assert(fn);
263
264 #ifdef HAVE_SYSTEMD_DAEMON
265     {
266         int n = sd_listen_fds(0);
267         if (n > 0) {
268             for (int i = 0; i < n; ++i) {
269                 if (sd_is_socket_unix(SD_LISTEN_FDS_START + i, SOCK_STREAM, 1, fn, 0) > 0) {
270                     /* This is a socket activated socket, therefore do not consider
271                     * it stale. */
272                     return 0;
273                 }
274             }
275         }
276     }
277 #endif
278
279     if ((r = pa_unix_socket_is_stale(fn)) < 0)
280         return errno != ENOENT ? -1 : 0;
281
282     if (!r)
283         return 0;
284
285     /* Yes, here is a race condition. But who cares? */
286     if (unlink(fn) < 0)
287         return -1;
288
289     return 0;
290 }
291
292 #else /* HAVE_SYS_UN_H */
293
294 int pa_unix_socket_is_stale(const char *fn) {
295     return -1;
296 }
297
298 int pa_unix_socket_remove_stale(const char *fn) {
299     return -1;
300 }
301
302 #endif /* HAVE_SYS_UN_H */
303
304 bool pa_socket_address_is_local(const struct sockaddr *sa) {
305     pa_assert(sa);
306
307     switch (sa->sa_family) {
308         case AF_UNIX:
309             return true;
310
311         case AF_INET:
312             return ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK;
313
314 #ifdef HAVE_IPV6
315         case AF_INET6:
316             return memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0;
317 #endif
318
319         default:
320             return false;
321     }
322 }
323
324 bool pa_socket_is_local(int fd) {
325
326     union {
327         struct sockaddr_storage storage;
328         struct sockaddr sa;
329         struct sockaddr_in in;
330 #ifdef HAVE_IPV6
331         struct sockaddr_in6 in6;
332 #endif
333 #ifdef HAVE_SYS_UN_H
334         struct sockaddr_un un;
335 #endif
336     } sa;
337     socklen_t sa_len = sizeof(sa);
338
339     if (getpeername(fd, &sa.sa, &sa_len) < 0)
340         return false;
341
342     return pa_socket_address_is_local(&sa.sa);
343 }