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>
42 #ifdef HAVE_NETINET_IN_H
43 #include <netinet/in.h>
45 #ifdef HAVE_NETINET_IN_SYSTM_H
46 #include <netinet/in_systm.h>
48 #ifdef HAVE_NETINET_IP_H
49 #include <netinet/ip.h>
51 #ifdef HAVE_NETINET_TCP_H
52 #include <netinet/tcp.h>
57 #ifdef HAVE_ARPA_INET_H
58 #include <arpa/inet.h>
61 #ifndef HAVE_INET_NTOP
62 #include <pulsecore/inet_ntop.h>
65 #include <pulse/xmalloc.h>
67 #include <pulsecore/core-error.h>
68 #include <pulsecore/core-util.h>
69 #include <pulsecore/log.h>
70 #include <pulsecore/macro.h>
71 #include <pulsecore/socket.h>
73 #include "socket-util.h"
75 void pa_socket_peer_to_string(int fd
, char *c
, size_t l
) {
83 pa_assert_se(fstat(fd
, &st
) == 0);
85 if (S_ISSOCK(st
.st_mode
)) {
88 struct sockaddr_storage storage
;
90 struct sockaddr_in in
;
92 struct sockaddr_in6 in6
;
95 struct sockaddr_un un
;
98 socklen_t sa_len
= sizeof(sa
);
100 if (getpeername(fd
, &sa
.sa
, &sa_len
) >= 0) {
102 if (sa
.sa
.sa_family
== AF_INET
) {
103 uint32_t ip
= ntohl(sa
.in
.sin_addr
.s_addr
);
105 pa_snprintf(c
, l
, "TCP/IP client from %i.%i.%i.%i:%u",
110 ntohs(sa
.in
.sin_port
));
113 } else if (sa
.sa
.sa_family
== AF_INET6
) {
114 char buf
[INET6_ADDRSTRLEN
];
117 res
= inet_ntop(AF_INET6
, &sa
.in6
.sin6_addr
, buf
, sizeof(buf
));
119 pa_snprintf(c
, l
, "TCP/IP client from [%s]:%u", buf
, ntohs(sa
.in6
.sin6_port
));
124 } else if (sa
.sa
.sa_family
== AF_UNIX
) {
125 pa_snprintf(c
, l
, "UNIX socket client");
132 pa_snprintf(c
, l
, "Unknown network client");
134 } else if (S_ISCHR(st
.st_mode
) && (fd
== 0 || fd
== 1)) {
135 pa_snprintf(c
, l
, "STDIN/STDOUT client");
138 #endif /* OS_IS_WIN32 */
140 pa_snprintf(c
, l
, "Unknown client");
143 void pa_make_socket_low_delay(int fd
) {
150 if (setsockopt(fd
, SOL_SOCKET
, SO_PRIORITY
, &priority
, sizeof(priority
)) < 0)
151 pa_log_warn("SO_PRIORITY failed: %s", pa_cstrerror(errno
));
155 void pa_make_tcp_socket_low_delay(int fd
) {
158 pa_make_socket_low_delay(fd
);
160 #if defined(SOL_TCP) || defined(IPPROTO_TCP)
164 if (setsockopt(fd
, SOL_TCP
, TCP_NODELAY
, &on
, sizeof(on
)) < 0)
166 if (setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &on
, sizeof(on
)) < 0)
168 pa_log_warn("TCP_NODELAY failed: %s", pa_cstrerror(errno
));
172 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
174 int tos
= IPTOS_LOWDELAY
;
176 if (setsockopt(fd
, SOL_IP
, IP_TOS
, &tos
, sizeof(tos
)) < 0)
178 if (setsockopt(fd
, IPPROTO_IP
, IP_TOS
, &tos
, sizeof(tos
)) < 0)
180 pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno
));
185 void pa_make_udp_socket_low_delay(int fd
) {
188 pa_make_socket_low_delay(fd
);
190 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
192 int tos
= IPTOS_LOWDELAY
;
194 if (setsockopt(fd
, SOL_IP
, IP_TOS
, &tos
, sizeof(tos
)) < 0)
196 if (setsockopt(fd
, IPPROTO_IP
, IP_TOS
, &tos
, sizeof(tos
)) < 0)
198 pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno
));
203 int pa_socket_set_rcvbuf(int fd
, size_t l
) {
208 if (setsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &bufsz
, sizeof(bufsz
)) < 0) {
209 pa_log_warn("SO_RCVBUF: %s", pa_cstrerror(errno
));
216 int pa_socket_set_sndbuf(int fd
, size_t l
) {
221 if (setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &bufsz
, sizeof(bufsz
)) < 0) {
222 pa_log_warn("SO_SNDBUF: %s", pa_cstrerror(errno
));
231 int pa_unix_socket_is_stale(const char *fn
) {
232 struct sockaddr_un sa
;
233 int fd
= -1, ret
= -1;
237 if ((fd
= pa_socket_cloexec(PF_UNIX
, SOCK_STREAM
, 0)) < 0) {
238 pa_log("socket(): %s", pa_cstrerror(errno
));
242 sa
.sun_family
= AF_UNIX
;
243 strncpy(sa
.sun_path
, fn
, sizeof(sa
.sun_path
)-1);
244 sa
.sun_path
[sizeof(sa
.sun_path
) - 1] = 0;
246 if (connect(fd
, (struct sockaddr
*) &sa
, sizeof(sa
)) < 0) {
247 if (errno
== ECONNREFUSED
)
259 int pa_unix_socket_remove_stale(const char *fn
) {
264 if ((r
= pa_unix_socket_is_stale(fn
)) < 0)
265 return errno
!= ENOENT
? -1 : 0;
270 /* Yes, here is a race condition. But who cares? */
277 #else /* HAVE_SYS_UN_H */
279 int pa_unix_socket_is_stale(const char *fn
) {
283 int pa_unix_socket_remove_stale(const char *fn
) {
287 #endif /* HAVE_SYS_UN_H */
290 pa_bool_t
pa_socket_address_is_local(const struct sockaddr
*sa
) {
293 switch (sa
->sa_family
) {
298 return ((const struct sockaddr_in
*) sa
)->sin_addr
.s_addr
== INADDR_LOOPBACK
;
302 return memcmp(&((const struct sockaddr_in6
*) sa
)->sin6_addr
, &in6addr_loopback
, sizeof(struct in6_addr
)) == 0;
310 pa_bool_t
pa_socket_is_local(int fd
) {
313 struct sockaddr_storage storage
;
315 struct sockaddr_in in
;
317 struct sockaddr_in6 in6
;
320 struct sockaddr_un un
;
323 socklen_t sa_len
= sizeof(sa
);
325 if (getpeername(fd
, &sa
.sa
, &sa_len
) < 0)
328 return pa_socket_address_is_local(&sa
.sa
);