From: Tom Kistner Date: Mon, 27 Mar 2017 13:11:06 +0000 (+0200) Subject: IPTV/RTP input: handle source specific multicast (SSM) URLs in Linux X-Git-Tag: v4.2.1~56 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=071badd22cf83661dac1963ece071196634b6dc0;p=thirdparty%2Ftvheadend.git IPTV/RTP input: handle source specific multicast (SSM) URLs in Linux --- diff --git a/src/input/mpegts/iptv/iptv_udp.c b/src/input/mpegts/iptv/iptv_udp.c index 7f5f3bff2..1d61cc98d 100644 --- a/src/input/mpegts/iptv/iptv_udp.c +++ b/src/input/mpegts/iptv/iptv_udp.c @@ -40,7 +40,9 @@ iptv_udp_start ( iptv_mux_t *im, const char *raw, const url_t *url ) mpegts_mux_nice_name((mpegts_mux_t*)im, name, sizeof(name)); - conn = udp_bind(LS_IPTV, name, url->host, url->port, + /* Note: url->user is used for specifying multicast source address (SSM) + here. The URL format is rtp://@: */ + conn = udp_bind(LS_IPTV, name, url->host, url->port, url->user, im->mm_iptv_interface, IPTV_BUF_SIZE, 4*1024); if (conn == UDP_FATAL_ERROR) return SM_CODE_TUNING_FAILED; diff --git a/src/udp.c b/src/udp.c index bb607256c..7c9f6de1d 100644 --- a/src/udp.c +++ b/src/udp.c @@ -119,7 +119,7 @@ udp_get_ifindex( const char *ifname ) return r; } -#if defined(PLATFORM_DARWIN) +#if defined(PLATFORM_LINUX) || defined(PLATFORM_DARWIN) static int udp_get_ifaddr( int fd, const char *ifname, struct in_addr *addr ) { @@ -154,7 +154,7 @@ udp_get_solip( void ) udp_connection_t * udp_bind ( int subsystem, const char *name, - const char *bindaddr, int port, + const char *bindaddr, int port, const char *multicast_src, const char *ifname, int rxsize, int txsize ) { int fd, ifindex, reuse = 1; @@ -233,11 +233,48 @@ udp_bind ( int subsystem, const char *name, } #endif - if (setsockopt(fd, udp_get_solip(), IP_ADD_MEMBERSHIP, &m, sizeof(m))) { - inet_ntop(AF_INET, &m.imr_multiaddr, buf, sizeof(buf)); - tvhwarn(subsystem, "%s - cannot join %s [%s]", - name, buf, strerror(errno)); +#if defined(PLATFORM_LINUX) + if (multicast_src) { + + struct ip_mreq_source ms; + memset(&ms, 0, sizeof(ms)); + + ms.imr_multiaddr = IP_AS_V4(uc->ip, addr); + + /* Unfortunately, ip_mreq_source does not support the ifindex parameter, + so we have to resolve to the ip of the interface. */ + if (udp_get_ifaddr(fd, ifname, &ms.imr_interface) == -1) { + tvherror(subsystem, "%s - cannot find ip address for interface %s [e=%s]", + name, ifname, strerror(errno)); + goto error; + } + + if (inet_pton(AF_INET, multicast_src, &ms.imr_sourceaddr) < 1) { + tvherror(subsystem, "%s - invalid ipv4 address '%s' specified as multicast source [e=%s]", + name, multicast_src, strerror(errno)); + goto error; + } + + if (setsockopt(fd, udp_get_solip(), IP_ADD_SOURCE_MEMBERSHIP, + &ms, sizeof(ms)) < 0) { + tvherror(subsystem, "%s - setsockopt IP_ADD_SOURCE_MEMBERSHIP failed [e=%s]", + name, strerror(errno)); + goto error; + } + + } + else { +#endif + if (setsockopt(fd, udp_get_solip(), IP_ADD_MEMBERSHIP, &m, sizeof(m))) { + inet_ntop(AF_INET, &m.imr_multiaddr, buf, sizeof(buf)); + tvhwarn(subsystem, "%s - cannot join %s [%s]", + name, buf, strerror(errno)); + } +#if defined(PLATFORM_LINUX) } +#endif + + } /* Bind to IPv6 group */ @@ -309,13 +346,13 @@ udp_bind_double ( udp_connection_t **_u1, udp_connection_t **_u2, memset(&ucs, 0, sizeof(ucs)); while (1) { - u1 = udp_bind(subsystem, name1, host, port, ifname, rxsize1, txsize1); + u1 = udp_bind(subsystem, name1, host, port, NULL, ifname, rxsize1, txsize1); if (u1 == NULL || u1 == UDP_FATAL_ERROR) goto fail; port2 = ntohs(IP_PORT(u1->ip)); /* RTP port should be even, RTCP port should be odd */ if ((port2 % 2) == 0) { - u2 = udp_bind(subsystem, name2, host, port2 + 1, ifname, rxsize2, txsize2); + u2 = udp_bind(subsystem, name2, host, port2 + 1, NULL, ifname, rxsize2, txsize2); if (u2 != NULL && u2 != UDP_FATAL_ERROR) break; } diff --git a/src/udp.h b/src/udp.h index bb6a5bf6b..7e810727c 100644 --- a/src/udp.h +++ b/src/udp.h @@ -43,7 +43,7 @@ typedef struct udp_connection { udp_connection_t * udp_bind ( int subsystem, const char *name, - const char *bindaddr, int port, + const char *bindaddr, int port, const char *multicast_src, const char *ifname, int rxsize, int txsize ); int udp_bind_double ( udp_connection_t **_u1, udp_connection_t **_u2, diff --git a/src/upnp.c b/src/upnp.c index 5193b0703..81fef3804 100644 --- a/src/upnp.c +++ b/src/upnp.c @@ -138,11 +138,11 @@ upnp_thread( void *aux ) int r, delay_ms; multicast = udp_bind(LS_UPNP, "upnp_thread_multicast", - "239.255.255.250", 1900, + "239.255.255.250", 1900, NULL, NULL, 32*1024, 32*1024); if (multicast == NULL || multicast == UDP_FATAL_ERROR) goto error; - unicast = udp_bind(LS_UPNP, "upnp_thread_unicast", bindaddr, 0, + unicast = udp_bind(LS_UPNP, "upnp_thread_unicast", bindaddr, 0, NULL, NULL, 32*1024, 32*1024); if (unicast == NULL || unicast == UDP_FATAL_ERROR) goto error;