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);
91 if (S_ISSOCK(st.st_mode)) {
95 struct sockaddr_in in;
97 struct sockaddr_in6 in6;
100 struct sockaddr_un un;
103 socklen_t sa_len = sizeof(sa);
105 if (getpeername(fd, &sa.sa, &sa_len) >= 0) {
107 if (sa.sa.sa_family == AF_INET) {
108 uint32_t ip = ntohl(sa.in.sin_addr.s_addr);
110 pa_snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u",
115 ntohs(sa.in.sin_port));
118 } else if (sa.sa.sa_family == AF_INET6) {
119 char buf[INET6_ADDRSTRLEN];
122 res = inet_ntop(AF_INET6, &sa.in6.sin6_addr, buf, sizeof(buf));
124 pa_snprintf(c, l, "TCP/IP client from [%s]:%u", buf, ntohs(sa.in6.sin6_port));
129 } else if (sa.sa.sa_family == AF_UNIX) {
130 pa_snprintf(c, l, "UNIX socket client");
137 pa_snprintf(c, l, "Unknown network client");
139 } else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) {
140 pa_snprintf(c, l, "STDIN/STDOUT client");
143 #endif /* OS_IS_WIN32 */
145 pa_snprintf(c, l, "Unknown client");
148 void pa_make_socket_low_delay(int fd) {
155 if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority, sizeof(priority)) < 0)
156 pa_log_warn("SO_PRIORITY failed: %s", pa_cstrerror(errno));
160 void pa_make_tcp_socket_low_delay(int fd) {
163 pa_make_socket_low_delay(fd);
165 #if defined(SOL_TCP) || defined(IPPROTO_TCP)
169 if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0)
171 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void*)&on, sizeof(on)) < 0)
173 pa_log_warn("TCP_NODELAY failed: %s", pa_cstrerror(errno));
177 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
179 int tos = IPTOS_LOWDELAY;
181 if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
183 if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
185 pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
190 void pa_make_udp_socket_low_delay(int fd) {
193 pa_make_socket_low_delay(fd);
195 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
197 int tos = IPTOS_LOWDELAY;
199 if (setsockopt(fd, SOL_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
201 if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) < 0)
203 pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
208 int pa_socket_set_rcvbuf(int fd, size_t l) {
213 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsz, sizeof(bufsz)) < 0) {
214 pa_log_warn("SO_RCVBUF: %s", pa_cstrerror(errno));
221 int pa_socket_set_sndbuf(int fd, size_t l) {
226 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsz, sizeof(bufsz)) < 0) {
227 pa_log("SO_SNDBUF: %s", pa_cstrerror(errno));
236 int pa_unix_socket_is_stale(const char *fn) {
237 struct sockaddr_un sa;
238 int fd = -1, ret = -1;
242 if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
243 pa_log("socket(): %s", pa_cstrerror(errno));
247 sa.sun_family = AF_UNIX;
248 strncpy(sa.sun_path, fn, sizeof(sa.sun_path)-1);
249 sa.sun_path[sizeof(sa.sun_path) - 1] = 0;
251 if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) {
252 if (errno == ECONNREFUSED)
264 int pa_unix_socket_remove_stale(const char *fn) {
269 if ((r = pa_unix_socket_is_stale(fn)) < 0)
270 return errno != ENOENT ? -1 : 0;
275 /* Yes, here is a race condition. But who cares? */
282 #else /* HAVE_SYS_UN_H */
284 int pa_unix_socket_is_stale(const char *fn) {
288 int pa_unix_socket_remove_stale(const char *fn) {
292 #endif /* HAVE_SYS_UN_H */
295 pa_bool_t pa_socket_address_is_local(const struct sockaddr *sa) {
298 switch (sa->sa_family) {
303 return ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK;
307 return memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0;
315 pa_bool_t pa_socket_is_local(int fd) {
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);