Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for service blacklisting for CAMs #1148

Merged
merged 5 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 51 additions & 28 deletions src/ddci.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,38 +288,57 @@ int create_channel_for_pmt(Sddci_channel *c, SPMT *pmt) {
return 0;
}

/**
* Find the DDCI device that should be used to handle the specified PMT. The
* first suitable device is returned. If a suitable device is found but the
* device is still initializing, -1 is returned. If no suitable device is found,
* -2 is returned.
*/
int find_ddci_for_pmt(Sddci_channel *c, SPMT *pmt) {
int ddid = -100;
int retry = 0;

// search always from the beginning when the PMT is started
int ddid = -100; // -100 means we didn't find a suitable device

// continue where we left off
for (c->pos = 0; c->pos < c->ddcis; c->pos++) {
ddid = c->ddci[c->pos].ddci;
ddci_device_t *d = get_ddci(ddid);
int i = 0;
for (i = 0; i < c->ddcis; i++) {
int candidate = c->ddci[i].ddci;
ddci_device_t *d = get_ddci(candidate);
if (!d) {
LOG("DDID %d not enabled", ddid);
LOG("%s: DDCI %d not enabled, skipping", __FUNCTION__, candidate);
continue;
}
if (is_ca_initializing(ddid)) {
LOG("DD %d is initializing", ddid);
retry = 1;

} else {
if (d && d->channels < d->max_channels)
break;
else
LOG("DDCI %d cannot be used for PMT %d, pid %d (used "
"channels "
"%d max %d)",
ddid, pmt->id, pmt->pid, d ? d->channels : -1,
d ? d->max_channels : -1);
if (d->channels >= d->max_channels) {
LOG("%s: DDCI %d cannot be used for PMT %d, pid %d, sid, %d (used "
"channels "
"%d max %d), skipping",
__FUNCTION__, candidate, pmt->id, pmt->pid, pmt->sid,
d ? d->channels : -1, d ? d->max_channels : -1);
continue;
}
ddid = -100;

ddid = candidate;
break;
}
if (retry)

if (ddid == -100) {
// Distinguish between otherwise not found and deliberately not assigned
if (c->ddcis == 0) {
LOG("%s: no suitable DDCI found for PMT %d (sid %d): not mapped to "
"any DDCI "
"device in ddci.conf",
__FUNCTION__, pmt->id, pmt->sid);
} else {
LOG("%s: no suitable DDCI found for PMT %d (sid %d)", __FUNCTION__,
pmt->id, pmt->sid);
}

return -TABLES_RESULT_ERROR_NORETRY;
} else if (is_ca_initializing(ddid)) {
LOG("%s: DDCI %d is initializing, retrying", __FUNCTION__, ddid);
return -TABLES_RESULT_ERROR_RETRY;
return ddid;
} else {
LOG("%s: Using DDCI %d", __FUNCTION__, ddid);
return ddid;
}
}

int is_pmt_running(SPMT *pmt) {
Expand Down Expand Up @@ -382,10 +401,14 @@ int ddci_process_pmt(adapter *ad, SPMT *pmt) {
"Could not allocate channel");
}

// Determine which DDCI should handle this PMT
if (ddid == -1)
ddid = find_ddci_for_pmt(channel, pmt);
// Negative return values are used to distinguish from valid return values (>= 0)
if (ddid == -TABLES_RESULT_ERROR_RETRY)
return -ddid;
return TABLES_RESULT_ERROR_RETRY;
else if (ddid == -TABLES_RESULT_ERROR_NORETRY)
return TABLES_RESULT_ERROR_NORETRY;

d = get_ddci(ddid);
if (!d) {
Expand Down Expand Up @@ -1278,14 +1301,15 @@ void load_channels(SHashTable *ch) {
opts.cache_dir, CONFIG_FILE_NAME);

FILE *f = fopen(ddci_conf_path, "rt");
Sddci_channel c;
char line[1000];
int channels = 0;
int pos = 0;
if (!f)
return;
while (fgets(line, sizeof(line), f)) {
int pos = 0;
char buf[1000];
memset(buf, 0, sizeof(buf));
Sddci_channel c;
memset(&c, 0, sizeof(c));
char *x = strchr(line, '#');
if (x)
Expand All @@ -1304,7 +1328,6 @@ void load_channels(SHashTable *ch) {
int la = split(arg, cc, ARRAY_SIZE(arg), ',');
int i = 0;
channels++;
pos = 0;
for (i = 0; i < la; i++) {
int v = map_intd(arg[i], NULL, -1);
if (v != -1) {
Expand Down
1 change: 0 additions & 1 deletion src/ddci.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ typedef struct ddci_channel {
uint8_t ddci;
} ddci[MAX_ADAPTERS];
int ddcis;
int pos;
int sid;
char name[50];
char locked;
Expand Down
52 changes: 43 additions & 9 deletions tests/test_ddci.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,29 +85,51 @@ void create_adapter(adapter *ad, int id) {
int test_channels() {
SHashTable h;
int i;
Sddci_channel c, *t;
Sddci_channel c1, c2, c3, *t;
memset(&h, 0, sizeof(h));
create_hash_table(&h, 10);
memset(&c, 0, sizeof(c));
c.sid = 200;
c.ddci[1].ddci = 1;
c.ddcis = 1;
setItem(&h, c.sid, &c, sizeof(c));

// Add one channel (SID 200) that can be decoded by DDCI 1
memset(&c1, 0, sizeof(c1));
c1.sid = 200;
c1.ddci[0].ddci = 1;
c1.ddcis = 1;
setItem(&h, c1.sid, &c1, sizeof(c1));

// Add a second channel (SID 300) that can be decoded by both DDCI 1 and 2
memset(&c2, 0, sizeof(c2));
c2.sid = 300;
c2.ddci[0].ddci = 1;
c2.ddci[1].ddci = 2;
c2.ddcis = 2;
setItem(&h, c2.sid, &c2, sizeof(c2));

// Add a third channel (SID 400) that cannot be decoded by any adapter
memset(&c3, 0, sizeof(c3));
c3.sid = 400;
c3.ddcis = 0;
setItem(&h, c3.sid, &c3, sizeof(c3));

// Save and reload the table
save_channels(&h);
free_hash(&h);
create_hash_table(&h, 10);
load_channels(&h);
ASSERT(getItem(&h, 200) != NULL, "Saved SID not found in table");

// Check the contents
ASSERT(getItem(&h, 200) != NULL, "Saved SID 200 not found in table");
ASSERT(getItem(&h, 300) != NULL, "Saved SID 300 not found in table");
ASSERT(getItem(&h, 400) != NULL, "Saved SID 400 not found in table");
int ch = 0;
FOREACH_ITEM(&h, t) { ch++; }
ASSERT(ch == 1, "Expected one channel after loading");
ASSERT(ch == 3, "Expected two channels after loading");
free_hash(&h);
return 0;
}

int test_add_del_pmt() {
int i;
SPMT *pmt0, *pmt1, *pmt2, *pmt3;
SPMT *pmt0, *pmt1, *pmt2, *pmt3, *pmt4;
ddci_device_t d0, d1;
ca_device_t ca0, ca1;
adapter ad, a0, a1;
Expand All @@ -120,6 +142,7 @@ int test_add_del_pmt() {
pmt1 = create_pmt(8, 200, 201, 202, 0x100, 0x500);
pmt2 = create_pmt(8, 300, 301, 302, 0x500, 0x100);
pmt3 = create_pmt(8, 400, 401, 402, 0x600, 0x601);
pmt4 = create_pmt(8, 500, 501, 502, 0x500, 0x500);
memset(&d0, 0, sizeof(d0));
memset(&d1, 0, sizeof(d1));
memset(&d0.pmt, -1, sizeof(d0.pmt));
Expand All @@ -133,6 +156,14 @@ int test_add_del_pmt() {
create_hash_table(&d1.mapping, 30);
create_hash_table(&channels, 30);

// Save a channel for pmt4, we'll check that it is not assigned to
// any DDCI adapter even though its CAID matches etc.
Sddci_channel c4;
memset(&c4, 0, sizeof(c4));
c4.sid = pmt4->sid;
c4.ddcis = 0;
setItem(&channels, c4.sid, &c4, sizeof(c4));

int dvbca_id = add_ca(&dvbca, 0xFFFFFFFF);
// DD 0 - 0x100, DD 1 - 0x500
add_caid_mask(dvbca_id, 0, 0x100, 0xFFFF);
Expand All @@ -155,6 +186,9 @@ int test_add_del_pmt() {
ASSERT(ddci_process_pmt(&ad, pmt3) == TABLES_RESULT_ERROR_NORETRY,
"DDCI ready, expected no retry");

ASSERT(ddci_process_pmt(&ad, pmt4) == TABLES_RESULT_ERROR_NORETRY,
"Channel not assigned to any DDCI adapter, expected no retry");

// One matching channel
ASSERT(ddci_process_pmt(&ad, pmt0) == TABLES_RESULT_OK,
"DDCI matching DD 0");
Expand Down
Loading