]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
descrambler: update the keystate depending variables only once, cleanups
authorJaroslav Kysela <perex@perex.cz>
Mon, 12 Jun 2017 15:34:10 +0000 (17:34 +0200)
committerJaroslav Kysela <perex@perex.cz>
Mon, 12 Jun 2017 16:20:25 +0000 (18:20 +0200)
src/descrambler.h
src/descrambler/capmt.c
src/descrambler/cccam.c
src/descrambler/cwc.c
src/descrambler/descrambler.c
src/descrambler/tsdebugcw.c

index ec4a676745fc84bbf6fe2f1242effbeca6b621b7..d45003930b9646b7aa708cb56d7771b88edba99c 100644 (file)
@@ -41,6 +41,14 @@ struct th_descrambler_data;
 
 #define DESCRAMBLER_KEY_SIZE(type) ((type >= DESCRAMBLER_AES128_ECB) ? 16 : 8)
 
+typedef enum {
+    DS_INIT,
+    DS_READY,
+    DS_RESOLVED,
+    DS_FORBIDDEN,
+    DS_IDLE
+} th_descrambler_keystate_t;
+
 /**
  * Descrambler superclass
  *
@@ -51,12 +59,7 @@ typedef struct th_descrambler {
 
   char *td_nicename;
 
-  enum {
-    DS_UNKNOWN,
-    DS_RESOLVED,
-    DS_FORBIDDEN,
-    DS_IDLE
-  } td_keystate;
+  th_descrambler_keystate_t td_keystate;
 
   struct service *td_service;
 
@@ -82,6 +85,9 @@ typedef struct th_descrambler_key {
 
 typedef struct th_descrambler_runtime {
   struct service *dr_service;
+  int      dr_ca_count;
+  int      dr_ca_resolved;
+  int      dr_ca_failed;
   uint32_t dr_external:1;
   uint32_t dr_skip:1;
   uint32_t dr_quick_ecm:1;
@@ -165,6 +171,8 @@ LIST_HEAD(caid_list, caid);
 
 void descrambler_init          ( void );
 void descrambler_done          ( void );
+void descrambler_change_keystate ( th_descrambler_t *t, th_descrambler_keystate_t state, int lock );
+const char *descrambler_keystate2str( th_descrambler_keystate_t keystate );
 void descrambler_service_start ( struct service *t );
 void descrambler_service_stop  ( struct service *t );
 void descrambler_caid_changed  ( struct service *t );
index c5ded71af1c64c96fd5d94ee93eee021cae5c2c9..a569f1dd445aa4f7fe96bc18d72b3dd3880b7279 100644 (file)
@@ -1068,7 +1068,7 @@ capmt_abort(capmt_t *capmt, int keystate)
                t->s_dvb_svcname,
                keystate == DS_FORBIDDEN ?
                  "access denied" : "connection close");
-      ct->td_keystate = keystate;
+      descrambler_change_keystate((th_descrambler_t *)ct, keystate, 1);
     }
   }
   pthread_mutex_unlock(&capmt->capmt_mutex);
@@ -1078,9 +1078,7 @@ capmt_abort(capmt_t *capmt, int keystate)
 static int
 capmt_ecm_reset(th_descrambler_t *th)
 {
-  capmt_service_t *ct = (capmt_service_t *)th;
-
-  ct->td_keystate = DS_UNKNOWN;
+  descrambler_change_keystate(th, DS_READY, 1);
   return 0;
 }
 
@@ -1103,7 +1101,7 @@ capmt_process_key(capmt_t *capmt, uint8_t adapter, ca_info_t *cai,
         tvherror(LS_CAPMT,
                  "%s: Can not descramble service \"%s\", access denied",
                  capmt_name(capmt), t->s_dvb_svcname);
-        ct->td_keystate = DS_FORBIDDEN;
+        descrambler_change_keystate((th_descrambler_t *)ct, DS_FORBIDDEN, 1);
       }
       continue;
     }
@@ -1740,7 +1738,7 @@ handle_ca0_wrapper(capmt_t *capmt)
     }
   }
 
-  capmt_abort(capmt, DS_UNKNOWN);
+  capmt_abort(capmt, DS_READY);
   tvhinfo(LS_CAPMT, "%s: connection from client closed ...", capmt_name(capmt));
 }
 #endif
@@ -2446,6 +2444,8 @@ capmt_service_start(caclient_t *cac, service_t *s)
   LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
   LIST_INSERT_HEAD(&capmt->capmt_services, ct, ct_link);
 
+  descrambler_change_keystate((th_descrambler_t *)td, DS_READY, 0);
+
   /* wake-up idle thread */
   tvh_cond_signal(&capmt->capmt_cond, 0);
 
index 9bcef6095f366c8ae875a8a255316f67c60fa237..af9da373b4e389b8bcefc8031e464b99c0fa1a5f 100644 (file)
@@ -522,7 +522,7 @@ cccam_ecm_reset(th_descrambler_t *th)
   ecm_section_t *es;
 
   pthread_mutex_lock(&cccam->cccam_mutex);
-  ct->td_keystate = DS_UNKNOWN;
+  descrambler_change_keystate(th, DS_READY, 1);
   LIST_FOREACH(ep, &ct->cs_pids, ep_link)
     LIST_FOREACH(es, &ep->ep_sections, es_link)
       es->es_keystate = ES_UNKNOWN;
@@ -591,8 +591,8 @@ handle_ecm_reply(cccam_service_t *ct, ecm_section_t *es, uint8_t *msg,
                es->es_section, ct->td_nicename, t->s_dvb_svcname);
       es->es_nok = CCCAM_MAX_NOKS; /* do not send more ECM requests */
       es->es_keystate = ES_IDLE;
-      if (ct->td_keystate == DS_UNKNOWN)
-        ct->td_keystate = DS_IDLE;
+      if (ct->td_keystate == DS_READY)
+        descrambler_change_keystate((th_descrambler_t *)ct, DS_IDLE, 1);
     }
 
     tvhdebug(LS_CCCAM,
@@ -627,7 +627,7 @@ forbid:
                "Can not descramble service \"%s\", access denied (seqno: %d "
                "Req delay: %"PRId64" ms) from %s",
                t->s_dvb_svcname, seq, delay, ct->td_nicename);
-      ct->td_keystate = DS_FORBIDDEN;
+      descrambler_change_keystate((th_descrambler_t *)ct, DS_FORBIDDEN, 1);
       ct->ecm_state = ECM_RESET;
       /* this pid is not valid, force full scan */
       if (t->s_dvb_prefcapid == ct->cs_channel && t->s_dvb_prefcapid_lock == PREFCAPID_OFF)
@@ -1526,7 +1526,7 @@ found:
 
       if(cccam->cccam_fd == -1) {
         // New key, but we are not connected (anymore), can not descramble
-        ct->td_keystate = DS_UNKNOWN;
+        descrambler_change_keystate((th_descrambler_t *)ct, DS_READY, 0);
         break;
       }
 
@@ -1703,6 +1703,8 @@ cccam_service_start(caclient_t *cac, service_t *t)
 
   LIST_INSERT_HEAD(&cccam->cccam_services, ct, cs_link);
 
+  descrambler_change_keystate((th_descrambler_t *)td, DS_READY, 0);
+
 add:
   i = 0;
   TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
index b1c4e8c510d54e3e2dec051292e1a4b7757979e3..731e1dcdcbf20b584320cbf6824178a7cb647826 100644 (file)
@@ -676,7 +676,7 @@ cwc_ecm_reset(th_descrambler_t *th)
   ecm_section_t *es;
 
   pthread_mutex_lock(&cwc->cwc_mutex);
-  ct->td_keystate = DS_UNKNOWN;
+  descrambler_change_keystate(th, DS_READY, 1);
   LIST_FOREACH(ep, &ct->cs_pids, ep_link)
     LIST_FOREACH(es, &ep->ep_sections, es_link)
       es->es_keystate = ES_UNKNOWN;
@@ -742,8 +742,8 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
                es->es_section, ct->td_nicename, t->s_dvb_svcname);
       es->es_nok = CWC_MAX_NOKS; /* do not send more ECM requests */
       es->es_keystate = ES_IDLE;
-      if (ct->td_keystate == DS_UNKNOWN)
-        ct->td_keystate = DS_IDLE;
+      if (ct->td_keystate == DS_READY)
+        descrambler_change_keystate((th_descrambler_t *)ct, DS_IDLE, 1);
     }
 
     tvhdebug(LS_CWC,
@@ -778,7 +778,7 @@ forbid:
                "Can not descramble service \"%s\", access denied (seqno: %d "
                "Req delay: %"PRId64" ms) from %s",
                t->s_dvb_svcname, seq, delay, ct->td_nicename);
-      ct->td_keystate = DS_FORBIDDEN;
+      descrambler_change_keystate((th_descrambler_t *)ct, DS_FORBIDDEN, 1);
       ct->ecm_state = ECM_RESET;
       /* this pid is not valid, force full scan */
       if (t->s_dvb_prefcapid == ct->cs_channel && t->s_dvb_prefcapid_lock == PREFCAPID_OFF)
@@ -1455,7 +1455,7 @@ found:
 
       if(cwc->cwc_fd == -1) {
         // New key, but we are not connected (anymore), can not descramble
-        ct->td_keystate = DS_UNKNOWN;
+        descrambler_change_keystate((th_descrambler_t *)ct, DS_READY, 0);
         break;
       }
 
@@ -1626,6 +1626,8 @@ cwc_service_start(caclient_t *cac, service_t *t)
 
   LIST_INSERT_HEAD(&cwc->cwc_services, ct, cs_link);
 
+  descrambler_change_keystate((th_descrambler_t *)td, DS_READY, 0);
+
 add:
   i = 0;
   TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
index aa4b84f605b5a872433a561c02be91a1c1be0edc..3d60e4256a969464798b6d8e686f374869b2daf2 100644 (file)
@@ -566,6 +566,59 @@ descrambler_multi_pid ( th_descrambler_t *td )
   return dr->dr_key_multipid;
 }
 
+static struct strtab keystatetab[] = {
+  { "INIT",       DS_INIT },
+  { "READY",      DS_READY },
+  { "RESOLVED",   DS_RESOLVED },
+  { "FORBIDDEN",  DS_FORBIDDEN },
+  { "IDLE",       DS_IDLE },
+};
+
+const char *
+descrambler_keystate2str( th_descrambler_keystate_t keystate )
+{
+  return val2str(keystate, keystatetab) ?: "INVALID";
+}
+
+void
+descrambler_change_keystate( th_descrambler_t *td, th_descrambler_keystate_t keystate, int lock )
+{
+  service_t *t = td->td_service;
+  th_descrambler_runtime_t *dr;
+  int count = 0, failed = 0, resolved = 0;
+
+  if (td->td_keystate == keystate)
+    return;
+
+  tvhtrace(LS_DESCRAMBLER, "%s: key state changed from %s to %s for \"%s\"",
+                           td->td_nicename,
+                           descrambler_keystate2str(td->td_keystate),
+                           descrambler_keystate2str(keystate),
+                           t->s_nicename);
+  td->td_keystate = keystate;
+  if (t == NULL || (dr = t->s_descramble) == NULL)
+    return;
+
+  if (lock)
+    pthread_mutex_lock(&t->s_stream_mutex);
+  count = failed = resolved = 0;
+  LIST_FOREACH(td, &t->s_descramblers, td_service_link) {
+    count++;
+    switch (td->td_keystate) {
+    case DS_FORBIDDEN: failed++;   break;
+    case DS_RESOLVED : resolved++; break;
+    default: break;
+    }
+  }
+  dr->dr_ca_count = count;
+  dr->dr_ca_resolved = resolved;
+  dr->dr_ca_failed = failed;
+  tvhtrace(LS_DESCRAMBLER, "service \"%s\": %d descramblers (%d ok %d failed)",
+                           t->s_nicename, count, resolved, failed);
+  if (lock)
+    pthread_mutex_unlock(&t->s_stream_mutex);
+}
+
 void
 descrambler_keys ( th_descrambler_t *td, int type, uint16_t pid,
                    const uint8_t *even, const uint8_t *odd )
@@ -581,7 +634,7 @@ descrambler_keys ( th_descrambler_t *td, int type, uint16_t pid,
   int j = 0, insert = 0;
 
   if (t == NULL || (dr = t->s_descramble) == NULL) {
-    td->td_keystate = DS_FORBIDDEN;
+    descrambler_change_keystate(td, DS_FORBIDDEN, 1);
     return;
   }
 
@@ -613,7 +666,7 @@ descrambler_keys ( th_descrambler_t *td, int type, uint16_t pid,
                ((mpegts_service_t *)td2->td_service)->s_dvb_svcname,
                td->td_nicename,
                dr->dr_key_const ? " (const)" : "");
-      td->td_keystate = DS_IDLE;
+      descrambler_change_keystate(td, DS_IDLE, 0);
       if (td->td_ecm_idle)
         td->td_ecm_idle(td);
       goto fin;
@@ -699,7 +752,7 @@ descrambler_keys ( th_descrambler_t *td, int type, uint16_t pid,
                pidname, pid, td->td_nicename, ((mpegts_service_t *)t)->s_dvb_svcname);
     }
     dr->dr_ecm_last_key_time = mclk();
-    td->td_keystate = DS_RESOLVED;
+    descrambler_change_keystate(td, DS_RESOLVED, 0);
     td->td_service->s_descrambler = td;
   } else {
     tvhdebug(LS_DESCRAMBLER,
@@ -913,11 +966,10 @@ descrambler_descramble ( service_t *t,
                          const uint8_t *tsb,
                          int len )
 {
-  th_descrambler_t *td;
   th_descrambler_runtime_t *dr = t->s_descramble;
   th_descrambler_key_t *tk;
   th_descrambler_data_t *dd, *dd_next;
-  int count, failed, resolved, len2, len3, r, flush_data = 0;
+  int len2, len3, r, flush_data = 0;
   uint32_t dbuflen;
   const uint8_t *tsb2;
   int64_t now;
@@ -945,23 +997,7 @@ descrambler_descramble ( service_t *t,
       return 1;
     }
 
-  count = failed = resolved = 0;
-  LIST_FOREACH(td, &t->s_descramblers, td_service_link) {
-    count++;
-    switch (td->td_keystate) {
-    case DS_FORBIDDEN: failed++;   break;
-    case DS_RESOLVED : resolved++; break;
-    default: break;
-    }
-  }
-
-  if (resolved) {
-
-    if (!dr->dr_key_multipid) {
-      tk = &dr->dr_keys[0];
-    } else {
-      tk = NULL;
-    }
+  if (dr->dr_ca_resolved > 0) {
 
     /* process the queued TS packets or key updates */
     for (dd = TAILQ_FIRST(&dr->dr_queue); dd; dd = dd_next) {
@@ -1012,7 +1048,10 @@ descrambler_descramble ( service_t *t,
                                     ((mpegts_service_t *)t)->s_dvb_svcname);
             if (key_late(dr, tk, ki, dd->dd_timestamp)) {
               descrambler_notify_nokey(dr);
-              if (ecm_reset(t, dr)) {
+              pthread_mutex_unlock(&t->s_stream_mutex);
+              r = ecm_reset(t, dr);
+              pthread_mutex_lock(&t->s_stream_mutex);
+              if (r) {
                 descrambler_data_cut(dr, tsb2 - sb->sb_data);
                 flush_data = 1;
                 goto queue;
@@ -1095,7 +1134,7 @@ next:
       }
     }
 queue:
-    if (count != failed) {
+    if (dr->dr_ca_count != dr->dr_ca_failed) {
       /*
        * Fill a temporary buffer until the keys are known to make
        * streaming faster.
@@ -1116,7 +1155,7 @@ queue:
       service_set_streaming_status_flags(t, TSS_NO_ACCESS);
     }
   } else {
-    if (dr->dr_skip || count == 0)
+    if (dr->dr_skip || dr->dr_ca_count == 0)
       ts_skip_packet2((mpegts_service_t *)dr->dr_service, tsb, len);
     service_set_streaming_status_flags(t, TSS_NO_ACCESS);
   }
@@ -1124,9 +1163,9 @@ queue:
     descrambler_flush_table_data(t);
 end:
   debug2("%p: end, %s", dr, keystr(tsb));
-  if (count && count == failed)
+  if (dr->dr_ca_count > 0 && dr->dr_ca_count == dr->dr_ca_failed)
     return -1;
-  return count;
+  return dr->dr_ca_count;
 }
 
 static int
index 3bcc7c20309fe0a7901185ff8542c7bc27ee584d..1c42dff5be0dd0795018ffda90143927ffbcce91 100644 (file)
@@ -103,7 +103,10 @@ tsdebugcw_service_start(service_t *t)
   td->td_service       = t;
   td->td_stop          = tsdebugcw_service_destroy;
   td->td_ecm_reset     = tsdebugcw_ecm_reset;
+  pthread_mutex_lock(&t->s_stream_mutex);
   LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
+  descrambler_change_keystate((th_descrambler_t *)td, DS_READY, 0);
+  pthread_mutex_unlock(&t->s_stream_mutex);
 }
 
 /*