source: trunk/module-dvbapi.c @ 5375

Last change on this file since 5375 was 5375, checked in by _network, 8 years ago

stapi: add log messages for debug and change lock behavior

File size: 79.8 KB
Line 
1#include "globals.h"
2
3#ifdef HAVE_DVBAPI
4
5#include "module-dvbapi.h"
6
7const char *boxdesc[] = { "none", "dreambox", "duckbox", "ufs910", "dbox2", "ipbox", "ipbox-pmt", "dm7000", "qboxhd", "coolstream", "neumo" };
8
9const struct box_devices devices[BOX_COUNT] = {
10    /* QboxHD (dvb-api-3)*/ { "/tmp/virtual_adapter/",  "ca%d",     "demux%d",          "/tmp/camd.socket" },
11    /* dreambox (dvb-api-3)*/   { "/dev/dvb/adapter%d/",    "ca%d",         "demux%d",          "/tmp/camd.socket" },
12    /* dreambox (dvb-api-1)*/   { "/dev/dvb/card%d/",   "ca%d",     "demux%d",          "/tmp/camd.socket" },
13    /* neumo (dvb-api-1)*/  { "/dev/",          "demuxapi",     "demuxapi",         "/tmp/camd.socket" },
14    /* sh4      (stapi)*/   { "/dev/stapi/",        "stpti4_ioctl", "stpti4_ioctl",     "/tmp/camd.socket" },
15    /* coolstream*/     { "/dev/cnxt/",         "null",     "null",         "/tmp/camd.socket" }
16};
17
18int32_t selected_box=-1;
19int32_t selected_api=-1;
20int32_t disable_pmt_files=0;
21int32_t dir_fd=-1, pausecam=0;
22DEMUXTYPE demux[MAX_DEMUX];
23int32_t ca_fd[8];
24
25struct s_dvbapi_priority *dvbapi_priority=NULL;
26struct s_client *dvbapi_client=NULL;
27
28#ifdef WITH_STAPI
29int32_t stapi_on    = 0;
30pthread_mutex_t filter_lock;
31struct STDEVICE dev_list[PTINUM];
32#endif
33
34int32_t dvbapi_set_filter(int32_t demux_id, int32_t api, uint16_t pid, uchar *filt, uchar *mask, int32_t timeout, int32_t pidindex, int32_t count, int32_t type) {
35#ifdef AZBOX
36    openxcas_caid = demux[demux_id].ECMpids[pidindex].CAID;
37    openxcas_ecm_pid = pid;
38
39    return 1;
40#endif
41    int32_t ret=-1,n=-1,i;
42
43    for (i=0; i<MAX_FILTER && demux[demux_id].demux_fd[i].fd>0; i++);
44
45    if (i>=MAX_FILTER) {
46        cs_log("no free filter");
47        return -1;
48    }
49    n=i;
50
51    demux[demux_id].demux_fd[n].pidindex = pidindex;
52    demux[demux_id].demux_fd[n].pid      = pid;
53    demux[demux_id].demux_fd[n].type     = type;
54    demux[demux_id].demux_fd[n].count    = count;
55
56    switch(api) {
57        case DVBAPI_3:
58            demux[demux_id].demux_fd[n].fd = dvbapi_open_device(0, demux[demux_id].demux_index, demux[demux_id].adapter_index);
59            struct dmx_sct_filter_params sFP2;
60
61            memset(&sFP2,0,sizeof(sFP2));
62
63            sFP2.pid            = pid;
64            sFP2.timeout            = timeout;
65            sFP2.flags          = DMX_IMMEDIATE_START;
66            memcpy(sFP2.filter.filter,filt,16);
67            memcpy(sFP2.filter.mask,mask,16);
68            ret=ioctl(demux[demux_id].demux_fd[n].fd, DMX_SET_FILTER, &sFP2);
69
70            break;
71        case DVBAPI_1:
72            demux[demux_id].demux_fd[n].fd = dvbapi_open_device(0, demux[demux_id].demux_index, demux[demux_id].adapter_index);
73            struct dmxSctFilterParams sFP1;
74
75            memset(&sFP1,0,sizeof(sFP1));
76
77            sFP1.pid            = pid;
78            sFP1.timeout            = timeout;
79            sFP1.flags          = DMX_IMMEDIATE_START;
80            memcpy(sFP1.filter.filter,filt,16);
81            memcpy(sFP1.filter.mask,mask,16);
82            ret=ioctl(demux[demux_id].demux_fd[n].fd, DMX_SET_FILTER1, &sFP1);
83
84            break;
85#ifdef WITH_STAPI
86        case STAPI:
87            demux[demux_id].demux_fd[n].fd = 1;
88            ret=stapi_set_filter(demux_id, pid, filt, mask, n, demux[demux_id].pmt_file);
89
90            break;
91#endif
92#ifdef COOL
93        case COOLAPI:
94            demux[demux_id].demux_fd[n].fd = coolapi_open_device(demux[demux_id].demux_index, demux_id);
95            if(demux[demux_id].demux_fd[n].fd > 0)
96                ret = coolapi_set_filter(demux[demux_id].demux_fd[n].fd, n, pid, filt, mask);
97            break;
98#endif
99        default:
100            break;
101    }
102
103    if (ret < 0)
104        cs_debug_mask(D_DVBAPI, "could not start demux filter (errno=%d %s)", errno, strerror(errno));
105
106    return ret;
107}
108
109static int32_t dvbapi_detect_api() {
110#ifdef COOL
111    selected_api=COOLAPI;
112    selected_box = 5;
113    disable_pmt_files = 1;
114    cs_debug_mask(D_DVBAPI, "Detected coolstream Api");
115    return 1;
116#else
117    int32_t num_apis=2, i,devnum=-1, dmx_fd=0, ret=-1;
118    uchar filter[32];
119    char device_path[128], device_path2[128];
120
121    for (i=0;i<BOX_COUNT;i++) {
122        snprintf(device_path2, sizeof(device_path2), devices[i].demux_device, 0);
123        snprintf(device_path, sizeof(device_path), devices[i].path, 0);
124
125        strncat(device_path, device_path2, sizeof(device_path)-strlen(device_path)-1);
126
127        if ((dmx_fd = open(device_path, O_RDWR)) > 0) {
128            devnum=i;
129            break;
130        }
131    }
132
133    if (dmx_fd < 0) return 0;
134    close(dmx_fd);
135    selected_box = devnum;
136
137#ifdef WITH_STAPI
138    if (devnum==4) {
139        if (stapi_open()==FALSE) {
140            cs_log("stapi: setting up stapi failed.");
141            return 0;
142        }
143
144        selected_api=STAPI;
145        selected_box=4;
146        close(dmx_fd);
147        return 1;
148    }
149#endif
150    if (cfg.dvbapi_boxtype == BOXTYPE_NEUMO) {
151        selected_api=DVBAPI_1;
152        return 1;
153    }
154
155    memset(filter,0,32);
156
157    filter[0]=0x01;
158    filter[16]=0xFF;
159
160    for (i=0;i<num_apis;i++) {
161        ret = dvbapi_set_filter(0, i, 0x0001, filter, filter+16, 1, 0, 0, TYPE_ECM);
162
163        if (ret >= 0) {
164            selected_api=i;
165            dvbapi_stop_filter(0, TYPE_ECM);
166            break;
167        }
168    }
169
170    if (ret < 0) return 0;
171
172    cs_debug_mask(D_DVBAPI, "Detected %s Api: %d", device_path, selected_api);
173#endif
174
175    return 1;
176}
177
178static int32_t dvbapi_read_device(int32_t dmx_fd, unsigned char *buf, int32_t length) 
179{
180    int32_t len, rc;
181    struct pollfd pfd[1];
182
183    pfd[0].fd = dmx_fd;
184    pfd[0].events = (POLLIN | POLLPRI);
185
186    rc = poll(pfd, 1, 7000);
187    if (rc<1) {
188        cs_log("read on %d timed out", dmx_fd);
189        return -1;
190    }
191
192    len = read(dmx_fd, buf, length);
193
194    if (len==-1)
195        cs_log("read error on fd %d (errno=%d %s)", dmx_fd, errno, strerror(errno));
196
197    return len;
198}
199
200int32_t dvbapi_open_device(int32_t type, int32_t num, int32_t adapter) {
201    int32_t dmx_fd;
202    int32_t ca_offset=0;
203    char device_path[128], device_path2[128];
204
205    if (type==0) {
206        snprintf(device_path2, sizeof(device_path2), devices[selected_box].demux_device, num);
207        snprintf(device_path, sizeof(device_path), devices[selected_box].path, adapter);
208
209        strncat(device_path, device_path2, sizeof(device_path)-strlen(device_path)-1);
210    } else {
211        if (cfg.dvbapi_boxtype==BOXTYPE_DUCKBOX || cfg.dvbapi_boxtype==BOXTYPE_DBOX2 || cfg.dvbapi_boxtype==BOXTYPE_UFS910)
212            ca_offset=1;
213
214        if (cfg.dvbapi_boxtype==BOXTYPE_QBOXHD)
215            num=0;
216
217        snprintf(device_path2, sizeof(device_path2), devices[selected_box].ca_device, num+ca_offset);
218        snprintf(device_path, sizeof(device_path), devices[selected_box].path, adapter);
219
220        strncat(device_path, device_path2, sizeof(device_path)-strlen(device_path)-1);
221    }
222
223    if ((dmx_fd = open(device_path, O_RDWR)) < 0) {
224        cs_debug_mask(D_DVBAPI, "error opening device %s (errno=%d %s)", device_path, errno, strerror(errno));
225        return -1;
226    }
227
228    cs_debug_mask(D_DVBAPI, "DEVICE open (%s) fd %d", device_path, dmx_fd);
229    return dmx_fd;
230}
231
232int32_t dvbapi_stop_filter(int32_t demux_index, int32_t type) {
233    int32_t g;
234
235    for (g=0;g<MAX_FILTER;g++) {
236        if (demux[demux_index].demux_fd[g].type==type) {
237            dvbapi_stop_filternum(demux_index, g);
238        }
239    }
240
241    return 1;
242}
243
244int32_t dvbapi_stop_filternum(int32_t demux_index, int32_t num) 
245{
246    int32_t ret=-1;
247    if (demux[demux_index].demux_fd[num].fd>0) {
248#ifdef COOL
249        ret=coolapi_remove_filter(demux[demux_index].demux_fd[num].fd, num);
250        coolapi_close_device(demux[demux_index].demux_fd[num].fd);
251#else
252#ifdef WITH_STAPI
253        ret=stapi_remove_filter(demux_index, num, demux[demux_index].pmt_file);
254#else
255        ret=ioctl(demux[demux_index].demux_fd[num].fd,DMX_STOP);
256        close(demux[demux_index].demux_fd[num].fd);
257#endif
258#endif
259        demux[demux_index].demux_fd[num].fd=0;
260    }
261    return ret;
262}
263
264void dvbapi_start_filter(int32_t demux_id, int32_t pidindex, uint16_t pid, uchar table, uchar mask, int32_t timeout, int32_t type, int32_t count) 
265{
266    uchar filter[32];
267
268    cs_debug_mask(D_DVBAPI, "set filter pid: %04x", pid);
269
270    memset(filter,0,32);
271
272    filter[0]=table;
273    filter[16]=mask;
274
275    dvbapi_set_filter(demux_id, selected_api, pid, filter, filter+16, timeout, pidindex, count, type);
276}
277
278void dvbapi_sort_nanos(unsigned char *dest, const unsigned char *src, int32_t len)
279{
280    int32_t w=0, c=-1, j=0;
281    while(1) {
282        int32_t n=0x100;
283        for(j=0; j<len;) {
284            int32_t l=src[j+1]+2;
285                if(src[j]==c) {
286                    if(w+l>len) {
287                        cs_debug_mask(D_DVBAPI, "sortnanos: sanity check failed. Exceeding memory area. Probably corrupted nanos!");
288                        memset(dest,0,len); // zero out everything
289                        return;
290                    }
291                    memcpy(&dest[w],&src[j],l);
292                w+=l;
293            } else if(src[j]>c && src[j]<n)
294                n=src[j];
295            j+=l;
296        }
297        if(n==0x100) break;
298        c=n;
299    }
300}
301
302
303int32_t dvbapi_find_emmpid(int32_t demux_id, uint8_t type) {
304    int32_t k;
305    int32_t bck = -1;
306    for (k=0; k<demux[demux_id].EMMpidcount; k++) {
307        if (demux[demux_id].EMMpids[k].CAID == demux[demux_id].ECMpids[demux[demux_id].pidindex].CAID
308         && demux[demux_id].EMMpids[k].PROVID == demux[demux_id].ECMpids[demux[demux_id].pidindex].PROVID
309         && demux[demux_id].EMMpids[k].type & type)
310            return k;
311        else if (demux[demux_id].EMMpids[k].CAID == demux[demux_id].ECMpids[demux[demux_id].pidindex].CAID
312         && (!demux[demux_id].EMMpids[k].PROVID || !demux[demux_id].ECMpids[demux[demux_id].pidindex].PROVID)
313         && (demux[demux_id].EMMpids[k].type & type) && bck == -1)
314            bck = k;
315    }
316    return bck;
317}
318
319void dvbapi_start_emm_filter(int32_t demux_index) {
320    int32_t j;
321    const char *typtext[] = { "UNIQUE", "SHARED", "GLOBAL", "UNKNOWN" };
322
323    if (demux[demux_index].pidindex==-1) return;
324
325    if (demux[demux_index].EMMpidcount == 0 || !demux[demux_index].rdr || !hexserialset(demux[demux_index].rdr))
326        return;
327
328    if (demux[demux_index].emm_filter==1 && !memcmp(demux[demux_index].rdr->hexserial, demux[demux_index].hexserial, 8))
329        return;
330
331    if (memcmp(demux[demux_index].rdr->hexserial, demux[demux_index].hexserial, 8))
332        dvbapi_stop_filter(demux_index, TYPE_EMM);
333
334    uchar dmx_filter[342]; // 10 filter + 2 byte header
335    memset(dmx_filter, 0, sizeof(dmx_filter));
336    dmx_filter[0]=0xFF;
337    dmx_filter[1]=0;
338
339    struct s_cardsystem *cs = get_cardsystem_by_caid(demux[demux_index].ECMpids[demux[demux_index].pidindex].CAID);
340
341    if (cs)
342        cs->get_emm_filter(demux[demux_index].rdr, dmx_filter);
343    else {
344        cs_debug_mask(D_DVBAPI, "cardsystem for emm filter not found");
345        return; 
346    }
347
348    int32_t filter_count=dmx_filter[1];
349
350    cs_debug_mask(D_DVBAPI, "start %d emm filter for %s", filter_count, demux[demux_index].rdr->label);
351
352    for (j=1;j<=filter_count && j <= 10;j++) {
353        int32_t startpos=2+(34*(j-1));
354
355        if (dmx_filter[startpos+1] != 0x00)
356            continue;
357
358        uchar filter[32];
359        memcpy(filter, dmx_filter+startpos+2, 32);
360        int32_t emmtype=dmx_filter[startpos];
361        int32_t count=dmx_filter[startpos+1];
362        int32_t l=-1;
363
364        if ( (filter[0] && (((1<<(filter[0] % 0x80)) & demux[demux_index].rdr->b_nano) && !((1<<(filter[0] % 0x80)) & demux[demux_index].rdr->s_nano))) )
365            continue;
366
367        if ((demux[demux_index].rdr->blockemm & emmtype) && !((1<<(filter[0] % 0x80)) & demux[demux_index].rdr->s_nano))
368            continue;
369
370        l = dvbapi_find_emmpid(demux_index, emmtype);
371
372        if (l>-1) {
373            uint32_t typtext_idx = 0;
374            while (((emmtype >> typtext_idx) & 0x01) == 0 && typtext_idx < sizeof(typtext) / sizeof(const char *))
375                           ++typtext_idx;
376            cs_ddump_mask(D_DVBAPI, filter, 32, "starting emm filter type %s, pid: 0x%04X", typtext[typtext_idx], demux[demux_index].EMMpids[l].PID);
377            dvbapi_set_filter(demux_index, selected_api, demux[demux_index].EMMpids[l].PID, filter, filter+16, 0, demux[demux_index].pidindex, count, TYPE_EMM);
378        } else {
379            cs_debug_mask(D_DVBAPI, "no emm pid found");
380        }
381    }
382
383    memcpy(demux[demux_index].hexserial, demux[demux_index].rdr->hexserial, 8);
384    demux[demux_index].emm_filter=1;
385}
386
387void dvbapi_add_ecmpid(int32_t demux_id, uint16_t caid, uint16_t ecmpid, uint32_t provid) {
388    int32_t n,added=0;
389
390    if (demux[demux_id].ECMpidcount>=ECM_PIDS)
391        return;
392
393    int32_t stream = demux[demux_id].STREAMpidcount-1;
394    for (n=0;n<demux[demux_id].ECMpidcount;n++) {
395        if (stream>-1 && demux[demux_id].ECMpids[n].CAID == caid && demux[demux_id].ECMpids[n].ECM_PID == ecmpid) {
396            if (!demux[demux_id].ECMpids[n].streams) {
397                //we already got this caid/ecmpid as global, no need to add the single stream
398                cs_debug_mask(D_DVBAPI, "[SKIP STREAM %d] CAID: %04X\tECM_PID: %04X\tPROVID: %06X", n, caid, ecmpid, provid);
399                continue;
400            }
401            added=1;
402            demux[demux_id].ECMpids[n].streams |= (1 << stream);
403            cs_debug_mask(D_DVBAPI, "[ADD STREAM %d] CAID: %04X\tECM_PID: %04X\tPROVID: %06X", n, caid, ecmpid, provid);
404        }
405    }
406
407    if (added==1)
408        return;
409
410    demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].ECM_PID = ecmpid;
411    demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].CAID = caid;
412    demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].PROVID = provid;
413    if (stream>-1)
414        demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].streams |= (1 << stream);
415
416    cs_log("[ADD PID %d] CAID: %04X\tECM_PID: %04X\tPROVID: %06X", demux[demux_id].ECMpidcount, caid, ecmpid, provid);
417    demux[demux_id].ECMpidcount++;
418}
419
420void dvbapi_add_emmpid(int32_t demux_id, uint16_t caid, uint16_t emmpid, uint32_t provid, uint8_t type) {
421    demux[demux_id].EMMpids[demux[demux_id].EMMpidcount].PID = emmpid;
422    demux[demux_id].EMMpids[demux[demux_id].EMMpidcount].CAID = caid;
423    demux[demux_id].EMMpids[demux[demux_id].EMMpidcount].PROVID = provid;
424    demux[demux_id].EMMpids[demux[demux_id].EMMpidcount++].type = type;
425    cs_debug_mask(D_DVBAPI, "[ADD EMMPID] CAID: %04X\tEMM_PID: %04X\tPROVID: %06X - (type %d)", caid, emmpid, provid, type);
426}
427
428void dvbapi_parse_cat(int32_t demux_id, uchar *buf, int32_t len) {
429    uint16_t i, k;
430
431    cs_ddump_mask(D_DVBAPI, buf, len, "cat:");
432
433    for (i = 8; i < (((buf[1] & 0x0F) << 8) | buf[2]) - 1; i += buf[i + 1] + 2) {
434        if (buf[i] != 0x09) continue;
435
436        if (demux[demux_id].EMMpidcount >= ECM_PIDS) break;
437
438        uint16_t caid=(((buf[i + 2] & 0x1F) << 8) | buf[i + 3]);
439        uint16_t emm_pid=(((buf[i + 4] & 0x1F) << 8) | buf[i + 5]);
440        uint32_t emm_provider = 0;
441
442        switch (caid >> 8) {
443            case 0x01:
444                dvbapi_add_emmpid(demux_id, caid, emm_pid, 0, EMM_UNIQUE);
445                cs_debug_mask(D_DVBAPI, "[cat] CAID: %04x\tEMM_PID: %04x", caid, emm_pid);
446                for (k = i+7; k < i+buf[i+1]+2; k += 4) {
447                    emm_provider = (buf[k+2] << 8| buf[k+3]);
448                    emm_pid = (buf[k] & 0x0F) << 8 | buf[k+1];
449                    cs_debug_mask(D_DVBAPI, "[cat] CAID: %04X\tEMM_PID: %04X\tPROVID: %06X", caid, emm_pid, emm_provider);
450                    dvbapi_add_emmpid(demux_id, caid, emm_pid, emm_provider, EMM_SHARED);
451                }
452                break;
453            case 0x05:
454                for (k = i+6; k < i+buf[i+1]+2; k += buf[k+1]+2) {
455                    if (buf[k]==0x14) {
456                        emm_provider = buf[k+2] << 16 | (buf[k+3] << 8| (buf[k+4] & 0xF0));
457                        cs_debug_mask(D_DVBAPI, "[cat] CAID: %04x\tEMM_PID: %04x\tPROVID: %06X", caid, emm_pid, emm_provider);
458                        dvbapi_add_emmpid(demux_id, caid, emm_pid, emm_provider, EMM_UNIQUE|EMM_SHARED|EMM_GLOBAL);
459                    }
460                }
461                break;
462            case 0x18:
463                emm_provider = (buf[i+1] == 0x07) ? (buf[i+6] << 16 | (buf[i+7] << 8| (buf[i+8]))) : 0;
464                cs_debug_mask(D_DVBAPI, "[cat] CAID: %04x\tEMM_PID: %04x\tPROVID: %06X", caid, emm_pid, emm_provider);
465                dvbapi_add_emmpid(demux_id, caid, emm_pid, emm_provider, EMM_UNIQUE|EMM_SHARED|EMM_GLOBAL);
466                break;
467            default:
468                cs_debug_mask(D_DVBAPI, "[cat] CAID: %04x\tEMM_PID: %04x", caid, emm_pid);
469                dvbapi_add_emmpid(demux_id, caid, emm_pid, 0, EMM_UNIQUE|EMM_SHARED|EMM_GLOBAL);
470                break;
471        }
472    }
473    return;
474}
475
476int32_t dvbapi_get_descindex() {
477    int32_t i,j,idx=1,fail=1;
478    while (fail) {
479        fail=0;
480        for (i=0;i<MAX_DEMUX;i++) {
481            for (j=0;j<demux[i].ECMpidcount;j++) {
482                if (demux[i].ECMpids[j].index==idx) {
483                    idx++;
484                    fail=1;
485                    break;
486                }
487            }
488        }
489    }
490    return idx;
491}
492
493void dvbapi_set_pid(int32_t demux_id, int32_t num, int32_t index) {
494    int32_t i;
495
496    if (demux[demux_id].pidindex == -1) return;
497
498    switch(selected_api) {
499#ifdef WITH_STAPI
500        case STAPI:
501            stapi_set_pid(demux_id, num, index, demux[demux_id].STREAMpids[num], demux[demux_id].pmt_file);
502            break;
503#endif
504        default:
505            for (i=0;i<8;i++) {
506                if (demux[demux_id].ca_mask & (1 << i)) {
507                    if (ca_fd[i]<=0)
508                        ca_fd[i]=dvbapi_open_device(1, i, demux[demux_id].adapter_index);
509                    if (ca_fd[i]>0) {
510                        ca_pid_t ca_pid2;
511                        memset(&ca_pid2,0,sizeof(ca_pid2));
512                        ca_pid2.pid = demux[demux_id].STREAMpids[num];
513                        ca_pid2.index = index;
514                        if (ioctl(ca_fd[i], CA_SET_PID, &ca_pid2)==-1)
515                            cs_debug_mask(D_DVBAPI, "Error CA_SET_PID pid=0x%04x index=%d (errno=%d %s)", ca_pid2.pid, ca_pid2.index, errno, strerror(errno));
516                        else
517                            cs_debug_mask(D_DVBAPI, "CA_SET_PID pid=0x%04x index=%d", ca_pid2.pid, ca_pid2.index);
518                    }
519                }
520            }
521            break;
522    }
523    return;
524}
525
526void dvbapi_stop_descrambling(int32_t demux_id) {
527    int32_t i;
528
529    if (demux[demux_id].program_number==0) return;
530
531    cs_debug_mask(D_DVBAPI, "stop descrambling (demux_id: %d)", demux_id);
532
533    dvbapi_stop_filter(demux_id, TYPE_ECM);
534    dvbapi_stop_filter(demux_id, TYPE_EMM);
535
536    for (i=0;i<demux[demux_id].STREAMpidcount;i++) {
537        dvbapi_set_pid(demux_id, i, -1);
538    }
539
540    memset(&demux[demux_id], 0 ,sizeof(DEMUXTYPE));
541    demux[demux_id].pidindex=-1;
542
543    unlink(ECMINFO_FILE);
544
545    return;
546}
547
548void dvbapi_start_descrambling(int32_t demux_id) {
549    int32_t j,k;
550    int32_t streamcount=0;
551
552    demux[demux_id].pidindex = demux[demux_id].curindex;
553
554    for (j=0; j<demux[demux_id].ECMpidcount; j++) {
555        if (demux[demux_id].curindex == j || (demux[demux_id].ECMpids[demux[demux_id].curindex].CAID == demux[demux_id].ECMpids[j].CAID
556                && demux[demux_id].ECMpids[demux[demux_id].curindex].PROVID == demux[demux_id].ECMpids[j].PROVID
557                && demux[demux_id].ECMpids[j].PROVID > 0)) {
558
559            if (demux[demux_id].curindex != j) {
560                if (demux[demux_id].ECMpids[j].status < 0 || !demux[demux_id].ECMpids[demux[demux_id].curindex].streams)
561                    continue;
562
563                dvbapi_start_filter(demux_id, j, demux[demux_id].ECMpids[j].ECM_PID, 0x80, 0xF0, 3000, TYPE_ECM, 0);
564            }
565
566            if (!demux[demux_id].ECMpids[j].index)
567                demux[demux_id].ECMpids[j].index=dvbapi_get_descindex();
568
569            demux[demux_id].ECMpids[j].checked=1;
570            demux[demux_id].ECMpids[j].irdeto_curchid=demux[demux_id].ECMpids[demux[demux_id].curindex].irdeto_curchid;
571
572            for (k=0;k<demux[demux_id].STREAMpidcount;k++) {
573                if (!demux[demux_id].ECMpids[j].streams || (demux[demux_id].ECMpids[j].streams & (1 << k))) {
574                    dvbapi_set_pid(demux_id, k, demux[demux_id].ECMpids[j].index-1);
575                }
576            }
577
578            streamcount++;
579        }
580    }
581
582    cs_log("Start descrambling PID #%d (CAID: %04X) %d", demux[demux_id].curindex, demux[demux_id].ECMpids[demux[demux_id].curindex].CAID, streamcount);
583
584    if (cfg.dvbapi_au>0)
585        dvbapi_start_filter(demux_id, demux[demux_id].pidindex, 0x001, 0x01, 0xFF, 0, TYPE_EMM, 0); //CAT
586}
587
588#ifdef READER_VIACCESS
589extern int32_t viaccess_reassemble_emm(uchar *buffer, uint32_t *len);
590#endif
591#ifdef READER_CRYPTOWORKS
592extern int32_t cryptoworks_reassemble_emm(uchar *buffer, uint32_t *len);
593#endif
594
595void dvbapi_process_emm (int32_t demux_index, int32_t filter_num, unsigned char *buffer, uint32_t len) {
596    EMM_PACKET epg;
597
598    if (demux[demux_index].pidindex==-1) return;
599
600    uint32_t provider = demux[demux_index].ECMpids[demux[demux_index].pidindex].PROVID;
601    uint16_t caid = demux[demux_index].ECMpids[demux[demux_index].pidindex].CAID;
602
603    switch (caid >> 8) {
604        case 0x05:
605#ifdef READER_VIACCESS
606            if (!viaccess_reassemble_emm(buffer, &len))
607#endif
608                return;
609            break;
610            case 0x0d:
611#ifdef READER_CRYPTOWORKS
612            if (!cryptoworks_reassemble_emm(buffer, &len))
613#endif
614                return;
615            break;
616    }
617
618
619    cs_ddump_mask(D_DVBAPI, buffer, len, "emm from fd %d:", demux[demux_index].demux_fd[filter_num].fd);
620
621    struct s_dvbapi_priority *mapentry = dvbapi_check_prio_match(demux_index, demux[demux_index].pidindex, 'm');
622    if (mapentry) {
623        cs_debug_mask(D_DVBAPI, "Mapping EMM from %04X:%06X to %04X:%06X", caid, provider, mapentry->mapcaid, mapentry->mapprovid);
624        caid = mapentry->mapcaid;
625        provider = mapentry->mapprovid;
626    }
627
628    memset(&epg, 0, sizeof(epg));
629
630    i2b_buf(2, caid, epg.caid);
631    i2b_buf(4, provider, epg.provid);
632
633    epg.l=len;
634    memcpy(epg.emm, buffer, epg.l);
635
636    do_emm(dvbapi_client, &epg);
637}
638
639void dvbapi_read_priority() {
640    FILE *fp;
641    char token[128], str1[128];
642    char type;
643    int32_t i, ret, count=0;
644
645    const char *cs_prio="oscam.dvbapi";
646
647    snprintf(token, sizeof(token), "%s%s", cs_confdir, cs_prio);
648    fp=fopen(token, "r");
649
650    if (!fp) {
651        cs_log("can't open priority file %s", token);
652        return;
653    }
654
655    if (dvbapi_priority) {
656        cs_log("reread priority file %s", cs_prio);
657        struct s_dvbapi_priority *o, *p;
658        for (p = dvbapi_priority; p != NULL; p = o) {
659            o = p->next;
660            free(p);
661        }
662        dvbapi_priority = NULL;
663    }
664
665    while (fgets(token, sizeof(token), fp)) {
666        if (token[0]=='#' || token[0]=='/') continue;
667        if (strlen(token)>100) continue;
668
669        memset(str1, 0, 128);
670
671        for (i=0;i<(int)strlen(token);i++) {
672            if ((token[i]==':' || token[i]==' ') && token[i+1]==':') {
673                memmove(token+i+2, token+i+1, strlen(token)-i+1);
674                token[i+1]='0';
675            }
676            if (token[i]=='#' || token[i]=='/') {
677                token[i]='\0';
678                break;
679            }
680        }
681
682        type = 0;
683#ifdef WITH_STAPI
684        uint32_t disablefilter=0;
685        ret = sscanf(trim(token), "%c: %63s %63s %d", &type, str1, str1+64, &disablefilter);
686#else
687        ret = sscanf(trim(token), "%c: %63s %63s", &type, str1, str1+64);
688#endif
689        type = tolower(type);
690
691        if (ret<1 || (type != 'p' && type != 'i' && type != 'm' && type != 'd' && type != 's' && type != 'l'))
692            continue;
693
694        struct s_dvbapi_priority *entry;
695        if(!cs_malloc(&entry,sizeof(struct s_dvbapi_priority), -1)){
696            fclose(fp);
697            return;
698        }
699
700        entry->type=type;
701        entry->next=NULL;
702
703        count++;
704
705#ifdef WITH_STAPI
706        if (type=='s') {
707            strncpy(entry->devname, str1, 29);
708            strncpy(entry->pmtfile, str1+64, 29);
709
710            entry->disablefilter=disablefilter;
711
712            cs_debug_mask(D_DVBAPI, "stapi prio: ret=%d | %c: %s %s | disable %d", ret, type, entry->devname, entry->pmtfile, disablefilter);
713
714            if (!dvbapi_priority) {
715                dvbapi_priority=entry;
716            } else {
717                struct s_dvbapi_priority *p;
718                for (p = dvbapi_priority; p->next != NULL; p = p->next);
719                p->next = entry;
720            }
721            continue;
722        }
723#endif
724
725        char c_srvid[34];
726        c_srvid[0]='\0';
727        uint32_t caid=0, provid=0, srvid=0, ecmpid=0, chid=0;
728        sscanf(str1, "%4x:%6x:%33[^:s]:%4x:%4x", &caid, &provid, c_srvid, &ecmpid, &chid);
729
730        entry->caid=caid;
731        entry->provid=provid;
732        entry->ecmpid=ecmpid;
733        entry->chid=chid;
734
735        uint32_t delay=0, force=0, mapcaid=0, mapprovid=0;
736        switch (type) {
737            case 'd':
738                sscanf(str1+64, "%4d", &delay);
739                entry->delay=delay;
740                break;
741            case 'l':
742                entry->delay = dyn_word_atob(str1+64);
743                if (entry->delay == -1) entry->delay = 0;
744                break;
745            case 'p':
746                sscanf(str1+64, "%1d", &force);
747                entry->force=force;
748                break;
749            case 'm':
750                sscanf(str1+64, "%4x:%6x", &mapcaid, &mapprovid);
751                entry->mapcaid=mapcaid;
752                entry->mapprovid=mapprovid;
753                break;
754        }
755
756        if (c_srvid[0]=='=') {
757            struct s_srvid *this;
758
759            for (i=0;i<16;i++)
760            for (this = cfg.srvid[i]; this; this = this->next) {
761                if (strcmp(this->prov, c_srvid+1)==0) {
762                    struct s_dvbapi_priority *entry2;
763                    if(!cs_malloc(&entry2,sizeof(struct s_dvbapi_priority), -1)) continue;
764                    memcpy(entry2, entry, sizeof(struct s_dvbapi_priority));
765
766                    entry2->srvid=this->srvid;
767
768                    cs_debug_mask(D_DVBAPI, "prio srvid: ret=%d | %c: %04X %06X %04X %04X %04X -> map %04X %06X | prio %d | delay %d",
769                        ret, entry2->type, entry2->caid, entry2->provid, entry2->srvid, entry2->ecmpid, entry2->chid, entry2->mapcaid, entry2->mapprovid, entry2->force, entry2->delay);
770
771                    if (!dvbapi_priority) {
772                        dvbapi_priority=entry2;
773                    } else {
774                        struct s_dvbapi_priority *p;
775                        for (p = dvbapi_priority; p->next != NULL; p = p->next);
776                        p->next = entry2;
777                    }
778                }
779            }
780            free(entry);
781            continue;
782        } else {
783            sscanf(c_srvid, "%4x", &srvid);
784            entry->srvid=srvid;
785        }
786
787        cs_debug_mask(D_DVBAPI, "prio: ret=%d | %c: %04X %06X %04X %04X %04X -> map %04X %06X | prio %d | delay %d",
788            ret, entry->type, entry->caid, entry->provid, entry->srvid, entry->ecmpid, entry->chid, entry->mapcaid, entry->mapprovid, entry->force, entry->delay);
789
790        if (!dvbapi_priority) {
791            dvbapi_priority=entry;
792        } else {
793            struct s_dvbapi_priority *p;
794            for (p = dvbapi_priority; p->next != NULL; p = p->next);
795            p->next = entry;
796        }
797    }
798
799    cs_log("%d entries read from %s", count, cs_prio);
800
801    fclose(fp);
802    return;
803}
804
805struct s_dvbapi_priority *dvbapi_check_prio_match(int32_t demux_id, int32_t pidindex, char type) {
806    struct s_dvbapi_priority *p;
807    struct s_ecmpids *ecmpid = &demux[demux_id].ECMpids[pidindex];
808    int32_t i;
809
810    for (p=dvbapi_priority, i=0; p != NULL; p=p->next, i++) {
811        if (p->type != type) continue;
812
813        if (p->caid     && p->caid  != ecmpid->CAID)    continue;
814        if (p->provid && p->provid  != ecmpid->PROVID)  continue;
815        if (p->ecmpid   && p->ecmpid    != ecmpid->ECM_PID) continue;
816        if (p->srvid    && p->srvid     != demux[demux_id].program_number)          continue;
817
818        if (p->type == 'i' && p->chid) continue;
819
820        return p;
821    }
822    return NULL;
823
824}
825
826void dvbapi_resort_ecmpids(int32_t demux_index) {
827    int32_t n,i;
828
829    for (n=0; n<demux[demux_index].ECMpidcount; n++)
830        demux[demux_index].ECMpids[n].status=0;
831
832    demux[demux_index].max_status=0;
833    int32_t new_status=1;
834
835    if (dvbapi_priority) {
836        struct s_dvbapi_priority *p;
837        for (p=dvbapi_priority, i=0; p != NULL; p=p->next, i++) {
838            if (p->type != 'p' && p->type != 'i') continue;
839            for (n=0; n<demux[demux_index].ECMpidcount; n++) {
840                if (demux[demux_index].ECMpids[n].status != 0) continue;
841
842                if (p->caid     && p->caid  != demux[demux_index].ECMpids[n].CAID)  continue;
843                if (p->provid && p->provid  != demux[demux_index].ECMpids[n].PROVID)    continue;
844                if (p->ecmpid   && p->ecmpid    != demux[demux_index].ECMpids[n].ECM_PID)   continue;
845                if (p->srvid    && p->srvid != demux[demux_index].program_number)   continue;
846
847                if (p->type=='p') {
848                    demux[demux_index].ECMpids[n].status = new_status++;
849                    cs_debug_mask(D_DVBAPI, "[PRIORITIZE PID %d] %04X:%06X (position: %d)", n, demux[demux_index].ECMpids[n].CAID, demux[demux_index].ECMpids[n].PROVID, demux[demux_index].ECMpids[n].status);
850                } else if (p->type=='i') {
851                    if (p->chid) continue;
852                    demux[demux_index].ECMpids[n].status = -1;
853                    cs_debug_mask(D_DVBAPI, "[IGNORE PID %d] %04X:%06X (file)", n, demux[demux_index].ECMpids[n].CAID, demux[demux_index].ECMpids[n].PROVID);
854                }
855            }
856        }
857    }
858
859    for (n=0; n<demux[demux_index].ECMpidcount; n++) {
860        int32_t nr;
861        SIDTAB *sidtab;
862        ECM_REQUEST er;
863        er.caid  = demux[demux_index].ECMpids[n].CAID;
864        er.prid  = demux[demux_index].ECMpids[n].PROVID;
865        er.srvid = demux[demux_index].program_number;
866
867        for (nr=0, sidtab=cfg.sidtab; sidtab; sidtab=sidtab->next, nr++) {
868            if (sidtab->num_caid | sidtab->num_provid | sidtab->num_srvid) {
869                if ((cfg.dvbapi_sidtabno&((SIDTABBITS)1<<nr)) && (chk_srvid_match(&er, sidtab))) {
870                    demux[demux_index].ECMpids[n].status = -1; //ignore
871                    cs_debug_mask(D_DVBAPI, "[IGNORE PID %d] %04X:%06X (service %s) pos %d", n, demux[demux_index].ECMpids[n].CAID, demux[demux_index].ECMpids[n].PROVID, sidtab->label, nr);
872                }
873                if ((cfg.dvbapi_sidtabok&((SIDTABBITS)1<<nr)) && (chk_srvid_match(&er, sidtab))) {
874                    demux[demux_index].ECMpids[n].status = new_status++; //priority
875                    cs_debug_mask(D_DVBAPI, "[PRIORITIZE PID %d] %04X:%06X (service: %s position: %d)", n, demux[demux_index].ECMpids[n].CAID, demux[demux_index].ECMpids[n].PROVID, sidtab->label, demux[demux_index].ECMpids[n].status);
876                }
877            }
878        }
879    }
880
881    demux[demux_index].max_status = new_status;
882    return;
883}
884
885
886void dvbapi_parse_descriptor(int32_t demux_id, uint32_t info_length, unsigned char *buffer) {
887    //int32_t ca_pmt_cmd_id = buffer[i + 5];
888    uint32_t descriptor_length=0;
889    uint32_t j,u;
890
891    if (info_length<1)
892        return;
893
894    if (buffer[0]==0x01) {
895        buffer=buffer+1;
896        info_length--;
897    }
898
899    for (j = 0; j < info_length; j += descriptor_length + 2) {
900        descriptor_length = buffer[j+1];
901        int32_t descriptor_ca_system_id = (buffer[j+2] << 8) | buffer[j+3];
902        int32_t descriptor_ca_pid = ((buffer[j+4] & 0x1F) << 8) | buffer[j+5];
903        int32_t descriptor_ca_provider = 0;
904
905        if (demux[demux_id].ECMpidcount>=ECM_PIDS)
906            break;
907
908        cs_debug_mask(D_DVBAPI, "[pmt] type: %02x\tlength: %d", buffer[j], descriptor_length);
909
910        if (buffer[j] != 0x09) continue;
911
912        if (descriptor_ca_system_id >> 8 == 0x01) {
913            for (u=2; u<descriptor_length; u+=15) {
914                descriptor_ca_pid = ((buffer[j+2+u] & 0x1F) << 8) | buffer[j+2+u+1];
915                descriptor_ca_provider = (buffer[j+2+u+2] << 8) | buffer[j+2+u+3];
916                dvbapi_add_ecmpid(demux_id, descriptor_ca_system_id, descriptor_ca_pid, descriptor_ca_provider);
917            }
918        } else {
919            if (descriptor_ca_system_id >> 8 == 0x05 && descriptor_length == 0x0F && buffer[j+12] == 0x14)
920                descriptor_ca_provider = buffer[j+14] << 16 | (buffer[j+15] << 8| (buffer[j+16] & 0xF0));
921
922            if (descriptor_ca_system_id >> 8 == 0x18 && descriptor_length == 0x07)
923                descriptor_ca_provider = buffer[j+6] << 16 | (buffer[j+7] << 8| (buffer[j+8]));
924
925            if (descriptor_ca_system_id >> 8 == 0x4A && descriptor_length == 0x05)
926                descriptor_ca_provider = buffer[j+6];
927
928            dvbapi_add_ecmpid(demux_id, descriptor_ca_system_id, descriptor_ca_pid, descriptor_ca_provider);
929        }
930    }
931}
932
933void dvbapi_try_next_caid(int32_t demux_id) {
934    int32_t num=-1, n, j;
935
936    if (demux[demux_id].tries > 2) {
937        cs_log("can't decode channel");
938        dvbapi_stop_filter(demux_id, TYPE_ECM);
939        return;
940    }
941
942    //values for first run (status > 0)
943    int32_t start=1;
944    int32_t end=demux[demux_id].max_status;
945
946    while (num==-1) {
947        for (j = start; j <= end && num == -1; j++) {
948            for (n=0; n<demux[demux_id].ECMpidcount; n++) {
949                if (demux[demux_id].ECMpids[n].checked == 0 && demux[demux_id].ECMpids[n].status == j) {
950                    num=n;
951                    break;
952                }
953            }
954        }
955        if (start==0 || num>-1) break;
956        //values for second run (status==0)
957        start=0;
958        end=0;
959    }
960
961    if (num == -1) {
962        if (cfg.dvbapi_requestmode == 1)
963            return;
964
965        demux[demux_id].tries++;
966        cs_log("try pids again #%d", demux[demux_id].tries);
967        for (n=0; n<demux[demux_id].ECMpidcount; n++) {
968            demux[demux_id].ECMpids[n].checked=0;
969            demux[demux_id].ECMpids[n].irdeto_curchid=0;
970            demux[demux_id].ECMpids[n].irdeto_chids=0;
971            demux[demux_id].ECMpids[n].irdeto_cycle=0;
972            demux[demux_id].ECMpids[n].table=0;
973        }
974        dvbapi_try_next_caid(demux_id);
975        return;
976    }
977
978    if (cfg.dvbapi_requestmode != 1)
979        dvbapi_stop_filter(demux_id, TYPE_ECM);
980
981    cs_debug_mask(D_DVBAPI, "[TRY PID %d] CAID: %04X PROVID: %06X CA_PID: %04X", num, demux[demux_id].ECMpids[num].CAID, demux[demux_id].ECMpids[num].PROVID, demux[demux_id].ECMpids[num].ECM_PID);
982#ifdef AZBOX
983    openxcas_provid = demux[demux_id].ECMpids[num].PROVID;
984    openxcas_caid = demux[demux_id].ECMpids[num].CAID;
985    openxcas_ecm_pid = demux[demux_id].ECMpids[num].ECM_PID;
986#endif
987    demux[demux_id].curindex=num;
988
989    demux[demux_id].ECMpids[num].checked=1;
990
991    if (cfg.dvbapi_requestmode == 1) {
992        dvbapi_start_filter(demux_id, num, demux[demux_id].ECMpids[num].ECM_PID, 0x80, 0xF0, 3000, TYPE_ECM, 3); 
993        dvbapi_try_next_caid(demux_id);
994    } else {
995        dvbapi_start_filter(demux_id, num, demux[demux_id].ECMpids[num].ECM_PID, 0x80, 0xF0, 3000, TYPE_ECM, 0);
996    }
997}
998
999int32_t dvbapi_parse_capmt(unsigned char *buffer, uint32_t length, int32_t connfd, char *pmtfile) {
1000    uint32_t i;
1001    int32_t demux_id=-1;
1002    uint16_t ca_mask=0x01, demux_index=0x00, adapter_index=0x00;
1003
1004    int32_t ca_pmt_list_management = buffer[0];
1005    uint32_t program_number = (buffer[1] << 8) | buffer[2];
1006    uint32_t program_info_length = ((buffer[4] & 0x0F) << 8) | buffer[5];
1007
1008    if (buffer[17]==0x82 && buffer[18]==0x02) {
1009        //enigma2
1010        ca_mask = buffer[19];
1011        demux_index = buffer[20];
1012    }
1013
1014    cs_ddump_mask(D_DVBAPI, buffer, length, "capmt:");
1015
1016    for (i = 0; i < MAX_DEMUX; i++) {
1017        if (connfd>0 && demux[i].socket_fd == connfd) {
1018            //PMT Update
1019#ifdef COOL
1020            demux_id = i;
1021            unsigned char lastcw[16];
1022            int32_t n;
1023            for(n = 0; n < 2; n++) {
1024                memcpy(&lastcw[n*8], demux[demux_id].lastcw[n], 8);
1025                memset(demux[demux_id].lastcw[n], 0, 8);
1026            }
1027            demux[demux_id].ca_mask=ca_mask;
1028            dvbapi_write_cw(demux_id, lastcw, 0);//FIXME
1029            demux[demux_id].curindex = demux[demux_id].pidindex;
1030            demux[demux_id].STREAMpidcount=0;
1031            demux[demux_id].ECMpidcount=0;
1032            demux[demux_id].EMMpidcount=0;
1033            ca_pmt_list_management = 0x03;
1034#else
1035            if (ca_pmt_list_management == 0x05) {
1036                demux_id = i;
1037                demux[demux_id].curindex = demux[demux_id].pidindex;
1038                demux[demux_id].STREAMpidcount=0;
1039                demux[demux_id].ECMpidcount=0;
1040                demux[demux_id].EMMpidcount=0;
1041            }
1042            if (ca_pmt_list_management == 0x03 || ca_pmt_list_management == 0x01)
1043                dvbapi_stop_descrambling(i);
1044            if (ca_pmt_list_management == 0x02)
1045                demux_id=i;
1046#endif
1047        }
1048    }
1049
1050    if (demux_id==-1)
1051        for (demux_id=0; demux_id<MAX_DEMUX && demux[demux_id].program_number>0; demux_id++);
1052
1053    if (demux_id>=MAX_DEMUX) {
1054        cs_log("error no free id (MAX_DEMUX)");
1055        return -1;
1056    }
1057
1058    if (cfg.dvbapi_boxtype == BOXTYPE_IPBOX_PMT) {
1059        ca_mask = demux_id + 1;
1060        demux_index = demux_id;
1061    }
1062
1063    if (cfg.dvbapi_boxtype == BOXTYPE_QBOXHD && buffer[17]==0x82 && buffer[18]==0x03) {
1064        //ca_mask = buffer[19];     // with STONE 1.0.4 always 0x01
1065        demux_index = buffer[20];   // with STONE 1.0.4 always 0x00
1066        adapter_index = buffer[21]; // with STONE 1.0.4 adapter index can be 0,1,2
1067        ca_mask = (1 << adapter_index); // use adapter_index as ca_mask (used as index for ca_fd[] array)
1068    }
1069
1070    demux[demux_id].program_number=((buffer[1] << 8) | buffer[2]);
1071    demux[demux_id].demux_index=demux_index;
1072    demux[demux_id].adapter_index=adapter_index;
1073    demux[demux_id].ca_mask=ca_mask;
1074    demux[demux_id].socket_fd=connfd;
1075    demux[demux_id].rdr=NULL;
1076    demux[demux_id].pidindex=-1;
1077
1078    cs_debug_mask(D_DVBAPI, "id: %d\tdemux_index: %d\tca_mask: %02x\tprogram_info_length: %d\tca_pmt_list_management %02x", 
1079            demux_id, demux[demux_id].demux_index, demux[demux_id].ca_mask, program_info_length, ca_pmt_list_management);
1080
1081    if (pmtfile)
1082        cs_strncpy(demux[demux_id].pmt_file, pmtfile, sizeof(demux[demux_id].pmt_file));
1083
1084    if (program_info_length > 1 && program_info_length < length)
1085        dvbapi_parse_descriptor(demux_id, program_info_length-1, buffer+7);
1086
1087    uint32_t es_info_length=0;
1088    for (i = program_info_length + 6; i < length; i += es_info_length + 5) {
1089        int32_t stream_type = buffer[i];
1090        uint16_t elementary_pid = ((buffer[i + 1] & 0x1F) << 8) | buffer[i + 2];
1091        es_info_length = ((buffer[i + 3] & 0x0F) << 8) | buffer[i + 4];
1092
1093        cs_debug_mask(D_DVBAPI, "[pmt] stream_type: %02x\tpid: %04x\tlength: %d", stream_type, elementary_pid, es_info_length);
1094
1095        if (demux[demux_id].STREAMpidcount >= ECM_PIDS)
1096            break;
1097
1098        demux[demux_id].STREAMpids[demux[demux_id].STREAMpidcount++]=elementary_pid;
1099
1100        if (es_info_length != 0 && es_info_length < length) {
1101            dvbapi_parse_descriptor(demux_id, es_info_length, buffer+i+5);
1102        }
1103    }
1104    cs_debug_mask(D_DVBAPI, "Found %d ECMpids and %d STREAMpids in PMT", demux[demux_id].ECMpidcount, demux[demux_id].STREAMpidcount);
1105
1106    char channame[32];
1107    get_servicename(dvbapi_client, demux[demux_id].program_number, demux[demux_id].ECMpidcount>0 ? demux[demux_id].ECMpids[0].CAID : 0, channame);
1108    cs_log("new program number: %04X (%s)", program_number, channame);
1109
1110#ifdef AZBOX
1111    openxcas_sid = program_number;
1112#endif
1113
1114    if (ca_pmt_list_management == 0x05) {
1115        if (demux[demux_id].curindex==-1) {
1116            dvbapi_resort_ecmpids(demux_id);
1117            dvbapi_try_next_caid(demux_id);
1118        } else
1119            dvbapi_start_descrambling(demux_id);
1120    } else if (demux[demux_id].ECMpidcount>0 && ca_pmt_list_management != 0x01) {
1121        dvbapi_resort_ecmpids(demux_id);
1122        dvbapi_try_next_caid(demux_id);
1123    } else {
1124        // set channel srvid+caid
1125        dvbapi_client->last_srvid = demux[demux_id].program_number;
1126        dvbapi_client->last_caid = 0;
1127        // reset idle-Time
1128        dvbapi_client->last=time((time_t)0);
1129    }
1130
1131    return demux_id;
1132}
1133
1134
1135void dvbapi_handlesockmsg (unsigned char *buffer, uint32_t len, int32_t connfd) {
1136    uint32_t val=0, size=0, i, k;
1137
1138    //cs_dump(buffer, len, "handlesockmsg:");
1139    for (k = 0; k < len; k += 3 + size + val) {
1140        if (buffer[0+k] != 0x9F || buffer[1+k] != 0x80) {
1141            cs_log("unknown socket command: %02x", buffer[0+k]);
1142            return;
1143        }
1144
1145        if (k>0) {
1146            cs_log("Unsupported capmt. Please report");
1147            cs_dump(buffer, len, "capmt:");
1148        }
1149
1150        if (buffer[3+k] & 0x80) {
1151            val = 0;
1152            size = buffer[3+k] & 0x7F;
1153            for (i = 0; i < size; i++)
1154                val = (val << 8) | buffer[i + 1 + 3 + k];
1155            size++;
1156        } else  {
1157            val = buffer[3+k] & 0x7F;
1158            size = 1;
1159        }
1160        switch(buffer[2+k]) {
1161            case 0x32:
1162                dvbapi_parse_capmt(buffer + size + 3 + k, val, connfd, NULL);
1163                break;
1164            case 0x3f:
1165                //9F 80 3f 04 83 02 00 <demux index>
1166                cs_ddump_mask(D_DVBAPI, buffer, len, "capmt 3f:");
1167                // ipbox fix
1168                if (cfg.dvbapi_boxtype==BOXTYPE_IPBOX) {
1169                    int32_t demux_index=buffer[7+k];
1170                    for (i = 0; i < MAX_DEMUX; i++) {
1171                        if (demux[i].demux_index == demux_index) {
1172                            dvbapi_stop_descrambling(i);
1173                            break;
1174                        }
1175                    }
1176                    // check do we have any demux running on this fd
1177                    int16_t execlose = 1;
1178                    for (i = 0; i < MAX_DEMUX; i++) {
1179                        if (demux[i].socket_fd == connfd) {
1180                             execlose = 0;
1181                             break;
1182                        }
1183                    }
1184                    if (execlose) close(connfd);
1185                } else {
1186                    close(connfd);
1187                }
1188                break;
1189            default:
1190                cs_log("handlesockmsg() unknown command");
1191                cs_dump(buffer, len, "unknown command:");
1192                break;
1193        }
1194    }
1195}
1196
1197int32_t dvbapi_init_listenfd() {
1198    int32_t clilen,listenfd;
1199    struct sockaddr_un servaddr;
1200
1201    memset(&servaddr, 0, sizeof(struct sockaddr_un));
1202    servaddr.sun_family = AF_UNIX;
1203    cs_strncpy(servaddr.sun_path, devices[selected_box].cam_socket_path, sizeof(servaddr.sun_path));
1204    clilen = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path);
1205
1206    if ((unlink(devices[selected_box].cam_socket_path) < 0) && (errno != ENOENT))
1207        return 0;
1208    if ((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
1209        return 0;
1210    if (bind(listenfd, (struct sockaddr *) &servaddr, clilen) < 0)
1211        return 0;
1212    if (listen(listenfd, 5) < 0)
1213        return 0;
1214    // change the access right on the camd.socket
1215    // this will allow oscam to run as root if needed
1216    // and still allow non root client to connect to the socket
1217
1218    chmod(devices[selected_box].cam_socket_path, S_IRWXU | S_IRWXG | S_IRWXO);
1219
1220    return listenfd;
1221}
1222
1223void dvbapi_chk_caidtab(char *caidasc, char type) {
1224    char *ptr1, *ptr3, *saveptr1 = NULL;
1225    int32_t i;
1226
1227    for (i=0, ptr1=strtok_r(caidasc, ",", &saveptr1); (ptr1); ptr1=strtok_r(NULL, ",", &saveptr1)) {
1228        uint32_t caid, prov;
1229        if( (ptr3=strchr(trim(ptr1), ':')) )
1230            *ptr3++='\0';
1231        else
1232            ptr3="";
1233
1234        if (((caid=a2i(ptr1, 2))|(prov=a2i(ptr3, 3)))) {
1235            struct s_dvbapi_priority *entry;
1236            if(!cs_malloc(&entry,sizeof(struct s_dvbapi_priority), -1)) return;
1237            entry->caid=caid;
1238
1239            if (type=='d') {
1240                char tmp1[5];
1241                snprintf(tmp1, sizeof(tmp1), "%04X", (uint)prov);
1242                int32_t cw_delay = strtol(tmp1, '\0', 10);
1243                entry->delay=cw_delay;
1244            } else
1245                entry->provid=prov;
1246
1247            entry->type=type;
1248
1249            entry->next=NULL;
1250
1251            if (!dvbapi_priority) {
1252                dvbapi_priority=entry;
1253            } else {
1254                struct s_dvbapi_priority *p;
1255                for (p = dvbapi_priority; p->next != NULL; p = p->next);
1256                p->next = entry;
1257            }
1258
1259        }
1260    }
1261}
1262
1263pthread_mutex_t event_handler_lock;
1264
1265void event_handler(int32_t signal) {
1266    struct stat pmt_info;
1267    char dest[1024];
1268    DIR *dirp;
1269    struct dirent *dp;
1270    int32_t i, pmt_fd;
1271    uchar mbuf[1024];
1272
1273    if (dvbapi_client != cur_client()) return;
1274
1275    signal=signal; //avoid compiler warnings
1276
1277    if (pthread_mutex_trylock(&event_handler_lock) == EBUSY)
1278        return;
1279
1280    int32_t standby_fd = open(STANDBY_FILE, O_RDONLY);
1281    pausecam = (standby_fd > 0) ? 1 : 0;
1282    if (standby_fd) close(standby_fd);
1283
1284    if (cfg.dvbapi_boxtype==BOXTYPE_IPBOX || cfg.dvbapi_pmtmode == 1) {
1285        pthread_mutex_unlock(&event_handler_lock);
1286        return;
1287    }
1288
1289    for (i=0;i<MAX_DEMUX;i++) {
1290        if (demux[i].pmt_file[0] != 0) {
1291            snprintf(dest, sizeof(dest), "%s%s", TMPDIR, demux[i].pmt_file);
1292            pmt_fd = open(dest, O_RDONLY);
1293            if(pmt_fd>0) {
1294                if (fstat(pmt_fd, &pmt_info) != 0) {
1295                    close(pmt_fd);
1296                    continue;
1297                }
1298
1299                if (pmt_info.st_mtime != demux[i].pmt_time) {
1300                    cs_log("stoping demux for pmt file %s", dest);
1301                    dvbapi_stop_descrambling(i);
1302                }
1303
1304                close(pmt_fd);
1305                continue;
1306            } else {
1307                cs_log("stoping demux for pmt file %s", dest);
1308                dvbapi_stop_descrambling(i);
1309            }
1310        }
1311    }
1312
1313    if (disable_pmt_files) {
1314        pthread_mutex_unlock(&event_handler_lock);
1315        return;
1316    }
1317
1318    dirp = opendir(TMPDIR);
1319    if (!dirp) {
1320        cs_log("opendir failed (errno=%d %s)", errno, strerror(errno));
1321        pthread_mutex_unlock(&event_handler_lock);
1322        return;
1323    }
1324
1325    while ((dp = readdir(dirp))) {
1326        if (strlen(dp->d_name) < 7)
1327            continue;
1328        if (strncmp(dp->d_name, "pmt", 3)!=0 || strncmp(dp->d_name+strlen(dp->d_name)-4, ".tmp", 4)!=0)
1329            continue;
1330
1331        snprintf(dest, sizeof(dest), "%s%s", TMPDIR, dp->d_name);
1332        pmt_fd = open(dest, O_RDONLY);
1333        if (pmt_fd < 0)
1334            continue;
1335
1336        if (fstat(pmt_fd, &pmt_info) != 0)
1337            { close(pmt_fd); continue; }
1338
1339        int32_t found=0;
1340        for (i=0;i<MAX_DEMUX;i++) {
1341            if (strcmp(demux[i].pmt_file, dp->d_name)==0) {
1342                if (pmt_info.st_mtime == demux[i].pmt_time) {
1343                    found=1;
1344                    continue;
1345                }
1346                dvbapi_stop_descrambling(i);
1347            }
1348        }
1349        if (found)
1350            { close(pmt_fd); continue; }
1351
1352        cs_log("found pmt file %s", dest);
1353        cs_sleepms(100);
1354
1355        uint32_t len = read(pmt_fd,mbuf,sizeof(mbuf));
1356        close(pmt_fd);
1357
1358        if (len < 1) {
1359            cs_log("pmt file %s have invalid len!", dest);
1360            continue;
1361        }
1362
1363        int32_t pmt_id;
1364#ifdef QBOXHD
1365        uint32_t j1,j2;
1366        // QboxHD pmt.tmp is the full capmt written as a string of hex values
1367        // pmt.tmp must be longer than 3 bytes (6 hex chars) and even length
1368        if ((len<6) || ((len%2) != 0) || ((len/2)>sizeof(dest))) {
1369            cs_log("error parsing QboxHD pmt.tmp, incorrect length");
1370            continue;
1371        }
1372
1373        for(j2=0,j1=0;j2<len;j2+=2,j1++) {
1374            if (sscanf((char*)mbuf+j2, "%02X", dest+j1) != 1) {
1375                cs_log("error parsing QboxHD pmt.tmp, data not valid in position %d",j2);
1376                pthread_mutex_unlock(&event_handler_lock);
1377                return;
1378            }
1379        }
1380
1381        cs_ddump_mask(D_DVBAPI, dest,len/2,"QboxHD pmt.tmp:");
1382
1383        pmt_id = dvbapi_parse_capmt(dest+4, (len/2)-4, -1, dp->d_name);
1384#else
1385        if (len>sizeof(dest)) {
1386            cs_log("event_handler() dest buffer is to small for pmt data!");
1387            continue;
1388        }
1389        cs_ddump_mask(D_DVBAPI, mbuf,len,"pmt:");
1390
1391        memcpy(dest, "\x03\xFF\xFF\x00\x00\x13\x00", 7);
1392
1393        dest[1] = mbuf[3];
1394        dest[2] = mbuf[4];
1395        dest[5] = mbuf[11]+1;
1396
1397        memcpy(dest + 7, mbuf + 12, len - 12 - 4);
1398
1399        pmt_id = dvbapi_parse_capmt((uchar*)dest, 7 + len - 12 - 4, -1, dp->d_name);
1400#endif
1401        if (pmt_id>=0) {
1402            cs_strncpy(demux[pmt_id].pmt_file, dp->d_name, sizeof(demux[pmt_id].pmt_file));
1403            demux[pmt_id].pmt_time = pmt_info.st_mtime;
1404        }
1405
1406        if (cfg.dvbapi_pmtmode == 3) {
1407            disable_pmt_files=1;
1408            break;
1409        }
1410    }
1411    closedir(dirp);
1412    pthread_mutex_unlock(&event_handler_lock);
1413}
1414
1415void *dvbapi_event_thread(void *cli) {
1416    struct s_client * client = (struct s_client *) cli;
1417    pthread_setspecific(getclient, client);
1418
1419    while(1) {
1420        cs_sleepms(750);
1421        event_handler(0);
1422    }
1423   
1424    return NULL;
1425}
1426
1427void dvbapi_process_input(int32_t demux_id, int32_t filter_num, uchar *buffer, int32_t len) {
1428    struct s_ecmpids *curpid = &demux[demux_id].ECMpids[demux[demux_id].demux_fd[filter_num].pidindex];
1429    uint16_t chid = 0;
1430
1431#ifdef COOL
1432    cs_debug_mask(D_DVBAPI, "dvbapi_process_input: demux %d filter %d len %d buffer %x curtable %x curindex %d\n", demux_id, filter_num, len, buffer[0], curpid->table, demux[demux_id].curindex);
1433#endif
1434
1435    if (pausecam)
1436        return;
1437
1438    struct s_dvbapi_priority *p;
1439    for (p = dvbapi_priority; p != NULL; p = p->next) {
1440        if (p->type != 'l')     continue;
1441
1442        if (p->caid     && p->caid  != curpid->CAID)    continue;
1443        if (p->provid && p->provid  != curpid->PROVID)  continue;
1444        if (p->ecmpid   && p->ecmpid    != curpid->ECM_PID) continue;
1445        if (p->srvid    && p->srvid     != demux[demux_id].program_number)  continue;
1446
1447        if (p->delay == len && p->force < 6) {
1448            p->force++;
1449            return;
1450        }
1451        if (p->force >= 6)
1452            p->force=0;
1453    }
1454
1455    if (demux[demux_id].demux_fd[filter_num].type==TYPE_ECM) {
1456        if (len != (((buffer[1] & 0xf) << 8) | buffer[2]) + 3) //invaild CAT length
1457            return;
1458
1459        if (buffer[0] != 0x80 && buffer[0] != 0x81)
1460            return;
1461
1462        uint16_t caid = curpid->CAID;
1463        uint32_t provid = curpid->PROVID;
1464
1465        if ((caid >> 8) == 0x06) {
1466            //80 70 39 53 04 05 00 88
1467            if (buffer[5]>20) return;
1468            if (curpid->irdeto_numchids != buffer[5]+1) {
1469                cs_log("Found %d IRDETO ECM CHIDs", buffer[5]+1);
1470                curpid->irdeto_numchids = buffer[5]+1;
1471                curpid->irdeto_curchid = 0;
1472                curpid->irdeto_cycle = 0;
1473                curpid->irdeto_chids = 0;
1474                if (demux[demux_id].demux_fd[filter_num].count && (demux[demux_id].demux_fd[filter_num].count < (curpid->irdeto_numchids * 3)))
1475                    demux[demux_id].demux_fd[filter_num].count = curpid->irdeto_numchids * 3;
1476            }
1477
1478            if (curpid->irdeto_curchid+1 > curpid->irdeto_numchids) {
1479                curpid->irdeto_cycle++;
1480                curpid->irdeto_curchid = 0;
1481            }
1482
1483            if (buffer[4] != curpid->irdeto_curchid) {
1484                //wait for the correct chid
1485                return;
1486            }
1487
1488            chid = (buffer[6] << 8) | buffer[7];
1489            if (demux[demux_id].pidindex==-1) {
1490                int8_t i = 0, found = 0;
1491
1492                if (curpid->irdeto_chids & (1<<curpid->irdeto_curchid)) {
1493                    curpid->irdeto_curchid++;
1494                    return;
1495                }
1496
1497                for (p=dvbapi_priority, i=0; p != NULL && curpid->irdeto_cycle > -1; p = p->next) {
1498                    if (p->type != 'p' && p->type != 'i') continue;
1499
1500                    if (!p->chid) continue;
1501
1502                    if (p->caid     && p->caid  != curpid->CAID)    continue;
1503                    if (p->provid && p->provid  != curpid->PROVID)  continue;
1504                    if (p->ecmpid   && p->ecmpid    != curpid->ECM_PID) continue;
1505                    if (p->srvid    && p->srvid     != demux[demux_id].program_number)  continue;
1506
1507                    if (p->type == 'i' && p->chid == chid) {
1508                        curpid->irdeto_chids |= (1<<curpid->irdeto_curchid);
1509                        curpid->irdeto_curchid++;
1510                        return;
1511                    } else if (p->type == 'i')
1512                        continue;
1513   
1514                    if (i++ != curpid->irdeto_cycle)
1515                        continue;
1516
1517                    if (p->chid == chid) {
1518                        found=1;
1519                        break;
1520                    } else {
1521                        curpid->irdeto_curchid++;
1522                        return;
1523                    }
1524                }
1525
1526                if (!found && curpid->irdeto_cycle > -1) {
1527                    curpid->irdeto_cycle = -1;
1528                    curpid->irdeto_curchid = 0;
1529                    return;
1530                }
1531
1532                if (curpid->irdeto_curchid+1 > curpid->irdeto_numchids)
1533                    return;
1534            }
1535            curpid->irdeto_chids |= (1<<curpid->irdeto_curchid);
1536        }
1537
1538        if (curpid->table == buffer[0])
1539            return;
1540
1541        curpid->table = buffer[0];
1542#ifdef COOL
1543        int32_t num = demux[demux_id].curindex;//FIXME or pidindex ?
1544        dvbapi_stop_filternum(demux_id, filter_num);
1545        dvbapi_start_filter(demux_id, num, demux[demux_id].ECMpids[num].ECM_PID, buffer[0] ^ 1, 0xFF, 3000, TYPE_ECM, 0);
1546#endif
1547
1548        struct s_dvbapi_priority *mapentry = dvbapi_check_prio_match(demux_id, demux[demux_id].demux_fd[filter_num].pidindex, 'm');
1549
1550        if (!provid)
1551            provid = chk_provid(buffer, caid);
1552
1553        if (provid != curpid->PROVID)
1554            curpid->PROVID = provid;
1555
1556        if (cfg.dvbapi_au>0)
1557            dvbapi_start_emm_filter(demux_id);
1558
1559        ECM_REQUEST *er;
1560        if (!(er=get_ecmtask()))
1561            return;
1562
1563        er->srvid = demux[demux_id].program_number;
1564        er->caid  = caid;
1565        er->pid   = curpid->ECM_PID;
1566        er->prid  = provid;
1567
1568        if (mapentry) {
1569            cs_debug_mask(D_DVBAPI, "mapping ECM from %04X:%06X to %04X:%06X", er->caid, er->prid, mapentry->mapcaid, mapentry->mapprovid);
1570            er->caid = mapentry->mapcaid;
1571            er->prid = mapentry->mapprovid;
1572        }
1573
1574        er->l=len;
1575        memcpy(er->ecm, buffer, er->l);
1576
1577        cs_debug_mask(D_DVBAPI, "request cw for caid %04X provid %06X srvid %04X pid %04X chid %04X", er->caid, er->prid, er->srvid, er->pid, chid);
1578        get_cw(dvbapi_client, er);
1579    }
1580
1581    if (demux[demux_id].demux_fd[filter_num].type==TYPE_EMM) {
1582        if (buffer[0]==0x01) { //CAT
1583            cs_debug_mask(D_DVBAPI, "receiving cat");
1584            dvbapi_parse_cat(demux_id, buffer, len);
1585
1586            dvbapi_stop_filternum(demux_id, filter_num);
1587            return;
1588        }
1589        dvbapi_process_emm(demux_id, filter_num, buffer, len);
1590    }
1591
1592    if (demux[demux_id].demux_fd[filter_num].count==1) {
1593        cs_debug_mask(D_DVBAPI, "auto disable filter #%d", filter_num);
1594        dvbapi_stop_filternum(demux_id, filter_num);
1595    }
1596    if (demux[demux_id].demux_fd[filter_num].count>1) {
1597        demux[demux_id].demux_fd[filter_num].count--;
1598    }
1599}
1600
1601#pragma GCC diagnostic ignored "-Wempty-body"
1602static void * dvbapi_main_local(void *cli) {
1603    struct s_client * client = (struct s_client *) cli;
1604    client->thread=pthread_self();
1605    pthread_setspecific(getclient, cli);
1606    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
1607    pthread_cleanup_push(cleanup_thread, (void *) client);
1608
1609    dvbapi_client=cli;
1610
1611    int32_t maxpfdsize=(MAX_DEMUX*MAX_FILTER)+MAX_DEMUX+2;
1612    struct pollfd pfd2[maxpfdsize];
1613    int32_t i,rc,pfdcount,g,connfd,clilen,j;
1614    int32_t ids[maxpfdsize], fdn[maxpfdsize], type[maxpfdsize];
1615    struct sockaddr_un servaddr;
1616    ssize_t len=0;
1617    uchar mbuf[1024];
1618
1619    struct s_auth *account;
1620    int32_t ok=0;
1621    for (ok=0, account=cfg.account; (account) && (!ok); account=account->next)
1622        if( (ok=!strcmp(cfg.dvbapi_usr, account->usr)) )
1623            break;
1624    cs_auth_client(client, ok ? account : (struct s_auth *)(-1), "dvbapi");
1625
1626    memset(demux, 0, sizeof(struct demux_s) * MAX_DEMUX);
1627    memset(ca_fd, 0, sizeof(ca_fd));
1628
1629    dvbapi_read_priority();
1630    dvbapi_detect_api();
1631
1632    if (selected_box == -1 || selected_api==-1) {
1633        cs_log("could not detect api version");
1634        return NULL;
1635    }
1636
1637    if (cfg.dvbapi_pmtmode == 1)
1638        disable_pmt_files=1;
1639
1640    int32_t listenfd = -1;
1641    if (cfg.dvbapi_boxtype != BOXTYPE_IPBOX_PMT && cfg.dvbapi_pmtmode != 2 && cfg.dvbapi_pmtmode != 5) {
1642        listenfd = dvbapi_init_listenfd();
1643        if (listenfd < 1) {
1644            cs_log("could not init camd.socket.");
1645            return NULL;
1646        }
1647    }
1648
1649    pthread_mutex_init(&event_handler_lock, NULL);
1650
1651    if (cfg.dvbapi_pmtmode != 4 && cfg.dvbapi_pmtmode != 5) {
1652        struct sigaction signal_action;
1653        signal_action.sa_handler = event_handler;
1654        sigemptyset(&signal_action.sa_mask);
1655        signal_action.sa_flags = SA_RESTART;
1656        sigaction(SIGRTMIN + 1, &signal_action, NULL);
1657
1658        dir_fd = open(TMPDIR, O_RDONLY);
1659        if (dir_fd >= 0) {
1660            fcntl(dir_fd, F_SETSIG, SIGRTMIN + 1);
1661            fcntl(dir_fd, F_NOTIFY, DN_MODIFY | DN_CREATE | DN_DELETE | DN_MULTISHOT);
1662            event_handler(SIGRTMIN + 1);
1663        }
1664    } else {
1665        pthread_t event_thread;
1666        pthread_create(&event_thread, NULL, dvbapi_event_thread, (void*) dvbapi_client);
1667        pthread_detach(event_thread);
1668    }
1669
1670    pfd2[0].fd = client->fd_m2c_c;
1671    pfd2[0].events = (POLLIN | POLLPRI);
1672    type[0]=0;
1673
1674    pfd2[1].fd = listenfd;
1675    pfd2[1].events = (POLLIN | POLLPRI);
1676    type[1]=1;
1677
1678    while (1) {
1679        pfdcount = (listenfd > -1) ? 2 : 1;
1680
1681        chk_pending(500);
1682
1683        for (i=0;i<MAX_DEMUX;i++) {
1684            for (g=0;g<MAX_FILTER;g++) {
1685                if (demux[i].demux_fd[g].fd>0 && selected_api != STAPI && selected_api != COOLAPI) {
1686                    pfd2[pfdcount].fd = demux[i].demux_fd[g].fd;
1687                    pfd2[pfdcount].events = (POLLIN | POLLPRI);
1688                    ids[pfdcount]=i;
1689                    fdn[pfdcount]=g;
1690                    type[pfdcount++]=0;
1691                }
1692            }
1693
1694            if (demux[i].socket_fd>0) {
1695                rc=0;
1696                if (cfg.dvbapi_boxtype==BOXTYPE_IPBOX) {
1697                    for (j = 0; j < pfdcount; j++) {
1698                        if (pfd2[j].fd == demux[i].socket_fd) {
1699                            rc=1;
1700                            break;
1701                        }
1702                    }
1703                    if (rc==1) continue;
1704                }
1705
1706                pfd2[pfdcount].fd=demux[i].socket_fd;
1707                pfd2[pfdcount].events = (POLLIN | POLLPRI | POLLHUP);
1708                ids[pfdcount]=i;
1709                type[pfdcount++]=1;
1710            }
1711        }
1712
1713        rc = poll(pfd2, pfdcount, 500);
1714        if (rc<1) continue;
1715
1716        for (i = 0; i < pfdcount; i++) {
1717            if (pfd2[i].revents > 3)
1718                cs_debug_mask(D_DVBAPI, "event %d on fd %d", pfd2[i].revents, pfd2[i].fd);
1719
1720            if (pfd2[i].revents & (POLLHUP | POLLNVAL)) {
1721                if (type[i]==1) {
1722                    for (j=0;j<MAX_DEMUX;j++) {
1723                        if (demux[j].socket_fd==pfd2[i].fd) {
1724                            dvbapi_stop_descrambling(j);
1725                        }
1726                    }
1727                    close(pfd2[i].fd);
1728                    continue;
1729                }
1730                if (pfd2[i].fd==client->fd_m2c_c) {
1731                    cs_exit(0);
1732                }
1733            }
1734            if (pfd2[i].revents & (POLLIN | POLLPRI)) {
1735                if (pfd2[i].fd==client->fd_m2c_c) {
1736                    process_client_pipe(client, NULL, 0);
1737                    continue;
1738                }
1739
1740                if (type[i]==1) {
1741                    if (pfd2[i].fd==listenfd) {
1742                        connfd = accept(listenfd, (struct sockaddr *)&servaddr, (socklen_t *)&clilen);
1743                        cs_debug_mask(D_DVBAPI, "new socket connection fd: %d", connfd);
1744
1745                        disable_pmt_files=1;
1746
1747                        if (connfd <= 0) {
1748                            cs_log("accept() returns error on fd event %d (errno=%d %s)", pfd2[i].revents, errno, strerror(errno));
1749                            continue;
1750                        }
1751                    } else {
1752                        cs_debug_mask(D_DVBAPI, "PMT Update on socket %d.", pfd2[i].fd);
1753                        connfd = pfd2[i].fd;
1754                    }
1755
1756                    len = read(connfd, mbuf, sizeof(mbuf));
1757
1758                    if (len < 3) {
1759                        cs_debug_mask(D_DVBAPI, "camd.socket: too int16_t message received");
1760                        continue;
1761                    }
1762
1763                    dvbapi_handlesockmsg(mbuf, len, connfd);
1764                } else { // type==0
1765                    int32_t demux_index=ids[i];
1766                    int32_t n=fdn[i];
1767
1768                    if ((len=dvbapi_read_device(pfd2[i].fd, mbuf, sizeof(mbuf))) <= 0) {
1769                        if (demux[demux_index].pidindex==-1) {
1770                            dvbapi_try_next_caid(demux_index);
1771                        }
1772                        continue;
1773                    }
1774
1775                    if (pfd2[i].fd==(int)demux[demux_index].demux_fd[n].fd) {
1776                        dvbapi_process_input(demux_index,n,mbuf,len);
1777                    }
1778                }
1779            }
1780        }
1781    }
1782    pthread_cleanup_pop(1);
1783    return NULL;
1784}
1785
1786static void dvbapi_write_cw(int32_t demux_id, uchar *cw, int32_t index) {
1787    int32_t n;
1788    unsigned char nullcw[8];
1789    memset(nullcw, 0, 8);
1790    ca_descr_t ca_descr;
1791    memset(&ca_descr,0,sizeof(ca_descr));
1792
1793    for (n=0;n<2;n++) {
1794        if (memcmp(cw+(n*8),demux[demux_id].lastcw[n],8)!=0 && memcmp(cw+(n*8),nullcw,8)!=0) {
1795            ca_descr.index = index;
1796            ca_descr.parity = n;
1797            memcpy(demux[demux_id].lastcw[n],cw+(n*8),8);
1798            memcpy(ca_descr.cw,cw+(n*8),8);
1799#ifdef COOL
1800            cs_debug_mask(D_DVBAPI, "write cw%d index: %d (ca_mask %d)", n, ca_descr.index, demux[demux_id].ca_mask);
1801            coolapi_write_cw(demux[demux_id].ca_mask, demux[demux_id].STREAMpids, demux[demux_id].STREAMpidcount, &ca_descr);
1802#else
1803            int32_t i;
1804            for (i=0;i<8;i++) {
1805                if (demux[demux_id].ca_mask & (1 << i)) {
1806                    cs_debug_mask(D_DVBAPI, "write cw%d index: %d (ca%d)", n, ca_descr.index, i);
1807                    if (ca_fd[i]<=0) {
1808                        ca_fd[i]=dvbapi_open_device(1, i, demux[demux_id].adapter_index);
1809                        if (ca_fd[i]<=0)
1810                            return;
1811                    }
1812
1813                    if (ioctl(ca_fd[i], CA_SET_DESCR, &ca_descr) < 0)
1814                        cs_debug_mask(D_DVBAPI, "Error CA_SET_DESCR");
1815                }
1816            }
1817#endif
1818        }
1819    }
1820}
1821
1822static void dvbapi_send_dcw(struct s_client *client, ECM_REQUEST *er) 
1823{
1824#ifdef AZBOX
1825    azbox_send_dcw(client, er);
1826    return;
1827#endif
1828    int32_t i,j;
1829
1830    for (i=0;i<MAX_DEMUX;i++) {
1831        if (demux[i].program_number==er->srvid) {
1832            demux[i].rdr=er->selected_reader;
1833
1834            for (j=0; j<demux[i].ECMpidcount; j++)
1835                if (demux[i].ECMpids[j].CAID == er->caid && demux[i].ECMpids[j].ECM_PID == er->pid)
1836                        break;
1837            if (j==demux[i].ECMpidcount) continue;
1838
1839            if (er->rc < E_NOTFOUND && demux[i].pidindex==-1 && er->caid!=0) {
1840                if (cfg.dvbapi_requestmode == 1) {
1841                    int32_t o=0;
1842                    for (o=0; o<MAX_FILTER; o++) {
1843                        if (demux[i].demux_fd[o].fd > 0) {
1844                            if (demux[i].demux_fd[o].pid == er->pid)
1845                                demux[i].demux_fd[o].count=0;
1846                            else
1847                                dvbapi_stop_filternum(i, o);
1848                        }
1849                    }
1850                    demux[i].curindex=j;   
1851                }
1852                dvbapi_start_descrambling(i);
1853            }
1854
1855            if (er->rc >= E_NOTFOUND) {
1856                if ((er->caid >> 8) == 0x06 && demux[i].ECMpids[j].irdeto_chids < (((0xFFFF<<(demux[i].ECMpids[j].irdeto_numchids)) ^ 0xFFFF) & 0xFFFF)) {
1857                    demux[i].ECMpids[j].irdeto_curchid++;
1858                    demux[i].ECMpids[j].table=0;
1859                    cs_log("trying irdeto chid index: %d", demux[i].ECMpids[j].irdeto_curchid);
1860                    return;
1861                }
1862                demux[i].ECMpids[j].irdeto_chids = 0;
1863                demux[i].ECMpids[j].irdeto_curchid = 0;
1864                demux[i].ECMpids[j].irdeto_cycle = 0;
1865
1866                if (demux[i].pidindex==-1) {
1867                    if (cfg.dvbapi_requestmode == 1)
1868                        return;
1869
1870                    struct s_dvbapi_priority *forceentry=dvbapi_check_prio_match(i, demux[i].curindex, 'p');
1871                    if (forceentry) {
1872                        if (forceentry->force>0)
1873                            dvbapi_start_descrambling(i);
1874                        else
1875                            dvbapi_try_next_caid(i);
1876                    } else {
1877                        dvbapi_try_next_caid(i);
1878                    }
1879                } else {
1880                    demux[i].tries++;
1881                    struct s_dvbapi_priority *forceentry=dvbapi_check_prio_match(i, demux[i].curindex, 'p');
1882                    if (!forceentry && demux[i].tries>3) {
1883                        demux[i].tries = 0;
1884                        demux[i].curindex = 0;
1885                        demux[i].pidindex = -1;
1886                        dvbapi_try_next_caid(i);
1887                    }
1888                }
1889                return;
1890            }
1891
1892            struct s_dvbapi_priority *delayentry=dvbapi_check_prio_match(i, demux[i].pidindex, 'd');
1893            if (delayentry) {
1894                if (delayentry->delay<1000) {
1895                    cs_debug_mask(D_DVBAPI, "wait %d ms", delayentry->delay);
1896                    cs_sleepms(delayentry->delay);
1897                }
1898            }
1899
1900            switch (selected_api) {
1901#ifdef WITH_STAPI
1902                case STAPI:
1903                    stapi_write_cw(i, er->cw, demux[i].STREAMpids, demux[i].STREAMpidcount, demux[i].pmt_file);
1904                    break;
1905#endif
1906                default:
1907                    if (cfg.dvbapi_boxtype == BOXTYPE_NEUMO) {
1908                        int32_t idx=0;
1909                        sscanf(demux[i].pmt_file, "pmt%d.tmp", &idx);
1910                        dvbapi_write_cw(i, er->cw, idx);
1911                        break;
1912                    }
1913                    dvbapi_write_cw(i, er->cw, demux[i].ECMpids[j].index-1);
1914                    break;
1915            }
1916
1917            // reset idle-Time
1918            client->last=time((time_t)0);
1919
1920            FILE *ecmtxt;
1921            ecmtxt = fopen(ECMINFO_FILE, "w"); 
1922            if(ecmtxt != NULL && er->selected_reader) { 
1923                fprintf(ecmtxt, "caid: 0x%04X\npid: 0x%04X\nprov: 0x%06X\n", er->caid, er->pid, (uint) er->prid);
1924                fprintf(ecmtxt, "reader: %s\n", er->selected_reader->label);
1925                if (er->selected_reader->typ & R_IS_CASCADING)
1926                    fprintf(ecmtxt, "from: %s\n", er->selected_reader->device);
1927                else
1928                    fprintf(ecmtxt, "from: local\n");
1929                fprintf(ecmtxt, "protocol: %s\n", er->selected_reader->ph.desc);
1930#ifdef MODULE_CCCAM
1931                fprintf(ecmtxt, "hops: %d\n", er->selected_reader->cc_currenthops);
1932#endif
1933                fprintf(ecmtxt, "ecm time: %.3f\n", (float) client->cwlastresptime/1000);
1934                fprintf(ecmtxt, "cw0: %s\n", cs_hexdump(1,demux[i].lastcw[0],8));
1935                fprintf(ecmtxt, "cw1: %s\n", cs_hexdump(1,demux[i].lastcw[1],8));
1936                fclose(ecmtxt);
1937                ecmtxt = NULL;
1938            }
1939        }
1940    }
1941}
1942
1943static void * dvbapi_handler(int32_t ctyp) {
1944    //cs_log("dvbapi loaded fd=%d", idx);
1945    if (cfg.dvbapi_enabled == 1) {
1946        struct s_client * cl = create_client(0);
1947        cl->typ='c';
1948        cl->ctyp=ctyp;
1949#ifdef AZBOX
1950        pthread_create(&cl->thread, NULL, azbox_main, (void*) cl);
1951#else
1952        pthread_create(&cl->thread, NULL, dvbapi_main_local, (void*) cl);
1953#endif
1954        pthread_detach(cl->thread);
1955    }
1956
1957    return NULL;
1958}
1959
1960
1961#ifdef WITH_STAPI
1962static void stapi_off() {
1963    int32_t i;
1964
1965    pthread_mutex_lock(&filter_lock);
1966
1967    cs_log("stapi shutdown");
1968
1969    disable_pmt_files=1;
1970    stapi_on=0;
1971
1972    for (i=0;i<MAX_DEMUX;i++)
1973        dvbapi_stop_descrambling(i);
1974
1975    for (i=0;i<PTINUM;i++) {
1976        if (dev_list[i].SessionHandle>0) {
1977            if (dev_list[i].SignalHandle > 0) {
1978                oscam_stapi_SignalAbort(dev_list[i].SignalHandle);
1979            }
1980            pthread_cancel(dev_list[i].thread);
1981        }
1982    }
1983
1984    pthread_mutex_unlock(&filter_lock);
1985    sleep(2);
1986    return;
1987}
1988
1989static int32_t stapi_open() {
1990    uint32_t ErrorCode;
1991
1992    DIR *dirp;
1993    struct dirent *dp;
1994    struct stat buf;
1995    int32_t i;
1996    char pfad[80];
1997    stapi_on=1;
1998    int32_t stapi_priority=0;
1999
2000    dirp = opendir(PROCDIR);
2001    if (!dirp) {
2002        cs_log("opendir failed (errno=%d %s)", errno, strerror(errno));
2003        return FALSE;
2004    }
2005
2006    memset(dev_list, 0, sizeof(struct STDEVICE)*PTINUM);
2007
2008    if (dvbapi_priority) {
2009        struct s_dvbapi_priority *p;
2010        for (p=dvbapi_priority; p != NULL; p=p->next) {
2011            if (p->type=='s') {
2012                stapi_priority=1;
2013                break;
2014            }
2015        }
2016    }
2017
2018    if (!stapi_priority) {
2019        cs_log("WARNING: no PTI devices defined, stapi disabled"); 
2020        return FALSE;
2021    }
2022
2023    oscam_stapi_CheckVersion();
2024
2025    i=0;
2026    while ((dp = readdir(dirp))) {
2027        snprintf(pfad, sizeof(pfad), "%s%s", PROCDIR, dp->d_name);
2028        if (stat(pfad,&buf) != 0)
2029            continue;
2030
2031        if (!(buf.st_mode & S_IFDIR && strncmp(dp->d_name, ".", 1)!=0)) 
2032            continue;
2033
2034        int32_t do_open=0;
2035        struct s_dvbapi_priority *p;
2036
2037        for (p=dvbapi_priority; p != NULL; p=p->next) {
2038            if (p->type!='s') continue;
2039            if(strcmp(dp->d_name, p->devname)==0) {
2040                do_open=1;
2041                break;
2042            }
2043        } 
2044
2045        if (!do_open) {
2046            cs_log("PTI: %s skipped", dp->d_name);
2047            continue;
2048        }
2049
2050        ErrorCode= oscam_stapi_Open(dp->d_name, &dev_list[i].SessionHandle);
2051        if (ErrorCode != 0) {
2052            cs_log("STPTI_Open ErrorCode: %d", ErrorCode);
2053            continue;
2054        }
2055
2056        //debug
2057        //oscam_stapi_Capability(dp->d_name);
2058
2059        cs_strncpy(dev_list[i].name,dp->d_name, sizeof(dev_list[i].name));
2060        cs_log("PTI: %s open %d", dp->d_name, i);
2061
2062        ErrorCode = oscam_stapi_SignalAllocate(dev_list[i].SessionHandle, &dev_list[i].SignalHandle);
2063        if (ErrorCode != 0)
2064            cs_log("SignalAllocate: ErrorCode: %d SignalHandle: %x", ErrorCode, dev_list[i].SignalHandle);
2065
2066        i++;
2067        if (i>=PTINUM) break;   
2068    }
2069    closedir(dirp);
2070
2071    if (i==0) return FALSE;
2072
2073    pthread_mutex_init(&filter_lock, NULL);
2074
2075    for (i=0;i<PTINUM;i++) {
2076        if (dev_list[i].SessionHandle==0)
2077            continue;
2078
2079        struct read_thread_param *para;
2080        if(!cs_malloc(&para,sizeof(struct read_thread_param), -1)) return FALSE;
2081        para->id=i;
2082        para->cli=cur_client();
2083
2084        pthread_create(&dev_list[i].thread, NULL, stapi_read_thread, (void *)para);
2085        pthread_detach(dev_list[i].thread);
2086    }
2087
2088    atexit(stapi_off);
2089
2090    cs_log("liboscam_stapi v.%s initialized", oscam_stapi_LibVersion());
2091    return TRUE;
2092}
2093
2094static int32_t stapi_set_filter(int32_t demux_id, uint16_t pid, uchar *filter, uchar *mask, int32_t num, char *pmtfile) {
2095    int32_t i;
2096    uint16_t pids[1] = { pid };
2097    struct s_dvbapi_priority *p;
2098
2099    if (!pmtfile) return FALSE;
2100
2101    cs_debug_mask(D_DVBAPI, "pmt file %s demux_id %d", pmtfile, demux_id);
2102
2103    for (p=dvbapi_priority; p != NULL; p=p->next) {
2104        if (p->type!='s') continue;
2105        if (strcmp(pmtfile, p->pmtfile)!=0)
2106            continue;
2107
2108        for (i=0;i<PTINUM;i++) {
2109            if(strcmp(dev_list[i].name, p->devname)==0 && p->disablefilter==0) {
2110                cs_debug_mask(D_DVBAPI, "set stapi filter on %s for pid %04X", dev_list[i].name, pids[0]);
2111                stapi_do_set_filter(demux_id, &dev_list[i].demux_fd[demux_id][num], pids, 1, filter, mask, i);
2112            }
2113        }
2114    }
2115
2116    cs_debug_mask(D_DVBAPI, "filter #%d set (pid %04X)", num, pid);
2117    return TRUE;
2118}
2119
2120static int32_t stapi_remove_filter(int32_t demux_id, int32_t num, char *pmtfile) {
2121    int32_t i;
2122    struct s_dvbapi_priority *p;
2123
2124    if (!pmtfile) return FALSE;
2125   
2126    for (p=dvbapi_priority; p != NULL; p=p->next) {
2127        if (p->type!='s') continue;
2128        if (strcmp(pmtfile, p->pmtfile)!=0) 
2129            continue;
2130
2131        for (i=0;i<PTINUM;i++) {
2132            if(strcmp(dev_list[i].name, p->devname)==0 && p->disablefilter==0) {
2133                stapi_do_remove_filter(demux_id, &dev_list[i].demux_fd[demux_id][num], i);
2134            }
2135        }
2136    }
2137
2138    cs_debug_mask(D_DVBAPI, "filter #%d removed", num);
2139    return TRUE;
2140}
2141
2142static uint32_t check_slot(int32_t dev_id, uint32_t checkslot, FILTERTYPE *skipfilter) {
2143    int32_t d,f,l;
2144    for (d=0; d<MAX_DEMUX; d++) {
2145        for (f=0; f<MAX_FILTER; f++) {
2146            if (skipfilter && &dev_list[dev_id].demux_fd[d][f] == skipfilter)
2147                continue;
2148            for (l=0; l<dev_list[dev_id].demux_fd[d][f].NumSlots; l++) {
2149                if (checkslot == dev_list[dev_id].demux_fd[d][f].SlotHandle[l]) {
2150                    return dev_list[dev_id].demux_fd[d][f].BufferHandle[l];
2151                }
2152            }
2153        }
2154    }
2155    return 0;
2156}
2157
2158
2159static int32_t stapi_do_set_filter(int32_t demux_id, FILTERTYPE *filter, uint16_t *pids, int32_t pidcount, uchar *filt, uchar *mask, int32_t dev_id) {
2160    uint32_t FilterAssociateError=0;
2161    int32_t k, ErrorCode=0, ret=0;
2162
2163    filter->fd          = 0;
2164    filter->BufferHandle[0]     = 0;
2165    filter->SlotHandle[0]   = 0;
2166
2167    if (dev_list[dev_id].SessionHandle==0) return FALSE;
2168
2169    uint32_t FilterAllocateError = oscam_stapi_FilterAllocate(dev_list[dev_id].SessionHandle, &filter->fd);
2170
2171    if (FilterAllocateError != 0) {
2172        cs_log("FilterAllocate problem");
2173        filter->fd=0;
2174        return FALSE;
2175    }
2176
2177    for (k=0;k<pidcount;k++) {
2178        uint16_t pid = pids[k];
2179
2180        uint32_t QuerySlot = oscam_stapi_PidQuery(dev_list[dev_id].name, pid);
2181        int32_t SlotInit=1;
2182
2183        if (QuerySlot != 0) {
2184            uint32_t checkslot = check_slot(dev_id, QuerySlot, NULL);
2185            if (checkslot>0) {
2186                filter->SlotHandle[k] = QuerySlot;
2187                filter->BufferHandle[k] = checkslot;
2188                SlotInit=0;
2189            } else {
2190                cs_log("overtake: clear pid: %d", oscam_stapi_SlotClearPid(QuerySlot));
2191                SlotInit=1;
2192            } 
2193        }
2194
2195        if (SlotInit==1) {
2196            ret = oscam_stapi_SlotInit(dev_list[dev_id].SessionHandle, dev_list[dev_id].SignalHandle, &filter->BufferHandle[k], &filter->SlotHandle[k], pid);
2197        }
2198
2199        FilterAssociateError        = oscam_stapi_FilterAssociate(filter->fd, filter->SlotHandle[k]);
2200        filter->NumSlots++;
2201    }
2202
2203    uint32_t FilterSetError         = oscam_stapi_FilterSet(filter->fd, filt, mask);
2204
2205    if (ret || FilterAllocateError || FilterAssociateError || FilterSetError) {
2206        cs_log("set_filter: dev: %d FAl: %d FAs: %d FS: %d",
2207            dev_id, FilterAllocateError, FilterAssociateError, FilterSetError);
2208        stapi_do_remove_filter(demux_id, filter, dev_id);
2209        return FALSE;
2210    } else {
2211        return TRUE;
2212    }
2213}
2214
2215static int32_t stapi_do_remove_filter(int32_t demux_id, FILTERTYPE *filter, int32_t dev_id) {
2216    if (filter->fd==0) return FALSE;
2217
2218    uint32_t BufferDeallocateError=0, SlotDeallocateError=0;
2219
2220    if (dev_list[dev_id].SessionHandle==0) return FALSE;
2221
2222    int32_t k;
2223    for (k=0;k<filter->NumSlots;k++) {
2224        uint32_t checkslot = check_slot(dev_id, filter->SlotHandle[k], filter);
2225
2226        if (checkslot==0) {
2227            BufferDeallocateError   = oscam_stapi_BufferDeallocate(filter->BufferHandle[k]);
2228            SlotDeallocateError     = oscam_stapi_SlotDeallocate(filter->SlotHandle[k]);
2229        }
2230    }
2231    uint32_t FilterDeallocateError      = oscam_stapi_FilterDeallocate(filter->fd);
2232
2233    memset(filter, 0, sizeof(FILTERTYPE));
2234
2235    if (BufferDeallocateError||SlotDeallocateError||FilterDeallocateError) {
2236        cs_log("remove_filter: dev: %d BD: %d SD: %d FDe: %d",
2237            dev_id, BufferDeallocateError, SlotDeallocateError, FilterDeallocateError);
2238        return FALSE;
2239    } else {
2240        return TRUE;
2241    }
2242}
2243
2244static void stapi_cleanup_thread(void *dev){
2245    int32_t dev_index=(int)dev;
2246   
2247    int32_t ErrorCode;
2248    ErrorCode = oscam_stapi_Close(dev_list[dev_index].SessionHandle);
2249
2250    printf("liboscam_stapi: PTI %s closed - %d\n", dev_list[dev_index].name, ErrorCode);
2251    dev_list[dev_index].SessionHandle=0;
2252}
2253
2254static void *stapi_read_thread(void *sparam) {
2255    int32_t     dev_index, ErrorCode, i, j, CRCValid;
2256    uint32_t    QueryBufferHandle = 0, DataSize = 0;
2257    uchar buf[BUFFLEN];
2258
2259    struct read_thread_param *para=sparam;
2260    dev_index=para->id;
2261
2262    pthread_setspecific(getclient, para->cli);
2263    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
2264    pthread_cleanup_push(stapi_cleanup_thread, (void*) dev_index);
2265
2266    int32_t error_count=0;
2267
2268    while (1) {
2269        QueryBufferHandle = 0;
2270        ErrorCode = oscam_stapi_SignalWaitBuffer(dev_list[dev_index].SignalHandle, &QueryBufferHandle, 1000);
2271
2272        switch (ErrorCode) {
2273            case 0: // NO_ERROR:
2274                break;
2275            case 852042: // ERROR_SIGNAL_ABORTED
2276                cs_log("Caught abort signal");
2277                pthread_exit(NULL);
2278                break;
2279            case 11: // ERROR_TIMEOUT:
2280                //cs_log("timeout %d", dev_index);
2281                //TODO: if pidindex == -1 try next
2282                continue;
2283                break;     
2284            default:
2285                if (QueryBufferHandle != 0) { 
2286                    cs_log("SignalWaitBuffer error: %d", ErrorCode);
2287                    oscam_stapi_BufferFlush(QueryBufferHandle); 
2288                    continue; 
2289                }
2290                cs_log("SignalWaitBuffer: index %d ErrorCode: %d - QueryBuffer: %x", dev_index, ErrorCode, QueryBufferHandle);
2291                error_count++;
2292                if (error_count>10) {
2293                    cs_log("Too many errors in reader thread %d, quitting.", dev_index);
2294                    pthread_exit(NULL);
2295                }
2296                continue;   
2297                break;
2298        }
2299
2300        uint32_t NumFilterMatches = 0;
2301        int32_t demux_id=0, filter_num=0;
2302        DataSize = 0;
2303        int32_t found=0, k;
2304
2305        uint32_t MatchedFilterList[10];
2306        ErrorCode = oscam_stapi_BufferReadSection(QueryBufferHandle, MatchedFilterList, 10, &NumFilterMatches, &CRCValid, buf, BUFFLEN, &DataSize); 
2307
2308        if (ErrorCode != 0) {
2309            cs_log("BufferRead: index: %d ErrorCode: %d", dev_index, ErrorCode);
2310            cs_sleepms(1000);
2311            continue;
2312        }
2313
2314        if (DataSize<=0)
2315            continue;
2316
2317        pthread_mutex_lock(&filter_lock); // don't use cs_lock() here; multiple threads using same s_client struct
2318        for(k=0;k<NumFilterMatches;k++) {
2319            for (i=0;i<MAX_DEMUX;i++) {
2320                for (j=0;j<MAX_FILTER;j++) {
2321                    if (dev_list[dev_index].demux_fd[i][j].fd == MatchedFilterList[k]) {
2322                        demux_id=i;
2323                        filter_num=j;
2324
2325                        dvbapi_process_input(demux_id, filter_num, buf, DataSize);
2326                    }
2327                }   
2328            }
2329        }
2330        pthread_mutex_unlock(&filter_lock);
2331    }
2332    pthread_cleanup_pop(0);
2333}
2334
2335#define ASSOCIATE 1
2336#define DISASSOCIATE 0
2337
2338#define DE_START 0
2339#define DE_STOP 1
2340
2341static void stapi_DescramblerAssociate(int32_t demux_id, uint16_t pid, int32_t mode, int32_t n) {
2342    uint32_t Slot=0;
2343    int32_t ErrorCode=0;
2344
2345    if (dev_list[n].SessionHandle==0) return;
2346
2347    Slot = oscam_stapi_PidQuery(dev_list[n].name, pid);
2348    if (!Slot) return;
2349
2350    if (demux[demux_id].DescramblerHandle[n]==0) return;
2351
2352    if (mode == ASSOCIATE) {
2353        int32_t k;
2354        for (k=0;k<SLOTNUM;k++) {
2355            if (demux[demux_id].slot_assc[n][k]==Slot) {
2356                return;
2357            }
2358        }
2359
2360        ErrorCode = oscam_stapi_DescramblerAssociate(demux[demux_id].DescramblerHandle[n], Slot);
2361        cs_debug_mask(D_DVBAPI, "set pid %04x on %s", pid, dev_list[n].name);
2362
2363        if (ErrorCode != 0)
2364            cs_log("DescramblerAssociate %d",ErrorCode);
2365
2366        for (k=0;k<SLOTNUM;k++) {
2367            if (demux[demux_id].slot_assc[n][k]==0) {
2368                demux[demux_id].slot_assc[n][k]=Slot;
2369                break;
2370            }
2371        }
2372    } else {
2373        ErrorCode = oscam_stapi_DescramblerDisassociate(demux[demux_id].DescramblerHandle[n], Slot);
2374        if (ErrorCode != 0)
2375            cs_debug_mask(D_DVBAPI, "DescramblerDisassociate %d", ErrorCode);
2376
2377        cs_debug_mask(D_DVBAPI, "unset pid %04x on %s", pid, dev_list[n].name);
2378
2379        int32_t k;
2380        for (k=0;k<SLOTNUM;k++) {
2381            if (demux[demux_id].slot_assc[n][k]==Slot) {
2382                demux[demux_id].slot_assc[n][k]=0;
2383                return;
2384            }
2385        }
2386    }
2387
2388    return;
2389}
2390
2391static void stapi_startdescrambler(int32_t demux_id, int32_t dev_index, int32_t mode) {
2392    int32_t ErrorCode;
2393
2394    if (mode == DE_START && demux[demux_id].DescramblerHandle[dev_index] == 0) {
2395        uint32_t DescramblerHandle=0;
2396        ErrorCode = oscam_stapi_DescramblerAllocate(dev_list[dev_index].SessionHandle, &DescramblerHandle);
2397        if (ErrorCode != 0) {
2398            cs_log("DescramblerAllocate: ErrorCode: %d SignalHandle: %x", ErrorCode, dev_list[dev_index].SignalHandle);
2399            return;
2400        }
2401
2402        demux[demux_id].DescramblerHandle[dev_index]=DescramblerHandle;
2403    }
2404
2405    if (mode == DE_STOP && demux[demux_id].DescramblerHandle[dev_index] > 0) {
2406        ErrorCode = oscam_stapi_DescramblerDeallocate(demux[demux_id].DescramblerHandle[dev_index]);
2407
2408        if (ErrorCode != 0)
2409            cs_log("DescramblerDeallocate: ErrorCode: %d", ErrorCode);
2410               
2411        demux[demux_id].DescramblerHandle[dev_index]=0;
2412    }
2413
2414    return;
2415}
2416
2417static int32_t stapi_set_pid(int32_t demux_id, int32_t num, int32_t index, uint16_t pid, char *pmtfile) {
2418    int32_t n;
2419
2420    if (index==-1) {
2421        for (n=0;n<PTINUM;n++) {
2422            if (demux[demux_id].DescramblerHandle[n]==0) continue;
2423
2424            cs_debug_mask(D_DVBAPI, "stop descrambling PTI: %s", dev_list[n].name);
2425            stapi_startdescrambler(demux_id, n, DE_STOP);
2426            memset(demux[demux_id].slot_assc[n], 0, sizeof(demux[demux_id].slot_assc[n]));
2427        }
2428    }
2429   
2430    return TRUE;
2431}
2432
2433static int32_t stapi_write_cw(int32_t demux_id, uchar *cw, uint16_t *STREAMpids, int32_t STREAMpidcount, char *pmtfile) {
2434    int32_t ErrorCode, l, n, k;
2435    unsigned char nullcw[8];
2436    memset(nullcw, 0, 8);
2437    char *text[] = { "even", "odd" };
2438
2439    if (!pmtfile) return FALSE;
2440
2441    for (n=0;n<PTINUM;n++) {
2442        if (dev_list[n].SessionHandle==0) continue;
2443        if (demux[demux_id].DescramblerHandle[n]==0) {
2444            struct s_dvbapi_priority *p;
2445
2446            for (p=dvbapi_priority; p != NULL; p=p->next) {
2447                if (p->type!='s') continue;
2448                if (strcmp(pmtfile, p->pmtfile)!=0)
2449                    continue;
2450
2451                if(strcmp(dev_list[n].name, p->devname)==0) {
2452                    cs_debug_mask(D_DVBAPI, "start descrambling PTI: %s", dev_list[n].name);
2453                    stapi_startdescrambler(demux_id, n, DE_START);
2454                }
2455            }
2456        }
2457
2458        if (demux[demux_id].DescramblerHandle[n] == 0) continue;
2459        for (k=0;k<STREAMpidcount;k++) {
2460            stapi_DescramblerAssociate(demux_id, STREAMpids[k], ASSOCIATE, n);
2461        }
2462    }
2463
2464    for (l=0;l<2;l++) {
2465        if (memcmp(cw+(l*8), demux[demux_id].lastcw[l], 8)!=0 && memcmp(cw+(l*8),nullcw,8)!=0) {
2466            for (n=0;n<PTINUM;n++) {
2467                if (demux[demux_id].DescramblerHandle[n]==0) continue;
2468
2469                ErrorCode = oscam_stapi_DescramblerSet(demux[demux_id].DescramblerHandle[n], l, cw+(l*8));
2470                if (ErrorCode != 0)
2471                    cs_log("DescramblerSet: ErrorCode: %d", ErrorCode);
2472
2473                memcpy(demux[demux_id].lastcw[l],cw+(l*8),8);
2474                cs_debug_mask(D_DVBAPI, "write cw %s index: %d %s", text[l], demux_id, dev_list[n].name);
2475            }
2476        }
2477    }
2478
2479    return TRUE;
2480}
2481#endif //WITH_STAPI
2482
2483
2484#ifdef AZBOX
2485void azbox_openxcas_ecm_callback(int32_t stream_id, uint32_t seq, int32_t cipher_index, uint32_t caid, unsigned char *ecm_data, int32_t l, uint16_t pid) {
2486    cs_debug_mask(D_DVBAPI, "openxcas: ecm callback received");
2487
2488  openxcas_stream_id = stream_id;
2489  //openxcas_seq = seq;
2490    //openxcas_caid = caid;
2491    openxcas_ecm_pid = pid;
2492    openxcas_busy = 1;
2493
2494    ECM_REQUEST *er;
2495    if (!(er=get_ecmtask()))
2496        return;
2497
2498    er->srvid = openxcas_sid;
2499    er->caid  = openxcas_caid;
2500    er->pid   = openxcas_ecm_pid;
2501    er->prid  = openxcas_provid;
2502
2503    er->l=l;
2504    memcpy(er->ecm, ecm_data, er->l);
2505
2506    cs_debug_mask(D_DVBAPI, "request cw for caid %04X provid %06X srvid %04X pid %04X", er->caid, er->prid, er->srvid, er->pid);
2507    get_cw(dvbapi_client, er);
2508
2509    //openxcas_stop_filter(openxcas_stream_id, OPENXCAS_FILTER_ECM);
2510    //openxcas_remove_filter(openxcas_stream_id, OPENXCAS_FILTER_ECM);
2511
2512    openxcas_cipher_idx = cipher_index;
2513
2514    struct timeb tp;
2515    cs_ftime(&tp);
2516    tp.time+=500;
2517
2518    struct pollfd pfd;
2519    pfd.fd = dvbapi_client->fd_m2c_c;
2520    pfd.events = POLLIN | POLLPRI;
2521/*
2522    while(1) {
2523        chk_pending(tp);
2524
2525        if (poll(&pfd, 1, 10) < 0)
2526            continue;
2527
2528        if (pfd.revents & (POLLHUP | POLLNVAL)) {
2529            cs_debug_mask(D_DVBAPI, "openxcas: ecm/cw error");
2530            break;
2531        }
2532
2533        if (pfd.revents & (POLLIN | POLLPRI)) {
2534            chk_dcw(cur_client()->fd_m2c_c);
2535            break;
2536        }
2537    }*/
2538}
2539
2540
2541void azbox_openxcas_ex_callback(int32_t stream_id, uint32_t seq, int32_t idx, uint32_t pid, unsigned char *ecm_data, int32_t l) {
2542    cs_debug_mask(D_DVBAPI, "openxcas: ex callback received");
2543
2544    openxcas_stream_id = stream_id;
2545    openxcas_ecm_pid = pid;
2546    openxcas_cipher_idx = idx; // is this really cipher_idx?
2547
2548    ECM_REQUEST *er;
2549    if (!(er=get_ecmtask()))
2550        return;
2551
2552    er->srvid = openxcas_sid;
2553    er->caid  = openxcas_caid;
2554    er->pid   = openxcas_ecm_pid;
2555    er->prid  = openxcas_provid;
2556
2557    er->l=l;
2558    memcpy(er->ecm, ecm_data, er->l);
2559
2560    cs_debug_mask(D_DVBAPI, "request cw for caid %04X provid %06X srvid %04X pid %04X", er->caid, er->prid, er->srvid, er->pid);
2561    get_cw(dvbapi_client, er);
2562
2563    if (openxcas_stop_filter_ex(stream_id, seq, openxcas_filter_idx) < 0)
2564        cs_log("openxcas: unable to stop ex filter");
2565    else
2566        cs_debug_mask(D_DVBAPI, "openxcas: ex filter stopped");
2567
2568    chk_pending(500);
2569    process_client_pipe(dvbapi_client, NULL, 0);
2570
2571    unsigned char mask[12];
2572    unsigned char comp[12];
2573    memset(&mask, 0x00, sizeof(mask));
2574    memset(&comp, 0x00, sizeof(comp));
2575
2576    mask[0] = 0xff;
2577    comp[0] = ecm_data[0] ^ 1;
2578
2579    if ((openxcas_filter_idx = openxcas_start_filter_ex(stream_id, seq, openxcas_ecm_pid, mask, comp, (void *)azbox_openxcas_ex_callback)) < 0)
2580        cs_log("openxcas: unable to start ex filter");
2581    else
2582        cs_debug_mask(D_DVBAPI, "openxcas: ex filter started, pid = %x", openxcas_ecm_pid);
2583}
2584
2585#pragma GCC diagnostic ignored "-Wempty-body"
2586void * azbox_main(void *cli) {
2587    struct s_client * client = (struct s_client *) cli;
2588    client->thread=pthread_self();
2589    pthread_setspecific(getclient, cli);
2590    dvbapi_client=cli;
2591    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
2592    pthread_cleanup_push(cleanup_thread, (void *) client);
2593
2594    struct s_auth *account;
2595    int32_t ok=0;
2596    for (ok=0, account=cfg.account; (account) && (!ok); account=account->next)
2597        if( (ok=!strcmp(cfg.dvbapi_usr, account->usr)) )
2598            break;
2599    cs_auth_client(client, ok ? account : (struct s_auth *)(-1), "dvbapi");
2600
2601    dvbapi_read_priority();
2602
2603    openxcas_msg_t msg;
2604    int32_t ret;
2605    while ((ret = openxcas_get_message(&msg, 0)) >= 0) {
2606        cs_sleepms(10);
2607
2608        chk_pending(500);
2609
2610        if (ret) {
2611            openxcas_stream_id = msg.stream_id;
2612            openxcas_seq = msg.sequence;
2613
2614            switch(msg.cmd) {
2615                case OPENXCAS_SELECT_CHANNEL:
2616                    cs_debug_mask(D_DVBAPI, "openxcas: msg: OPENXCAS_SELECT_CHANNEL");
2617
2618                    // parse channel info
2619                    struct stOpenXCASChannel chan;
2620                    memcpy(&chan, msg.buf, msg.buf_len);
2621
2622                    cs_log("openxcas: channel change: sid = %x, vpid = %x. apid = %x", chan.service_id, chan.v_pid, chan.a_pid);
2623
2624                    openxcas_video_pid = chan.v_pid;
2625                    openxcas_audio_pid = chan.a_pid;
2626                    openxcas_data_pid = chan.d_pid;
2627                    break;
2628                case OPENXCAS_START_PMT_ECM:
2629                    cs_debug_mask(D_DVBAPI, "openxcas: msg: OPENXCAS_START_PMT_ECM");
2630
2631                     // parse pmt
2632                    uchar *dest;
2633                    if(!cs_malloc(&dest, msg.buf_len + 7 - 12 - 4, -1)) break;
2634
2635                    memcpy(dest, "\x00\xFF\xFF\x00\x00\x13\x00", 7);
2636
2637                    dest[1] = msg.buf[3];
2638                    dest[2] = msg.buf[4];
2639                    dest[5] = msg.buf[11]+1;
2640
2641                    memcpy(dest + 7, msg.buf + 12, msg.buf_len - 12 - 4);
2642
2643                    dvbapi_parse_capmt(dest, 7 + msg.buf_len - 12 - 4, -1, NULL);
2644                    free(dest);
2645
2646                    unsigned char mask[12];
2647                    unsigned char comp[12];
2648                    memset(&mask, 0x00, sizeof(mask));
2649                    memset(&comp, 0x00, sizeof(comp));
2650
2651                    mask[0] = 0xfe;
2652                    comp[0] = 0x80;
2653
2654                    if ((ret = openxcas_add_filter(msg.stream_id, OPENXCAS_FILTER_ECM, 0, 0xffff, openxcas_ecm_pid, mask, comp, (void *)azbox_openxcas_ecm_callback)) < 0)
2655                        cs_log("openxcas: unable to add ecm filter");
2656                    else
2657                        cs_debug_mask(D_DVBAPI, "openxcas: ecm filter added, pid = %x, caid = %x", openxcas_ecm_pid, 0);
2658
2659                    if (openxcas_start_filter(msg.stream_id, msg.sequence, OPENXCAS_FILTER_ECM) < 0)
2660                        cs_log("openxcas: unable to start ecm filter");
2661                    else
2662                        cs_debug_mask(D_DVBAPI, "openxcas: ecm filter started");
2663
2664                    if (!openxcas_create_cipher_ex(msg.stream_id, openxcas_seq, 0, openxcas_ecm_pid, openxcas_video_pid, 0xffff, openxcas_audio_pid, 0xffff, 0xffff, 0xffff))
2665                        cs_log("openxcas: failed to create cipher ex");
2666                    else
2667                        cs_debug_mask(D_DVBAPI, "openxcas: cipher created");
2668                    break;
2669                case OPENXCAS_STOP_PMT_ECM:
2670                    cs_debug_mask(D_DVBAPI, "openxcas: msg: OPENXCAS_STOP_PMT_ECM");
2671                    openxcas_stop_filter(msg.stream_id, OPENXCAS_FILTER_ECM);
2672                    openxcas_remove_filter(msg.stream_id, OPENXCAS_FILTER_ECM);
2673                    openxcas_stop_filter_ex(msg.stream_id, msg.sequence, openxcas_filter_idx);
2674                    openxcas_destory_cipher_ex(msg.stream_id, msg.sequence);
2675                    memset(&demux, 0, sizeof(demux));
2676                    break;
2677                case OPENXCAS_ECM_CALLBACK:
2678                    cs_debug_mask(D_DVBAPI, "openxcas: msg: OPENXCAS_ECM_CALLBACK");
2679                    struct stOpenXCAS_Data data;
2680                    memcpy(&data, msg.buf, msg.buf_len);
2681                    if (!openxcas_busy)
2682                      openxcas_filter_callback(msg.stream_id, msg.sequence, OPENXCAS_FILTER_ECM, &data);
2683                    break;
2684                case OPENXCAS_PID_FILTER_CALLBACK:
2685                    cs_debug_mask(D_DVBAPI, "openxcas: msg: OPENXCAS_PID_FILTER_CALLBACK");
2686                    openxcas_filter_callback_ex(msg.stream_id, msg.sequence, (struct stOpenXCAS_Data *)msg.buf);
2687                    break;
2688                case OPENXCAS_QUIT:
2689                    cs_debug_mask(D_DVBAPI, "openxcas: msg: OPENXCAS_QUIT");
2690                    openxcas_close();
2691                    cs_log("openxcas: exited");
2692                    return NULL;
2693                    break;
2694                case OPENXCAS_UKNOWN_MSG:
2695                default:
2696                    cs_debug_mask(D_DVBAPI, "openxcas: msg: OPENXCAS_UKNOWN_MSG (%d)", msg.cmd);
2697                    //cs_ddump_mask(D_DVBAPI, &msg, sizeof(msg), "msg dump:");
2698                    break;
2699            }
2700        }
2701    }
2702    cs_log("openxcas: invalid message");
2703    pthread_cleanup_pop(1);
2704    return NULL;
2705}
2706
2707void azbox_send_dcw(struct s_client *client, ECM_REQUEST *er) {
2708    cs_debug_mask(D_DVBAPI, "openxcas: send_dcw");
2709
2710    FILE *ecmtxt;
2711    if (ecmtxt = fopen(ECMINFO_FILE, "w")) {
2712        if(er->rc <= E_EMU) {
2713            fprintf(ecmtxt, "caid: 0x%04X\npid: 0x%04X\nprov: 0x%06X\n", er->caid, er->pid, (uint) er->prid);
2714            fprintf(ecmtxt, "reader: %s\n", er->selected_reader->label);
2715            if (er->selected_reader->typ & R_IS_CASCADING)
2716                fprintf(ecmtxt, "from: %s\n", er->selected_reader->device);
2717            else
2718                fprintf(ecmtxt, "from: local\n");
2719            fprintf(ecmtxt, "protocol: %s\n", er->selected_reader->ph.desc);
2720            fprintf(ecmtxt, "hops: %d\n", er->selected_reader->cc_currenthops);
2721            fprintf(ecmtxt, "ecm time: %.3f\n", (float) client->cwlastresptime/1000);
2722            fprintf(ecmtxt, "cw0: %s\n", cs_hexdump(1,demux[0].lastcw[0],8));
2723            fprintf(ecmtxt, "cw1: %s\n", cs_hexdump(1,demux[0].lastcw[1],8));
2724            fclose(ecmtxt);
2725            ecmtxt = NULL;
2726        } else {
2727            fprintf(ecmtxt, "ECM information not found\n");
2728            fclose(ecmtxt);
2729        }
2730    }
2731
2732    openxcas_busy = 0;
2733
2734    int32_t i;
2735    for (i=0; i < MAX_DEMUX; i++) {
2736        if (er->rc >= E_NOTFOUND) {
2737            cs_debug_mask(D_DVBAPI, "cw not found");
2738
2739            if (demux[i].pidindex==-1)
2740              dvbapi_try_next_caid(i);
2741
2742            openxcas_stop_filter(openxcas_stream_id, OPENXCAS_FILTER_ECM);
2743            openxcas_remove_filter(openxcas_stream_id, OPENXCAS_FILTER_ECM);
2744
2745            unsigned char mask[12];
2746            unsigned char comp[12];
2747            memset(&mask, 0x00, sizeof(mask));
2748            memset(&comp, 0x00, sizeof(comp));
2749
2750            mask[0] = 0xfe;
2751            comp[0] = 0x80;
2752
2753            if (openxcas_add_filter(openxcas_stream_id, OPENXCAS_FILTER_ECM, 0, 0xffff, openxcas_ecm_pid, mask, comp, (void *)azbox_openxcas_ecm_callback) < 0) {
2754                cs_log("openxcas: unable to add ecm filter (0)");
2755                if (openxcas_add_filter(openxcas_stream_id, OPENXCAS_FILTER_ECM, openxcas_caid, 0xffff, openxcas_ecm_pid, mask, comp, (void *)azbox_openxcas_ecm_callback) < 0)
2756                    cs_log("openxcas: unable to add ecm filter (%04x)", openxcas_caid);
2757                else
2758                    cs_debug_mask(D_DVBAPI, "openxcas: ecm filter added, pid = %x, caid = %x", openxcas_ecm_pid, openxcas_caid);
2759            } else
2760                cs_debug_mask(D_DVBAPI, "openxcas: ecm filter added, pid = %x, caid = %x", openxcas_ecm_pid, 0);
2761
2762            if (openxcas_start_filter(openxcas_stream_id, openxcas_seq, OPENXCAS_FILTER_ECM) < 0)
2763                cs_log("openxcas: unable to start ecm filter");
2764            else
2765                cs_debug_mask(D_DVBAPI, "openxcas: ecm filter started");
2766
2767            return;
2768        }
2769    }
2770
2771  unsigned char nullcw[8];
2772  memset(nullcw, 0, 8);
2773
2774  int32_t n;
2775  for (n=0;n<2;n++) {
2776    if (memcmp(er->cw + (n * 8), demux[0].lastcw[n], 8) && memcmp(er->cw + (n * 8), nullcw, 8)) {
2777      memcpy(demux[0].lastcw[n], er->cw + (n * 8), 8);
2778      memcpy(openxcas_cw + (n * 8), er->cw + (n * 8), 8);
2779    }
2780  }
2781
2782    if (openxcas_set_key(openxcas_stream_id, openxcas_seq, 0, openxcas_cipher_idx, openxcas_cw, openxcas_cw + 8) != 1)
2783        cs_log("openxcas: set cw failed");
2784    else
2785        cs_ddump_mask(D_DVBAPI, openxcas_cw, 16, "openxcas: write cws to descrambler");
2786}
2787#endif
2788/*
2789 *  protocol structure
2790 */
2791
2792void module_dvbapi(struct s_module *ph)
2793{
2794    cs_strncpy(ph->desc, "dvbapi", sizeof(ph->desc));
2795    ph->type=MOD_CONN_SERIAL;
2796    ph->multi=1;
2797    ph->watchdog=0;
2798    ph->s_handler=dvbapi_handler;
2799    ph->send_dcw=dvbapi_send_dcw;
2800}
2801#endif // HAVE_DVBAPI
Note: See TracBrowser for help on using the repository browser.