]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Initial work to fix code word client
authorAndreas Öman <andreas@lonelycoder.com>
Mon, 1 Sep 2008 18:33:46 +0000 (18:33 +0000)
committerAndreas Öman <andreas@lonelycoder.com>
Mon, 1 Sep 2008 18:33:46 +0000 (18:33 +0000)
cwc.c
cwc.h

diff --git a/cwc.c b/cwc.c
index 14b1a4fb7352dbf8d887895383fb0f6162cb2dd9..1291605150bb9b4969ccceca69269ddd85edf2ba 100644 (file)
--- a/cwc.c
+++ b/cwc.c
@@ -110,21 +110,6 @@ typedef struct cwc_transport {
 } cwc_transport_t;
 
 
-/**
- *
- */
-static void
-cwc_set_state(cwc_t *cwc, int newstate, const char *errtxt)
-{
-  cwc->cwc_state = newstate;
-
-  if(newstate == CWC_STATE_IDLE)
-    cwc->cwc_errtxt = errtxt;
-
-  //notify_cwc_status_change(cwc);
-}
-
-
 
 /**
  *
@@ -276,26 +261,12 @@ des_make_session_key(cwc_t *cwc)
   memcpy(cwc->cwc_key, des_key_spread(des14), 16);
 }
 
-
-/**
- *
- */
-static void
-cwc_timeout(void *aux, int64_t now)
-{
-  cwc_t *cwc = aux;
-  tcp_disconnect(&cwc->cwc_tcp_session, ETIMEDOUT);
-}
-
-
 /**
  *
  */
 static int
 cwc_send_msg(cwc_t *cwc, const uint8_t *msg, size_t len, int sid)
 {
-  tcp_session_t *ses = &cwc->cwc_tcp_session;
-
   uint8_t *buf = malloc(CWS_NETMSGSIZE);
 
   memset(buf, 0, 12);
@@ -318,10 +289,8 @@ cwc_send_msg(cwc_t *cwc, const uint8_t *msg, size_t len, int sid)
   buf[0] = (len - 2) >> 8;
   buf[1] =  len - 2;
 
-  tcp_send_msg(ses, 0, buf, len);
-
-  /* Expect a response within 4 seconds */
-  dtimer_arm(&cwc->cwc_idle_timer, cwc_timeout, cwc, 4);
+  write(cwc->cwc_fd, buf, len);
+  free(buf);
   return cwc->cwc_seq;
 }
 
@@ -330,13 +299,12 @@ cwc_send_msg(cwc_t *cwc, const uint8_t *msg, size_t len, int sid)
 /**
  * Card data command
  */
+
 static void
 cwc_send_data_req(cwc_t *cwc)
 {
   uint8_t buf[CWS_NETMSGSIZE];
 
-  cwc_set_state(cwc, CWC_STATE_WAIT_CARD_DATA, NULL);
-
   buf[0] = MSG_CARD_DATA_REQ;
   buf[1] = 0;
   buf[2] = 0;
@@ -348,6 +316,7 @@ cwc_send_data_req(cwc_t *cwc)
 /**
  * Send keep alive
  */
+#if 0
 static void
 cwc_send_ka(void *aux, int64_t now)
 {
@@ -359,49 +328,44 @@ cwc_send_ka(void *aux, int64_t now)
   buf[2] = 0;
 
   cwc_send_msg(cwc, buf, 3, 0);
-  dtimer_arm(&cwc->cwc_send_ka_timer, cwc_send_ka, cwc,
-            CWC_KEEPALIVE_INTERVAL);
 }
+#endif
 
 
 /**
  * Handle reply to card data request
  */
 static int
-cwc_dispatch_card_data_reply(cwc_t *cwc, uint8_t msgtype, 
-                            uint8_t *msg, int len)
+cwc_decode_card_data_reply(cwc_t *cwc, uint8_t *msg, int len)
 {
   int plen;
   const char *n;
 
-  if(msgtype != MSG_CARD_DATA)
-    return EBADMSG;
-
   msg += 12;
   len -= 12;
+
+  if(len < 3) {
+    tvhlog(LOG_INFO, "cwc", "Invalid card data reply");
+    return -1;
+  }
+
   plen = (msg[1] & 0xf) << 8 | msg[2];
 
-  if(plen < 14)
-    return EBADMSG;
-  
+  if(plen < 14) {
+    tvhlog(LOG_INFO, "cwc", "Invalid card data reply");
+    return -1;
+  }
+
   cwc->cwc_caid = (msg[4] << 8) | msg[5];
   n = psi_caid2name(cwc->cwc_caid) ?: "Unknown";
 
   tvhlog(LOG_INFO, "cwc", "%s: Connected as user 0x%02x "
         "to a %s-card [0x%04x : %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x] "
         "with %d providers", 
-        cwc->cwc_tcp_session.tcp_hostname,
+        cwc->cwc_hostname,
         msg[3], n, cwc->cwc_caid, 
         msg[6], msg[7], msg[8], msg[9], msg[10], msg[11], msg[12], msg[13],
         msg[14]);
-
-  cwc_set_state(cwc, CWC_STATE_RUNNING, NULL);
-
-  /* Send KA every CWC_KEEPALIVE_INTERVAL seconds */
-
-  dtimer_arm(&cwc->cwc_send_ka_timer, cwc_send_ka, cwc,
-            CWC_KEEPALIVE_INTERVAL);
-
   return 0;
 }
 
@@ -416,8 +380,6 @@ cwc_send_login(cwc_t *cwc)
   int ul = strlen(cwc->cwc_username) + 1;
   int pl = strlen(cwc->cwc_password_salted) + 1;
 
-  cwc_set_state(cwc, CWC_STATE_WAIT_LOGIN_ACK, NULL);
-
   buf[0] = MSG_CLIENT_2_SERVER_LOGIN;
   buf[1] = 0;
   buf[2] = ul + pl;
@@ -427,7 +389,7 @@ cwc_send_login(cwc_t *cwc)
   cwc_send_msg(cwc, buf, ul + pl + 3, 0);
 }
 
-
+#if 0
 /**
  * Handle reply to login
  */
@@ -591,37 +553,155 @@ cwc_data_input(cwc_t *cwc)
     }
   }
 }
+#endif
 
 
+/**
+ *
+ */
+static int
+cwc_read_message(cwc_t *cwc, const char *state)
+{
+  char buf[2];
+  int msglen, r;
+
+  if((r = tcp_read(cwc->cwc_fd, buf, 2))) {
+    tvhlog(LOG_INFO, "cwc", "%s: %s: Read error (header): %s",
+          cwc->cwc_hostname, state, strerror(r));
+    return -1;
+  }
+
+  msglen = (buf[0] << 8) | buf[1];
+  if(msglen >= CWS_NETMSGSIZE) {
+    tvhlog(LOG_INFO, "cwc", "%s: %s: Invalid message size: %d",
+          cwc->cwc_hostname, state, msglen);
+    return -1;
+  }
+
+  if((r = tcp_read(cwc->cwc_fd, cwc->cwc_buf + 2, msglen))) {
+    tvhlog(LOG_INFO, "cwc", "%s: %s: Read error: %s",
+          cwc->cwc_hostname, state, strerror(r));
+    return -1;
+  }
+
+  if((msglen = des_decrypt(cwc->cwc_buf, msglen + 2, cwc->cwc_key)) < 15) {
+    tvhlog(LOG_INFO, "cwc", "%s: %s: Decrypt failed", state, cwc->cwc_hostname);
+    return -1;
+  }
+
+  return msglen;
+}
+
 
 /**
  *
  */
 static void
-cwc_tcp_callback(tcpevent_t event, void *tcpsession)
+cwc_session(cwc_t *cwc)
 {
-  cwc_t *cwc = tcpsession;
+  int r;
+  
+  /**
+   * Get login key
+   */
+  if((r = tcp_read(cwc->cwc_fd, cwc->cwc_buf, 14))) {
+    tvhlog(LOG_INFO, "cwc", "%s: No login key received: %s",
+          cwc->cwc_hostname, strerror(r));
+    return;
+  }
 
-  dtimer_disarm(&cwc->cwc_idle_timer);
+  des_make_login_key(cwc, cwc->cwc_buf);
 
-  switch(event) {
-  case TCP_CONNECT:
-    cwc->cwc_seq = 0;
-    cwc->cwc_bufptr = 0;
-    cwc_set_state(cwc, CWC_STATE_WAIT_LOGIN_KEY, NULL);
-    /* We want somthing within 20 seconds */
-    dtimer_arm(&cwc->cwc_idle_timer, cwc_timeout, cwc, 20); 
-    break;
+  /**
+   * Login
+   */
+  cwc_send_login(cwc);
+  
+  if(cwc_read_message(cwc, "Wait login response") < 0)
+    return;
 
-  case TCP_DISCONNECT:
-    cwc_set_state(cwc, CWC_STATE_IDLE, "Disconnected");
-    dtimer_disarm(&cwc->cwc_send_ka_timer);
-    break;
+  if(!cwc->cwc_running || !cwc->cwc_enabled)
+    return;
 
-  case TCP_INPUT:
-    cwc_data_input(cwc);
-    break;
+  if(cwc->cwc_buf[12] != MSG_CLIENT_2_SERVER_LOGIN_ACK) {
+    tvhlog(LOG_INFO, "cwc", "%s: Login failed", cwc->cwc_hostname);
+    return;
+  }
+
+  des_make_session_key(cwc);
+
+  /**
+   * Request card data
+   */
+  cwc_send_data_req(cwc);
+  if((r = cwc_read_message(cwc, "Request card data")) < 0)
+    return;
+
+  if(cwc->cwc_buf[12] != MSG_CARD_DATA) {
+    tvhlog(LOG_INFO, "cwc", "%s: Card data request failed", cwc->cwc_hostname);
+    return;
+  }
+
+  if(!cwc->cwc_running || !cwc->cwc_enabled)
+    return;
+
+  cwc_decode_card_data_reply(cwc, cwc->cwc_buf, r);
+  sleep(4);
+
+
+}
+
+
+/**
+ *
+ */
+static void *
+cwc_thread(void *aux)
+{
+  cwc_t *cwc = aux;
+  int fd;
+  char errbuf[100];
+
+  pthread_mutex_lock(&cwc->cwc_mutex);
+
+  while(cwc->cwc_running) {
+    
+    while(cwc->cwc_running && cwc->cwc_enabled == 0)
+      pthread_cond_wait(&cwc->cwc_cond, &cwc->cwc_mutex);
+
+    tvhlog(LOG_INFO, "cwc", "Attemping to connect to %s:%d",
+          cwc->cwc_hostname, cwc->cwc_port);
+
+    fd = tcp_connect(cwc->cwc_hostname, cwc->cwc_port, errbuf,
+                    sizeof(errbuf), 10);
+
+    if(fd == -1) {
+      tvhlog(LOG_INFO, "cwc", "Connection attempt to %s:%d failed: %s",
+            cwc->cwc_hostname, cwc->cwc_port, errbuf);
+      continue;
+    }
+
+    if(cwc->cwc_running == 0)
+      break;
+
+    tvhlog(LOG_INFO, "cwc", "Connected to %s:%d",
+          cwc->cwc_hostname, cwc->cwc_port);
+
+    cwc->cwc_fd = fd;
+    pthread_mutex_unlock(&cwc->cwc_mutex);
+
+    cwc_session(cwc);
+
+    pthread_mutex_lock(&cwc->cwc_mutex);
+    cwc->cwc_fd = -1;
+    close(fd);
+
+    tvhlog(LOG_INFO, "cwc", "Disconnected from %s", cwc->cwc_hostname);
+    sleep(1);
   }
+
+  pthread_mutex_unlock(&cwc->cwc_mutex);
+  return NULL;
 }
 
 
@@ -653,11 +733,14 @@ cwc_table_input(struct th_descrambler *td, struct th_transport *t,
     if(ct->ct_ecmsize == len && !memcmp(ct->ct_ecm, data, len))
       return; /* key already sent */
 
+    abort(); 
+    /*
     if(cwc->cwc_state != CWC_STATE_RUNNING) {
-      /* New key, but we are not connected (anymore), can not descramble */
+      // New key, but we are not connected (anymore), can not descramble
       ct->ct_keystate = CT_UNKNOWN;
       break;
     }
+*/
 
     memcpy(ct->ct_ecm, data, len);
     ct->ct_ecmsize = len;
@@ -757,6 +840,8 @@ cwc_transport_start(th_transport_t *t)
   th_descrambler_t *td;
   th_stream_t *st;
 
+  lock_assert(&global_lock);
+
   TAILQ_FOREACH(cwc, &cwcs, cwc_link) {
     if(cwc->cwc_caid == 0)
       continue;
@@ -794,6 +879,13 @@ cwc_destroy(cwc_t *cwc)
 {
   cwc_transport_t *ct;
 
+  pthread_mutex_lock(&cwc->cwc_mutex);
+  cwc->cwc_running = 0;
+  pthread_cond_signal(&cwc->cwc_cond);
+  pthread_mutex_unlock(&cwc->cwc_mutex);
+
+  pthread_join(cwc->cwc_thread_id, NULL);
+
   while((ct = LIST_FIRST(&cwc->cwc_transports)) != NULL)
     cwc_transport_destroy(ct);
 
@@ -801,8 +893,8 @@ cwc_destroy(cwc_t *cwc)
   free((void *)cwc->cwc_password);
   free((void *)cwc->cwc_password_salted);
   free((void *)cwc->cwc_username);
-
-  tcp_destroy_client(&cwc->cwc_tcp_session);
+  free((void *)cwc->cwc_hostname);
+  free(cwc);
 }
 
 
@@ -831,14 +923,12 @@ cwc_entry_find(const char *id, int create)
     cwc_tally = atoi(id);
   }
 
-  cwc = tcp_create_client(NULL, 11000, sizeof(cwc_t), 
-                         "cwc", cwc_tcp_callback, 0);
-
+  cwc = calloc(1, sizeof(cwc_t));
   cwc->cwc_id = strdup(id); 
-  cwc->cwc_username = NULL;
-  cwc->cwc_password = NULL;
-
+  cwc->cwc_running = 1;
   TAILQ_INSERT_TAIL(&cwcs, cwc, cwc_link);  
+
+  pthread_create(&cwc->cwc_thread_id, NULL, cwc_thread, cwc);
   return cwc;
 }
 
@@ -855,8 +945,8 @@ cwc_record_build(cwc_t *cwc)
   htsmsg_add_str(e, "id", cwc->cwc_id);
   htsmsg_add_u32(e, "enabled",  !!cwc->cwc_enabled);
 
-  htsmsg_add_str(e, "hostname", cwc->cwc_tcp_session.tcp_hostname ?: "");
-  htsmsg_add_u32(e, "port", cwc->cwc_tcp_session.tcp_port);
+  htsmsg_add_str(e, "hostname", cwc->cwc_hostname ?: "");
+  htsmsg_add_u32(e, "port", cwc->cwc_port);
 
   htsmsg_add_str(e, "username", cwc->cwc_username ?: "");
   htsmsg_add_str(e, "password", cwc->cwc_password ?: "");
@@ -920,8 +1010,7 @@ cwc_entry_update(void *opaque, const char *id, htsmsg_t *values, int maycreate)
   if((cwc = cwc_entry_find(id, maycreate)) == NULL)
     return NULL;
 
-  /* Disable while changing */
-  tcp_enable_disable(&cwc->cwc_tcp_session, 0);
+  pthread_mutex_lock(&cwc->cwc_mutex);
   
   if((s = htsmsg_get_str(values, "username")) != NULL) {
     free(cwc->cwc_username);
@@ -941,14 +1030,15 @@ cwc_entry_update(void *opaque, const char *id, htsmsg_t *values, int maycreate)
   }
 
   if((s = htsmsg_get_str(values, "hostname")) != NULL) {
-    tcp_set_hostname(&cwc->cwc_tcp_session, s);
+    free(cwc->cwc_hostname);
+    cwc->cwc_hostname = strdup(s);
   }
 
   if(!htsmsg_get_u32(values, "enabled", &u32))
     cwc->cwc_enabled = u32;
 
   if(!htsmsg_get_u32(values, "port", &u32))
-    cwc->cwc_tcp_session.tcp_port = u32;
+    cwc->cwc_port = u32;
 
   if((s = htsmsg_get_str(values, "deskey")) != NULL) {
     for(i = 0; i < 14; i++) {
@@ -965,8 +1055,8 @@ cwc_entry_update(void *opaque, const char *id, htsmsg_t *values, int maycreate)
     memcpy(cwc->cwc_confedkey, key, 14);
   }
 
-  if(cwc->cwc_enabled)
-    tcp_enable_disable(&cwc->cwc_tcp_session, 1);
+  pthread_cond_signal(&cwc->cwc_cond);
+  pthread_mutex_unlock(&cwc->cwc_mutex);
 
   return cwc_record_build(cwc);
 }
@@ -1058,38 +1148,3 @@ cwc_init(void)
   dt = dtable_create(&cwc_dtc, "cwc", NULL);
   dtable_load(dt);
 }
-
-/**
- *
- */
-static struct strtab cwcstatustab[] = {
-  { "Waiting for login key",                 CWC_STATE_WAIT_LOGIN_KEY },
-  { "Waiting for login ACK",                 CWC_STATE_WAIT_LOGIN_ACK },
-  { "Waiting for card data",                 CWC_STATE_WAIT_CARD_DATA },
-  { "Running",                               CWC_STATE_RUNNING },
-};
-
-const char *
-cwc_status_to_text(struct cwc *cwc)
-{
-  static char buf[100];
-  char buf2[30];
-  const char *n;
-
-  if(cwc->cwc_state == CWC_STATE_IDLE)
-    return cwc->cwc_errtxt ?: "Not connected";
-
-  if(cwc->cwc_state == CWC_STATE_RUNNING) {
-
-    n = psi_caid2name(cwc->cwc_caid);
-    if(n == NULL) {
-      snprintf(buf2, sizeof(buf2), "0x%x", cwc->cwc_caid);
-      n = buf2;
-    }
-
-    snprintf(buf, sizeof(buf), "Connected to a %s card", n);
-    return buf;
-  }
-
-  return val2str(cwc->cwc_state, cwcstatustab) ?: "Invalid status";
-}
diff --git a/cwc.h b/cwc.h
index 19678ec27430ffd540e7af0bb55d6b65db78ffe8..47ab313120a0b65d2ec4a906c169e6f2d6cdbe4b 100644 (file)
--- a/cwc.h
+++ b/cwc.h
@@ -26,22 +26,16 @@ TAILQ_HEAD(cwc_queue, cwc);
 extern struct cwc_queue cwcs;
 
 typedef struct cwc {
-  //  tcp_session_t cwc_tcp_session; /* Must be first */
+  int cwc_fd;
 
-  TAILQ_ENTRY(cwc) cwc_link;
+  pthread_mutex_t cwc_mutex;
+  pthread_cond_t cwc_cond;
+  pthread_t cwc_thread_id;
+
+  TAILQ_ENTRY(cwc) cwc_link; /* Linkage protected via global_lock */
 
   LIST_HEAD(, cwc_transport) cwc_transports;
 
-  enum {
-    CWC_STATE_IDLE,
-    CWC_STATE_WAIT_LOGIN_KEY,
-    CWC_STATE_WAIT_LOGIN_ACK,
-    CWC_STATE_WAIT_CARD_DATA,
-    CWC_STATE_RUNNING,
-    CWC_STATE_HOST_ERROR,
-    CWC_STATE_ACCESS_ERROR,
-  } cwc_state;
-  
   uint16_t cwc_caid;
 
   uint16_t cwc_seq;
@@ -58,17 +52,14 @@ typedef struct cwc {
   char *cwc_password;
   char *cwc_password_salted;   /* salted version */
   char *cwc_comment;
-
-  // dtimer_t cwc_idle_timer;
-
-  // dtimer_t cwc_send_ka_timer;
-
+  char *cwc_hostname;
+  int cwc_port;
   char *cwc_id;
 
   const char *cwc_errtxt;
 
   int cwc_enabled;
-
+  int cwc_running;
 } cwc_t;
 
 
@@ -76,14 +67,9 @@ void cwc_init(void);
 
 void cwc_transport_start(th_transport_t *t);
 
-const char *cwc_add(const char *hostname, const char *porttxt,
-                   const char *username, const char *password, 
-                   const char *deskey, const char *enabled,
-                   int save, int salt);
-
 const char *cwc_status_to_text(struct cwc *cwc);
 
-cwc_t *cwc_find(int id);
+//cwc_t *cwc_find(int id);
 
 void cwc_delete(cwc_t *cwc);