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, see <http://www.gnu.org/licenses/>.
31 #include <sys/types.h>
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
41 #ifdef HAVE_NETINET_IN_SYSTM_H
42 #include <netinet/in_systm.h>
44 #ifdef HAVE_NETINET_IP_H
45 #include <netinet/ip.h>
47 #ifdef HAVE_NETINET_TCP_H
48 #include <netinet/tcp.h>
53 #ifdef HAVE_SYSTEMD_DAEMON
54 #include <systemd/sd-daemon.h>
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>
64 #include "socket-util.h"
66 void pa_socket_peer_to_string(int fd, char *c, size_t l) {
76 pa_assert_se(fstat(fd, &st) == 0);
78 if (S_ISSOCK(st.st_mode))
82 struct sockaddr_storage storage;
84 struct sockaddr_in in;
86 struct sockaddr_in6 in6;
89 struct sockaddr_un un;
92 socklen_t sa_len = sizeof(sa);
94 if (getpeername(fd, &sa.sa, &sa_len) >= 0) {
96 if (sa.sa.sa_family == AF_INET) {
97 uint32_t ip = ntohl(sa.in.sin_addr.s_addr);
99 pa_snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u",
104 ntohs(sa.in.sin_port));
107 } else if (sa.sa.sa_family == AF_INET6) {
108 char buf[INET6_ADDRSTRLEN];
111 res = inet_ntop(AF_INET6, &sa.in6.sin6_addr, buf, sizeof(buf));
113 pa_snprintf(c, l, "TCP/IP client from [%s]:%u", buf, ntohs(sa.in6.sin6_port));
118 } else if (sa.sa.sa_family == AF_UNIX) {
119 pa_snprintf(c, l, "UNIX socket client");
125 pa_snprintf(c, l, "Unknown network client");
129 else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) {
130 pa_snprintf(c, l, "STDIN/STDOUT client");
133 #endif /* OS_IS_WIN32 */
135 pa_snprintf(c, l, "Unknown client");
138 void pa_make_socket_low_delay(int fd) {
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));
150 void pa_make_tcp_socket_low_delay(int fd) {
153 pa_make_socket_low_delay(fd);
155 #if defined(SOL_TCP) || defined(IPPROTO_TCP)
159 if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *) &on, sizeof(on)) < 0)
161 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &on, sizeof(on)) < 0)
163 pa_log_warn("TCP_NODELAY failed: %s", pa_cstrerror(errno));
167 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
169 int tos = IPTOS_LOWDELAY;
171 if (setsockopt(fd, SOL_IP, IP_TOS, (const void *) &tos, sizeof(tos)) < 0)
173 if (setsockopt(fd, IPPROTO_IP, IP_TOS, (const void *) &tos, sizeof(tos)) < 0)
175 pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
180 void pa_make_udp_socket_low_delay(int fd) {
183 pa_make_socket_low_delay(fd);
185 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
187 int tos = IPTOS_LOWDELAY;
189 if (setsockopt(fd, SOL_IP, IP_TOS, (const void *) &tos, sizeof(tos)) < 0)
191 if (setsockopt(fd, IPPROTO_IP, IP_TOS, (const void *) &tos, sizeof(tos)) < 0)
193 pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
198 int pa_socket_set_rcvbuf(int fd, size_t l) {
203 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const void *) &bufsz, sizeof(bufsz)) < 0) {
204 pa_log_warn("SO_RCVBUF: %s", pa_cstrerror(errno));
211 int pa_socket_set_sndbuf(int fd, size_t l) {
216 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &bufsz, sizeof(bufsz)) < 0) {
217 pa_log_warn("SO_SNDBUF: %s", pa_cstrerror(errno));
226 int pa_unix_socket_is_stale(const char *fn) {
227 struct sockaddr_un sa;
228 int fd = -1, ret = -1;
232 if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) {
233 pa_log("socket(): %s", pa_cstrerror(errno));
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;
241 if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) {
242 #if !defined(OS_IS_WIN32)
243 if (errno == ECONNREFUSED)
246 if (WSAGetLastError() == WSAECONNREFUSED || WSAGetLastError() == WSAEINVAL)
259 int pa_unix_socket_remove_stale(const char *fn) {
264 #ifdef HAVE_SYSTEMD_DAEMON
266 int n = sd_listen_fds(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
279 if ((r = pa_unix_socket_is_stale(fn)) < 0)
280 return errno != ENOENT ? -1 : 0;
285 /* Yes, here is a race condition. But who cares? */
292 #else /* HAVE_SYS_UN_H */
294 int pa_unix_socket_is_stale(const char *fn) {
298 int pa_unix_socket_remove_stale(const char *fn) {
302 #endif /* HAVE_SYS_UN_H */
304 bool pa_socket_address_is_local(const struct sockaddr *sa) {
307 switch (sa->sa_family) {
312 return ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK;
316 return memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0;
324 bool pa_socket_is_local(int fd) {
327 struct sockaddr_storage storage;
329 struct sockaddr_in in;
331 struct sockaddr_in6 in6;
334 struct sockaddr_un un;
337 socklen_t sa_len = sizeof(sa);
339 if (getpeername(fd, &sa.sa, &sa_len) < 0)
342 return pa_socket_address_is_local(&sa.sa);