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 63void 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 135void 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 147void 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 177void 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 195int 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 208int 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 221bool 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 241bool 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