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
34 #include <sys/types.h>
39 #ifdef HAVE_SYS_SOCKET_H
40 #include <sys/socket.h>
45 #ifdef HAVE_NETINET_IN_H
46 #include <netinet/in.h>
48 #ifdef HAVE_NETINET_IN_SYSTM_H
49 #include <netinet/in_systm.h>
51 #ifdef HAVE_NETINET_IP_H
52 #include <netinet/ip.h>
54 #ifdef HAVE_NETINET_TCP_H
55 #include <netinet/tcp.h>
60 #ifdef HAVE_ARPA_INET_H
61 #include <arpa/inet.h>
64 #ifndef HAVE_INET_NTOP
65 #include "inet_ntop.h"
70 #include <pulse/xmalloc.h>
72 #include <pulsecore/core-error.h>
73 #include <pulsecore/core-util.h>
74 #include <pulsecore/log.h>
75 #include <pulsecore/macro.h>
77 #include "socket-util.h"
79 void pa_socket_peer_to_string(int fd, char *c, size_t l) {
87 pa_assert_se(fstat(fd, &st) == 0);
89 if (S_ISSOCK(st.st_mode)) {
92 struct sockaddr_storage storage;
94 struct sockaddr_in in;
96 struct sockaddr_in6 in6;
99 struct sockaddr_un un;
102 socklen_t sa_len = sizeof(sa);
104 if (getpeername(fd, &sa.sa, &sa_len) >= 0) {
106 if (sa.sa.sa_family == AF_INET) {
107 uint32_t ip = ntohl(sa.in.sin_addr.s_addr);
109 pa_snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u",
114 ntohs(sa.in.sin_port));
117 } else if (sa.sa.sa_family == AF_INET6) {
118 char buf[INET6_ADDRSTRLEN];
121 res = inet_ntop(AF_INET6, &sa.in6.sin6_addr, buf, sizeof(buf));
123 pa_snprintf(c, l, "TCP/IP client from [%s]:%u", buf, ntohs(sa.in6.sin6_port));
128 } else if (sa.sa.sa_family == AF_UNIX) {
129 pa_snprintf(c, l, "UNIX socket client");
136 pa_snprintf(c, l, "Unknown network client");
138 } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) {
139 pa_snprintf(c, l, "STDIN/STDOUT client");
142 #endif /* OS_IS_WIN32 */
144 pa_snprintf(c, l, "Unknown client");
147 void pa_make_socket_low_delay(int fd) {
154 if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0)
155 pa_log_warn("SO_PRIORITY failed: %s", pa_cstrerror(errno));
159 void pa_make_tcp_socket_low_delay(int fd) {
162 pa_make_socket_low_delay(fd);
164 #if defined(SOL_TCP) || defined(IPPROTO_TCP)
168 if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
170 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
172 pa_log_warn("TCP_NODELAY failed: %s", pa_cstrerror(errno));
176 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
178 int tos = IPTOS_LOWDELAY;
180 if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0)
182 if (setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0)
184 pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
189 void pa_make_udp_socket_low_delay(int fd) {
192 pa_make_socket_low_delay(fd);
194 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
196 int tos = IPTOS_LOWDELAY;
198 if (setsockopt(fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0)
200 if (setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0)
202 pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
207 int pa_socket_set_rcvbuf(int fd, size_t l) {
212 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsz, sizeof(bufsz)) < 0) {
213 pa_log_warn("SO_RCVBUF: %s", pa_cstrerror(errno));
220 int pa_socket_set_sndbuf(int fd, size_t l) {
225 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bufsz, sizeof(bufsz)) < 0) {
226 pa_log_warn("SO_SNDBUF: %s", pa_cstrerror(errno));
235 int pa_unix_socket_is_stale(const char *fn) {
236 struct sockaddr_un sa;
237 int fd = -1, ret = -1;
241 if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) {
242 pa_log("socket(): %s", pa_cstrerror(errno));
246 sa.sun_family = AF_UNIX;
247 strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1);
248 sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
250 if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) {
251 if (errno == ECONNREFUSED)
263 int pa_unix_socket_remove_stale(const char *fn) {
268 if ((r = pa_unix_socket_is_stale(fn)) < 0)
269 return errno != ENOENT ? -1 : 0;
274 /* Yes, here is a race condition. But who cares? */
281 #else /* HAVE_SYS_UN_H */
283 int pa_unix_socket_is_stale(const char *fn) {
287 int pa_unix_socket_remove_stale(const char *fn) {
291 #endif /* HAVE_SYS_UN_H */
294 pa_bool_t pa_socket_address_is_local(const struct sockaddr *sa) {
297 switch (sa->sa_family) {
302 return ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK;
306 return memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0;
314 pa_bool_t pa_socket_is_local(int fd) {
317 struct sockaddr_storage storage;
319 struct sockaddr_in in;
321 struct sockaddr_in6 in6;
324 struct sockaddr_un un;
327 socklen_t sa_len = sizeof(sa);
329 if (getpeername(fd, &sa.sa, &sa_len) < 0)
332 return pa_socket_address_is_local(&sa.sa);