From cf74b5f1c9efaedd19bbb17d94f87717d45272e5 Mon Sep 17 00:00:00 2001 From: Bernhard Froehlich Date: Sat, 4 May 2013 16:34:03 +0200 Subject: [PATCH] Fix IPv4 multicasting on FreeBSD and make IPv6 multicasting optional because it's not yet supported on FreeBSD. --- src/iptv_input.c | 78 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/src/iptv_input.c b/src/iptv_input.c index 6c39a866..7ca96f6d 100644 --- a/src/iptv_input.c +++ b/src/iptv_input.c @@ -18,6 +18,7 @@ #include +#include #include #include #include @@ -31,7 +32,6 @@ #include #include #include -#include #include "tvheadend.h" #include "htsmsg.h" @@ -41,6 +41,17 @@ #include "psi.h" #include "settings.h" +#if defined(PLATFORM_LINUX) +#include +#elif defined(PLATFORM_FREEBSD) +# include +# include +# ifndef IPV6_ADD_MEMBERSHIP +# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +# endif +#endif + static int iptv_thread_running; static int iptv_epollfd; static pthread_mutex_t iptv_recvmutex; @@ -202,6 +213,7 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start) { pthread_t tid; int fd; + int solip; char straddr[INET6_ADDRSTRLEN]; struct ip_mreqn m; struct ipv6_mreq m6; @@ -260,9 +272,23 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start) memset(&m, 0, sizeof(m)); m.imr_multiaddr.s_addr = t->s_iptv_group.s_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 - if(setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &m, +#ifdef SOL_IP + solip = SOL_IP; +#else + { + struct protoent *pent; + pent = getprotobyname("ip"); + solip = (pent != NULL) ? pent->p_proto : 0; + } +#endif + + if(setsockopt(fd, solip, IP_ADD_MEMBERSHIP, &m, sizeof(struct ip_mreqn)) == -1) { tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot join %s -- %s", t->s_identifier, inet_ntoa(m.imr_multiaddr), strerror(errno)); @@ -287,8 +313,13 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start) /* Join IPv6 group */ memset(&m6, 0, sizeof(m6)); m6.ipv6mr_multiaddr = t->s_iptv_group6; +#if defined(PLATFORM_LINUX) m6.ipv6mr_interface = ifr.ifr_ifindex; +#elif defined(PLATFORM_FREEBSD) + m6.ipv6mr_interface = ifr.ifr_index; +#endif +#ifdef SOL_IPV6 if(setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &m6, sizeof(struct ipv6_mreq)) == -1) { inet_ntop(AF_INET6, m6.ipv6mr_multiaddr.s6_addr, @@ -298,6 +329,12 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start) close(fd); return -1; } +#else + tvhlog(LOG_ERR, "IPTV", "IPv6 multicast not supported on your platform"); + + close(fd); + return -1; +#endif } @@ -342,6 +379,7 @@ iptv_service_refresh(service_t *t) static void iptv_service_stop(service_t *t) { + int solip; struct ifreq ifr; pthread_mutex_lock(&iptv_recvmutex); @@ -366,33 +404,51 @@ iptv_service_stop(service_t *t) /* Leave multicast group */ m.imr_multiaddr.s_addr = t->s_iptv_group.s_addr; m.imr_address.s_addr = 0; +#if defined(PLATFORM_LINUX) m.imr_ifindex = ifr.ifr_ifindex; - - if(setsockopt(t->s_iptv_fd, SOL_IP, IP_DROP_MEMBERSHIP, &m, +#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 + + if(setsockopt(t->s_iptv_fd, solip, IP_DROP_MEMBERSHIP, &m, sizeof(struct ip_mreqn)) == -1) { tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot leave %s -- %s", t->s_identifier, inet_ntoa(m.imr_multiaddr), strerror(errno)); } } else { - char straddr[INET6_ADDRSTRLEN]; - struct ipv6_mreq m6; memset(&m6, 0, sizeof(m6)); m6.ipv6mr_multiaddr = t->s_iptv_group6; +#if defined(PLATFORM_LINUX) m6.ipv6mr_interface = ifr.ifr_ifindex; +#elif defined(PLATFORM_FREEBSD) + m6.ipv6mr_interface = ifr.ifr_index; +#endif +#ifdef SOL_IPV6 if(setsockopt(t->s_iptv_fd, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &m6, sizeof(struct ipv6_mreq)) == -1) { + char straddr[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, m6.ipv6mr_multiaddr.s6_addr, straddr, sizeof(straddr)); tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot leave %s -- %s", t->s_identifier, straddr, strerror(errno)); } - - - +#else + tvhlog(LOG_ERR, "IPTV", "IPv6 multicast not supported on your platform"); +#endif } close(t->s_iptv_fd); // Automatically removes fd from epoll set @@ -408,7 +464,9 @@ iptv_service_save(service_t *t) { htsmsg_t *m = htsmsg_create_map(); char abuf[INET_ADDRSTRLEN]; +#ifdef SOL_IPV6 char abuf6[INET6_ADDRSTRLEN]; +#endif lock_assert(&global_lock); @@ -427,10 +485,12 @@ iptv_service_save(service_t *t) inet_ntop(AF_INET, &t->s_iptv_group, abuf, sizeof(abuf)); htsmsg_add_str(m, "group", abuf); } +#ifdef SOL_IPV6 if(IN6_IS_ADDR_MULTICAST(t->s_iptv_group6.s6_addr) ) { inet_ntop(AF_INET6, &t->s_iptv_group6, abuf6, sizeof(abuf6)); htsmsg_add_str(m, "group", abuf6); } +#endif if(t->s_ch != NULL) { htsmsg_add_str(m, "channelname", t->s_ch->ch_name); htsmsg_add_u32(m, "mapped", 1);