summaryrefslogtreecommitdiff
path: root/mcast/client/.svn/text-base/mld_reporter.c.svn-base
diff options
context:
space:
mode:
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-base225
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);
+ }
+}