• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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