From 91f00fc536b50d4bc9cdb2db2dca86b1f6483ae1 Mon Sep 17 00:00:00 2001 From: Nikolai Lontke Date: Mon, 16 Jun 2014 12:16:10 +0200 Subject: [PATCH] Hack: implement iptv-udp-handler stop() in order to leave the multicast group --- src/input/mpegts/iptv/iptv_udp.c | 116 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/src/input/mpegts/iptv/iptv_udp.c b/src/input/mpegts/iptv/iptv_udp.c index ea8cac0..e9a784a 100644 --- a/src/input/mpegts/iptv/iptv_udp.c +++ b/src/input/mpegts/iptv/iptv_udp.c @@ -178,6 +178,120 @@ error: return -1; } +static void +iptv_udp_stop ( iptv_mux_t *im) +{ + int solip, ipv6 = 0; + struct ifreq ifr; + struct in_addr saddr; + struct in6_addr s6addr; + char name[256], buf[256]; + url_t url; + + im->mm_display_name((mpegts_mux_t*)im, name, sizeof(name)); + + /* Parse URL */ + im->mm_display_name((mpegts_mux_t*)im, buf, sizeof(buf)); + if (urlparse(im->mm_iptv_url ?: "", &url)) { + tvherror("iptv", "%s - invalid URL [%s]", buf, im->mm_iptv_url); + return; + } + + /* Determine if this is IPv6 */ + if (!inet_pton(AF_INET, url.host, &saddr)) { + ipv6 = 1; + if (!inet_pton(AF_INET6, url.host, &s6addr)) { + tvherror("iptv", "%s - failed to stop (invalid addr)", name); + return; + } + } + + if (im->mm_iptv_fd < 0) { + tvherror("iptv", "%s - failed to stop (invalid fd)", name); + return; + } + + /* Bind to interface */ + memset(&ifr, 0, sizeof(ifr)); + if (im->mm_iptv_interface && *im->mm_iptv_interface) { + snprintf(ifr.ifr_name, IFNAMSIZ, "%s", im->mm_iptv_interface); + if (ioctl(im->mm_iptv_fd, SIOCGIFINDEX, &ifr)) { + tvherror("iptv", "%s - could not find interface %s", + name, im->mm_iptv_interface); + return; + } + } + + /* IPv4 */ + if (!ipv6) { + struct ip_mreqn m; + struct sockaddr_in sin; + memset(&m, 0, sizeof(m)); + memset(&sin, 0, sizeof(sin)); + + /* Prepare */ + sin.sin_family = AF_INET; + sin.sin_port = htons(url.port); + sin.sin_addr = saddr; + + /* Leave group */ + m.imr_multiaddr = sin.sin_addr; + m.imr_address.s_addr = 0; +#if defined(PLATFORM_LINUX) + m.imr_ifindex = ifr.ifr_ifindex; +#elif defined(PLATFORM_FREEBSD) + m.imr_ifindex = ifr.ifr_index; +#endif +#ifdef SOL_IP + solip = SOL_IP; +#else + { + struct protoent *pent; + pent = getprotobyname("ip"); + solip = (pent != NULL) ? pent->p_proto : 0; + } +#endif + tvhlog(LOG_INFO, "iptv_udp" , "now leaving group"); + if (setsockopt(im->mm_iptv_fd, solip, IP_DROP_MEMBERSHIP, &m, sizeof(m))) { + inet_ntop(AF_INET, &m.imr_multiaddr, buf, sizeof(buf)); + tvhwarn("iptv", "%s - cannot drop membership %s [%s]", + name, buf, strerror(errno)); + } + + /* Bind to IPv6 group */ + } else { + struct ipv6_mreq m; + struct sockaddr_in6 sin; + memset(&m, 0, sizeof(m)); + memset(&sin, 0, sizeof(sin)); + + /* Prepare */ + sin.sin6_family = AF_INET6; + sin.sin6_port = htons(url.port); + sin.sin6_addr = s6addr; + + /* Leave group */ + m.ipv6mr_multiaddr = sin.sin6_addr; +#if defined(PLATFORM_LINUX) + m.ipv6mr_interface = ifr.ifr_ifindex; +#elif defined(PLATFORM_FREEBSD) + m.ipv6mr_interface = ifr.ifr_index; +#endif +#ifdef SOL_IPV6 + if (setsockopt(im->mm_iptv_fd, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &m, sizeof(m))) { + inet_ntop(AF_INET, &m.ipv6mr_multiaddr, buf, sizeof(buf)); + tvhwarn("iptv", "%s - cannot join drop membership %s [%s]", + name, buf, strerror(errno)); + } +#else + tvherror("iptv", "IPv6 multicast not supported"); +#endif + } + + /* Done */ + // close(im->mm_iptv_fd); +} + static ssize_t iptv_udp_read ( iptv_mux_t *im, size_t *off ) { @@ -242,11 +356,13 @@ iptv_udp_init ( void ) { .scheme = "udp", .start = iptv_udp_start, + .stop = iptv_udp_stop, .read = iptv_udp_read, }, { .scheme = "rtp", .start = iptv_udp_start, + .stop = iptv_udp_stop, .read = iptv_rtp_read, } }; -- 2.0.0