diff options
Diffstat (limited to 'mcast/client/.svn/text-base/mld_reporter.c.svn-base')
-rw-r--r-- | mcast/client/.svn/text-base/mld_reporter.c.svn-base | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/mcast/client/.svn/text-base/mld_reporter.c.svn-base b/mcast/client/.svn/text-base/mld_reporter.c.svn-base new file mode 100644 index 0000000..e0530ab --- /dev/null +++ b/mcast/client/.svn/text-base/mld_reporter.c.svn-base @@ -0,0 +1,225 @@ +/* + * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de + * + * See the COPYING file for copyright information and + * how to reach the author. + * + */ + +#undef DEBUG +#include "headers.h" + +extern pthread_mutex_t lock; +extern recv_info_t receivers; + +extern int mld_start; +static pthread_t mld_send_reports_thread; +static char iface[IFNAMSIZ]; + +static int find_mcg_in_mld_mcas (struct in6_addr *mld_mca, int len, struct in6_addr *mcg) +{ + int i; + + for (i = 0; i < len; i++) { + if (!memcmp (mld_mca + i, mcg, sizeof (struct in6_addr))) { + return 1; + } + } + return 0; +} +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +typedef struct { + struct in6_addr *mld_mca_add; + struct in6_addr *mld_mca_drop; +} mld_reporter_context_t; + +static void clean_mld_send_reports_thread(void *p) +{ + mld_reporter_context_t *c=(mld_reporter_context_t*)p; + if(c->mld_mca_add) { + free(c->mld_mca_add); + } + if(c->mld_mca_drop) { + free(c->mld_mca_drop); + } +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +static void *mld_send_reports (void *arg) +{ + recv_info_t *receivers = (recv_info_t *) arg; + + int grec_num_drop; + int grec_num_add; + pid_info_t *p; + pid_info_t *ptmp; + recv_info_t *r; + int maxpids=128; + mld_reporter_context_t c; + memset(&c, 0, sizeof(mld_reporter_context_t)); + + c.mld_mca_add=(struct in6_addr *)malloc(maxpids*sizeof(struct in6_addr)); + if (!c.mld_mca_add) + err ("mld_send_reports: out of memory\n"); + c.mld_mca_drop=(struct in6_addr *)malloc(maxpids*sizeof(struct in6_addr)); + if (!c.mld_mca_drop) + err ("mld_send_reports: out of memory\n"); + + pthread_cleanup_push (clean_mld_send_reports_thread, &c); + + struct intnode *intn = int_find_name (iface); + + if( !c.mld_mca_add || !c.mld_mca_drop) { + err ("Cannot get memory for add/drop list\n"); + } + mld_start=1; + while (mld_start) { + grec_num_drop=0; + pthread_mutex_lock (&lock); + + int pids=count_all_pids(receivers); + if(pids>maxpids) { + maxpids=pids; + c.mld_mca_add=(struct in6_addr *)realloc(c.mld_mca_add, pids*sizeof(struct in6_addr)); + if (!c.mld_mca_add) + err ("mld_send_reports: out of memory\n"); + c.mld_mca_drop=(struct in6_addr *)realloc(c.mld_mca_drop, pids*sizeof(struct in6_addr)); + if (!c.mld_mca_drop) + err ("mld_send_reports: out of memory\n"); + } + + //Send listener reports for all recently dropped MCGs + DVBMC_LIST_FOR_EACH_ENTRY (r, &receivers->list, recv_info_t, list) { + DVBMC_LIST_FOR_EACH_ENTRY_SAFE (p, ptmp, &r->slots.list, pid_info_t, list) { + // prevent a somewhere running mcg on any device to be dropped and prevent to drop same mcg multiple times + if (!p->run) { + if ( p->dropped && !find_any_slot_by_mcg (receivers, &p->mcg) && !find_mcg_in_mld_mcas (c.mld_mca_drop, grec_num_drop, &p->mcg)) { + memcpy (c.mld_mca_drop + grec_num_drop++, &p->mcg.s6_addr, sizeof (struct in6_addr)); + p->dropped--; +#ifdef DEBUG + char host[INET6_ADDRSTRLEN]; + inet_ntop (AF_INET6, p->mcg.s6_addr, (char *) host, INET6_ADDRSTRLEN); + dbg ("DROP_GROUP %d %s\n", grec_num_drop, host); +#endif + } else { + dvbmc_list_remove(&p->list); + free(p); + } + } + } + } + if(grec_num_drop > maxpids) { + err ("Wrong number of pids: %d>%d\n", grec_num_drop, maxpids); + } + grec_num_add=0; + //Send listener reports for all current MCG in use + DVBMC_LIST_FOR_EACH_ENTRY (r, &receivers->list, recv_info_t, list) { + DVBMC_LIST_FOR_EACH_ENTRY (p, &r->slots.list, pid_info_t, list) { + if (p->run && !find_mcg_in_mld_mcas (c.mld_mca_add, grec_num_add, &p->mcg)) { + memcpy (c.mld_mca_add + grec_num_add++, p->mcg.s6_addr, sizeof (struct in6_addr)); +#ifdef DEBUG + char host[INET6_ADDRSTRLEN]; + inet_ntop (AF_INET6, &p->mcg.s6_addr, (char *) host, INET6_ADDRSTRLEN); + dbg ("ADD_GROUP %d %s\n", grec_num_add, host); +#endif + } + } + } + + if(grec_num_add > maxpids) { + err ("Wrong number of pids: %d>%d\n", grec_num_add, maxpids); + } + + pthread_mutex_unlock (&lock); + + if (intn && intn->mtu) { + if (grec_num_drop) { + send_mldv2_report (intn, grec_num_drop, c.mld_mca_drop, 0, NULL, MLD2_MODE_IS_INCLUDE); + } + if (grec_num_add) { + send_mldv2_report (intn, grec_num_add, c.mld_mca_add, 0, NULL, MLD2_MODE_IS_EXCLUDE); + } + } + usleep (REP_TIME); + pthread_testcancel(); + } + pthread_cleanup_pop (1); + return NULL; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +int mld_client_init (char *intf) +{ + if(intf) { + strcpy(iface, intf); + } else { + iface[0]=0; + } + + if (!strlen (iface)) { + struct intnode *intn = int_find_first (); + if (intn) { + strcpy (iface, intn->name); + } else { + warn ("Cannot find any usable network interface\n"); + return -1; + } + } + +#if ! (defined WIN32 || defined APPLE) + g_conf->rawsocket = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_ALL)); +#endif +#ifdef WIN32 + g_conf->rawsocket = socket (PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); +#endif +#ifdef APPLE + g_conf->rawsocket = socket (PF_INET6, SOCK_RAW, IPPROTO_HOPOPTS); +#endif + if (g_conf->rawsocket < 0) { + warn ("Cannot get a packet socket\n"); + return -1; + } +#ifdef WIN32 + #define IPV6_HDRINCL 2 + DWORD n=1; + if (setsockopt (g_conf->rawsocket, IPPROTO_IPV6, IPV6_HDRINCL, (char *)&n, sizeof (n)) < 0) { + err ("setsockopt IPV6_HDRINCL"); + } + int idx; + if ((idx = if_nametoindex (iface))>0) { + int ret=setsockopt (g_conf->rawsocket, IPPROTO_IPV6, IPV6_MULTICAST_IF, (_SOTYPE)&idx, sizeof (idx)); + if(ret<0) { + warn("setsockopt for IPV6_MULTICAST_IF failed with %d error %s (%d)\n",ret,strerror (errno), errno); + } + } +#endif + pthread_create (&mld_send_reports_thread, NULL, mld_send_reports, &receivers); + return 0; +} + +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +void mld_client_exit (void) +{ + if(g_conf) { + mld_start=0; + if(pthread_exist(mld_send_reports_thread)) { + if(pthread_exist(mld_send_reports_thread) && !pthread_cancel (mld_send_reports_thread)) { + pthread_join (mld_send_reports_thread, NULL); + } + } +#if 0 + struct intnode *intn; + unsigned int i; + for (i = 0; i < g_conf->maxinterfaces; i++) { + intn = &g_conf->ints[i]; + if (intn->mtu == 0) + continue; + int_destroy (intn); + } +#endif + closesocket(g_conf->rawsocket); + } +} |