summaryrefslogtreecommitdiff
path: root/mcast/client/.svn/text-base/ci_handler.c.svn-base
diff options
context:
space:
mode:
Diffstat (limited to 'mcast/client/.svn/text-base/ci_handler.c.svn-base')
-rw-r--r--mcast/client/.svn/text-base/ci_handler.c.svn-base321
1 files changed, 321 insertions, 0 deletions
diff --git a/mcast/client/.svn/text-base/ci_handler.c.svn-base b/mcast/client/.svn/text-base/ci_handler.c.svn-base
new file mode 100644
index 0000000..beef8ff
--- /dev/null
+++ b/mcast/client/.svn/text-base/ci_handler.c.svn-base
@@ -0,0 +1,321 @@
+/*
+ * (c) BayCom GmbH, http://www.baycom.de, info@baycom.de
+ *
+ * See the COPYING file for copyright information and
+ * how to reach the author.
+ *
+ */
+
+#include "headers.h"
+
+//#define SHOW_TPDU
+
+static ci_dev_t devs;
+static int dev_num = 0;
+static int ci_run = 0;
+static pthread_t ci_handler_thread;
+static int port = 23000;
+static char iface[IFNAMSIZ];
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static int ci_connect (ci_dev_t * c)
+{
+ int ret;
+ int j;
+ struct in6_addr nc;
+
+ if (c->connected) {
+ return 0;
+ }
+
+ if (c->fd_ci) {
+ closesocket (c->fd_ci);
+ }
+
+ c->fd_ci = socket (PF_INET6, SOCK_STREAM, 0);
+ j = 1;
+ if (setsockopt (c->fd_ci, SOL_SOCKET, SO_REUSEADDR, (_SOTYPE) & j, sizeof (j)) < 0) {
+ warn ("setsockopt REUSEADDR\n");
+ }
+
+ j = 1;
+ if (setsockopt (c->fd_ci, SOL_SOCKET, TCP_NODELAY, (_SOTYPE) & j, sizeof (j)) < 0) {
+ warn ("setsockopt TCP_NODELAY\n");
+ }
+
+ inet_pton (AF_INET6, c->uuid, &nc);
+#ifdef SHOW_TPDU
+ char host[INET6_ADDRSTRLEN];
+ inet_ntop (AF_INET6, &nc, (char *) host, INET6_ADDRSTRLEN);
+ info ("Connect To: %s\n", host);
+#endif
+ struct sockaddr_in6 addr;
+ memset (&addr, 0, sizeof (struct sockaddr_in6));
+
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons (port);
+ addr.sin6_addr = nc;
+ addr.sin6_scope_id = if_nametoindex (iface);
+
+ ret = connect (c->fd_ci, (struct sockaddr *) &addr, sizeof (struct sockaddr_in6));
+ if (ret < 0) {
+ warn ("Failed to access NetCeiver CA support\n");
+ } else {
+ c->connected = 1;
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int ci_write_pdu (ci_dev_t * c, ci_pdu_t * tpdu)
+{
+ int ret = -1;
+
+ dbg ("ci_write_pdu: %p %d\n", tpdu->data, tpdu->len);
+
+ ci_decode_ll (tpdu->data, tpdu->len);
+ memcpy (c->txdata + 2, tpdu->data, tpdu->len);
+ c->txdata[0] = tpdu->len >> 8;
+ c->txdata[1] = tpdu->len & 0xff;
+ if (!ci_connect (c)) {
+#ifdef SHOW_TPDU
+ int j;
+ info ("Send TPDU: ");
+ for (j = 0; j < tpdu->len; j++) {
+ info ("%02x ", tpdu->data[j]);
+ }
+ info ("\n");
+#endif
+ ret = send (c->fd_ci, (char *) c->txdata, tpdu->len + 2, 0);
+ if (ret < 0) {
+ c->connected = 0;
+ }
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void clean_ci_recv_thread (void *argp)
+{
+ ci_dev_t *c = (ci_dev_t *) argp;
+ if (c->txdata) {
+ free (c->txdata);
+ }
+ if (c->rxdata) {
+ free (c->rxdata);
+ }
+ closesocket (c->fd_ci);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void *ci_recv (void *argp)
+{
+ ci_dev_t *c = (ci_dev_t *) argp;
+ ci_pdu_t tpdu;
+ int ret = -1;
+
+ pthread_cleanup_push (clean_ci_recv_thread, c);
+
+ c->rxdata = (u_int8_t *) malloc (CA_TPDU_MAX + 2);
+ if (!c->rxdata)
+ err ("ci_recv: out of memory\n");
+ c->txdata = (u_int8_t *) malloc (CA_TPDU_MAX + 2);
+ if (!c->txdata)
+ err ("ci_recv: out of memory\n");
+
+ if (c->rxdata && c->txdata) {
+ c->recv_run = 1;
+
+ while (c->recv_run) {
+ if (c->connected) {
+ ret = recv (c->fd_ci, (char *) c->rxdata, CA_TPDU_MAX + 2, 0);
+ if (ret > 0) {
+ tpdu.data = c->rxdata;
+ while (ret > 0) {
+ tpdu.len = ntohs16 (tpdu.data);
+ if (tpdu.len >= ret) {
+ break;
+ }
+ tpdu.data += 2;
+#ifdef SHOW_TPDU
+ int j;
+ info ("Received TPDU: ");
+ for (j = 0; j < tpdu.len; j++) {
+ info ("%02x ", tpdu.data[j]);
+ }
+ info ("\n");
+#endif
+ ci_decode_ll (tpdu.data, tpdu.len);
+ unsigned int slot = (unsigned int) tpdu.data[0];
+ if (slot < CA_MAX_SLOTS) {
+ if (c->handle_ci_slot[slot]) {
+ c->handle_ci_slot[slot] (&tpdu, c->handle_ci_slot_context[slot]);
+ }
+ }
+
+ tpdu.data += tpdu.len;
+ ret -= tpdu.len + 2;
+ }
+ } else {
+ if (errno == EAGAIN) {
+ ret = 0;
+ } else {
+ c->connected = 0;
+ }
+ }
+ }
+ usleep (10 * 1000);
+ }
+ }
+ pthread_cleanup_pop (1);
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int ci_register_handler (ci_dev_t * c, int slot, int (*p) (ci_pdu_t *, void *), void *context)
+{
+ if (slot < CA_MAX_SLOTS) {
+ c->handle_ci_slot[slot] = p;
+ c->handle_ci_slot_context[slot] = context;
+ return 0;
+ }
+ return -1;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+int ci_unregister_handler (ci_dev_t * c, int slot)
+{
+ if (slot < CA_MAX_SLOTS) {
+ c->handle_ci_slot[slot] = NULL;
+ c->handle_ci_slot_context[slot] = NULL;
+ return 0;
+ }
+ return -1;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static ci_dev_t *ci_add (void)
+{
+ ci_dev_t *c = (ci_dev_t *) malloc (sizeof (ci_dev_t));
+ if (!c)
+ return NULL;
+ memset (c, 0, sizeof (ci_dev_t));
+ dvbmc_list_add_head (&devs.list, &c->list);
+ return c;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void ci_del (ci_dev_t * c)
+{
+ c->recv_run = 0;
+ if (pthread_exist(c->ci_recv_thread) && !pthread_cancel (c->ci_recv_thread)) {
+ pthread_join (c->ci_recv_thread, NULL);
+ }
+ dvbmc_list_remove (&c->list);
+ free (c);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+ci_dev_t *ci_find_dev_by_uuid (char *uuid)
+{
+ ci_dev_t *c;
+ DVBMC_LIST_FOR_EACH_ENTRY (c, &devs.list, ci_dev_t, list) {
+ if (!strcmp (c->uuid, uuid)) {
+ return c;
+ }
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+static void *ci_handler (void *p)
+{
+ int n;
+ netceiver_info_list_t *nc_list = nc_get_list ();
+ ci_run = 1;
+ while (ci_run) {
+ nc_lock_list ();
+ for (n = 0; n < nc_list->nci_num; n++) {
+ netceiver_info_t *nci = nc_list->nci + n;
+ char *uuid = nci->uuid;
+ if (!strlen (uuid) || ci_find_dev_by_uuid (uuid)) {
+ //already seen
+ continue;
+ }
+
+ ci_dev_t *c = ci_add ();
+ if (!c) {
+ err ("Cannot get memory for dvb loopback context\n");
+ }
+
+ dbg ("allocate ci dev %d for uuid %s\n", dev_num, uuid);
+
+ strcpy (c->uuid, uuid);
+ c->cacaps = &nci->ci;
+ c->device = dev_num++;
+
+ info ("Starting ci thread for netceiver UUID %s\n", c->uuid);
+ int ret = pthread_create (&c->ci_recv_thread, NULL, ci_recv, c);
+ while (!ret && !c->recv_run) {
+ usleep (10000);
+ }
+ if (ret) {
+ err ("pthread_create failed with %d\n", ret);
+ }
+ }
+ nc_unlock_list ();
+ sleep (1);
+ }
+ return NULL;
+}
+
+int ci_init (int ca_enable, char *intf, int p)
+{
+ int ret = 0;
+ if (intf) {
+ strcpy (iface, intf);
+ } else {
+ iface[0] = 0;
+ }
+ if (p) {
+ port = p;
+ }
+
+ dvbmc_list_init (&devs.list);
+ if (ca_enable) {
+ ret = pthread_create (&ci_handler_thread, NULL, ci_handler, NULL);
+ while (!ret && !ci_run) {
+ usleep (10000);
+ }
+ }
+ return ret;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+void ci_exit (void)
+{
+ ci_dev_t *c;
+ ci_dev_t *ctmp;
+ if (pthread_exist (ci_handler_thread)) {
+ if (pthread_exist(ci_handler_thread) && !pthread_cancel (ci_handler_thread)) {
+ pthread_join (ci_handler_thread, NULL);
+ }
+
+ DVBMC_LIST_FOR_EACH_ENTRY_SAFE (c, ctmp, &devs.list, ci_dev_t, list) {
+ ci_del (c);
+ }
+ }
+}