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
33 #include <sys/types.h>
40 #ifdef HAVE_NETINET_IN_H
41 #include <netinet/in.h>
43 #ifdef HAVE_NETINET_IN_SYSTM_H
44 #include <netinet/in_systm.h>
46 #ifdef HAVE_NETINET_IP_H
47 #include <netinet/ip.h>
49 #ifdef HAVE_NETINET_TCP_H
50 #include <netinet/tcp.h>
56 #include <pulsecore/core-error.h>
57 #include <pulsecore/core-util.h>
58 #include <pulsecore/log.h>
59 #include <pulsecore/macro.h>
60 #include <pulsecore/socket.h>
61 #include <pulsecore/arpa-inet.h>
63 #include "socket-util.h"
65 void pa_socket_peer_to_string(int fd
, char *c
, size_t l
) {
73 pa_assert_se(fstat(fd
, &st
) == 0);
75 if (S_ISSOCK(st
.st_mode
))
79 struct sockaddr_storage storage
;
81 struct sockaddr_in in
;
83 struct sockaddr_in6 in6
;
86 struct sockaddr_un un
;
89 socklen_t sa_len
= sizeof(sa
);
91 if (getpeername(fd
, &sa
.sa
, &sa_len
) >= 0) {
93 if (sa
.sa
.sa_family
== AF_INET
) {
94 uint32_t ip
= ntohl(sa
.in
.sin_addr
.s_addr
);
96 pa_snprintf(c
, l
, "TCP/IP client from %i.%i.%i.%i:%u",
101 ntohs(sa
.in
.sin_port
));
104 } else if (sa
.sa
.sa_family
== AF_INET6
) {
105 char buf
[INET6_ADDRSTRLEN
];
108 res
= inet_ntop(AF_INET6
, &sa
.in6
.sin6_addr
, buf
, sizeof(buf
));
110 pa_snprintf(c
, l
, "TCP/IP client from [%s]:%u", buf
, ntohs(sa
.in6
.sin6_port
));
115 } else if (sa
.sa
.sa_family
== AF_UNIX
) {
116 pa_snprintf(c
, l
, "UNIX socket client");
122 pa_snprintf(c
, l
, "Unknown network client");
126 else if (S_ISCHR(st
.st_mode
) && (fd
== 0 || fd
== 1)) {
127 pa_snprintf(c
, l
, "STDIN/STDOUT client");
130 #endif /* OS_IS_WIN32 */
132 pa_snprintf(c
, l
, "Unknown client");
135 void pa_make_socket_low_delay(int fd
) {
142 if (setsockopt(fd
, SOL_SOCKET
, SO_PRIORITY
, &priority
, sizeof(priority
)) < 0)
143 pa_log_warn("SO_PRIORITY failed: %s", pa_cstrerror(errno
));
147 void pa_make_tcp_socket_low_delay(int fd
) {
150 pa_make_socket_low_delay(fd
);
152 #if defined(SOL_TCP) || defined(IPPROTO_TCP)
156 if (setsockopt(fd
, SOL_TCP
, TCP_NODELAY
, &on
, sizeof(on
)) < 0)
158 if (setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &on
, sizeof(on
)) < 0)
160 pa_log_warn("TCP_NODELAY failed: %s", pa_cstrerror(errno
));
164 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
166 int tos
= IPTOS_LOWDELAY
;
168 if (setsockopt(fd
, SOL_IP
, IP_TOS
, &tos
, sizeof(tos
)) < 0)
170 if (setsockopt(fd
, IPPROTO_IP
, IP_TOS
, &tos
, sizeof(tos
)) < 0)
172 pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno
));
177 void pa_make_udp_socket_low_delay(int fd
) {
180 pa_make_socket_low_delay(fd
);
182 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
184 int tos
= IPTOS_LOWDELAY
;
186 if (setsockopt(fd
, SOL_IP
, IP_TOS
, &tos
, sizeof(tos
)) < 0)
188 if (setsockopt(fd
, IPPROTO_IP
, IP_TOS
, &tos
, sizeof(tos
)) < 0)
190 pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno
));
195 int pa_socket_set_rcvbuf(int fd
, size_t l
) {
200 if (setsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &bufsz
, sizeof(bufsz
)) < 0) {
201 pa_log_warn("SO_RCVBUF: %s", pa_cstrerror(errno
));
208 int pa_socket_set_sndbuf(int fd
, size_t l
) {
213 if (setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &bufsz
, sizeof(bufsz
)) < 0) {
214 pa_log_warn("SO_SNDBUF: %s", pa_cstrerror(errno
));
223 int pa_unix_socket_is_stale(const char *fn
) {
224 struct sockaddr_un sa
;
225 int fd
= -1, ret
= -1;
229 if ((fd
= pa_socket_cloexec(PF_UNIX
, SOCK_STREAM
, 0)) < 0) {
230 pa_log("socket(): %s", pa_cstrerror(errno
));
234 sa
.sun_family
= AF_UNIX
;
235 strncpy(sa
.sun_path
, fn
, sizeof(sa
.sun_path
)-1);
236 sa
.sun_path
[sizeof(sa
.sun_path
) - 1] = 0;
238 if (connect(fd
, (struct sockaddr
*) &sa
, sizeof(sa
)) < 0) {
239 if (errno
== ECONNREFUSED
)
251 int pa_unix_socket_remove_stale(const char *fn
) {
256 if ((r
= pa_unix_socket_is_stale(fn
)) < 0)
257 return errno
!= ENOENT
? -1 : 0;
262 /* Yes, here is a race condition. But who cares? */
269 #else /* HAVE_SYS_UN_H */
271 int pa_unix_socket_is_stale(const char *fn
) {
275 int pa_unix_socket_remove_stale(const char *fn
) {
279 #endif /* HAVE_SYS_UN_H */
282 pa_bool_t
pa_socket_address_is_local(const struct sockaddr
*sa
) {
285 switch (sa
->sa_family
) {
290 return ((const struct sockaddr_in
*) sa
)->sin_addr
.s_addr
== INADDR_LOOPBACK
;
294 return memcmp(&((const struct sockaddr_in6
*) sa
)->sin6_addr
, &in6addr_loopback
, sizeof(struct in6_addr
)) == 0;
302 pa_bool_t
pa_socket_is_local(int fd
) {
305 struct sockaddr_storage storage
;
307 struct sockaddr_in in
;
309 struct sockaddr_in6 in6
;
312 struct sockaddr_un un
;
315 socklen_t sa_len
= sizeof(sa
);
317 if (getpeername(fd
, &sa
.sa
, &sa_len
) < 0)
320 return pa_socket_address_is_local(&sa
.sa
);