source: trunk/module-coolapi.c @ 5375

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

Fix memcpy issues in reader-videoguard2 and smartreader module: Memcpy() has undefined behaviour if it copies data onto itself => use memmove() instead.
Fix: Set CCCam client into shutdown mode before sleeping in cleanup_thread() to prevent race conditions.
Fix some locking behaviours: A trylock with an unlock might lead to undefined behaviour if the lock was not gained.
Fix: If a thread holds a mutex and is killed, a deadlock may arise as the mutex never gets unlocked. Thus, the mutex is now saved in the client structure and cleaned up in cleanup_thread().

File size: 11.4 KB
Line 
1/* Reversed from libcoolstream.so, this comes without any warranty */
2
3#ifdef COOL
4#define _GNU_SOURCE
5
6#include <pthread.h>
7#include <stdio.h>
8#include <stdbool.h>
9#include <poll.h>
10#include <string.h>
11#include <unistd.h>
12#include <sys/time.h>
13#include <stdint.h>
14
15#include "module-coolapi.h"
16#include "globals.h"
17
18#define MAX_PIDS 20
19#define MAX_FILTER 10
20
21#define MAX_DEMUX 3
22
23int32_t cooldebug = 0;
24static bool dmx_opened = false;
25
26#define check_error(label, ret) \
27{ \
28        if(ret != 0) { \
29                cs_log("[%s:%d] %s: API ERROR %d",  \
30        __FUNCTION__, __LINE__ ,        \
31        label, ret);                \
32    }                       \
33}
34
35typedef struct ca_descr {
36        uint32_t index;
37        uint32_t parity;    /* 0 == even, 1 == odd */
38        unsigned char cw[8];
39} ca_descr_t;
40
41struct cool_dmx
42{
43    bool        opened;
44    bool        filter_attached;
45    int32_t     fd;
46    void *      buffer1;
47    void *      buffer2;
48    void *      channel;
49    void *      filter;
50    void *      device;
51    int32_t     pid;
52    pthread_mutex_t mutex;
53    int32_t         demux_id;
54    int32_t         demux_index;
55    int32_t         filter_num;
56};
57typedef struct cool_dmx dmx_t;
58
59static void * dmx_device[MAX_DEMUX];
60static dmx_t cdemuxes[MAX_DEMUX][MAX_FILTER];
61
62int32_t coolapi_read(int32_t fd, unsigned char * buffer, uint32_t len);
63void coolapi_open();
64
65extern void dvbapi_process_input(int32_t demux_num, int32_t filter_num, unsigned char *buffer, int32_t len);
66extern pthread_key_t getclient;
67extern void * dvbapi_client;
68
69#define COOLDEMUX_FD(device, num) (('O' << 24) | ('S' << 16) | (device << 8) | num)
70#define COOLDEMUX_DMX_DEV(fd) (((fd) >> 8) & 0xFF)
71#define COOLDEMUX_DMX(fd) ((fd) & 0xFF)
72
73static dmx_t *find_demux(int32_t fd, int32_t dmx_dev_num)
74{
75    int32_t i, idx;
76
77    if(dmx_dev_num < 0 || dmx_dev_num >= MAX_DEMUX) {
78        cs_log("Invalid demux %d", dmx_dev_num);
79        return NULL;
80    }
81    idx = dmx_dev_num;
82
83    if(fd == 0) {
84        for(i = 0; i < MAX_FILTER; i++) {
85            if (cdemuxes[idx][i].opened == false) {
86                cdemuxes[idx][i].fd = COOLDEMUX_FD(dmx_dev_num, i);
87                cs_debug_mask(D_DVBAPI, "opening new fd: %08x", cdemuxes[idx][i].fd);
88                cdemuxes[idx][i].demux_index = dmx_dev_num;
89                return &cdemuxes[idx][i];
90            }
91        }
92        cs_debug_mask(D_DVBAPI, "ERROR: no free demux found");
93        return NULL;
94    }
95
96    idx = COOLDEMUX_DMX_DEV(fd);
97    for(i = 0; i < MAX_FILTER; i++) {
98        if(cdemuxes[idx][i].fd == fd)
99            return &cdemuxes[idx][i];
100    }
101
102    cs_debug_mask(D_DVBAPI, "ERROR: CANT FIND Demux %x", fd);
103
104    return NULL;
105}
106
107void coolapi_read_data(int32_t fd, int32_t len)
108{
109    int32_t ret;
110    unsigned char buffer[4096];
111    dmx_t * dmx =  find_demux(fd, 0);
112
113    if(!dmx) {
114        cs_debug_mask(D_DVBAPI, "handle is NULL!");
115        return;
116    }
117
118    cs_lock(&dmx->mutex);
119    pthread_setspecific(getclient, dvbapi_client);
120    ret = coolapi_read(dmx->fd, buffer, len);
121    cs_unlock(&dmx->mutex);
122    dvbapi_process_input(dmx->demux_id, dmx->filter_num, buffer, len);
123}
124
125static void dmx_callback(void * unk, dmx_t * dmx, int32_t type, void * data)
126{
127    dmx_callback_data_t * cdata = (dmx_callback_data_t *) data;
128    unk = unk;
129
130    if(!dmx) {
131        cs_debug_mask(D_DVBAPI, "wrong dmx pointer !!!");
132        return;
133    }
134    if(cdata != NULL) {
135        switch(type) {
136            case 0xE:
137                if(cdata->type == 1) {
138                    coolapi_read_data(dmx->fd, cdata->len);
139                } else
140                    cs_debug_mask(D_DVBAPI, "unknown callback data %d len %d", cdata->type, cdata->len);
141                break;
142            default:
143                break;
144
145        }
146    }
147}
148
149int32_t coolapi_set_filter (int32_t fd, int32_t num, int32_t pid, unsigned char * flt, unsigned char * mask)
150{
151    int32_t result;
152    filter_set_t filter;
153
154    dmx_t * dmx =  find_demux(fd, 0);
155
156    if(!dmx) {
157        cs_debug_mask(D_DVBAPI, "dmx is NULL!");
158        return -1;
159    }
160
161    dmx->filter_num = num;
162    cs_debug_mask(D_DVBAPI, "fd %08x demux %d channel %x num %d pid %x flt %x mask %x", fd, dmx->demux_index, (int) dmx->channel, num, pid, flt[0], mask[0]);
163
164    memset(&filter, 0, sizeof(filter));
165
166    filter.length = 12;
167    memcpy(filter.filter, flt, 12);
168    memcpy(filter.mask, mask, 12);
169
170    cs_lock(&dmx->mutex);
171    if(dmx->filter == NULL) {
172        dmx->filter_attached = false;
173        result = cnxt_dmx_open_filter(dmx->device, &dmx->filter);
174        check_error ("cnxt_dmx_open_filter", result);
175    }
176
177    result = cnxt_dmx_set_filter(dmx->filter, &filter, NULL);
178    check_error ("cnxt_dmx_set_filter", result);
179
180    if(!dmx->filter_attached) {
181        result = cnxt_dmx_channel_attach_filter(dmx->channel, dmx->filter);
182        check_error ("cnxt_dmx_channel_attach_filter", result);
183    }
184
185    if(dmx->pid != pid) {
186        result = cnxt_dmx_set_channel_pid(dmx->channel, pid);
187        check_error ("cnxt_dmx_set_channel_pid", result);
188    }
189
190    result = cnxt_cbuf_flush (dmx->buffer1, 0);
191    check_error ("cnxt_cbuf_flush", result);
192    result = cnxt_cbuf_flush (dmx->buffer2, 0);
193    check_error ("cnxt_cbuf_flush", result);
194
195    result = cnxt_dmx_channel_ctrl(dmx->channel, 2, 0);
196    check_error ("cnxt_dmx_channel_ctrl", result);
197    dmx->pid = pid;
198    cs_unlock(&dmx->mutex);
199    return 0;
200}
201
202int32_t coolapi_remove_filter (int32_t fd, int32_t num)
203{
204    int32_t result;
205    dmx_t * dmx = find_demux(fd, 0);
206    if(!dmx) {
207         cs_debug_mask(D_DVBAPI, "dmx is NULL!");
208         return -1;
209    }
210
211    if(dmx->pid <= 0)
212        return -1;
213
214        cs_debug_mask(D_DVBAPI, "fd %08x channel %x num %d pid %x opened %s", fd, (int) dmx->channel, num, dmx->pid, dmx->opened ? "yes" : "no");
215
216    cs_lock(&dmx->mutex);
217    result = cnxt_dmx_channel_ctrl(dmx->channel, 0, 0);
218    check_error ("cnxt_dmx_channel_ctrl", result);
219
220    result = cnxt_dmx_set_channel_pid(dmx->channel, 0x1FFF);
221    check_error ("cnxt_dmx_set_channel_pid", result);
222
223    result = cnxt_cbuf_flush (dmx->buffer1, 0);
224    check_error ("cnxt_cbuf_flush", result);
225    result = cnxt_cbuf_flush (dmx->buffer2, 0);
226    check_error ("cnxt_cbuf_flush", result);
227    cs_unlock(&dmx->mutex);
228
229    dmx->pid = -1;
230    return 0;
231}
232
233int32_t coolapi_open_device (int32_t demux_index, int32_t demux_id)
234{
235    int32_t result = 0;
236    buffer_open_arg_t bufarg;
237    channel_open_arg_t chanarg;
238    int32_t uBufferSize = 8256;
239    dmx_t * dmx;
240
241    coolapi_open();
242
243    dmx = find_demux(0, demux_index);
244    if(dmx == 0) {
245        cs_log("no free demux found");
246        return 0;
247    }
248
249    dmx->demux_index = demux_index;
250    dmx->demux_id = demux_id;
251    dmx->pid = -1;
252
253    memset(&bufarg, 0, sizeof(bufarg));
254
255    dmx->device = dmx_device[demux_index];
256    dmx->opened = true;
257
258    bufarg.type = 3;
259    bufarg.size = uBufferSize;
260    bufarg.unknown3 = (uBufferSize * 7) / 8;
261
262    result = cnxt_cbuf_open(&dmx->buffer1, &bufarg, NULL, NULL);
263    check_error ("cnxt_cbuf_open", result);
264
265    bufarg.type = 0;
266
267    result = cnxt_cbuf_open(&dmx->buffer2, &bufarg, NULL, NULL);
268    check_error ("cnxt_cbuf_open", result);
269
270    memset(&chanarg, 0, sizeof(channel_open_arg_t));
271    chanarg.type = 4;
272
273    result = cnxt_dmx_channel_open(dmx->device, &dmx->channel, &chanarg, dmx_callback, dmx);
274    check_error ("cnxt_dmx_channel_open", result);
275
276    result = cnxt_dmx_set_channel_buffer(dmx->channel, 0, dmx->buffer1);
277    check_error ("cnxt_dmx_set_channel_buffer", result);
278
279    result = cnxt_dmx_channel_attach(dmx->channel, 0xB, 0, dmx->buffer2);
280    check_error ("cnxt_dmx_channel_attach", result);
281
282    result = cnxt_cbuf_attach(dmx->buffer2, 2, dmx->channel);
283    check_error ("cnxt_cbuf_attach", result);
284
285    pthread_mutexattr_t attr;
286    pthread_mutexattr_init(&attr);
287    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
288    pthread_mutex_init(&dmx->mutex, &attr);
289
290    cs_debug_mask(D_DVBAPI, "fd %08x demux #%d demux_id %d channel %x", dmx->fd, demux_index, demux_id, (int) dmx->channel);
291    return dmx->fd;
292}
293
294int32_t coolapi_close_device(int32_t fd)
295{
296    int32_t result;
297    dmx_t * dmx = find_demux(fd, 0);
298    if(!dmx) {
299        cs_debug_mask(D_DVBAPI, "dmx is NULL!");
300        return -1;
301    }
302    cs_debug_mask(D_DVBAPI, "fd %08x channel %x pid %x", fd, (int) dmx->channel, dmx->pid);
303
304    if(dmx->filter != NULL) {
305        result = cnxt_dmx_channel_detach_filter(dmx->channel, dmx->filter);
306        check_error ("cnxt_dmx_channel_detach_filter", result);
307        result = cnxt_dmx_close_filter(dmx->filter);
308        check_error ("cnxt_dmx_close_filter", result);
309        dmx->filter = NULL;
310        dmx->filter_attached = false;
311    }
312
313    result = cnxt_cbuf_detach(dmx->buffer2, 2, dmx->channel);
314    check_error ("cnxt_cbuf_detach", result);
315    result = cnxt_dmx_channel_detach(dmx->channel, 0xB, 0, dmx->buffer2);
316    check_error ("cnxt_dmx_channel_detach", result);
317
318    result = cnxt_dmx_channel_detach(dmx->channel, 0xB, 0, dmx->buffer1);
319    check_error ("cnxt_dmx_channel_detach", result);
320    result = cnxt_dmx_channel_close(dmx->channel);
321    check_error ("cnxt_dmx_channel_close", result);
322
323    result = cnxt_cbuf_close(dmx->buffer2);
324    check_error ("cnxt_cbuf_close", result);
325
326    result = cnxt_cbuf_close(dmx->buffer1);
327    check_error ("cnxt_cbuf_close", result);
328
329    dmx->opened = false;
330
331    pthread_mutex_destroy(&dmx->mutex);
332
333    memset(dmx, 0, sizeof(dmx_t));
334    return 0;
335}
336
337/* write cw to all demuxes in mask with passed index */
338int32_t coolapi_write_cw(int32_t mask, uint16_t *STREAMpids, int32_t count, ca_descr_t * ca_descr)
339{
340        int32_t i, index = ca_descr->index;
341        int32_t result;
342        void * channel;
343
344    cs_debug_mask(D_DVBAPI, "cw%d: mask %d index %d pid count %d", ca_descr->parity, mask, index, count);
345    for(i = 0; i < count; i++) {
346        int32_t pid = STREAMpids[i]; 
347        int32_t j;
348        for(j = 0; j < 3; j++) {
349            if(mask & (1 << j))
350            {
351                result = cnxt_dmx_get_channel_from_pid(dmx_device[j], pid, &channel);
352                if(result == 0) {
353                    cs_debug_mask(D_DVBAPI, "Found demux %d channel %x for pid %x", j, (int) channel, pid);
354                    result = cnxt_dmx_set_channel_key(channel, 0, ca_descr->parity, ca_descr->cw, 8);
355                    check_error ("cnxt_dmx_set_channel_key", result);
356                    if(result != 0) {
357                        cs_log("set_channel_key failed for demux %d pid 0x%x", j, pid);
358                    }
359                }
360            }
361        }
362    }
363        return 0;
364}
365
366int32_t coolapi_read(int32_t fd, unsigned char * buffer, uint32_t len)
367{
368    int32_t result;
369    uint32_t done = 0, toread;
370    unsigned char * buff = &buffer[0];
371
372    dmx_t * dmx = find_demux(fd, 0);
373    if(!dmx) {
374        cs_debug_mask(D_DVBAPI, "dmx is NULL!");
375        return 0;
376    }
377    cs_debug_mask(D_DVBAPI, "dmx channel %x pid %x len %d",  (int) dmx->channel, dmx->pid, len);
378
379    result = cnxt_cbuf_read_data(dmx->buffer2, buff, 3, &done);
380    check_error ("cnxt_cbuf_read_data", result);
381
382    if(done != 3)
383        return 0;
384
385    toread = ((buff[1] << 8) | buff[2]) & 0xFFF;
386    if((toread+3) > len)
387        return 0;
388    result = cnxt_cbuf_read_data(dmx->buffer2, buff+3, toread, &done);
389    check_error ("cnxt_cbuf_read_data", result);
390    if(done != toread)
391        return 0;
392    done += 3;
393
394    cs_debug_mask(D_DVBAPI, "bytes read %d\n", done);
395    return done;
396}
397
398void coolapi_open_all()
399{
400    cnxt_kal_initialize();
401    cnxt_drv_init();
402}
403
404void coolapi_open()
405{
406    int32_t result = 0;
407    device_open_arg_t devarg;
408
409        if(!dmx_opened) { 
410                int32_t i;
411
412        cs_log("Open coolstream dmx api");
413                cnxt_cbuf_init(NULL);
414                cnxt_dmx_init(NULL);
415
416                memset(&devarg, 0, sizeof(device_open_arg_t));
417
418                devarg.unknown1 = 1;
419                devarg.unknown3 = 3;
420                devarg.unknown6 = 1;
421                for(i = 0; i < MAX_DEMUX; i++) {
422                        devarg.number = i;
423                        result = cnxt_dmx_open (&dmx_device[i], &devarg, NULL, NULL);
424                        check_error ("cnxt_dmx_open", result);
425                }
426                dmx_opened = true;
427        }
428}
429
430void coolapi_close_all()
431{
432    int32_t result;
433    int32_t i, j;
434
435    if(!dmx_opened)
436        return;
437
438    for(i = 0; i < MAX_DEMUX; i++) {
439        for(j = 0; j < MAX_FILTER; j++) {
440            if(cdemuxes[i][j].fd > 0) {
441                coolapi_remove_filter(cdemuxes[i][j].fd, cdemuxes[i][j].filter_num);
442                coolapi_close_device(cdemuxes[i][j].fd);
443            }
444        }
445    }
446    for(i = 0; i < MAX_DEMUX; i++) {
447        result = cnxt_dmx_close(dmx_device[i]);
448        check_error ("cnxt_dmx_close", result);
449        dmx_device[i] = NULL;
450    }
451    cnxt_kal_terminate();
452    cnxt_drv_term();
453}
454#endif
Note: See TracBrowser for help on using the repository browser.