1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2004 Joe Marcus Clarke
6 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
7
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.
12
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.
17
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/>.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <signal.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34
35 #ifdef HAVE_SYS_UN_H
36 #include <sys/un.h>
37 #endif
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
40 #endif
41 #ifdef HAVE_NETINET_IN_SYSTM_H
42 #include <netinet/in_systm.h>
43 #endif
44 #ifdef HAVE_NETINET_IP_H
45 #include <netinet/ip.h>
46 #endif
47 #ifdef HAVE_NETINET_TCP_H
48 #include <netinet/tcp.h>
49 #endif
50 #ifdef HAVE_NETDB_H
51 #include <netdb.h>
52 #endif
53
54 #include <pulsecore/core-error.h>
55 #include <pulsecore/core-util.h>
56 #include <pulsecore/log.h>
57 #include <pulsecore/macro.h>
58 #include <pulsecore/socket.h>
59 #include <pulsecore/arpa-inet.h>
60
61 #include "socket-util.h"
62
pa_socket_peer_to_string(int fd,char * c,size_t l)63 void pa_socket_peer_to_string(int fd, char *c, size_t l) {
64 #ifndef OS_IS_WIN32
65 struct stat st;
66 #endif
67
68 pa_assert(fd >= 0);
69 pa_assert(c);
70 pa_assert(l > 0);
71
72 #ifndef OS_IS_WIN32
73 pa_assert_se(fstat(fd, &st) == 0);
74
75 if (S_ISSOCK(st.st_mode))
76 #endif
77 {
78 union {
79 struct sockaddr_storage storage;
80 struct sockaddr sa;
81 struct sockaddr_in in;
82 #ifdef HAVE_IPV6
83 struct sockaddr_in6 in6;
84 #endif
85 #ifdef HAVE_SYS_UN_H
86 struct sockaddr_un un;
87 #endif
88 } sa;
89 socklen_t sa_len = sizeof(sa);
90
91 if (getpeername(fd, &sa.sa, &sa_len) >= 0) {
92
93 if (sa.sa.sa_family == AF_INET) {
94 uint32_t ip = ntohl(sa.in.sin_addr.s_addr);
95
96 pa_snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u",
97 ip >> 24,
98 (ip >> 16) & 0xFF,
99 (ip >> 8) & 0xFF,
100 ip & 0xFF,
101 ntohs(sa.in.sin_port));
102 return;
103 #ifdef HAVE_IPV6
104 } else if (sa.sa.sa_family == AF_INET6) {
105 char buf[INET6_ADDRSTRLEN];
106 const char *res;
107
108 res = inet_ntop(AF_INET6, &sa.in6.sin6_addr, buf, sizeof(buf));
109 if (res) {
110 pa_snprintf(c, l, "TCP/IP client from [%s]:%u", buf, ntohs(sa.in6.sin6_port));
111 return;
112 }
113 #endif
114 #ifdef HAVE_SYS_UN_H
115 } else if (sa.sa.sa_family == AF_UNIX) {
116 pa_snprintf(c, l, "UNIX socket client");
117 return;
118 #endif
119 }
120 }
121
122 pa_snprintf(c, l, "Unknown network client");
123 return;
124 }
125 #ifndef OS_IS_WIN32
126 else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) {
127 pa_snprintf(c, l, "STDIN/STDOUT client");
128 return;
129 }
130 #endif /* OS_IS_WIN32 */
131
132 pa_snprintf(c, l, "Unknown client");
133 }
134
pa_make_socket_low_delay(int fd)135 void pa_make_socket_low_delay(int fd) {
136
137 #ifdef SO_PRIORITY
138 int priority;
139 pa_assert(fd >= 0);
140
141 priority = 6;
142 if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (const void *) &priority, sizeof(priority)) < 0)
143 pa_log_warn("SO_PRIORITY failed: %s", pa_cstrerror(errno));
144 #endif
145 }
146
pa_make_tcp_socket_low_delay(int fd)147 void pa_make_tcp_socket_low_delay(int fd) {
148 pa_assert(fd >= 0);
149
150 pa_make_socket_low_delay(fd);
151
152 #if defined(SOL_TCP) || defined(IPPROTO_TCP)
153 {
154 int on = 1;
155 #if defined(SOL_TCP)
156 if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *) &on, sizeof(on)) < 0)
157 #else
158 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &on, sizeof(on)) < 0)
159 #endif
160 pa_log_warn("TCP_NODELAY failed: %s", pa_cstrerror(errno));
161 }
162 #endif
163
164 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
165 {
166 int tos = IPTOS_LOWDELAY;
167 #ifdef SOL_IP
168 if (setsockopt(fd, SOL_IP, IP_TOS, (const void *) &tos, sizeof(tos)) < 0)
169 #else
170 if (setsockopt(fd, IPPROTO_IP, IP_TOS, (const void *) &tos, sizeof(tos)) < 0)
171 #endif
172 pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
173 }
174 #endif
175 }
176
pa_make_udp_socket_low_delay(int fd)177 void pa_make_udp_socket_low_delay(int fd) {
178 pa_assert(fd >= 0);
179
180 pa_make_socket_low_delay(fd);
181
182 #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
183 {
184 int tos = IPTOS_LOWDELAY;
185 #ifdef SOL_IP
186 if (setsockopt(fd, SOL_IP, IP_TOS, (const void *) &tos, sizeof(tos)) < 0)
187 #else
188 if (setsockopt(fd, IPPROTO_IP, IP_TOS, (const void *) &tos, sizeof(tos)) < 0)
189 #endif
190 pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
191 }
192 #endif
193 }
194
pa_socket_set_rcvbuf(int fd,size_t l)195 int pa_socket_set_rcvbuf(int fd, size_t l) {
196 int bufsz = (int) l;
197
198 pa_assert(fd >= 0);
199
200 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const void *) &bufsz, sizeof(bufsz)) < 0) {
201 pa_log_warn("SO_RCVBUF: %s", pa_cstrerror(errno));
202 return -1;
203 }
204
205 return 0;
206 }
207
pa_socket_set_sndbuf(int fd,size_t l)208 int pa_socket_set_sndbuf(int fd, size_t l) {
209 int bufsz = (int) l;
210
211 pa_assert(fd >= 0);
212
213 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &bufsz, sizeof(bufsz)) < 0) {
214 pa_log_warn("SO_SNDBUF: %s", pa_cstrerror(errno));
215 return -1;
216 }
217
218 return 0;
219 }
220
pa_socket_address_is_local(const struct sockaddr * sa)221 bool pa_socket_address_is_local(const struct sockaddr *sa) {
222 pa_assert(sa);
223
224 switch (sa->sa_family) {
225 case AF_UNIX:
226 return true;
227
228 case AF_INET:
229 return ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK;
230
231 #ifdef HAVE_IPV6
232 case AF_INET6:
233 return memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0;
234 #endif
235
236 default:
237 return false;
238 }
239 }
240
pa_socket_is_local(int fd)241 bool pa_socket_is_local(int fd) {
242
243 union {
244 struct sockaddr_storage storage;
245 struct sockaddr sa;
246 struct sockaddr_in in;
247 #ifdef HAVE_IPV6
248 struct sockaddr_in6 in6;
249 #endif
250 #ifdef HAVE_SYS_UN_H
251 struct sockaddr_un un;
252 #endif
253 } sa;
254 socklen_t sa_len = sizeof(sa);
255
256 if (getpeername(fd, &sa.sa, &sa_len) < 0)
257 return false;
258
259 return pa_socket_address_is_local(&sa.sa);
260 }
261