From: Jaroslav Kysela Date: Mon, 12 Jun 2017 15:34:10 +0000 (+0200) Subject: descrambler: update the keystate depending variables only once, cleanups X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=502349dc157d8fa266e5a20839ad553e9205151f;p=thirdparty%2Ftvheadend.git descrambler: update the keystate depending variables only once, cleanups --- diff --git a/src/descrambler.h b/src/descrambler.h index ec4a67674..d45003930 100644 --- a/src/descrambler.h +++ b/src/descrambler.h @@ -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 ); diff --git a/src/descrambler/capmt.c b/src/descrambler/capmt.c index c5ded71af..a569f1dd4 100644 --- a/src/descrambler/capmt.c +++ b/src/descrambler/capmt.c @@ -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); diff --git a/src/descrambler/cccam.c b/src/descrambler/cccam.c index 9bcef6095..af9da373b 100644 --- a/src/descrambler/cccam.c +++ b/src/descrambler/cccam.c @@ -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) { diff --git a/src/descrambler/cwc.c b/src/descrambler/cwc.c index b1c4e8c51..731e1dcdc 100644 --- a/src/descrambler/cwc.c +++ b/src/descrambler/cwc.c @@ -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) { diff --git a/src/descrambler/descrambler.c b/src/descrambler/descrambler.c index aa4b84f60..3d60e4256 100644 --- a/src/descrambler/descrambler.c +++ b/src/descrambler/descrambler.c @@ -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 diff --git a/src/descrambler/tsdebugcw.c b/src/descrambler/tsdebugcw.c index 3bcc7c203..1c42dff5b 100644 --- a/src/descrambler/tsdebugcw.c +++ b/src/descrambler/tsdebugcw.c @@ -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); } /*