153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2004-2006 Lennart Poettering
553a5a1b3Sopenharmony_ci  Copyright 2004 Joe Marcus Clarke
653a5a1b3Sopenharmony_ci  Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
753a5a1b3Sopenharmony_ci
853a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
953a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
1053a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
1153a5a1b3Sopenharmony_ci  or (at your option) any later version.
1253a5a1b3Sopenharmony_ci
1353a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1453a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1553a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1653a5a1b3Sopenharmony_ci  General Public License for more details.
1753a5a1b3Sopenharmony_ci
1853a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1953a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
2053a5a1b3Sopenharmony_ci***/
2153a5a1b3Sopenharmony_ci
2253a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2353a5a1b3Sopenharmony_ci#include <config.h>
2453a5a1b3Sopenharmony_ci#endif
2553a5a1b3Sopenharmony_ci
2653a5a1b3Sopenharmony_ci#include <stdlib.h>
2753a5a1b3Sopenharmony_ci#include <signal.h>
2853a5a1b3Sopenharmony_ci#include <errno.h>
2953a5a1b3Sopenharmony_ci#include <string.h>
3053a5a1b3Sopenharmony_ci#include <stdio.h>
3153a5a1b3Sopenharmony_ci#include <sys/types.h>
3253a5a1b3Sopenharmony_ci#include <unistd.h>
3353a5a1b3Sopenharmony_ci#include <sys/stat.h>
3453a5a1b3Sopenharmony_ci
3553a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_UN_H
3653a5a1b3Sopenharmony_ci#include <sys/un.h>
3753a5a1b3Sopenharmony_ci#endif
3853a5a1b3Sopenharmony_ci#ifdef HAVE_NETINET_IN_H
3953a5a1b3Sopenharmony_ci#include <netinet/in.h>
4053a5a1b3Sopenharmony_ci#endif
4153a5a1b3Sopenharmony_ci#ifdef HAVE_NETINET_IN_SYSTM_H
4253a5a1b3Sopenharmony_ci#include <netinet/in_systm.h>
4353a5a1b3Sopenharmony_ci#endif
4453a5a1b3Sopenharmony_ci#ifdef HAVE_NETINET_IP_H
4553a5a1b3Sopenharmony_ci#include <netinet/ip.h>
4653a5a1b3Sopenharmony_ci#endif
4753a5a1b3Sopenharmony_ci#ifdef HAVE_NETINET_TCP_H
4853a5a1b3Sopenharmony_ci#include <netinet/tcp.h>
4953a5a1b3Sopenharmony_ci#endif
5053a5a1b3Sopenharmony_ci#ifdef HAVE_NETDB_H
5153a5a1b3Sopenharmony_ci#include <netdb.h>
5253a5a1b3Sopenharmony_ci#endif
5353a5a1b3Sopenharmony_ci
5453a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h>
5553a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
5653a5a1b3Sopenharmony_ci#include <pulsecore/log.h>
5753a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
5853a5a1b3Sopenharmony_ci#include <pulsecore/socket.h>
5953a5a1b3Sopenharmony_ci#include <pulsecore/arpa-inet.h>
6053a5a1b3Sopenharmony_ci
6153a5a1b3Sopenharmony_ci#include "socket-util.h"
6253a5a1b3Sopenharmony_ci
6353a5a1b3Sopenharmony_civoid pa_socket_peer_to_string(int fd, char *c, size_t l) {
6453a5a1b3Sopenharmony_ci#ifndef OS_IS_WIN32
6553a5a1b3Sopenharmony_ci    struct stat st;
6653a5a1b3Sopenharmony_ci#endif
6753a5a1b3Sopenharmony_ci
6853a5a1b3Sopenharmony_ci    pa_assert(fd >= 0);
6953a5a1b3Sopenharmony_ci    pa_assert(c);
7053a5a1b3Sopenharmony_ci    pa_assert(l > 0);
7153a5a1b3Sopenharmony_ci
7253a5a1b3Sopenharmony_ci#ifndef OS_IS_WIN32
7353a5a1b3Sopenharmony_ci    pa_assert_se(fstat(fd, &st) == 0);
7453a5a1b3Sopenharmony_ci
7553a5a1b3Sopenharmony_ci    if (S_ISSOCK(st.st_mode))
7653a5a1b3Sopenharmony_ci#endif
7753a5a1b3Sopenharmony_ci    {
7853a5a1b3Sopenharmony_ci        union {
7953a5a1b3Sopenharmony_ci            struct sockaddr_storage storage;
8053a5a1b3Sopenharmony_ci            struct sockaddr sa;
8153a5a1b3Sopenharmony_ci            struct sockaddr_in in;
8253a5a1b3Sopenharmony_ci#ifdef HAVE_IPV6
8353a5a1b3Sopenharmony_ci            struct sockaddr_in6 in6;
8453a5a1b3Sopenharmony_ci#endif
8553a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_UN_H
8653a5a1b3Sopenharmony_ci            struct sockaddr_un un;
8753a5a1b3Sopenharmony_ci#endif
8853a5a1b3Sopenharmony_ci        } sa;
8953a5a1b3Sopenharmony_ci        socklen_t sa_len = sizeof(sa);
9053a5a1b3Sopenharmony_ci
9153a5a1b3Sopenharmony_ci        if (getpeername(fd, &sa.sa, &sa_len) >= 0) {
9253a5a1b3Sopenharmony_ci
9353a5a1b3Sopenharmony_ci            if (sa.sa.sa_family == AF_INET) {
9453a5a1b3Sopenharmony_ci                uint32_t ip = ntohl(sa.in.sin_addr.s_addr);
9553a5a1b3Sopenharmony_ci
9653a5a1b3Sopenharmony_ci                pa_snprintf(c, l, "TCP/IP client from %i.%i.%i.%i:%u",
9753a5a1b3Sopenharmony_ci                            ip >> 24,
9853a5a1b3Sopenharmony_ci                            (ip >> 16) & 0xFF,
9953a5a1b3Sopenharmony_ci                            (ip >> 8) & 0xFF,
10053a5a1b3Sopenharmony_ci                            ip & 0xFF,
10153a5a1b3Sopenharmony_ci                            ntohs(sa.in.sin_port));
10253a5a1b3Sopenharmony_ci                return;
10353a5a1b3Sopenharmony_ci#ifdef HAVE_IPV6
10453a5a1b3Sopenharmony_ci            } else if (sa.sa.sa_family == AF_INET6) {
10553a5a1b3Sopenharmony_ci                char buf[INET6_ADDRSTRLEN];
10653a5a1b3Sopenharmony_ci                const char *res;
10753a5a1b3Sopenharmony_ci
10853a5a1b3Sopenharmony_ci                res = inet_ntop(AF_INET6, &sa.in6.sin6_addr, buf, sizeof(buf));
10953a5a1b3Sopenharmony_ci                if (res) {
11053a5a1b3Sopenharmony_ci                    pa_snprintf(c, l, "TCP/IP client from [%s]:%u", buf, ntohs(sa.in6.sin6_port));
11153a5a1b3Sopenharmony_ci                    return;
11253a5a1b3Sopenharmony_ci                }
11353a5a1b3Sopenharmony_ci#endif
11453a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_UN_H
11553a5a1b3Sopenharmony_ci            } else if (sa.sa.sa_family == AF_UNIX) {
11653a5a1b3Sopenharmony_ci                pa_snprintf(c, l, "UNIX socket client");
11753a5a1b3Sopenharmony_ci                return;
11853a5a1b3Sopenharmony_ci#endif
11953a5a1b3Sopenharmony_ci            }
12053a5a1b3Sopenharmony_ci        }
12153a5a1b3Sopenharmony_ci
12253a5a1b3Sopenharmony_ci        pa_snprintf(c, l, "Unknown network client");
12353a5a1b3Sopenharmony_ci        return;
12453a5a1b3Sopenharmony_ci    }
12553a5a1b3Sopenharmony_ci#ifndef OS_IS_WIN32
12653a5a1b3Sopenharmony_ci    else if (S_ISCHR(st.st_mode) && (fd == 0 || fd == 1)) {
12753a5a1b3Sopenharmony_ci        pa_snprintf(c, l, "STDIN/STDOUT client");
12853a5a1b3Sopenharmony_ci        return;
12953a5a1b3Sopenharmony_ci    }
13053a5a1b3Sopenharmony_ci#endif /* OS_IS_WIN32 */
13153a5a1b3Sopenharmony_ci
13253a5a1b3Sopenharmony_ci    pa_snprintf(c, l, "Unknown client");
13353a5a1b3Sopenharmony_ci}
13453a5a1b3Sopenharmony_ci
13553a5a1b3Sopenharmony_civoid pa_make_socket_low_delay(int fd) {
13653a5a1b3Sopenharmony_ci
13753a5a1b3Sopenharmony_ci#ifdef SO_PRIORITY
13853a5a1b3Sopenharmony_ci    int priority;
13953a5a1b3Sopenharmony_ci    pa_assert(fd >= 0);
14053a5a1b3Sopenharmony_ci
14153a5a1b3Sopenharmony_ci    priority = 6;
14253a5a1b3Sopenharmony_ci    if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (const void *) &priority, sizeof(priority)) < 0)
14353a5a1b3Sopenharmony_ci        pa_log_warn("SO_PRIORITY failed: %s", pa_cstrerror(errno));
14453a5a1b3Sopenharmony_ci#endif
14553a5a1b3Sopenharmony_ci}
14653a5a1b3Sopenharmony_ci
14753a5a1b3Sopenharmony_civoid pa_make_tcp_socket_low_delay(int fd) {
14853a5a1b3Sopenharmony_ci    pa_assert(fd >= 0);
14953a5a1b3Sopenharmony_ci
15053a5a1b3Sopenharmony_ci    pa_make_socket_low_delay(fd);
15153a5a1b3Sopenharmony_ci
15253a5a1b3Sopenharmony_ci#if defined(SOL_TCP) || defined(IPPROTO_TCP)
15353a5a1b3Sopenharmony_ci    {
15453a5a1b3Sopenharmony_ci        int on = 1;
15553a5a1b3Sopenharmony_ci#if defined(SOL_TCP)
15653a5a1b3Sopenharmony_ci        if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *) &on, sizeof(on)) < 0)
15753a5a1b3Sopenharmony_ci#else
15853a5a1b3Sopenharmony_ci        if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &on, sizeof(on)) < 0)
15953a5a1b3Sopenharmony_ci#endif
16053a5a1b3Sopenharmony_ci            pa_log_warn("TCP_NODELAY failed: %s", pa_cstrerror(errno));
16153a5a1b3Sopenharmony_ci    }
16253a5a1b3Sopenharmony_ci#endif
16353a5a1b3Sopenharmony_ci
16453a5a1b3Sopenharmony_ci#if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
16553a5a1b3Sopenharmony_ci    {
16653a5a1b3Sopenharmony_ci        int tos = IPTOS_LOWDELAY;
16753a5a1b3Sopenharmony_ci#ifdef SOL_IP
16853a5a1b3Sopenharmony_ci        if (setsockopt(fd, SOL_IP, IP_TOS, (const void *) &tos, sizeof(tos)) < 0)
16953a5a1b3Sopenharmony_ci#else
17053a5a1b3Sopenharmony_ci        if (setsockopt(fd, IPPROTO_IP, IP_TOS, (const void *) &tos, sizeof(tos)) < 0)
17153a5a1b3Sopenharmony_ci#endif
17253a5a1b3Sopenharmony_ci            pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
17353a5a1b3Sopenharmony_ci    }
17453a5a1b3Sopenharmony_ci#endif
17553a5a1b3Sopenharmony_ci}
17653a5a1b3Sopenharmony_ci
17753a5a1b3Sopenharmony_civoid pa_make_udp_socket_low_delay(int fd) {
17853a5a1b3Sopenharmony_ci    pa_assert(fd >= 0);
17953a5a1b3Sopenharmony_ci
18053a5a1b3Sopenharmony_ci    pa_make_socket_low_delay(fd);
18153a5a1b3Sopenharmony_ci
18253a5a1b3Sopenharmony_ci#if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || defined(IPPROTO_IP))
18353a5a1b3Sopenharmony_ci    {
18453a5a1b3Sopenharmony_ci        int tos = IPTOS_LOWDELAY;
18553a5a1b3Sopenharmony_ci#ifdef SOL_IP
18653a5a1b3Sopenharmony_ci        if (setsockopt(fd, SOL_IP, IP_TOS, (const void *) &tos, sizeof(tos)) < 0)
18753a5a1b3Sopenharmony_ci#else
18853a5a1b3Sopenharmony_ci        if (setsockopt(fd, IPPROTO_IP, IP_TOS, (const void *) &tos, sizeof(tos)) < 0)
18953a5a1b3Sopenharmony_ci#endif
19053a5a1b3Sopenharmony_ci            pa_log_warn("IP_TOS failed: %s", pa_cstrerror(errno));
19153a5a1b3Sopenharmony_ci    }
19253a5a1b3Sopenharmony_ci#endif
19353a5a1b3Sopenharmony_ci}
19453a5a1b3Sopenharmony_ci
19553a5a1b3Sopenharmony_ciint pa_socket_set_rcvbuf(int fd, size_t l) {
19653a5a1b3Sopenharmony_ci    int bufsz = (int) l;
19753a5a1b3Sopenharmony_ci
19853a5a1b3Sopenharmony_ci    pa_assert(fd >= 0);
19953a5a1b3Sopenharmony_ci
20053a5a1b3Sopenharmony_ci    if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const void *) &bufsz, sizeof(bufsz)) < 0) {
20153a5a1b3Sopenharmony_ci        pa_log_warn("SO_RCVBUF: %s", pa_cstrerror(errno));
20253a5a1b3Sopenharmony_ci        return -1;
20353a5a1b3Sopenharmony_ci    }
20453a5a1b3Sopenharmony_ci
20553a5a1b3Sopenharmony_ci    return 0;
20653a5a1b3Sopenharmony_ci}
20753a5a1b3Sopenharmony_ci
20853a5a1b3Sopenharmony_ciint pa_socket_set_sndbuf(int fd, size_t l) {
20953a5a1b3Sopenharmony_ci    int bufsz = (int) l;
21053a5a1b3Sopenharmony_ci
21153a5a1b3Sopenharmony_ci    pa_assert(fd >= 0);
21253a5a1b3Sopenharmony_ci
21353a5a1b3Sopenharmony_ci    if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &bufsz, sizeof(bufsz)) < 0) {
21453a5a1b3Sopenharmony_ci        pa_log_warn("SO_SNDBUF: %s", pa_cstrerror(errno));
21553a5a1b3Sopenharmony_ci        return -1;
21653a5a1b3Sopenharmony_ci    }
21753a5a1b3Sopenharmony_ci
21853a5a1b3Sopenharmony_ci    return 0;
21953a5a1b3Sopenharmony_ci}
22053a5a1b3Sopenharmony_ci
22153a5a1b3Sopenharmony_cibool pa_socket_address_is_local(const struct sockaddr *sa) {
22253a5a1b3Sopenharmony_ci    pa_assert(sa);
22353a5a1b3Sopenharmony_ci
22453a5a1b3Sopenharmony_ci    switch (sa->sa_family) {
22553a5a1b3Sopenharmony_ci        case AF_UNIX:
22653a5a1b3Sopenharmony_ci            return true;
22753a5a1b3Sopenharmony_ci
22853a5a1b3Sopenharmony_ci        case AF_INET:
22953a5a1b3Sopenharmony_ci            return ((const struct sockaddr_in*) sa)->sin_addr.s_addr == INADDR_LOOPBACK;
23053a5a1b3Sopenharmony_ci
23153a5a1b3Sopenharmony_ci#ifdef HAVE_IPV6
23253a5a1b3Sopenharmony_ci        case AF_INET6:
23353a5a1b3Sopenharmony_ci            return memcmp(&((const struct sockaddr_in6*) sa)->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr)) == 0;
23453a5a1b3Sopenharmony_ci#endif
23553a5a1b3Sopenharmony_ci
23653a5a1b3Sopenharmony_ci        default:
23753a5a1b3Sopenharmony_ci            return false;
23853a5a1b3Sopenharmony_ci    }
23953a5a1b3Sopenharmony_ci}
24053a5a1b3Sopenharmony_ci
24153a5a1b3Sopenharmony_cibool pa_socket_is_local(int fd) {
24253a5a1b3Sopenharmony_ci
24353a5a1b3Sopenharmony_ci    union {
24453a5a1b3Sopenharmony_ci        struct sockaddr_storage storage;
24553a5a1b3Sopenharmony_ci        struct sockaddr sa;
24653a5a1b3Sopenharmony_ci        struct sockaddr_in in;
24753a5a1b3Sopenharmony_ci#ifdef HAVE_IPV6
24853a5a1b3Sopenharmony_ci        struct sockaddr_in6 in6;
24953a5a1b3Sopenharmony_ci#endif
25053a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_UN_H
25153a5a1b3Sopenharmony_ci        struct sockaddr_un un;
25253a5a1b3Sopenharmony_ci#endif
25353a5a1b3Sopenharmony_ci    } sa;
25453a5a1b3Sopenharmony_ci    socklen_t sa_len = sizeof(sa);
25553a5a1b3Sopenharmony_ci
25653a5a1b3Sopenharmony_ci    if (getpeername(fd, &sa.sa, &sa_len) < 0)
25753a5a1b3Sopenharmony_ci        return false;
25853a5a1b3Sopenharmony_ci
25953a5a1b3Sopenharmony_ci    return pa_socket_address_is_local(&sa.sa);
26053a5a1b3Sopenharmony_ci}
261