#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
*
char *td_nicename;
- enum {
- DS_UNKNOWN,
- DS_RESOLVED,
- DS_FORBIDDEN,
- DS_IDLE
- } td_keystate;
+ th_descrambler_keystate_t td_keystate;
struct service *td_service;
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;
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 );
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);
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;
}
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;
}
}
}
- capmt_abort(capmt, DS_UNKNOWN);
+ capmt_abort(capmt, DS_READY);
tvhinfo(LS_CAPMT, "%s: connection from client closed ...", capmt_name(capmt));
}
#endif
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);
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;
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,
"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)
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;
}
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) {
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;
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,
"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)
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;
}
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) {
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 )
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;
}
((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;
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,
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;
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) {
((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;
}
}
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.
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);
}
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
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);
}
/*