1 | #define MODULE_LOG_PREFIX "dvbapi"
|
---|
2 |
|
---|
3 | #include "globals.h"
|
---|
4 |
|
---|
5 | #ifdef HAVE_DVBAPI
|
---|
6 |
|
---|
7 | #include "module-dvbapi.h"
|
---|
8 | #include "module-cacheex.h"
|
---|
9 | #include "module-dvbapi-azbox.h"
|
---|
10 | #include "module-dvbapi-mca.h"
|
---|
11 | #include "module-dvbapi-coolapi.h"
|
---|
12 | #include "module-dvbapi-stapi.h"
|
---|
13 | #include "module-dvbapi-chancache.h"
|
---|
14 | #include "module-stat.h"
|
---|
15 | #include "oscam-chk.h"
|
---|
16 | #include "oscam-client.h"
|
---|
17 | #include "oscam-config.h"
|
---|
18 | #include "oscam-ecm.h"
|
---|
19 | #include "oscam-emm.h"
|
---|
20 | #include "oscam-files.h"
|
---|
21 | #include "oscam-net.h"
|
---|
22 | #include "oscam-reader.h"
|
---|
23 | #include "oscam-string.h"
|
---|
24 | #include "oscam-time.h"
|
---|
25 | #include "oscam-work.h"
|
---|
26 | #include "reader-irdeto.h"
|
---|
27 |
|
---|
28 | #if defined (__CYGWIN__)
|
---|
29 | #define F_NOTIFY 0
|
---|
30 | #define F_SETSIG 0
|
---|
31 | #define DN_MODIFY 0
|
---|
32 | #define DN_CREATE 0
|
---|
33 | #define DN_DELETE 0
|
---|
34 | #define DN_MULTISHOT 0
|
---|
35 | #endif
|
---|
36 |
|
---|
37 | const char *streamtxt[] = {
|
---|
38 | "", // 00
|
---|
39 | "", // 01
|
---|
40 | "Videostream ", // 02
|
---|
41 | "Audiostream ", // 03
|
---|
42 | "", // 04
|
---|
43 | "", // 05
|
---|
44 | "Datastream ", // 06
|
---|
45 | "", // 07
|
---|
46 | "", // 08
|
---|
47 | "Conditional Access ", // 09
|
---|
48 | "", // 0A
|
---|
49 | "", // 0B
|
---|
50 | "", // 0C
|
---|
51 | "", // 0D
|
---|
52 | "", // 0E
|
---|
53 | "", // 0F
|
---|
54 | "", // 10
|
---|
55 | "", // 11
|
---|
56 | "", // 12
|
---|
57 | "", // 13
|
---|
58 | "", // 14
|
---|
59 | "", // 15
|
---|
60 | "", // 16
|
---|
61 | "", // 17
|
---|
62 | "", // 18
|
---|
63 | "", // 19
|
---|
64 | "", // 1A
|
---|
65 | "MPEG-4 videostream ", // 1B
|
---|
66 | "MPEG-4 audiostream ",
|
---|
67 | };
|
---|
68 |
|
---|
69 | static int is_samygo;
|
---|
70 |
|
---|
71 | void flush_read_fd(int32_t demux_index, int32_t num, int fd)
|
---|
72 | {
|
---|
73 | if(!cfg.dvbapi_listenport && cfg.dvbapi_boxtype != BOXTYPE_PC_NODMX)
|
---|
74 | {
|
---|
75 | cs_log_dbg(D_DVBAPI,"Demuxer %d flushing stale input data of filter %d (fd:%d)", demux_index, num + 1, fd);
|
---|
76 | fd_set rd;
|
---|
77 | struct timeval t;
|
---|
78 | char buff[100];
|
---|
79 | t.tv_sec=0;
|
---|
80 | t.tv_usec=0;
|
---|
81 | FD_ZERO(&rd);
|
---|
82 | FD_SET(fd,&rd);
|
---|
83 | while(select(fd+1,&rd,NULL,NULL,&t) > 0)
|
---|
84 | {
|
---|
85 | if (read(fd,buff,100)){;}
|
---|
86 | }
|
---|
87 | }
|
---|
88 | }
|
---|
89 |
|
---|
90 | static int dvbapi_ioctl(int fd, uint32_t request, ...)
|
---|
91 | {
|
---|
92 | int ret = 0;
|
---|
93 | va_list args;
|
---|
94 | va_start(args, request);
|
---|
95 | if (!is_samygo)
|
---|
96 | {
|
---|
97 | void *param = va_arg(args, void *);
|
---|
98 | ret = ioctl(fd, request, param);
|
---|
99 | }
|
---|
100 | else
|
---|
101 | {
|
---|
102 | switch(request)
|
---|
103 | {
|
---|
104 | case DMX_SET_FILTER:
|
---|
105 | {
|
---|
106 | struct dmxSctFilterParams *sFP = va_arg(args, struct dmxSctFilterParams *);
|
---|
107 | // prepare packet
|
---|
108 | unsigned char packet[sizeof(request) + sizeof(struct dmxSctFilterParams)];
|
---|
109 | memcpy(&packet, &request, sizeof(request));
|
---|
110 | memcpy(&packet[sizeof(request)], sFP, sizeof(struct dmxSctFilterParams));
|
---|
111 | ret = send(fd, packet, sizeof(packet), 0);
|
---|
112 | break;
|
---|
113 | }
|
---|
114 | case DMX_SET_FILTER1:
|
---|
115 | {
|
---|
116 | struct dmx_sct_filter_params *sFP = va_arg(args, struct dmx_sct_filter_params *);
|
---|
117 | ret = send(fd, sFP, sizeof(struct dmx_sct_filter_params), 0);
|
---|
118 | break;
|
---|
119 | }
|
---|
120 | case DMX_STOP:
|
---|
121 | {
|
---|
122 | ret = send(fd, &request, sizeof(request), 0);
|
---|
123 | ret = 1;
|
---|
124 | break;
|
---|
125 | }
|
---|
126 | case CA_SET_PID:
|
---|
127 | {
|
---|
128 | ret = 1;
|
---|
129 | break;
|
---|
130 | }
|
---|
131 | case CA_SET_DESCR:
|
---|
132 | {
|
---|
133 | ret = 1;
|
---|
134 | break;
|
---|
135 | }
|
---|
136 | }
|
---|
137 | if (ret > 0) // send() may return larger than 1
|
---|
138 | ret = 1;
|
---|
139 | }
|
---|
140 | #if defined(__powerpc__)
|
---|
141 | // Old dm500 boxes (ppc old) are using broken kernel, se we need some fixups
|
---|
142 | switch (request)
|
---|
143 | {
|
---|
144 | case DMX_STOP:
|
---|
145 | case CA_SET_DESCR:
|
---|
146 | case CA_SET_PID:
|
---|
147 | ret = 1;
|
---|
148 | }
|
---|
149 | #endif
|
---|
150 | // FIXME: Workaround for su980 bug
|
---|
151 | // See: http://www.streamboard.tv/wbb2/thread.php?postid=533940
|
---|
152 | if(boxtype_is("su980"))
|
---|
153 | ret = 1;
|
---|
154 | va_end(args);
|
---|
155 | return ret;
|
---|
156 | }
|
---|
157 |
|
---|
158 | // tunemm_caid_map
|
---|
159 | #define FROM_TO 0
|
---|
160 | #define TO_FROM 1
|
---|
161 |
|
---|
162 | int32_t pausecam = 0, disable_pmt_files = 0, pmt_stopmarking = 0, pmthandling = 0;
|
---|
163 | DEMUXTYPE demux[MAX_DEMUX];
|
---|
164 | struct s_dvbapi_priority *dvbapi_priority;
|
---|
165 | struct s_client *dvbapi_client;
|
---|
166 |
|
---|
167 | const char *boxdesc[] = { "none", "dreambox", "duckbox", "ufs910", "dbox2", "ipbox", "ipbox-pmt", "dm7000", "qboxhd", "coolstream", "neumo", "pc", "pc-nodmx" };
|
---|
168 |
|
---|
169 | static const struct box_devices devices[BOX_COUNT] =
|
---|
170 | {
|
---|
171 | /* QboxHD (dvb-api-3)*/ { "/tmp/virtual_adapter/", "ca%d", "demux%d", "/tmp/camd.socket", DVBAPI_3 },
|
---|
172 | /* dreambox (dvb-api-3)*/ { "/dev/dvb/adapter%d/", "ca%d", "demux%d", "/tmp/camd.socket", DVBAPI_3 },
|
---|
173 | /* dreambox (dvb-api-1)*/ { "/dev/dvb/card%d/", "ca%d", "demux%d", "/tmp/camd.socket", DVBAPI_1 },
|
---|
174 | /* neumo (dvb-api-1)*/ { "/dev/", "demuxapi", "demuxapi", "/tmp/camd.socket", DVBAPI_1 },
|
---|
175 | /* sh4 (stapi)*/ { "/dev/stapi/", "stpti4_ioctl", "stpti4_ioctl", "/tmp/camd.socket", STAPI },
|
---|
176 | /* coolstream*/ { "/dev/cnxt/", "null", "null", "/tmp/camd.socket", COOLAPI }
|
---|
177 | };
|
---|
178 |
|
---|
179 | static int32_t selected_box = -1;
|
---|
180 | static int32_t selected_api = -1;
|
---|
181 | static int32_t maxfilter = MAX_FILTER;
|
---|
182 | static int32_t dir_fd = -1;
|
---|
183 | char *client_name = NULL;
|
---|
184 | static uint16_t client_proto_version = 0;
|
---|
185 |
|
---|
186 | static int32_t ca_fd[MAX_DEMUX]; // holds fd handle of each ca device 0 = not in use
|
---|
187 | static LLIST * ll_activestreampids; // list of all enabled streampids on ca devices
|
---|
188 |
|
---|
189 | static int32_t unassoc_fd[MAX_DEMUX];
|
---|
190 |
|
---|
191 | bool is_dvbapi_usr(char *usr) {
|
---|
192 | return streq(cfg.dvbapi_usr, usr);
|
---|
193 | }
|
---|
194 |
|
---|
195 | struct s_emm_filter
|
---|
196 | {
|
---|
197 | int32_t demux_id;
|
---|
198 | uchar filter[32];
|
---|
199 | uint16_t caid;
|
---|
200 | uint32_t provid;
|
---|
201 | uint16_t pid;
|
---|
202 | uint32_t num;
|
---|
203 | struct timeb time_started;
|
---|
204 | };
|
---|
205 |
|
---|
206 | static LLIST *ll_emm_active_filter;
|
---|
207 | static LLIST *ll_emm_inactive_filter;
|
---|
208 | static LLIST *ll_emm_pending_filter;
|
---|
209 |
|
---|
210 | int32_t add_emmfilter_to_list(int32_t demux_id, uchar *filter, uint16_t caid, uint32_t provid, uint16_t emmpid, int32_t num, bool enable)
|
---|
211 | {
|
---|
212 | if(!ll_emm_active_filter)
|
---|
213 | { ll_emm_active_filter = ll_create("ll_emm_active_filter"); }
|
---|
214 |
|
---|
215 | if(!ll_emm_inactive_filter)
|
---|
216 | { ll_emm_inactive_filter = ll_create("ll_emm_inactive_filter"); }
|
---|
217 |
|
---|
218 | if(!ll_emm_pending_filter)
|
---|
219 | { ll_emm_pending_filter = ll_create("ll_emm_pending_filter"); }
|
---|
220 |
|
---|
221 | struct s_emm_filter *filter_item;
|
---|
222 | if(!cs_malloc(&filter_item, sizeof(struct s_emm_filter)))
|
---|
223 | { return 0; }
|
---|
224 |
|
---|
225 | filter_item->demux_id = demux_id;
|
---|
226 | memcpy(filter_item->filter, filter, 32);
|
---|
227 | filter_item->caid = caid;
|
---|
228 | filter_item->provid = provid;
|
---|
229 | filter_item->pid = emmpid;
|
---|
230 | filter_item->num = num;
|
---|
231 | if (enable)
|
---|
232 | {
|
---|
233 | cs_ftime(&filter_item->time_started);
|
---|
234 | }
|
---|
235 | else
|
---|
236 | {
|
---|
237 | memset(&filter_item->time_started, 0, sizeof(filter_item->time_started));
|
---|
238 | }
|
---|
239 |
|
---|
240 | if(num > 0)
|
---|
241 | {
|
---|
242 | ll_append(ll_emm_active_filter, filter_item);
|
---|
243 | cs_log_dbg(D_DVBAPI, "Demuxer %d Filter %d added to active emmfilters (CAID %04X PROVID %06X EMMPID %04X)",
|
---|
244 | filter_item->demux_id, filter_item->num, filter_item->caid, filter_item->provid, filter_item->pid);
|
---|
245 | }
|
---|
246 | else if(num < 0)
|
---|
247 | {
|
---|
248 | ll_append(ll_emm_pending_filter, filter_item);
|
---|
249 | cs_log_dbg(D_DVBAPI, "Demuxer %d Filter added to pending emmfilters (CAID %04X PROVID %06X EMMPID %04X)",
|
---|
250 | filter_item->demux_id, filter_item->caid, filter_item->provid, filter_item->pid);
|
---|
251 | }
|
---|
252 | else
|
---|
253 | {
|
---|
254 | ll_append(ll_emm_inactive_filter, filter_item);
|
---|
255 | cs_log_dbg(D_DVBAPI, "Demuxer %d Filter added to inactive emmfilters (CAID %04X PROVID %06X EMMPID %04X)",
|
---|
256 | filter_item->demux_id, filter_item->caid, filter_item->provid, filter_item->pid);
|
---|
257 | }
|
---|
258 | return 1;
|
---|
259 | }
|
---|
260 |
|
---|
261 | int32_t is_emmfilter_in_list_internal(LLIST *ll, uchar *filter, uint16_t emmpid, uint32_t provid, uint16_t caid)
|
---|
262 | {
|
---|
263 | struct s_emm_filter *filter_item;
|
---|
264 | LL_ITER itr;
|
---|
265 | if(ll_count(ll) > 0)
|
---|
266 | {
|
---|
267 | itr = ll_iter_create(ll);
|
---|
268 | while((filter_item = ll_iter_next(&itr)) != NULL)
|
---|
269 | {
|
---|
270 | if(!memcmp(filter_item->filter, filter, 32) && (filter_item->pid == emmpid) && (filter_item->provid == provid) && (filter_item->caid == caid))
|
---|
271 | { return 1; }
|
---|
272 | }
|
---|
273 | }
|
---|
274 | return 0;
|
---|
275 | }
|
---|
276 |
|
---|
277 | int32_t is_emmfilter_in_list(uchar *filter, uint16_t emmpid, uint32_t provid, uint16_t caid)
|
---|
278 | {
|
---|
279 | if(!ll_emm_active_filter)
|
---|
280 | { ll_emm_active_filter = ll_create("ll_emm_active_filter"); }
|
---|
281 |
|
---|
282 | if(!ll_emm_inactive_filter)
|
---|
283 | { ll_emm_inactive_filter = ll_create("ll_emm_inactive_filter"); }
|
---|
284 |
|
---|
285 | if(!ll_emm_pending_filter)
|
---|
286 | { ll_emm_pending_filter = ll_create("ll_emm_pending_filter"); }
|
---|
287 |
|
---|
288 | if(is_emmfilter_in_list_internal(ll_emm_active_filter, filter, emmpid, provid, caid))
|
---|
289 | { return 1; }
|
---|
290 | if(is_emmfilter_in_list_internal(ll_emm_inactive_filter, filter, emmpid, provid, caid))
|
---|
291 | { return 1; }
|
---|
292 | if(is_emmfilter_in_list_internal(ll_emm_pending_filter, filter, emmpid, provid, caid))
|
---|
293 | { return 1; }
|
---|
294 |
|
---|
295 | return 0;
|
---|
296 | }
|
---|
297 |
|
---|
298 | struct s_emm_filter *get_emmfilter_by_filternum_internal(LLIST *ll, int32_t demux_id, uint32_t num)
|
---|
299 | {
|
---|
300 | struct s_emm_filter *filter;
|
---|
301 | LL_ITER itr;
|
---|
302 | if(ll_count(ll) > 0)
|
---|
303 | {
|
---|
304 | itr = ll_iter_create(ll);
|
---|
305 | while((filter = ll_iter_next(&itr)))
|
---|
306 | {
|
---|
307 | if(filter->demux_id == demux_id && filter->num == num)
|
---|
308 | { return filter; }
|
---|
309 | }
|
---|
310 | }
|
---|
311 | return NULL;
|
---|
312 | }
|
---|
313 |
|
---|
314 | struct s_emm_filter *get_emmfilter_by_filternum(int32_t demux_id, uint32_t num)
|
---|
315 | {
|
---|
316 | if(!ll_emm_active_filter)
|
---|
317 | { ll_emm_active_filter = ll_create("ll_emm_active_filter"); }
|
---|
318 |
|
---|
319 | if(!ll_emm_inactive_filter)
|
---|
320 | { ll_emm_inactive_filter = ll_create("ll_emm_inactive_filter"); }
|
---|
321 |
|
---|
322 | if(!ll_emm_pending_filter)
|
---|
323 | { ll_emm_pending_filter = ll_create("ll_emm_pending_filter"); }
|
---|
324 |
|
---|
325 | struct s_emm_filter *emm_filter = NULL;
|
---|
326 | emm_filter = get_emmfilter_by_filternum_internal(ll_emm_active_filter, demux_id, num);
|
---|
327 | if(emm_filter)
|
---|
328 | { return emm_filter; }
|
---|
329 | emm_filter = get_emmfilter_by_filternum_internal(ll_emm_inactive_filter, demux_id, num);
|
---|
330 | if(emm_filter)
|
---|
331 | { return emm_filter; }
|
---|
332 | emm_filter = get_emmfilter_by_filternum_internal(ll_emm_pending_filter, demux_id, num);
|
---|
333 | if(emm_filter)
|
---|
334 | { return emm_filter; }
|
---|
335 |
|
---|
336 | return NULL;
|
---|
337 | }
|
---|
338 |
|
---|
339 | int8_t remove_emmfilter_from_list_internal(LLIST *ll, int32_t demux_id, uint16_t caid, uint32_t provid, uint16_t pid, uint32_t num)
|
---|
340 | {
|
---|
341 | struct s_emm_filter *filter;
|
---|
342 | LL_ITER itr;
|
---|
343 | if(ll_count(ll) > 0)
|
---|
344 | {
|
---|
345 | itr = ll_iter_create(ll);
|
---|
346 | while((filter = ll_iter_next(&itr)))
|
---|
347 | {
|
---|
348 | if(filter->demux_id == demux_id && filter->caid == caid && filter->provid == provid && filter->pid == pid && filter->num == num)
|
---|
349 | {
|
---|
350 | ll_iter_remove_data(&itr);
|
---|
351 | return 1;
|
---|
352 | }
|
---|
353 | }
|
---|
354 | }
|
---|
355 | return 0;
|
---|
356 | }
|
---|
357 |
|
---|
358 | void remove_emmfilter_from_list(int32_t demux_id, uint16_t caid, uint32_t provid, uint16_t pid, uint32_t num)
|
---|
359 | {
|
---|
360 | if(ll_emm_active_filter && remove_emmfilter_from_list_internal(ll_emm_active_filter, demux_id, caid, provid, pid, num))
|
---|
361 | { return; }
|
---|
362 | if(ll_emm_inactive_filter && remove_emmfilter_from_list_internal(ll_emm_inactive_filter, demux_id, caid, provid, pid, num))
|
---|
363 | { return; }
|
---|
364 | if(ll_emm_pending_filter && remove_emmfilter_from_list_internal(ll_emm_pending_filter, demux_id, caid, provid, pid, num))
|
---|
365 | { return; }
|
---|
366 | }
|
---|
367 |
|
---|
368 | void dvbapi_net_add_str(unsigned char *packet, int *size, const char *str)
|
---|
369 | {
|
---|
370 | unsigned char *str_len = &packet[*size]; //string length
|
---|
371 | *size += 1;
|
---|
372 |
|
---|
373 | *str_len = snprintf((char *) &packet[*size], DVBAPI_MAX_PACKET_SIZE - *size, "%s", str);
|
---|
374 | *size += *str_len;
|
---|
375 | }
|
---|
376 |
|
---|
377 | int32_t dvbapi_net_send(uint32_t request, int32_t socket_fd, int32_t demux_index, uint32_t filter_number, unsigned char *data, struct s_client *client, ECM_REQUEST *er)
|
---|
378 | {
|
---|
379 | unsigned char packet[DVBAPI_MAX_PACKET_SIZE]; //maximum possible packet size
|
---|
380 | int32_t size = 0;
|
---|
381 |
|
---|
382 | // not connected?
|
---|
383 | if (socket_fd <= 0)
|
---|
384 | return 0;
|
---|
385 |
|
---|
386 | // preparing packet - header
|
---|
387 | // in old protocol client expect this first byte as adapter index, changed in the new protocol
|
---|
388 | // to be always after request type (opcode)
|
---|
389 | if (client_proto_version <= 0)
|
---|
390 | packet[size++] = demux[demux_index].adapter_index; //adapter index - 1 byte
|
---|
391 |
|
---|
392 | // type of request
|
---|
393 | uint32_t req = request;
|
---|
394 | if (client_proto_version >= 1)
|
---|
395 | req = htonl(req);
|
---|
396 | memcpy(&packet[size], &req, 4); //request - 4 bytes
|
---|
397 | size += 4;
|
---|
398 |
|
---|
399 | // preparing packet - adapter index for proto >= 1
|
---|
400 | if ((request != DVBAPI_SERVER_INFO) && client_proto_version >= 1)
|
---|
401 | packet[size++] = demux[demux_index].adapter_index; //adapter index - 1 byte
|
---|
402 |
|
---|
403 | // struct with data
|
---|
404 | switch (request)
|
---|
405 | {
|
---|
406 | case DVBAPI_SERVER_INFO:
|
---|
407 | {
|
---|
408 | int16_t proto_version = htons(DVBAPI_PROTOCOL_VERSION); //our protocol version
|
---|
409 | memcpy(&packet[size], &proto_version, 2);
|
---|
410 | size += 2;
|
---|
411 |
|
---|
412 | unsigned char *info_len = &packet[size]; //info string length
|
---|
413 | size += 1;
|
---|
414 |
|
---|
415 | *info_len = snprintf((char *) &packet[size], sizeof(packet) - size, "OSCam v%s, build r%s (%s)", CS_VERSION, CS_SVN_VERSION, CS_TARGET);
|
---|
416 | size += *info_len;
|
---|
417 | break;
|
---|
418 | }
|
---|
419 | case DVBAPI_ECM_INFO:
|
---|
420 | {
|
---|
421 | if (er->rc >= E_NOTFOUND)
|
---|
422 | return 0;
|
---|
423 |
|
---|
424 | int8_t hops = 0;
|
---|
425 |
|
---|
426 | uint16_t sid = htons(er->srvid); //service ID (program number)
|
---|
427 | memcpy(&packet[size], &sid, 2);
|
---|
428 | size += 2;
|
---|
429 |
|
---|
430 | uint16_t caid = htons(er->caid); //CAID
|
---|
431 | memcpy(&packet[size], &caid, 2);
|
---|
432 | size += 2;
|
---|
433 |
|
---|
434 | uint16_t pid = htons(er->pid); //PID
|
---|
435 | memcpy(&packet[size], &pid, 2);
|
---|
436 | size += 2;
|
---|
437 |
|
---|
438 | uint32_t prid = htonl(er->prid); //Provider ID
|
---|
439 | memcpy(&packet[size], &prid, 4);
|
---|
440 | size += 4;
|
---|
441 |
|
---|
442 | uint32_t ecmtime = htonl(client->cwlastresptime); //ECM time
|
---|
443 | memcpy(&packet[size], &ecmtime, 4);
|
---|
444 | size += 4;
|
---|
445 |
|
---|
446 | dvbapi_net_add_str(packet, &size, get_cardsystem_desc_by_caid(er->caid)); //cardsystem name
|
---|
447 |
|
---|
448 | switch (er->rc)
|
---|
449 | {
|
---|
450 | case E_FOUND:
|
---|
451 | if (er->selected_reader)
|
---|
452 | {
|
---|
453 | dvbapi_net_add_str(packet, &size, er->selected_reader->label); //reader
|
---|
454 | if (is_network_reader(er->selected_reader))
|
---|
455 | dvbapi_net_add_str(packet, &size, er->selected_reader->device); //from
|
---|
456 | else
|
---|
457 | dvbapi_net_add_str(packet, &size, "local"); //from
|
---|
458 | dvbapi_net_add_str(packet, &size, reader_get_type_desc(er->selected_reader, 1)); //protocol
|
---|
459 | hops = er->selected_reader->currenthops;
|
---|
460 | }
|
---|
461 | break;
|
---|
462 |
|
---|
463 | case E_CACHE1:
|
---|
464 | dvbapi_net_add_str(packet, &size, "Cache"); //reader
|
---|
465 | dvbapi_net_add_str(packet, &size, "cache1"); //from
|
---|
466 | dvbapi_net_add_str(packet, &size, "none"); //protocol
|
---|
467 | break;
|
---|
468 |
|
---|
469 | case E_CACHE2:
|
---|
470 | dvbapi_net_add_str(packet, &size, "Cache"); //reader
|
---|
471 | dvbapi_net_add_str(packet, &size, "cache2"); //from
|
---|
472 | dvbapi_net_add_str(packet, &size, "none"); //protocol
|
---|
473 | break;
|
---|
474 |
|
---|
475 | case E_CACHEEX:
|
---|
476 | dvbapi_net_add_str(packet, &size, "Cache"); //reader
|
---|
477 | dvbapi_net_add_str(packet, &size, "cache3"); //from
|
---|
478 | dvbapi_net_add_str(packet, &size, "none"); //protocol
|
---|
479 | break;
|
---|
480 | }
|
---|
481 |
|
---|
482 | packet[size++] = hops; //hops
|
---|
483 |
|
---|
484 | break;
|
---|
485 | }
|
---|
486 | case DVBAPI_CA_SET_PID:
|
---|
487 | {
|
---|
488 | int sct_capid_size = sizeof(ca_pid_t);
|
---|
489 |
|
---|
490 | if (client_proto_version >= 1)
|
---|
491 | {
|
---|
492 | ca_pid_t *capid = (ca_pid_t *) data;
|
---|
493 | capid->pid = htonl(capid->pid);
|
---|
494 | capid->index = htonl(capid->index);
|
---|
495 | }
|
---|
496 | memcpy(&packet[size], data, sct_capid_size);
|
---|
497 |
|
---|
498 | size += sct_capid_size;
|
---|
499 | break;
|
---|
500 | }
|
---|
501 | case DVBAPI_CA_SET_DESCR:
|
---|
502 | {
|
---|
503 | int sct_cadescr_size = sizeof(ca_descr_t);
|
---|
504 |
|
---|
505 | if (client_proto_version >= 1)
|
---|
506 | {
|
---|
507 | ca_descr_t *cadesc = (ca_descr_t *) data;
|
---|
508 | cadesc->index = htonl(cadesc->index);
|
---|
509 | cadesc->parity = htonl(cadesc->parity);
|
---|
510 | }
|
---|
511 | memcpy(&packet[size], data, sct_cadescr_size);
|
---|
512 |
|
---|
513 | size += sct_cadescr_size;
|
---|
514 | break;
|
---|
515 | }
|
---|
516 | case DVBAPI_DMX_SET_FILTER:
|
---|
517 | case DVBAPI_DMX_STOP:
|
---|
518 | {
|
---|
519 | int32_t sct_filter_size = sizeof(struct dmx_sct_filter_params);
|
---|
520 | packet[size++] = demux_index; //demux index - 1 byte
|
---|
521 | packet[size++] = filter_number; //filter number - 1 byte
|
---|
522 |
|
---|
523 | if (data) // filter data when starting
|
---|
524 | {
|
---|
525 | if (client_proto_version >= 1)
|
---|
526 | {
|
---|
527 | struct dmx_sct_filter_params *fp = (struct dmx_sct_filter_params *) data;
|
---|
528 |
|
---|
529 | // adding all dmx_sct_filter_params structure fields
|
---|
530 | // one by one to avoid padding problems
|
---|
531 | uint16_t pid = htons(fp->pid);
|
---|
532 | memcpy(&packet[size], &pid, 2);
|
---|
533 | size += 2;
|
---|
534 |
|
---|
535 | memcpy(&packet[size], fp->filter.filter, 16);
|
---|
536 | size += 16;
|
---|
537 | memcpy(&packet[size], fp->filter.mask, 16);
|
---|
538 | size += 16;
|
---|
539 | memcpy(&packet[size], fp->filter.mode, 16);
|
---|
540 | size += 16;
|
---|
541 |
|
---|
542 | uint32_t timeout = htonl(fp->timeout);
|
---|
543 | memcpy(&packet[size], &timeout, 4);
|
---|
544 | size += 4;
|
---|
545 |
|
---|
546 | uint32_t flags = htonl(fp->flags);
|
---|
547 | memcpy(&packet[size], &flags, 4);
|
---|
548 | size += 4;
|
---|
549 | }
|
---|
550 | else
|
---|
551 | {
|
---|
552 | memcpy(&packet[size], data, sct_filter_size); //dmx_sct_filter_params struct
|
---|
553 | size += sct_filter_size;
|
---|
554 | }
|
---|
555 | }
|
---|
556 | else // pid when stopping
|
---|
557 | {
|
---|
558 | if (client_proto_version >= 1)
|
---|
559 | {
|
---|
560 | uint16_t pid = htons(demux[demux_index].demux_fd[filter_number].pid);
|
---|
561 | memcpy(&packet[size], &pid, 2);
|
---|
562 | size += 2;
|
---|
563 | }
|
---|
564 | else
|
---|
565 | {
|
---|
566 | uint16_t pid = demux[demux_index].demux_fd[filter_number].pid;
|
---|
567 | packet[size++] = pid >> 8;
|
---|
568 | packet[size++] = pid & 0xff;
|
---|
569 | }
|
---|
570 | }
|
---|
571 | break;
|
---|
572 | }
|
---|
573 | default: //unknown request
|
---|
574 | {
|
---|
575 | cs_log("ERROR: dvbapi_net_send: invalid request");
|
---|
576 | return 0;
|
---|
577 | }
|
---|
578 | }
|
---|
579 |
|
---|
580 | // sending
|
---|
581 | cs_log_dump_dbg(D_DVBAPI, packet, size, "Sending packet to dvbapi client (fd=%d):", socket_fd);
|
---|
582 | send(socket_fd, &packet, size, MSG_DONTWAIT);
|
---|
583 |
|
---|
584 | // always returning success as the client could close socket
|
---|
585 | return 0;
|
---|
586 | }
|
---|
587 |
|
---|
588 | int32_t dvbapi_set_filter(int32_t demux_id, int32_t api, uint16_t pid, uint16_t caid, uint32_t provid, uchar *filt, uchar *mask, int32_t timeout, int32_t pidindex, int32_t type,
|
---|
589 | int8_t add_to_emm_list)
|
---|
590 | {
|
---|
591 | openxcas_set_caid(demux[demux_id].ECMpids[pidindex].CAID);
|
---|
592 | openxcas_set_ecm_pid(pid);
|
---|
593 | if (USE_OPENXCAS)
|
---|
594 | return 1;
|
---|
595 |
|
---|
596 | int32_t ret = -1, n = -1, i;
|
---|
597 |
|
---|
598 | for(i = 0; i < maxfilter && demux[demux_id].demux_fd[i].fd > 0; i++) { ; }
|
---|
599 |
|
---|
600 | if(i >= maxfilter)
|
---|
601 | {
|
---|
602 | cs_log_dbg(D_DVBAPI, "no free filter");
|
---|
603 | return -1;
|
---|
604 | }
|
---|
605 | n = i;
|
---|
606 |
|
---|
607 | demux[demux_id].demux_fd[n].pidindex = pidindex;
|
---|
608 | demux[demux_id].demux_fd[n].pid = pid;
|
---|
609 | demux[demux_id].demux_fd[n].caid = caid;
|
---|
610 | demux[demux_id].demux_fd[n].provid = provid;
|
---|
611 | demux[demux_id].demux_fd[n].type = type;
|
---|
612 |
|
---|
613 | switch(api)
|
---|
614 | {
|
---|
615 | case DVBAPI_3:
|
---|
616 | if (cfg.dvbapi_listenport || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX)
|
---|
617 | ret = demux[demux_id].demux_fd[n].fd = DUMMY_FD;
|
---|
618 | else
|
---|
619 | ret = demux[demux_id].demux_fd[n].fd = dvbapi_open_device(0, demux[demux_id].demux_index, demux[demux_id].adapter_index);
|
---|
620 | if(ret < 0) { return ret; } // return if device cant be opened!
|
---|
621 | struct dmx_sct_filter_params sFP2;
|
---|
622 |
|
---|
623 | memset(&sFP2, 0, sizeof(sFP2));
|
---|
624 |
|
---|
625 | sFP2.pid = pid;
|
---|
626 | sFP2.timeout = timeout;
|
---|
627 | sFP2.flags = DMX_IMMEDIATE_START;
|
---|
628 | if(cfg.dvbapi_boxtype == BOXTYPE_NEUMO)
|
---|
629 | {
|
---|
630 | //DeepThought: on dgs/cubestation and neumo images, perhaps others
|
---|
631 | //the following code is needed to descramble
|
---|
632 | sFP2.filter.filter[0] = filt[0];
|
---|
633 | sFP2.filter.mask[0] = mask[0];
|
---|
634 | sFP2.filter.filter[1] = 0;
|
---|
635 | sFP2.filter.mask[1] = 0;
|
---|
636 | sFP2.filter.filter[2] = 0;
|
---|
637 | sFP2.filter.mask[2] = 0;
|
---|
638 | memcpy(sFP2.filter.filter + 3, filt + 1, 16 - 3);
|
---|
639 | memcpy(sFP2.filter.mask + 3, mask + 1, 16 - 3);
|
---|
640 | //DeepThought: in the drivers of the dgs/cubestation and neumo images,
|
---|
641 | //dvbapi 1 and 3 are somehow mixed. In the kernel drivers, the DMX_SET_FILTER
|
---|
642 | //ioctl expects to receive a dmx_sct_filter_params structure (DVBAPI 3) but
|
---|
643 | //due to a bug its sets the "positive mask" wrongly (they should be all 0).
|
---|
644 | //On the other hand, the DMX_SET_FILTER1 ioctl also uses the dmx_sct_filter_params
|
---|
645 | //structure, which is incorrect (it should be dmxSctFilterParams).
|
---|
646 | //The only way to get it right is to call DMX_SET_FILTER1 with the argument
|
---|
647 | //expected by DMX_SET_FILTER. Otherwise, the timeout parameter is not passed correctly.
|
---|
648 | ret = dvbapi_ioctl(demux[demux_id].demux_fd[n].fd, DMX_SET_FILTER1, &sFP2);
|
---|
649 | }
|
---|
650 | else
|
---|
651 | {
|
---|
652 | memcpy(sFP2.filter.filter, filt, 16);
|
---|
653 | memcpy(sFP2.filter.mask, mask, 16);
|
---|
654 | if (cfg.dvbapi_listenport || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX)
|
---|
655 | ret = dvbapi_net_send(DVBAPI_DMX_SET_FILTER, demux[demux_id].socket_fd, demux_id, n, (unsigned char *) &sFP2, NULL, NULL);
|
---|
656 | else
|
---|
657 | ret = dvbapi_ioctl(demux[demux_id].demux_fd[n].fd, DMX_SET_FILTER, &sFP2);
|
---|
658 | }
|
---|
659 | break;
|
---|
660 |
|
---|
661 | case DVBAPI_1:
|
---|
662 | ret = demux[demux_id].demux_fd[n].fd = dvbapi_open_device(0, demux[demux_id].demux_index, demux[demux_id].adapter_index);
|
---|
663 | if(ret < 0) { return ret; } // return if device cant be opened!
|
---|
664 | struct dmxSctFilterParams sFP1;
|
---|
665 |
|
---|
666 | memset(&sFP1, 0, sizeof(sFP1));
|
---|
667 |
|
---|
668 | sFP1.pid = pid;
|
---|
669 | sFP1.timeout = timeout;
|
---|
670 | sFP1.flags = DMX_IMMEDIATE_START;
|
---|
671 | memcpy(sFP1.filter.filter, filt, 16);
|
---|
672 | memcpy(sFP1.filter.mask, mask, 16);
|
---|
673 | ret = dvbapi_ioctl(demux[demux_id].demux_fd[n].fd, DMX_SET_FILTER1, &sFP1);
|
---|
674 |
|
---|
675 | break;
|
---|
676 | #ifdef WITH_STAPI
|
---|
677 | case STAPI:
|
---|
678 | ret = stapi_set_filter(demux_id, pid, filt, mask, n, demux[demux_id].pmt_file);
|
---|
679 | if(ret != 0)
|
---|
680 | { demux[demux_id].demux_fd[n].fd = ret; }
|
---|
681 | else
|
---|
682 | { ret = -1; } // error setting filter!
|
---|
683 | break;
|
---|
684 | #endif
|
---|
685 | #ifdef WITH_COOLAPI
|
---|
686 | case COOLAPI:
|
---|
687 | demux[demux_id].demux_fd[n].fd = coolapi_open_device(demux[demux_id].demux_index, demux_id);
|
---|
688 | if(demux[demux_id].demux_fd[n].fd > 0)
|
---|
689 | { ret = coolapi_set_filter(demux[demux_id].demux_fd[n].fd, n, pid, filt, mask, type); }
|
---|
690 | break;
|
---|
691 | #endif
|
---|
692 | default:
|
---|
693 | break;
|
---|
694 | }
|
---|
695 | if(ret != -1) // filter set successful
|
---|
696 | {
|
---|
697 | cs_log_dbg(D_DVBAPI, "Demuxer %d Filter %d started successfully (caid %04X provid %06X pid %04X)", demux_id, n + 1, caid, provid, pid);
|
---|
698 | if(type == TYPE_EMM && add_to_emm_list){
|
---|
699 | add_emmfilter_to_list(demux_id, filt, caid, provid, pid, n + 1, true);
|
---|
700 | }
|
---|
701 | }
|
---|
702 | else
|
---|
703 | {
|
---|
704 | cs_log("ERROR: Could not start demux filter (api: %d errno=%d %s)", selected_api, errno, strerror(errno));
|
---|
705 | }
|
---|
706 | return ret;
|
---|
707 | }
|
---|
708 |
|
---|
709 | static int32_t dvbapi_detect_api(void)
|
---|
710 | {
|
---|
711 | #ifdef WITH_COOLAPI
|
---|
712 | selected_api = COOLAPI;
|
---|
713 | selected_box = 5;
|
---|
714 | disable_pmt_files = 1;
|
---|
715 | cfg.dvbapi_listenport = 0;
|
---|
716 | cs_log("Detected Coolstream API");
|
---|
717 | return 1;
|
---|
718 | #else
|
---|
719 | if (cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX || cfg.dvbapi_boxtype == BOXTYPE_PC ) {
|
---|
720 | selected_api = DVBAPI_3;
|
---|
721 | selected_box = 1;
|
---|
722 | if (cfg.dvbapi_listenport)
|
---|
723 | {
|
---|
724 | cs_log("Using TCP listen socket, API forced to DVBAPIv3 (%d), userconfig boxtype: %d", selected_api, cfg.dvbapi_boxtype);
|
---|
725 | }
|
---|
726 | else
|
---|
727 | {
|
---|
728 | cs_log("Using %s listen socket, API forced to DVBAPIv3 (%d), userconfig boxtype: %d", devices[selected_box].cam_socket_path, selected_api, cfg.dvbapi_boxtype);
|
---|
729 | }
|
---|
730 | return 1;
|
---|
731 | }
|
---|
732 | else
|
---|
733 | {
|
---|
734 | cfg.dvbapi_listenport = 0;
|
---|
735 | }
|
---|
736 |
|
---|
737 | int32_t i = 0, n = 0, devnum = -1, dmx_fd = 0, ret = 0, boxnum = sizeof(devices) / sizeof(struct box_devices);
|
---|
738 | char device_path[128], device_path2[128];
|
---|
739 |
|
---|
740 | while (i < boxnum)
|
---|
741 | {
|
---|
742 | snprintf(device_path2, sizeof(device_path2), devices[i].demux_device, 0);
|
---|
743 | snprintf(device_path, sizeof(device_path), devices[i].path, n);
|
---|
744 | strncat(device_path, device_path2, sizeof(device_path) - strlen(device_path) - 1);
|
---|
745 | // FIXME: *THIS SAMYGO CHECK IS UNTESTED*
|
---|
746 | // FIXME: Detect samygo, checking if default DVBAPI_3 device paths are sockets
|
---|
747 | if (i == 1) { // We need boxnum 1 only
|
---|
748 | struct stat sb;
|
---|
749 | if (stat(device_path, &sb) > 0 && S_ISSOCK(sb.st_mode)) {
|
---|
750 | selected_box = 0;
|
---|
751 | disable_pmt_files = 1;
|
---|
752 | is_samygo = 1;
|
---|
753 | devnum = i;
|
---|
754 | break;
|
---|
755 | }
|
---|
756 | }
|
---|
757 | if((dmx_fd = open(device_path, O_RDWR | O_NONBLOCK)) > 0)
|
---|
758 | {
|
---|
759 | devnum = i;
|
---|
760 | ret = close(dmx_fd);
|
---|
761 | break;
|
---|
762 | }
|
---|
763 | /* try at least 8 adapters */
|
---|
764 | if ((strchr(devices[i].path, '%') != NULL) && (n < 8)) n++; else { n = 0; i++; }
|
---|
765 | }
|
---|
766 |
|
---|
767 | if(devnum == -1) { return 0; }
|
---|
768 | selected_box = devnum;
|
---|
769 | if(selected_box > -1)
|
---|
770 | { selected_api = devices[selected_box].api; }
|
---|
771 |
|
---|
772 | if(ret < 0) { cs_log("ERROR: Could not close demuxer fd (errno=%d %s)", errno, strerror(errno)); } // log it here since some needed var are not inited before!
|
---|
773 | if(is_samygo){ cs_log("SAMYGO detected."); } // log it here since some needed var are not inited before!
|
---|
774 | #ifdef WITH_STAPI
|
---|
775 | if(devnum == 4 && stapi_open() == 0)
|
---|
776 | {
|
---|
777 | cs_log("ERROR: stapi: setting up stapi failed.");
|
---|
778 | return 0;
|
---|
779 | }
|
---|
780 | #endif
|
---|
781 | if(cfg.dvbapi_boxtype == BOXTYPE_NEUMO)
|
---|
782 | {
|
---|
783 | selected_api = DVBAPI_3; //DeepThought
|
---|
784 | }
|
---|
785 | cs_log("Detected %s Api: %d, userconfig boxtype: %d", device_path, selected_api, cfg.dvbapi_boxtype);
|
---|
786 | #endif
|
---|
787 | return 1;
|
---|
788 | }
|
---|
789 |
|
---|
790 | static int32_t dvbapi_read_device(int32_t dmx_fd, unsigned char *buf, int32_t length)
|
---|
791 | {
|
---|
792 | int32_t len, rc;
|
---|
793 | struct pollfd pfd[1];
|
---|
794 |
|
---|
795 | pfd[0].fd = dmx_fd;
|
---|
796 | pfd[0].events = (POLLIN | POLLPRI);
|
---|
797 |
|
---|
798 | rc = poll(pfd, 1, 7000);
|
---|
799 | if(rc < 1)
|
---|
800 | {
|
---|
801 | cs_log("ERROR: Read on %d timed out (errno=%d %s)", dmx_fd, errno, strerror(errno));
|
---|
802 | return -1;
|
---|
803 | }
|
---|
804 |
|
---|
805 | len = read(dmx_fd, buf, length);
|
---|
806 |
|
---|
807 | if(len < 1)
|
---|
808 | {
|
---|
809 | if(errno == EOVERFLOW)
|
---|
810 | {
|
---|
811 | cs_log("fd %d no valid data present since receiver reported an internal bufferoverflow!", dmx_fd);
|
---|
812 | return 0;
|
---|
813 | }
|
---|
814 | else if(errno != EBADF && errno !=EINVAL) // dont throw errors on invalid fd or invalid argument
|
---|
815 | {
|
---|
816 | cs_log("ERROR: Read error on fd %d (errno=%d %s)", dmx_fd, errno, strerror(errno));
|
---|
817 | }
|
---|
818 | }
|
---|
819 | else { cs_log_dump_dbg(D_TRACE, buf, len, "Readed:"); }
|
---|
820 | return len;
|
---|
821 | }
|
---|
822 |
|
---|
823 | int32_t dvbapi_open_device(int32_t type, int32_t num, int32_t adapter)
|
---|
824 | {
|
---|
825 | int32_t dmx_fd, ret;
|
---|
826 | int32_t ca_offset = 0;
|
---|
827 | char device_path[128], device_path2[128];
|
---|
828 |
|
---|
829 | if(cfg.dvbapi_listenport || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX)
|
---|
830 | return DUMMY_FD;
|
---|
831 |
|
---|
832 | if(type == 0)
|
---|
833 | {
|
---|
834 | snprintf(device_path2, sizeof(device_path2), devices[selected_box].demux_device, num);
|
---|
835 | snprintf(device_path, sizeof(device_path), devices[selected_box].path, adapter);
|
---|
836 |
|
---|
837 | strncat(device_path, device_path2, sizeof(device_path) - strlen(device_path) - 1);
|
---|
838 | }
|
---|
839 | else
|
---|
840 | {
|
---|
841 | if(cfg.dvbapi_boxtype == BOXTYPE_DUCKBOX || cfg.dvbapi_boxtype == BOXTYPE_DBOX2 || cfg.dvbapi_boxtype == BOXTYPE_UFS910)
|
---|
842 | { ca_offset = 1; }
|
---|
843 |
|
---|
844 | if(cfg.dvbapi_boxtype == BOXTYPE_QBOXHD)
|
---|
845 | { num = 0; }
|
---|
846 |
|
---|
847 | if(cfg.dvbapi_boxtype == BOXTYPE_PC)
|
---|
848 | { num = 0; }
|
---|
849 |
|
---|
850 | snprintf(device_path2, sizeof(device_path2), devices[selected_box].ca_device, num + ca_offset);
|
---|
851 | snprintf(device_path, sizeof(device_path), devices[selected_box].path, adapter);
|
---|
852 |
|
---|
853 | strncat(device_path, device_path2, sizeof(device_path) - strlen(device_path) - 1);
|
---|
854 | }
|
---|
855 |
|
---|
856 | if (is_samygo) {
|
---|
857 | struct sockaddr_un saddr;
|
---|
858 | memset(&saddr, 0, sizeof(saddr));
|
---|
859 | saddr.sun_family = AF_UNIX;
|
---|
860 | strncpy(saddr.sun_path, device_path, sizeof(saddr.sun_path) - 1);
|
---|
861 | dmx_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
---|
862 | ret = connect(dmx_fd, (struct sockaddr *)&saddr, sizeof(saddr));
|
---|
863 | if (ret < 0)
|
---|
864 | close(dmx_fd);
|
---|
865 | } else {
|
---|
866 | dmx_fd = ret = open(device_path, O_RDWR | O_NONBLOCK);
|
---|
867 | }
|
---|
868 |
|
---|
869 | if(ret < 0)
|
---|
870 | {
|
---|
871 | cs_log("ERROR: Can't open device %s (errno=%d %s)", device_path, errno, strerror(errno));
|
---|
872 | return -1;
|
---|
873 | }
|
---|
874 |
|
---|
875 | cs_log_dbg(D_DVBAPI, "Open device %s (fd %d)", device_path, dmx_fd);
|
---|
876 |
|
---|
877 | return dmx_fd;
|
---|
878 | }
|
---|
879 |
|
---|
880 | uint16_t tunemm_caid_map(uint8_t direct, uint16_t caid, uint16_t srvid)
|
---|
881 | {
|
---|
882 | int32_t i;
|
---|
883 | struct s_client *cl = cur_client();
|
---|
884 | TUNTAB *ttab = &cl->ttab;
|
---|
885 |
|
---|
886 | if (!ttab->ttnum)
|
---|
887 | return caid;
|
---|
888 |
|
---|
889 | if(direct)
|
---|
890 | {
|
---|
891 | for(i = 0; i < ttab->ttnum; i++)
|
---|
892 | {
|
---|
893 | if(caid == ttab->ttdata[i].bt_caidto
|
---|
894 | && (srvid == ttab->ttdata[i].bt_srvid || ttab->ttdata[i].bt_srvid == 0xFFFF || !ttab->ttdata[i].bt_srvid))
|
---|
895 | { return ttab->ttdata[i].bt_caidfrom; }
|
---|
896 | }
|
---|
897 | }
|
---|
898 | else
|
---|
899 | {
|
---|
900 | for(i = 0; i < ttab->ttnum; i++)
|
---|
901 | {
|
---|
902 | if(caid == ttab->ttdata[i].bt_caidfrom
|
---|
903 | && (srvid == ttab->ttdata[i].bt_srvid || ttab->ttdata[i].bt_srvid == 0xFFFF || !ttab->ttdata[i].bt_srvid))
|
---|
904 | { return ttab->ttdata[i].bt_caidto; }
|
---|
905 | }
|
---|
906 | }
|
---|
907 | return caid;
|
---|
908 | }
|
---|
909 |
|
---|
910 | int32_t dvbapi_stop_filter(int32_t demux_index, int32_t type)
|
---|
911 | {
|
---|
912 | int32_t g, ret = -1;
|
---|
913 |
|
---|
914 | for(g = 0; g < MAX_FILTER; g++) // just stop them all, we dont want to risk leaving any stale filters running due to lowering of maxfilters
|
---|
915 | {
|
---|
916 | if(demux[demux_index].demux_fd[g].type == type)
|
---|
917 | {
|
---|
918 | ret = dvbapi_stop_filternum(demux_index, g);
|
---|
919 | }
|
---|
920 | }
|
---|
921 | if(ret == -1) { return 0; } // on error return 0
|
---|
922 | else { return 1; }
|
---|
923 | }
|
---|
924 |
|
---|
925 | int32_t dvbapi_stop_filternum(int32_t demux_index, int32_t num)
|
---|
926 | {
|
---|
927 | int32_t retfilter = -1, retfd = -1, fd = demux[demux_index].demux_fd[num].fd;
|
---|
928 | if(fd > 0)
|
---|
929 | {
|
---|
930 | cs_log_dbg(D_DVBAPI, "Demuxer %d stop Filter %d (fd: %d api: %d, caid: %04X, provid: %06X, %spid: %04X)",
|
---|
931 | demux_index, num + 1, fd, selected_api, demux[demux_index].demux_fd[num].caid, demux[demux_index].demux_fd[num].provid,
|
---|
932 | (demux[demux_index].demux_fd[num].type == TYPE_ECM ? "ecm" : "emm"), demux[demux_index].demux_fd[num].pid);
|
---|
933 |
|
---|
934 | switch(selected_api)
|
---|
935 | {
|
---|
936 | case DVBAPI_3:
|
---|
937 | if (cfg.dvbapi_listenport || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX)
|
---|
938 | retfilter = dvbapi_net_send(DVBAPI_DMX_STOP, demux[demux_index].socket_fd, demux_index, num, NULL, NULL, NULL);
|
---|
939 | else
|
---|
940 | retfilter = dvbapi_ioctl(fd, DMX_STOP, NULL);
|
---|
941 | break;
|
---|
942 |
|
---|
943 | case DVBAPI_1:
|
---|
944 | retfilter = dvbapi_ioctl(fd, DMX_STOP, NULL);
|
---|
945 | break;
|
---|
946 |
|
---|
947 | #ifdef WITH_STAPI
|
---|
948 | case STAPI:
|
---|
949 | retfilter = stapi_remove_filter(demux_index, num, demux[demux_index].pmt_file);
|
---|
950 | if(retfilter != 1) // stapi returns 0 for error, 1 for all ok
|
---|
951 | {
|
---|
952 | retfilter = -1;
|
---|
953 | }
|
---|
954 | break;
|
---|
955 | #endif
|
---|
956 | #ifdef WITH_COOLAPI
|
---|
957 | case COOLAPI:
|
---|
958 | retfilter = coolapi_remove_filter(fd, num);
|
---|
959 | retfd = coolapi_close_device(fd);
|
---|
960 | break;
|
---|
961 | #endif
|
---|
962 | default:
|
---|
963 | break;
|
---|
964 | }
|
---|
965 | if(retfilter < 0)
|
---|
966 | {
|
---|
967 | cs_log("ERROR: Demuxer %d could not stop Filter %d (fd:%d api:%d errno=%d %s)", demux_index, num + 1, fd, selected_api, errno, strerror(errno));
|
---|
968 | }
|
---|
969 | #ifndef WITH_COOLAPI // no fd close for coolapi and stapi, all others do close fd!
|
---|
970 | if (!cfg.dvbapi_listenport && cfg.dvbapi_boxtype != BOXTYPE_PC_NODMX)
|
---|
971 | {
|
---|
972 | if(selected_api == STAPI) { retfd = 0; } // stapi closes its own filter fd!
|
---|
973 | else
|
---|
974 | {
|
---|
975 | flush_read_fd(demux_index, num, fd); // flush filter input buffer in attempt to avoid overflow receivers internal buffer
|
---|
976 | retfd = close(fd);
|
---|
977 | if(errno == 9) { retfd = 0; } // no error on bad file descriptor
|
---|
978 | }
|
---|
979 | }
|
---|
980 | else
|
---|
981 | retfd = 0;
|
---|
982 | #endif
|
---|
983 | if(retfd)
|
---|
984 | {
|
---|
985 | cs_log("ERROR: Demuxer %d could not close fd of Filter %d (fd=%d api:%d errno=%d %s)", demux_index, num + 1, fd,
|
---|
986 | selected_api, errno, strerror(errno));
|
---|
987 | }
|
---|
988 |
|
---|
989 | if(demux[demux_index].demux_fd[num].type == TYPE_ECM) //ecm filter stopped: reset index!
|
---|
990 | {
|
---|
991 | int32_t oldpid = demux[demux_index].demux_fd[num].pidindex;
|
---|
992 | int32_t curpid = demux[demux_index].pidindex;
|
---|
993 | int32_t idx = demux[demux_index].ECMpids[oldpid].index;
|
---|
994 | demux[demux_index].ECMpids[oldpid].index = 0;
|
---|
995 | if(idx) // if in use
|
---|
996 | {
|
---|
997 | int32_t i;
|
---|
998 | for(i = 0; i < demux[demux_index].STREAMpidcount; i++)
|
---|
999 | {
|
---|
1000 | int8_t match = 0;
|
---|
1001 | // check streams of old disabled ecmpid
|
---|
1002 | if(!demux[demux_index].ECMpids[oldpid].streams || ((demux[demux_index].ECMpids[oldpid].streams & (1 << i)) == (uint) (1 << i)))
|
---|
1003 | {
|
---|
1004 | // check if new ecmpid is using same streams
|
---|
1005 | if(curpid != -1 && (!demux[demux_index].ECMpids[curpid].streams || ((demux[demux_index].ECMpids[curpid].streams & (1 << i)) == (uint) (1 << i))))
|
---|
1006 | {
|
---|
1007 | continue; // found same stream on old and new ecmpid -> skip! (and leave it enabled!)
|
---|
1008 | }
|
---|
1009 | int32_t pidtobestopped = demux[demux_index].STREAMpids[i];
|
---|
1010 | int32_t j, k, otherdemuxpid, otherdemuxidx;
|
---|
1011 |
|
---|
1012 | for(j = 0; j < MAX_DEMUX; j++) // check other demuxers for same streampid with same index
|
---|
1013 | {
|
---|
1014 | if(demux[j].program_number == 0) { continue; } // skip empty demuxers
|
---|
1015 | if(demux_index == j) { continue; } // skip same demuxer
|
---|
1016 | if(demux[j].ca_mask != demux[demux_index].ca_mask) { continue;} // skip streampid running on other ca device
|
---|
1017 |
|
---|
1018 | otherdemuxpid = demux[j].pidindex;
|
---|
1019 | if(otherdemuxpid == -1) { continue; } // Other demuxer not descrambling yet
|
---|
1020 |
|
---|
1021 | otherdemuxidx = demux[j].ECMpids[otherdemuxpid].index;
|
---|
1022 | if(!otherdemuxidx || otherdemuxidx != idx) { continue; } // Other demuxer has no index yet, or index is different
|
---|
1023 |
|
---|
1024 | for(k = 0; k < demux[j].STREAMpidcount; k++)
|
---|
1025 | {
|
---|
1026 | if(!demux[j].ECMpids[otherdemuxpid].streams || ((demux[j].ECMpids[otherdemuxpid].streams & (1 << k)) == (uint) (1 << k)))
|
---|
1027 | {
|
---|
1028 | if(demux[j].STREAMpids[k] == pidtobestopped)
|
---|
1029 | {
|
---|
1030 | continue; // found same streampid enabled with same index on one or more other demuxers -> skip! (and leave it enabled!)
|
---|
1031 | }
|
---|
1032 | }
|
---|
1033 | match = 1; // matching stream found
|
---|
1034 | }
|
---|
1035 | }
|
---|
1036 |
|
---|
1037 | if(!match)
|
---|
1038 | {
|
---|
1039 | dvbapi_set_pid(demux_index, i, idx - 1, false); // disable streampid since its not used by this pid (or by the new ecmpid or any other demuxer!)
|
---|
1040 | }
|
---|
1041 | }
|
---|
1042 | }
|
---|
1043 | }
|
---|
1044 | }
|
---|
1045 |
|
---|
1046 | if(demux[demux_index].demux_fd[num].type == TYPE_EMM) // If emm type remove from emm filterlist
|
---|
1047 | {
|
---|
1048 | remove_emmfilter_from_list(demux_index, demux[demux_index].demux_fd[num].caid, demux[demux_index].demux_fd[num].provid, demux[demux_index].demux_fd[num].pid, num + 1);
|
---|
1049 | }
|
---|
1050 | demux[demux_index].demux_fd[num].fd = 0;
|
---|
1051 | demux[demux_index].demux_fd[num].type = 0;
|
---|
1052 | }
|
---|
1053 | if(retfilter < 0) { return retfilter; } // error on remove filter
|
---|
1054 | if(retfd < 0) { return retfd; } // error on close filter fd
|
---|
1055 | return 1; // all ok!
|
---|
1056 | }
|
---|
1057 |
|
---|
1058 | void dvbapi_start_filter(int32_t demux_id, int32_t pidindex, uint16_t pid, uint16_t caid, uint32_t provid, uchar table, uchar mask, int32_t timeout, int32_t type)
|
---|
1059 | {
|
---|
1060 | int32_t o;
|
---|
1061 | for(o = 0; o < maxfilter; o++) // check if ecmfilter is in use & stop all ecmfilters of lower status pids
|
---|
1062 | {
|
---|
1063 | if(demux[demux_id].demux_fd[o].fd > 0 &&
|
---|
1064 | demux[demux_id].demux_fd[o].pid == pid &&
|
---|
1065 | demux[demux_id].demux_fd[o].type == type && type == TYPE_ECM)
|
---|
1066 | {
|
---|
1067 | return;
|
---|
1068 | }
|
---|
1069 | }
|
---|
1070 | uchar filter[32];
|
---|
1071 | memset(filter, 0, 32);
|
---|
1072 |
|
---|
1073 | filter[0] = table;
|
---|
1074 | filter[16] = mask;
|
---|
1075 |
|
---|
1076 | cs_log_dbg(D_DVBAPI, "Demuxer %d try to start new filter for caid: %04X, provid: %06X, pid: %04X", demux_id, caid, provid, pid);
|
---|
1077 | dvbapi_set_filter(demux_id, selected_api, pid, caid, provid, filter, filter + 16, timeout, pidindex, type, 0);
|
---|
1078 | }
|
---|
1079 |
|
---|
1080 | void dvbapi_start_emm_filter(int32_t demux_index)
|
---|
1081 | {
|
---|
1082 | unsigned int j;
|
---|
1083 | if(!demux[demux_index].EMMpidcount)
|
---|
1084 | { return; }
|
---|
1085 |
|
---|
1086 | //if (demux[demux_index].emm_filter)
|
---|
1087 | // return;
|
---|
1088 |
|
---|
1089 |
|
---|
1090 | struct s_csystem_emm_filter *dmx_filter = NULL;
|
---|
1091 | unsigned int filter_count = 0;
|
---|
1092 | uint16_t caid, ncaid;
|
---|
1093 | uint32_t provid;
|
---|
1094 |
|
---|
1095 | struct s_reader *rdr = NULL;
|
---|
1096 | struct s_client *cl = cur_client();
|
---|
1097 | if(!cl || !cl->aureader_list)
|
---|
1098 | { return; }
|
---|
1099 |
|
---|
1100 | LL_ITER itr = ll_iter_create(cl->aureader_list);
|
---|
1101 | while((rdr = ll_iter_next(&itr)))
|
---|
1102 | {
|
---|
1103 | if(rdr->audisabled || !rdr->enable || (!is_network_reader(rdr) && rdr->card_status != CARD_INSERTED))
|
---|
1104 | { continue; }
|
---|
1105 |
|
---|
1106 | const struct s_cardsystem *csystem;
|
---|
1107 | uint16_t c, match;
|
---|
1108 | cs_log_dbg(D_DVBAPI, "Demuxer %d matching reader %s against available emmpids -> START!", demux_index, rdr->label);
|
---|
1109 | for(c = 0; c < demux[demux_index].EMMpidcount; c++)
|
---|
1110 | {
|
---|
1111 | caid = ncaid = demux[demux_index].EMMpids[c].CAID;
|
---|
1112 | if(!caid) continue;
|
---|
1113 |
|
---|
1114 | if(chk_is_betatunnel_caid(caid) == 2)
|
---|
1115 | {
|
---|
1116 | ncaid = tunemm_caid_map(FROM_TO, caid, demux[demux_index].program_number);
|
---|
1117 | }
|
---|
1118 | provid = demux[demux_index].EMMpids[c].PROVID;
|
---|
1119 | if (caid == ncaid)
|
---|
1120 | {
|
---|
1121 | match = emm_reader_match(rdr, caid, provid);
|
---|
1122 | }
|
---|
1123 | else
|
---|
1124 | {
|
---|
1125 | match = emm_reader_match(rdr, ncaid, provid);
|
---|
1126 | }
|
---|
1127 | if(match)
|
---|
1128 | {
|
---|
1129 | csystem = get_cardsystem_by_caid(caid);
|
---|
1130 | if(csystem)
|
---|
1131 | {
|
---|
1132 | if(caid != ncaid)
|
---|
1133 | {
|
---|
1134 | csystem = get_cardsystem_by_caid(ncaid);
|
---|
1135 | if(csystem && csystem->get_tunemm_filter)
|
---|
1136 | {
|
---|
1137 | csystem->get_tunemm_filter(rdr, &dmx_filter, &filter_count);
|
---|
1138 | cs_log_dbg(D_DVBAPI, "Demuxer %d setting emm filter for betatunnel: %04X -> %04X", demux_index, ncaid, caid);
|
---|
1139 | }
|
---|
1140 | else
|
---|
1141 | {
|
---|
1142 | cs_log_dbg(D_DVBAPI, "Demuxer %d cardsystem for emm filter for caid %04X of reader %s not found", demux_index, ncaid, rdr->label);
|
---|
1143 | continue;
|
---|
1144 | }
|
---|
1145 | }
|
---|
1146 | else if (csystem->get_emm_filter)
|
---|
1147 | {
|
---|
1148 | csystem->get_emm_filter(rdr, &dmx_filter, &filter_count);
|
---|
1149 | }
|
---|
1150 | }
|
---|
1151 | else
|
---|
1152 | {
|
---|
1153 | cs_log_dbg(D_DVBAPI, "Demuxer %d cardsystem for emm filter for caid %04X of reader %s not found", demux_index, caid, rdr->label);
|
---|
1154 | continue;
|
---|
1155 | }
|
---|
1156 |
|
---|
1157 | for(j = 0; j < filter_count ; j++)
|
---|
1158 | {
|
---|
1159 | if(dmx_filter[j].enabled == 0)
|
---|
1160 | { continue; }
|
---|
1161 |
|
---|
1162 | uchar filter[32];
|
---|
1163 | memset(filter, 0, sizeof(filter)); // reset filter
|
---|
1164 | uint32_t usefilterbytes = 16; // default use all filters
|
---|
1165 | memcpy(filter, dmx_filter[j].filter, usefilterbytes);
|
---|
1166 | memcpy(filter + 16, dmx_filter[j].mask, usefilterbytes);
|
---|
1167 | int32_t emmtype = dmx_filter[j].type;
|
---|
1168 |
|
---|
1169 | if(filter[0] && (((1 << (filter[0] % 0x80)) & rdr->b_nano) && !((1 << (filter[0] % 0x80)) & rdr->s_nano)))
|
---|
1170 | {
|
---|
1171 | cs_log_dbg(D_DVBAPI, "Demuxer %d reader %s emmfilter %d/%d blocked by userconfig -> SKIP!", demux_index, rdr->label, j+1, filter_count);
|
---|
1172 | continue;
|
---|
1173 | }
|
---|
1174 |
|
---|
1175 | if((rdr->blockemm & emmtype) && !(((1 << (filter[0] % 0x80)) & rdr->s_nano) || (rdr->saveemm & emmtype)))
|
---|
1176 | {
|
---|
1177 | cs_log_dbg(D_DVBAPI, "Demuxer %d reader %s emmfilter %d/%d blocked by userconfig -> SKIP!", demux_index, rdr->label, j+1, filter_count);
|
---|
1178 | continue;
|
---|
1179 | }
|
---|
1180 |
|
---|
1181 | if(demux[demux_index].EMMpids[c].type & emmtype)
|
---|
1182 | {
|
---|
1183 | cs_log_dbg(D_DVBAPI, "Demuxer %d reader %s emmfilter %d/%d type match -> ENABLE!", demux_index, rdr->label, j+1, filter_count);
|
---|
1184 | check_add_emmpid(demux_index, filter, c, emmtype);
|
---|
1185 | }
|
---|
1186 | else
|
---|
1187 | {
|
---|
1188 | cs_log_dbg(D_DVBAPI, "Demuxer %d reader %s emmfilter %d/%d type mismatch -> SKIP!", demux_index, rdr->label, j+1, filter_count);
|
---|
1189 | }
|
---|
1190 | }
|
---|
1191 |
|
---|
1192 | // dmx_filter not use below this point;
|
---|
1193 | NULLFREE(dmx_filter);
|
---|
1194 | }
|
---|
1195 | }
|
---|
1196 | cs_log_dbg(D_DVBAPI, "Demuxer %d matching reader %s against available emmpids -> DONE!", demux_index, rdr->label);
|
---|
1197 | }
|
---|
1198 | if(demux[demux_index].emm_filter == -1) // first run -1
|
---|
1199 | {
|
---|
1200 | demux[demux_index].emm_filter = 0;
|
---|
1201 | }
|
---|
1202 | cs_log_dbg(D_DVBAPI, "Demuxer %d handles %i emm filters", demux_index, demux[demux_index].emm_filter);
|
---|
1203 | }
|
---|
1204 |
|
---|
1205 | void dvbapi_add_ecmpid_int(int32_t demux_id, uint16_t caid, uint16_t ecmpid, uint32_t provid)
|
---|
1206 | {
|
---|
1207 | int32_t n, added = 0;
|
---|
1208 |
|
---|
1209 | if(demux[demux_id].ECMpidcount >= ECM_PIDS)
|
---|
1210 | { return; }
|
---|
1211 |
|
---|
1212 | int32_t stream = demux[demux_id].STREAMpidcount - 1;
|
---|
1213 | for(n = 0; n < demux[demux_id].ECMpidcount; n++)
|
---|
1214 | {
|
---|
1215 | if(stream > -1 && demux[demux_id].ECMpids[n].CAID == caid && demux[demux_id].ECMpids[n].ECM_PID == ecmpid && demux[demux_id].ECMpids[n].PROVID == provid)
|
---|
1216 | {
|
---|
1217 | if(!demux[demux_id].ECMpids[n].streams)
|
---|
1218 | {
|
---|
1219 | //we already got this caid/ecmpid as global, no need to add the single stream
|
---|
1220 | cs_log("Demuxer %d skipped stream CAID: %04X ECM_PID: %04X PROVID: %06X (Same as ECMPID %d)", demux_id, caid, ecmpid, provid, n);
|
---|
1221 | continue;
|
---|
1222 | }
|
---|
1223 | added = 1;
|
---|
1224 | demux[demux_id].ECMpids[n].streams |= (1 << stream);
|
---|
1225 | cs_log("Demuxer %d added stream to ecmpid %d CAID: %04X ECM_PID: %04X PROVID: %06X", demux_id, n, caid, ecmpid, provid);
|
---|
1226 | }
|
---|
1227 | }
|
---|
1228 |
|
---|
1229 | if(added == 1)
|
---|
1230 | { return; }
|
---|
1231 | for(n = 0; n < demux[demux_id].ECMpidcount; n++) // check for existing pid
|
---|
1232 | {
|
---|
1233 | if(demux[demux_id].ECMpids[n].CAID == caid && demux[demux_id].ECMpids[n].ECM_PID == ecmpid && demux[demux_id].ECMpids[n].PROVID == provid)
|
---|
1234 | { return; } // found same pid -> skip
|
---|
1235 | }
|
---|
1236 | demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].ECM_PID = ecmpid;
|
---|
1237 | demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].CAID = caid;
|
---|
1238 | demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].PROVID = provid;
|
---|
1239 | demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].CHID = 0x10000; // reset CHID
|
---|
1240 | demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].checked = 0;
|
---|
1241 | //demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].index = 0;
|
---|
1242 | demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].status = 0;
|
---|
1243 | demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].tries = 0xFE;
|
---|
1244 | demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].streams = 0; // reset streams!
|
---|
1245 | demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].irdeto_curindex = 0xFE; // reset
|
---|
1246 | demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].irdeto_maxindex = 0; // reset
|
---|
1247 | demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].irdeto_cycle = 0xFE; // reset
|
---|
1248 | demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].table = 0;
|
---|
1249 |
|
---|
1250 | cs_log("Demuxer %d ecmpid %d CAID: %04X ECM_PID: %04X PROVID: %06X", demux_id, demux[demux_id].ECMpidcount, caid, ecmpid, provid);
|
---|
1251 | if(caid_is_irdeto(caid)) { demux[demux_id].emmstart.time = 1; } // marker to fetch emms early irdeto needs them!
|
---|
1252 |
|
---|
1253 | demux[demux_id].ECMpidcount++;
|
---|
1254 | }
|
---|
1255 |
|
---|
1256 | void dvbapi_add_ecmpid(int32_t demux_id, uint16_t caid, uint16_t ecmpid, uint32_t provid)
|
---|
1257 | {
|
---|
1258 | dvbapi_add_ecmpid_int(demux_id, caid, ecmpid, provid);
|
---|
1259 | struct s_dvbapi_priority *joinentry;
|
---|
1260 |
|
---|
1261 | for(joinentry = dvbapi_priority; joinentry != NULL; joinentry = joinentry->next)
|
---|
1262 | {
|
---|
1263 | if((joinentry->type != 'j')
|
---|
1264 | || (joinentry->caid && joinentry->caid != caid)
|
---|
1265 | || (joinentry->provid && joinentry->provid != provid)
|
---|
1266 | || (joinentry->ecmpid && joinentry->ecmpid != ecmpid)
|
---|
1267 | || (joinentry->srvid && joinentry->srvid != demux[demux_id].program_number))
|
---|
1268 | { continue; }
|
---|
1269 | cs_log_dbg(D_DVBAPI, "Join ecmpid %04X:%06X:%04X to %04X:%06X:%04X",
|
---|
1270 | caid, provid, ecmpid, joinentry->mapcaid, joinentry->mapprovid, joinentry->mapecmpid);
|
---|
1271 | dvbapi_add_ecmpid_int(demux_id, joinentry->mapcaid, joinentry->mapecmpid, joinentry->mapprovid);
|
---|
1272 | }
|
---|
1273 | }
|
---|
1274 |
|
---|
1275 | void dvbapi_add_emmpid(int32_t demux_id, uint16_t caid, uint16_t emmpid, uint32_t provid, uint8_t type)
|
---|
1276 | {
|
---|
1277 | char typetext[40];
|
---|
1278 | cs_strncpy(typetext, ":", sizeof(typetext));
|
---|
1279 |
|
---|
1280 | if(type & 0x01) { strcat(typetext, "UNIQUE:"); }
|
---|
1281 | if(type & 0x02) { strcat(typetext, "SHARED:"); }
|
---|
1282 | if(type & 0x04) { strcat(typetext, "GLOBAL:"); }
|
---|
1283 | if(type & 0xF8) { strcat(typetext, "UNKNOWN:"); }
|
---|
1284 |
|
---|
1285 | uint16_t i;
|
---|
1286 | for(i = 0; i < demux[demux_id].EMMpidcount; i++)
|
---|
1287 | {
|
---|
1288 | if(demux[demux_id].EMMpids[i].PID == emmpid && demux[demux_id].EMMpids[i].CAID == caid && demux[demux_id].EMMpids[i].PROVID == provid)
|
---|
1289 | {
|
---|
1290 | if(!(demux[demux_id].EMMpids[i].type&type)){
|
---|
1291 | demux[demux_id].EMMpids[i].type |= type; // register this emm kind to this emmpid
|
---|
1292 | cs_log_dbg(D_DVBAPI, "Added to existing emmpid %d additional emmtype %s", demux[demux_id].EMMpidcount - 1, typetext);
|
---|
1293 | }
|
---|
1294 | return;
|
---|
1295 | }
|
---|
1296 | }
|
---|
1297 | demux[demux_id].EMMpids[demux[demux_id].EMMpidcount].PID = emmpid;
|
---|
1298 | demux[demux_id].EMMpids[demux[demux_id].EMMpidcount].CAID = caid;
|
---|
1299 | demux[demux_id].EMMpids[demux[demux_id].EMMpidcount].PROVID = provid;
|
---|
1300 | demux[demux_id].EMMpids[demux[demux_id].EMMpidcount++].type = type;
|
---|
1301 | cs_log_dbg(D_DVBAPI, "Added new emmpid %d CAID: %04X EMM_PID: %04X PROVID: %06X TYPE %s", demux[demux_id].EMMpidcount - 1, caid, emmpid, provid, typetext);
|
---|
1302 | }
|
---|
1303 |
|
---|
1304 | void dvbapi_parse_cat(int32_t demux_id, uchar *buf, int32_t len)
|
---|
1305 | {
|
---|
1306 | #ifdef WITH_COOLAPI
|
---|
1307 | // driver sometimes reports error if too many emm filter
|
---|
1308 | // but adding more ecm filter is no problem
|
---|
1309 | // ... so ifdef here instead of limiting MAX_FILTER
|
---|
1310 | demux[demux_id].max_emm_filter = 14;
|
---|
1311 | #else
|
---|
1312 | if(cfg.dvbapi_requestmode == 1)
|
---|
1313 | {
|
---|
1314 | uint16_t ecm_filter_needed = 0, n;
|
---|
1315 | for(n = 0; n < demux[demux_id].ECMpidcount; n++)
|
---|
1316 | {
|
---|
1317 | if(demux[demux_id].ECMpids[n].status > -1)
|
---|
1318 | { ecm_filter_needed++; }
|
---|
1319 | }
|
---|
1320 | if(maxfilter - ecm_filter_needed <= 0)
|
---|
1321 | { demux[demux_id].max_emm_filter = 0; }
|
---|
1322 | else
|
---|
1323 | { demux[demux_id].max_emm_filter = maxfilter - ecm_filter_needed; }
|
---|
1324 | }
|
---|
1325 | else
|
---|
1326 | {
|
---|
1327 | demux[demux_id].max_emm_filter = maxfilter - 1;
|
---|
1328 | }
|
---|
1329 | #endif
|
---|
1330 | uint16_t i, k;
|
---|
1331 |
|
---|
1332 | cs_log_dump_dbg(D_DVBAPI, buf, len, "cat:");
|
---|
1333 |
|
---|
1334 | for(i = 8; i < (b2i(2, buf + 1)&0xFFF) - 1; i += buf[i + 1] + 2)
|
---|
1335 | {
|
---|
1336 | if(buf[i] != 0x09) { continue; }
|
---|
1337 | if(demux[demux_id].EMMpidcount >= ECM_PIDS) { break; }
|
---|
1338 |
|
---|
1339 | uint16_t caid = b2i(2, buf + i + 2);
|
---|
1340 | uint16_t emm_pid = b2i(2, buf + i +4)&0x1FFF;
|
---|
1341 | uint32_t emm_provider = 0;
|
---|
1342 |
|
---|
1343 | switch(caid >> 8)
|
---|
1344 | {
|
---|
1345 | case 0x01:
|
---|
1346 | dvbapi_add_emmpid(demux_id, caid, emm_pid, 0, EMM_UNIQUE | EMM_GLOBAL);
|
---|
1347 | for(k = i + 7; k < i + buf[i + 1] + 2; k += 4)
|
---|
1348 | {
|
---|
1349 | emm_provider = b2i(2, buf + k + 2);
|
---|
1350 | emm_pid = b2i(2, buf + k)&0xFFF;
|
---|
1351 | dvbapi_add_emmpid(demux_id, caid, emm_pid, emm_provider, EMM_SHARED);
|
---|
1352 | }
|
---|
1353 | break;
|
---|
1354 | case 0x05:
|
---|
1355 | for(k = i + 6; k < i + buf[i + 1] + 2; k += buf[k + 1] + 2)
|
---|
1356 | {
|
---|
1357 | if (buf[k] == 0x14)
|
---|
1358 | {
|
---|
1359 | emm_provider = (b2i(3, buf + k + 2) & 0xFFFFF0); // viaccess fixup last digit is a dont care!
|
---|
1360 | dvbapi_add_emmpid(demux_id, caid, emm_pid, emm_provider, EMM_UNIQUE | EMM_SHARED | EMM_GLOBAL);
|
---|
1361 | }
|
---|
1362 | }
|
---|
1363 | break;
|
---|
1364 | case 0x18:
|
---|
1365 | if(buf[i + 1] == 0x07 || buf[i + 1] == 0x0B)
|
---|
1366 | {
|
---|
1367 | for(k = i + 7; k < i + 7 + buf[i + 6]; k += 2)
|
---|
1368 | {
|
---|
1369 | emm_provider = b2i(2, buf + k);
|
---|
1370 | dvbapi_add_emmpid(demux_id, caid, emm_pid, emm_provider, EMM_UNIQUE | EMM_SHARED | EMM_GLOBAL);
|
---|
1371 | }
|
---|
1372 | }
|
---|
1373 | else
|
---|
1374 | {
|
---|
1375 | dvbapi_add_emmpid(demux_id, caid, emm_pid, emm_provider, EMM_UNIQUE | EMM_SHARED | EMM_GLOBAL);
|
---|
1376 | }
|
---|
1377 | break;
|
---|
1378 | default:
|
---|
1379 | dvbapi_add_emmpid(demux_id, caid, emm_pid, 0, EMM_UNIQUE | EMM_SHARED | EMM_GLOBAL);
|
---|
1380 | break;
|
---|
1381 | }
|
---|
1382 | }
|
---|
1383 | return;
|
---|
1384 | }
|
---|
1385 |
|
---|
1386 | static pthread_mutex_t lockindex;
|
---|
1387 | int32_t dvbapi_get_descindex(int32_t demux_index)
|
---|
1388 | {
|
---|
1389 | int32_t i, j, idx = 1, fail = 1;
|
---|
1390 | if(cfg.dvbapi_boxtype == BOXTYPE_NEUMO)
|
---|
1391 | {
|
---|
1392 | idx = 0;
|
---|
1393 | sscanf(demux[demux_index].pmt_file, "pmt%3d.tmp", &idx);
|
---|
1394 | idx++; // fixup
|
---|
1395 | return idx;
|
---|
1396 | }
|
---|
1397 | pthread_mutex_lock(&lockindex); // to avoid race when readers become responsive!
|
---|
1398 | while(fail)
|
---|
1399 | {
|
---|
1400 | fail = 0;
|
---|
1401 | for(i = 0; i < MAX_DEMUX && !fail; i++)
|
---|
1402 | {
|
---|
1403 | for(j = 0; j < demux[i].ECMpidcount && !fail; j++)
|
---|
1404 | {
|
---|
1405 | if(demux[i].ECMpids[j].index == idx)
|
---|
1406 | {
|
---|
1407 | fail = 1;
|
---|
1408 | idx++;
|
---|
1409 | }
|
---|
1410 | }
|
---|
1411 | }
|
---|
1412 | cs_sleepms(1);
|
---|
1413 | }
|
---|
1414 | pthread_mutex_unlock(&lockindex); // and release it!
|
---|
1415 | return idx;
|
---|
1416 | }
|
---|
1417 |
|
---|
1418 | void dvbapi_set_pid(int32_t demux_id, int32_t num, int32_t idx, bool enable)
|
---|
1419 | {
|
---|
1420 | int32_t i, currentfd;
|
---|
1421 | if(demux[demux_id].pidindex == -1 && enable) return; // no current pid on enable? --> exit
|
---|
1422 |
|
---|
1423 | switch(selected_api)
|
---|
1424 | {
|
---|
1425 | #ifdef WITH_STAPI
|
---|
1426 | case STAPI:
|
---|
1427 | if(!enable) idx = -1;
|
---|
1428 | stapi_set_pid(demux_id, num, idx, demux[demux_id].STREAMpids[num], demux[demux_id].pmt_file); // only used to disable pids!!!
|
---|
1429 | break;
|
---|
1430 | #endif
|
---|
1431 | #ifdef WITH_COOLAPI
|
---|
1432 | case COOLAPI:
|
---|
1433 | break;
|
---|
1434 | #endif
|
---|
1435 | default:
|
---|
1436 | for(i = 0; i < MAX_DEMUX; i++)
|
---|
1437 | {
|
---|
1438 | if(((demux[demux_id].ca_mask & (1 << i)) == (uint) (1 << i)))
|
---|
1439 | {
|
---|
1440 | int8_t action = 0;
|
---|
1441 | if(enable){
|
---|
1442 | action = update_streampid_list(i, demux[demux_id].STREAMpids[num], idx);
|
---|
1443 | }
|
---|
1444 | if(!enable){
|
---|
1445 | action = remove_streampid_from_list(i, demux[demux_id].STREAMpids[num], idx);
|
---|
1446 | }
|
---|
1447 |
|
---|
1448 | if(action != NO_STREAMPID_LISTED && action != FOUND_STREAMPID_INDEX && action != ADDED_STREAMPID_INDEX)
|
---|
1449 | {
|
---|
1450 | ca_pid_t ca_pid2;
|
---|
1451 | memset(&ca_pid2, 0, sizeof(ca_pid2));
|
---|
1452 | ca_pid2.pid = demux[demux_id].STREAMpids[num];
|
---|
1453 |
|
---|
1454 | // removed last of this streampid on ca? -> disable this pid with -1 on this ca
|
---|
1455 | if((action == REMOVED_STREAMPID_LASTINDEX) && (is_ca_used(i, ca_pid2.pid) == CA_IS_CLEAR)) idx = -1;
|
---|
1456 |
|
---|
1457 | // removed index of streampid that is used to decode on ca -> get a fresh one
|
---|
1458 | if(action == REMOVED_DECODING_STREAMPID_INDEX)
|
---|
1459 | {
|
---|
1460 | idx = is_ca_used(i, demux[demux_id].STREAMpids[num]); // get an active index for this pid and enable it on ca device
|
---|
1461 | enable = 1;
|
---|
1462 | }
|
---|
1463 |
|
---|
1464 | ca_pid2.index = idx;
|
---|
1465 | cs_log_dbg(D_DVBAPI, "Demuxer %d %s stream %d pid=0x%04x index=%d on ca%d", demux_id,
|
---|
1466 | (enable ? "enable" : "disable"), num + 1, ca_pid2.pid, ca_pid2.index, i);
|
---|
1467 |
|
---|
1468 | if(cfg.dvbapi_boxtype == BOXTYPE_PC || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX)
|
---|
1469 | dvbapi_net_send(DVBAPI_CA_SET_PID, demux[demux_id].socket_fd, demux_id, -1 /*unused*/, (unsigned char *) &ca_pid2, NULL, NULL);
|
---|
1470 | else
|
---|
1471 | {
|
---|
1472 | currentfd = ca_fd[i];
|
---|
1473 | if(currentfd <= 0)
|
---|
1474 | {
|
---|
1475 | currentfd = dvbapi_open_device(1, i, demux[demux_id].adapter_index);
|
---|
1476 | ca_fd[i] = currentfd; // save fd of this ca
|
---|
1477 | }
|
---|
1478 | if(currentfd > 0)
|
---|
1479 | {
|
---|
1480 | if(dvbapi_ioctl(currentfd, CA_SET_PID, &ca_pid2) == -1)
|
---|
1481 | cs_log_dbg(D_TRACE | D_DVBAPI,"CA_SET_PID ioctl error (errno=%d %s)", errno, strerror(errno));
|
---|
1482 | int8_t result = is_ca_used(i,0); // check if in use by any pid
|
---|
1483 | if(!enable && result == CA_IS_CLEAR){
|
---|
1484 | cs_log_dbg(D_DVBAPI, "Demuxer %d close now unused CA%d device", demux_id, i);
|
---|
1485 | int32_t ret = close(currentfd);
|
---|
1486 | if(ret < 0) { cs_log("ERROR: Could not close demuxer fd (errno=%d %s)", errno, strerror(errno)); }
|
---|
1487 | currentfd = ca_fd[i] = 0;
|
---|
1488 | }
|
---|
1489 | }
|
---|
1490 | }
|
---|
1491 | }
|
---|
1492 | }
|
---|
1493 | }
|
---|
1494 | break;
|
---|
1495 | }
|
---|
1496 | return;
|
---|
1497 | }
|
---|
1498 |
|
---|
1499 | void dvbapi_stop_all_descrambling(void)
|
---|
1500 | {
|
---|
1501 | int32_t j;
|
---|
1502 | for(j = 0; j < MAX_DEMUX; j++)
|
---|
1503 | {
|
---|
1504 | if(demux[j].program_number == 0) { continue; }
|
---|
1505 | dvbapi_stop_descrambling(j);
|
---|
1506 | }
|
---|
1507 | }
|
---|
1508 |
|
---|
1509 | void dvbapi_stop_descrambling(int32_t demux_id)
|
---|
1510 | {
|
---|
1511 | int32_t i;
|
---|
1512 | if(demux[demux_id].program_number == 0) { return; }
|
---|
1513 | char channame[32];
|
---|
1514 | i = demux[demux_id].pidindex;
|
---|
1515 | if(i < 0) { i = 0; }
|
---|
1516 | demux[demux_id].pidindex = -1; // no ecmpid is to be descrambling since we start stop descrambling!
|
---|
1517 | get_servicename(dvbapi_client, demux[demux_id].program_number, demux[demux_id].ECMpidcount > 0 ? demux[demux_id].ECMpids[i].CAID : 0, channame);
|
---|
1518 | cs_log_dbg(D_DVBAPI, "Demuxer %d stop descrambling program number %04X (%s)", demux_id, demux[demux_id].program_number, channame);
|
---|
1519 | dvbapi_stop_filter(demux_id, TYPE_EMM);
|
---|
1520 | if(demux[demux_id].ECMpidcount > 0)
|
---|
1521 | {
|
---|
1522 | dvbapi_stop_filter(demux_id, TYPE_ECM);
|
---|
1523 | }
|
---|
1524 |
|
---|
1525 | memset(&demux[demux_id], 0 , sizeof(DEMUXTYPE));
|
---|
1526 | demux[demux_id].pidindex = -1;
|
---|
1527 | demux[demux_id].curindex = -1;
|
---|
1528 | if (!cfg.dvbapi_listenport && cfg.dvbapi_boxtype != BOXTYPE_PC_NODMX)
|
---|
1529 | unlink(ECMINFO_FILE);
|
---|
1530 | return;
|
---|
1531 | }
|
---|
1532 |
|
---|
1533 | int32_t dvbapi_start_descrambling(int32_t demux_id, int32_t pid, int8_t checked)
|
---|
1534 | {
|
---|
1535 | int32_t started = 0; // in case ecmfilter started = 1
|
---|
1536 | int32_t fake_ecm = 0;
|
---|
1537 | ECM_REQUEST *er;
|
---|
1538 | struct s_reader *rdr;
|
---|
1539 | if(!(er = get_ecmtask())) { return started; }
|
---|
1540 | demux[demux_id].ECMpids[pid].checked = checked + 1; // mark this pid as checked!
|
---|
1541 |
|
---|
1542 | struct s_dvbapi_priority *p;
|
---|
1543 | for(p = dvbapi_priority; p != NULL ; p = p->next)
|
---|
1544 | {
|
---|
1545 | if((p->type != 'p')
|
---|
1546 | || (p->caid && p->caid != demux[demux_id].ECMpids[pid].CAID)
|
---|
1547 | || (p->provid && p->provid != demux[demux_id].ECMpids[pid].PROVID)
|
---|
1548 | || (p->ecmpid && p->ecmpid != demux[demux_id].ECMpids[pid].ECM_PID)
|
---|
1549 | || (p->srvid && p->srvid != demux[demux_id].program_number)
|
---|
1550 | || (p->pidx && p->pidx-1 != pid))
|
---|
1551 | { continue; }
|
---|
1552 | // if found chid and first run apply chid filter, on forced pids always apply!
|
---|
1553 | if(p->type == 'p' && p->chid < 0x10000 && (demux[demux_id].ECMpids[pid].checked == 1 || (p && p->force)))
|
---|
1554 | {
|
---|
1555 | if(demux[demux_id].ECMpids[pid].CHID < 0x10000) // channelcache delivered chid
|
---|
1556 | {
|
---|
1557 | er->chid = demux[demux_id].ECMpids[pid].CHID;
|
---|
1558 | }
|
---|
1559 | else
|
---|
1560 | {
|
---|
1561 | er->chid = p->chid; // no channelcache or no chid in use, so use prio chid
|
---|
1562 | demux[demux_id].ECMpids[pid].CHID = p->chid;
|
---|
1563 | }
|
---|
1564 | //cs_log("********* CHID %04X **************", demux[demux_id].ECMpids[pid].CHID);
|
---|
1565 | break; // we only accept one!
|
---|
1566 | }
|
---|
1567 | else
|
---|
1568 | {
|
---|
1569 | if(demux[demux_id].ECMpids[pid].CHID < 0x10000) // channelcache delivered chid
|
---|
1570 | {
|
---|
1571 | er->chid = demux[demux_id].ECMpids[pid].CHID;
|
---|
1572 | }
|
---|
1573 | else // no channelcache or no chid in use
|
---|
1574 | {
|
---|
1575 | er->chid = 0;
|
---|
1576 | demux[demux_id].ECMpids[pid].CHID = 0x10000;
|
---|
1577 | }
|
---|
1578 | }
|
---|
1579 | }
|
---|
1580 | er->srvid = demux[demux_id].program_number;
|
---|
1581 | er->caid = demux[demux_id].ECMpids[pid].CAID;
|
---|
1582 | er->pid = demux[demux_id].ECMpids[pid].ECM_PID;
|
---|
1583 | er->prid = demux[demux_id].ECMpids[pid].PROVID;
|
---|
1584 | er->vpid = demux[demux_id].ECMpids[pid].VPID;
|
---|
1585 | er->pmtpid = demux[demux_id].pmtpid;
|
---|
1586 |
|
---|
1587 | struct timeb now;
|
---|
1588 | cs_ftime(&now);
|
---|
1589 | for(rdr = first_active_reader; rdr != NULL ; rdr = rdr->next)
|
---|
1590 | {
|
---|
1591 | int8_t match = matching_reader(er, rdr); // check for matching reader
|
---|
1592 | int64_t gone = comp_timeb(&now, &rdr->emm_last);
|
---|
1593 | if(gone > 3600*1000 && rdr->needsemmfirst && caid_is_irdeto(er->caid))
|
---|
1594 | {
|
---|
1595 | cs_log("Warning reader %s received no emms for the last %d seconds -> skip, this reader needs emms first!", rdr->label,
|
---|
1596 | (int)(gone/1000));
|
---|
1597 | continue; // skip this card needs to process emms first before it can be used for descramble
|
---|
1598 | }
|
---|
1599 | if(p && p->force) { match = 1; } // forced pid always started!
|
---|
1600 |
|
---|
1601 | if(!match) // if this reader does not match, check betatunnel for it
|
---|
1602 | match = lb_check_auto_betatunnel(er, rdr);
|
---|
1603 |
|
---|
1604 | if(!match && chk_is_betatunnel_caid(er->caid)) // these caids might be tunneled invisible by peers
|
---|
1605 | { match = 1; } // so make it a match to try it!
|
---|
1606 |
|
---|
1607 | if(config_enabled(CS_CACHEEX) && (!match && (cacheex_is_match_alias(dvbapi_client, er)))) // check if cache-ex is matching
|
---|
1608 | {
|
---|
1609 | match = 1; // so make it a match to try it!
|
---|
1610 | }
|
---|
1611 |
|
---|
1612 | // BISS or FAKE CAID
|
---|
1613 | // ecm stream pid is fake, so send out one fake ecm request
|
---|
1614 | // special treatment: if we asked the cw first without starting a filter the cw request will be killed due to no ecmfilter started
|
---|
1615 | if(caid_is_fake(demux[demux_id].ECMpids[pid].CAID) || caid_is_biss(demux[demux_id].ECMpids[pid].CAID))
|
---|
1616 | {
|
---|
1617 | int32_t j, n;
|
---|
1618 | er->ecmlen = 5;
|
---|
1619 | er->ecm[0] = 0x80; // to pass the cache check it must be 0x80 or 0x81
|
---|
1620 | er->ecm[1] = 0x00;
|
---|
1621 | er->ecm[2] = 0x02;
|
---|
1622 | i2b_buf(2, er->srvid, er->ecm + 3);
|
---|
1623 |
|
---|
1624 | for(j = 0, n = 5; j < demux[demux_id].STREAMpidcount; j++, n += 2)
|
---|
1625 | {
|
---|
1626 | i2b_buf(2, demux[demux_id].STREAMpids[j], er->ecm + n);
|
---|
1627 | er->ecm[2] += 2;
|
---|
1628 | er->ecmlen += 2;
|
---|
1629 | }
|
---|
1630 |
|
---|
1631 | cs_log("Demuxer %d trying to descramble PID %d CAID %04X PROVID %06X ECMPID %04X ANY CHID PMTPID %04X VPID %04X", demux_id, pid,
|
---|
1632 | demux[demux_id].ECMpids[pid].CAID, demux[demux_id].ECMpids[pid].PROVID, demux[demux_id].ECMpids[pid].ECM_PID,
|
---|
1633 | demux[demux_id].pmtpid, demux[demux_id].ECMpids[pid].VPID);
|
---|
1634 |
|
---|
1635 | demux[demux_id].curindex = pid; // set current pid to the fresh started one
|
---|
1636 |
|
---|
1637 | dvbapi_start_filter(demux_id, pid, demux[demux_id].ECMpids[pid].ECM_PID, demux[demux_id].ECMpids[pid].CAID,
|
---|
1638 | demux[demux_id].ECMpids[pid].PROVID, 0x80, 0xF0, 3000, TYPE_ECM);
|
---|
1639 | started = 1;
|
---|
1640 |
|
---|
1641 | request_cw(dvbapi_client, er, demux_id, 0); // do not register ecm since this try!
|
---|
1642 | fake_ecm = 1;
|
---|
1643 | break; // we started an ecmfilter so stop looking for next matching reader!
|
---|
1644 | }
|
---|
1645 | if(match) // if matching reader found check for irdeto cas if local irdeto card check if it received emms in last 60 minutes
|
---|
1646 | {
|
---|
1647 |
|
---|
1648 | if(caid_is_irdeto(er->caid)) // irdeto cas init irdeto_curindex to wait for first index (00)
|
---|
1649 | {
|
---|
1650 | if(demux[demux_id].ECMpids[pid].irdeto_curindex == 0xFE) { demux[demux_id].ECMpids[pid].irdeto_curindex = 0x00; }
|
---|
1651 | }
|
---|
1652 |
|
---|
1653 | if(p && p->chid < 0x10000) // do we prio a certain chid?
|
---|
1654 | {
|
---|
1655 | cs_log("Demuxer %d trying to descramble PID %d CAID %04X PROVID %06X ECMPID %04X CHID %04X PMTPID %04X VPID %04X", demux_id, pid,
|
---|
1656 | demux[demux_id].ECMpids[pid].CAID, demux[demux_id].ECMpids[pid].PROVID, demux[demux_id].ECMpids[pid].ECM_PID,
|
---|
1657 | demux[demux_id].ECMpids[pid].CHID, demux[demux_id].pmtpid, demux[demux_id].ECMpids[pid].VPID);
|
---|
1658 | }
|
---|
1659 | else
|
---|
1660 | {
|
---|
1661 | cs_log("Demuxer %d trying to descramble PID %d CAID %04X PROVID %06X ECMPID %04X ANY CHID PMTPID %04X VPID %04X", demux_id, pid,
|
---|
1662 | demux[demux_id].ECMpids[pid].CAID, demux[demux_id].ECMpids[pid].PROVID, demux[demux_id].ECMpids[pid].ECM_PID,
|
---|
1663 | demux[demux_id].pmtpid, demux[demux_id].ECMpids[pid].VPID);
|
---|
1664 | }
|
---|
1665 |
|
---|
1666 | demux[demux_id].curindex = pid; // set current pid to the fresh started one
|
---|
1667 |
|
---|
1668 | dvbapi_start_filter(demux_id, pid, demux[demux_id].ECMpids[pid].ECM_PID, demux[demux_id].ECMpids[pid].CAID,
|
---|
1669 | demux[demux_id].ECMpids[pid].PROVID, 0x80, 0xF0, 3000, TYPE_ECM);
|
---|
1670 | started = 1;
|
---|
1671 | break; // we started an ecmfilter so stop looking for next matching reader!
|
---|
1672 | }
|
---|
1673 | }
|
---|
1674 | if(demux[demux_id].curindex != pid)
|
---|
1675 | {
|
---|
1676 | cs_log("Demuxer %d impossible to descramble PID %d CAID %04X PROVID %06X ECMPID %04X PMTPID %04X (NO MATCHING READER)", demux_id, pid,
|
---|
1677 | demux[demux_id].ECMpids[pid].CAID, demux[demux_id].ECMpids[pid].PROVID, demux[demux_id].ECMpids[pid].ECM_PID, demux[demux_id].pmtpid);
|
---|
1678 | demux[demux_id].ECMpids[pid].checked = 4; // flag this pid as checked
|
---|
1679 | demux[demux_id].ECMpids[pid].status = -1; // flag this pid as unusable
|
---|
1680 | dvbapi_edit_channel_cache(demux_id, pid, 0); // remove this pid from channelcache
|
---|
1681 | }
|
---|
1682 | if(!fake_ecm) { NULLFREE(er); }
|
---|
1683 | return started;
|
---|
1684 | }
|
---|
1685 |
|
---|
1686 | struct s_dvbapi_priority *dvbapi_check_prio_match_emmpid(int32_t demux_id, uint16_t caid, uint32_t provid, char type)
|
---|
1687 | {
|
---|
1688 | struct s_dvbapi_priority *p;
|
---|
1689 | int32_t i;
|
---|
1690 |
|
---|
1691 | uint16_t ecm_pid = 0;
|
---|
1692 | for(i = 0; i < demux[demux_id].ECMpidcount; i++)
|
---|
1693 | {
|
---|
1694 | if((demux[demux_id].ECMpids[i].CAID == caid) && (demux[demux_id].ECMpids[i].PROVID == provid))
|
---|
1695 | {
|
---|
1696 | ecm_pid = demux[demux_id].ECMpids[i].ECM_PID;
|
---|
1697 | break;
|
---|
1698 | }
|
---|
1699 | }
|
---|
1700 |
|
---|
1701 | if(!ecm_pid)
|
---|
1702 | { return NULL; }
|
---|
1703 |
|
---|
1704 | for(p = dvbapi_priority; p != NULL; p = p->next)
|
---|
1705 | {
|
---|
1706 | if(p->type != type
|
---|
1707 | || (p->caid && p->caid != caid)
|
---|
1708 | || (p->provid && p->provid != provid)
|
---|
1709 | || (p->ecmpid && p->ecmpid != ecm_pid)
|
---|
1710 | || (p->srvid && p->srvid != demux[demux_id].program_number)
|
---|
1711 | || (p->pidx && p->pidx-1 !=i)
|
---|
1712 | || (p->type == 'i' && (p->chid < 0x10000)))
|
---|
1713 | { continue; }
|
---|
1714 | return p;
|
---|
1715 | }
|
---|
1716 | return NULL;
|
---|
1717 | }
|
---|
1718 |
|
---|
1719 | struct s_dvbapi_priority *dvbapi_check_prio_match(int32_t demux_id, int32_t pidindex, char type)
|
---|
1720 | {
|
---|
1721 | struct s_dvbapi_priority *p;
|
---|
1722 | struct s_ecmpids *ecmpid = &demux[demux_id].ECMpids[pidindex];
|
---|
1723 |
|
---|
1724 | for(p = dvbapi_priority; p != NULL; p = p->next)
|
---|
1725 | {
|
---|
1726 | if(p->type != type
|
---|
1727 | || (p->caid && p->caid != ecmpid->CAID)
|
---|
1728 | || (p->provid && p->provid != ecmpid->PROVID)
|
---|
1729 | || (p->ecmpid && p->ecmpid != ecmpid->ECM_PID)
|
---|
1730 | || (p->srvid && p->srvid != demux[demux_id].program_number)
|
---|
1731 | //|| (p->type == 'i' && (p->chid > -1))) ///????
|
---|
1732 | || (p->pidx && p->pidx-1 != pidindex)
|
---|
1733 | || (p->chid < 0x10000 && p->chid != ecmpid->CHID))
|
---|
1734 | { continue; }
|
---|
1735 | return p;
|
---|
1736 | }
|
---|
1737 | return NULL;
|
---|
1738 | }
|
---|
1739 |
|
---|
1740 | void dvbapi_process_emm(int32_t demux_index, int32_t filter_num, unsigned char *buffer, uint32_t len)
|
---|
1741 | {
|
---|
1742 | EMM_PACKET epg;
|
---|
1743 |
|
---|
1744 | cs_log_dbg(D_DVBAPI, "Demuxer %d Filter %d fetched emm data", demux_index, filter_num + 1); // emm shown with -d64
|
---|
1745 |
|
---|
1746 | struct s_emm_filter *filter = get_emmfilter_by_filternum(demux_index, filter_num + 1);
|
---|
1747 |
|
---|
1748 | if(!filter)
|
---|
1749 | {
|
---|
1750 | cs_log_dbg(D_DVBAPI, "Demuxer %d Filter %d no filter matches -> SKIP!", demux_index, filter_num +1);
|
---|
1751 | return;
|
---|
1752 | }
|
---|
1753 |
|
---|
1754 | uint32_t provider = filter->provid;
|
---|
1755 | uint16_t caid = filter->caid;
|
---|
1756 |
|
---|
1757 | struct s_dvbapi_priority *mapentry = dvbapi_check_prio_match_emmpid(filter->demux_id, filter->caid, filter->provid, 'm');
|
---|
1758 | if(mapentry)
|
---|
1759 | {
|
---|
1760 | cs_log_dbg(D_DVBAPI, "Demuxer %d mapping EMM from %04X:%06X to %04X:%06X", demux_index, caid, provider, mapentry->mapcaid,
|
---|
1761 | mapentry->mapprovid);
|
---|
1762 | caid = mapentry->mapcaid;
|
---|
1763 | provider = mapentry->mapprovid;
|
---|
1764 | }
|
---|
1765 |
|
---|
1766 | memset(&epg, 0, sizeof(epg));
|
---|
1767 |
|
---|
1768 | i2b_buf(2, caid, epg.caid);
|
---|
1769 | i2b_buf(4, provider, epg.provid);
|
---|
1770 |
|
---|
1771 | epg.emmlen = len > sizeof(epg.emm) ? sizeof(epg.emm) : len;
|
---|
1772 | memcpy(epg.emm, buffer, epg.emmlen);
|
---|
1773 |
|
---|
1774 | if(config_enabled(READER_IRDETO) && chk_is_betatunnel_caid(caid) == 2)
|
---|
1775 | {
|
---|
1776 | uint16_t ncaid = tunemm_caid_map(FROM_TO, caid, demux[demux_index].program_number);
|
---|
1777 | if(caid != ncaid)
|
---|
1778 | {
|
---|
1779 | irdeto_add_emm_header(&epg);
|
---|
1780 | i2b_buf(2, ncaid, epg.caid);
|
---|
1781 | }
|
---|
1782 | }
|
---|
1783 |
|
---|
1784 | do_emm(dvbapi_client, &epg);
|
---|
1785 | }
|
---|
1786 |
|
---|
1787 | void dvbapi_read_priority(void)
|
---|
1788 | {
|
---|
1789 | FILE *fp;
|
---|
1790 | char token[128], str1[128];
|
---|
1791 | char type;
|
---|
1792 | int32_t i, ret, count = 0;
|
---|
1793 |
|
---|
1794 | const char *cs_prio = "oscam.dvbapi";
|
---|
1795 |
|
---|
1796 | fp = fopen(get_config_filename(token, sizeof(token), cs_prio), "r");
|
---|
1797 |
|
---|
1798 | if(!fp)
|
---|
1799 | {
|
---|
1800 | cs_log_dbg(D_DVBAPI, "ERROR: Can't open priority file %s", token);
|
---|
1801 | return;
|
---|
1802 | }
|
---|
1803 |
|
---|
1804 | if(dvbapi_priority)
|
---|
1805 | {
|
---|
1806 | cs_log_dbg(D_DVBAPI, "reread priority file %s", cs_prio);
|
---|
1807 | struct s_dvbapi_priority *o, *p;
|
---|
1808 | for(p = dvbapi_priority; p != NULL; p = o)
|
---|
1809 | {
|
---|
1810 | o = p->next;
|
---|
1811 | NULLFREE(p);
|
---|
1812 | }
|
---|
1813 | dvbapi_priority = NULL;
|
---|
1814 | }
|
---|
1815 |
|
---|
1816 | while(fgets(token, sizeof(token), fp))
|
---|
1817 | {
|
---|
1818 | // Ignore comments and empty lines
|
---|
1819 | if(token[0] == '#' || token[0] == '/' || token[0] == '\n' || token[0] == '\r' || token[0] == '\0')
|
---|
1820 | { continue; }
|
---|
1821 | if(strlen(token) > 100) { continue; }
|
---|
1822 |
|
---|
1823 | memset(str1, 0, 128);
|
---|
1824 |
|
---|
1825 | for(i = 0; i < (int)strlen(token) && token[i] == ' '; i++) { ; }
|
---|
1826 | if(i == (int)strlen(token) - 1) //empty line or all spaces
|
---|
1827 | { continue; }
|
---|
1828 |
|
---|
1829 | for(i = 0; i < (int)strlen(token); i++)
|
---|
1830 | {
|
---|
1831 | if((token[i] == ':' || token[i] == ' ') && token[i + 1] == ':') // if "::" or " :"
|
---|
1832 | {
|
---|
1833 | memmove(token + i + 2, token + i + 1, strlen(token) - i + 1); //insert extra position
|
---|
1834 | token[i + 1] = '0'; //and fill it with NULL
|
---|
1835 | }
|
---|
1836 | if(token[i] == '#' || token[i] == '/')
|
---|
1837 | {
|
---|
1838 | token[i] = '\0';
|
---|
1839 | break;
|
---|
1840 | }
|
---|
1841 | }
|
---|
1842 |
|
---|
1843 | type = 0;
|
---|
1844 | #ifdef WITH_STAPI
|
---|
1845 | uint32_t disablefilter = 0;
|
---|
1846 | ret = sscanf(trim(token), "%c: %63s %63s %d", &type, str1, str1 + 64, &disablefilter);
|
---|
1847 | #else
|
---|
1848 | ret = sscanf(trim(token), "%c: %63s %63s", &type, str1, str1 + 64);
|
---|
1849 | #endif
|
---|
1850 | type = tolower((uchar)type);
|
---|
1851 |
|
---|
1852 | if(ret < 1 || (type != 'p' && type != 'i' && type != 'm' && type != 'd' && type != 's' && type != 'l'
|
---|
1853 | && type != 'j' && type != 'a' && type != 'x'))
|
---|
1854 | {
|
---|
1855 | //fprintf(stderr, "Warning: line containing %s in %s not recognized, ignoring line\n", token, cs_prio);
|
---|
1856 | //fprintf would issue the warning to the command line, which is more consistent with other config warnings
|
---|
1857 | //however it takes OSCam a long time (>4 seconds) to reach this part of the program, so the warnings are reaching tty rather late
|
---|
1858 | //which leads to confusion. So send the warnings to log file instead
|
---|
1859 | cs_log_dbg(D_DVBAPI, "WARN: line containing %s in %s not recognized, ignoring line\n", token, cs_prio);
|
---|
1860 | continue;
|
---|
1861 | }
|
---|
1862 |
|
---|
1863 | struct s_dvbapi_priority *entry;
|
---|
1864 | if(!cs_malloc(&entry, sizeof(struct s_dvbapi_priority)))
|
---|
1865 | {
|
---|
1866 | ret = fclose(fp);
|
---|
1867 | if(ret < 0) { cs_log("ERROR: Could not close oscam.dvbapi fd (errno=%d %s)", errno, strerror(errno)); }
|
---|
1868 | return;
|
---|
1869 | }
|
---|
1870 |
|
---|
1871 | entry->type = type;
|
---|
1872 | entry->next = NULL;
|
---|
1873 |
|
---|
1874 | count++;
|
---|
1875 |
|
---|
1876 | #ifdef WITH_STAPI
|
---|
1877 | if(type == 's')
|
---|
1878 | {
|
---|
1879 | strncpy(entry->devname, str1, 29);
|
---|
1880 | strncpy(entry->pmtfile, str1 + 64, 29);
|
---|
1881 |
|
---|
1882 | entry->disablefilter = disablefilter;
|
---|
1883 |
|
---|
1884 | cs_log_dbg(D_DVBAPI, "stapi prio: ret=%d | %c: %s %s | disable %d",
|
---|
1885 | ret, type, entry->devname, entry->pmtfile, disablefilter);
|
---|
1886 |
|
---|
1887 | if(!dvbapi_priority)
|
---|
1888 | {
|
---|
1889 | dvbapi_priority = entry;
|
---|
1890 | }
|
---|
1891 | else
|
---|
1892 | {
|
---|
1893 | struct s_dvbapi_priority *p;
|
---|
1894 | for(p = dvbapi_priority; p->next != NULL; p = p->next) { ; }
|
---|
1895 | p->next = entry;
|
---|
1896 | }
|
---|
1897 | continue;
|
---|
1898 | }
|
---|
1899 | #endif
|
---|
1900 |
|
---|
1901 | char c_srvid[34];
|
---|
1902 | c_srvid[0] = '\0';
|
---|
1903 | uint32_t caid = 0, provid = 0, srvid = 0, ecmpid = 0;
|
---|
1904 | uint32_t chid = 0x10000; //chid=0 is a valid chid
|
---|
1905 | ret = sscanf(str1, "%4x:%6x:%33[^:]:%4x:%4x"SCNx16, &caid, &provid, c_srvid, &ecmpid, &chid);
|
---|
1906 | if(ret < 1)
|
---|
1907 | {
|
---|
1908 | cs_log("Error in oscam.dvbapi: ret=%d | %c: %04X %06X %s %04X %04X",
|
---|
1909 | ret, type, caid, provid, c_srvid, ecmpid, chid);
|
---|
1910 | continue; // skip this entry!
|
---|
1911 | }
|
---|
1912 | else
|
---|
1913 | {
|
---|
1914 | cs_log_dbg(D_DVBAPI, "Parsing rule: ret=%d | %c: %04X %06X %s %04X %04X",
|
---|
1915 | ret, type, caid, provid, c_srvid, ecmpid, chid);
|
---|
1916 | }
|
---|
1917 |
|
---|
1918 | entry->caid = caid;
|
---|
1919 | entry->provid = provid;
|
---|
1920 | entry->ecmpid = ecmpid;
|
---|
1921 | entry->chid = chid;
|
---|
1922 |
|
---|
1923 | uint32_t delay = 0, force = 0, mapcaid = 0, mapprovid = 0, mapecmpid = 0, pidx = 0;
|
---|
1924 | switch(type)
|
---|
1925 | {
|
---|
1926 | case 'i':
|
---|
1927 | ret = sscanf(str1 + 64, "%1d", &pidx);
|
---|
1928 | entry->pidx = pidx+1;
|
---|
1929 | if(ret < 1) entry->pidx = 0;
|
---|
1930 | break;
|
---|
1931 | case 'd':
|
---|
1932 | sscanf(str1 + 64, "%4d", &delay);
|
---|
1933 | entry->delay = delay;
|
---|
1934 | break;
|
---|
1935 | case 'l':
|
---|
1936 | entry->delay = dyn_word_atob(str1 + 64);
|
---|
1937 | if(entry->delay == -1) { entry->delay = 0; }
|
---|
1938 | break;
|
---|
1939 | case 'p':
|
---|
1940 | ret = sscanf(str1 + 64, "%1d:%1d", &force, &pidx);
|
---|
1941 | entry->force = force;
|
---|
1942 | entry->pidx = pidx+1;
|
---|
1943 | if(ret < 2) entry->pidx = 0;
|
---|
1944 | break;
|
---|
1945 | case 'm':
|
---|
1946 | sscanf(str1 + 64, "%4x:%6x", &mapcaid, &mapprovid);
|
---|
1947 | if(!mapcaid) { mapcaid = 0xFFFF; }
|
---|
1948 | entry->mapcaid = mapcaid;
|
---|
1949 | entry->mapprovid = mapprovid;
|
---|
1950 | break;
|
---|
1951 | case 'a':
|
---|
1952 | case 'j':
|
---|
1953 | sscanf(str1 + 64, "%4x:%6x:%4x", &mapcaid, &mapprovid, &mapecmpid);
|
---|
1954 | if(!mapcaid) { mapcaid = 0xFFFF; }
|
---|
1955 | entry->mapcaid = mapcaid;
|
---|
1956 | entry->mapprovid = mapprovid;
|
---|
1957 | entry->mapecmpid = mapecmpid;
|
---|
1958 | break;
|
---|
1959 | }
|
---|
1960 |
|
---|
1961 | if(c_srvid[0] == '=')
|
---|
1962 | {
|
---|
1963 | struct s_srvid *this;
|
---|
1964 |
|
---|
1965 | for(i = 0; i < 16; i++)
|
---|
1966 | for(this = cfg.srvid[i]; this != NULL; this = this->next)
|
---|
1967 | {
|
---|
1968 | if(strcmp(this->prov, c_srvid + 1) == 0)
|
---|
1969 | {
|
---|
1970 | struct s_dvbapi_priority *entry2;
|
---|
1971 | if(!cs_malloc(&entry2, sizeof(struct s_dvbapi_priority)))
|
---|
1972 | { continue; }
|
---|
1973 | memcpy(entry2, entry, sizeof(struct s_dvbapi_priority));
|
---|
1974 |
|
---|
1975 | entry2->srvid = this->srvid;
|
---|
1976 |
|
---|
1977 | cs_log_dbg(D_DVBAPI, "prio srvid: ret=%d | %c: %04X %06X %04X %04X %04X -> map %04X %06X %04X | prio %d | delay %d",
|
---|
1978 | ret, entry2->type, entry2->caid, entry2->provid, entry2->srvid, entry2->ecmpid, entry2->chid,
|
---|
1979 | entry2->mapcaid, entry2->mapprovid, entry2->mapecmpid, entry2->force, entry2->delay);
|
---|
1980 |
|
---|
1981 | if(!dvbapi_priority)
|
---|
1982 | {
|
---|
1983 | dvbapi_priority = entry2;
|
---|
1984 | }
|
---|
1985 | else
|
---|
1986 | {
|
---|
1987 | struct s_dvbapi_priority *p;
|
---|
1988 | for(p = dvbapi_priority; p->next != NULL; p = p->next) { ; }
|
---|
1989 | p->next = entry2;
|
---|
1990 | }
|
---|
1991 | }
|
---|
1992 | }
|
---|
1993 | NULLFREE(entry);
|
---|
1994 | continue;
|
---|
1995 | }
|
---|
1996 | else
|
---|
1997 | {
|
---|
1998 | sscanf(c_srvid, "%4x", &srvid);
|
---|
1999 | entry->srvid = srvid;
|
---|
2000 | }
|
---|
2001 |
|
---|
2002 | cs_log_dbg(D_DVBAPI, "prio: ret=%d | %c: %04X %06X %04X %04X %04X -> map %04X %06X %04X | prio %d | delay %d",
|
---|
2003 | ret, entry->type, entry->caid, entry->provid, entry->srvid, entry->ecmpid, entry->chid, entry->mapcaid,
|
---|
2004 | entry->mapprovid, entry->mapecmpid, entry->force, entry->delay);
|
---|
2005 |
|
---|
2006 | if(!dvbapi_priority)
|
---|
2007 | {
|
---|
2008 | dvbapi_priority = entry;
|
---|
2009 | }
|
---|
2010 | else
|
---|
2011 | {
|
---|
2012 | struct s_dvbapi_priority *p;
|
---|
2013 | for(p = dvbapi_priority; p->next != NULL; p = p->next) { ; }
|
---|
2014 | p->next = entry;
|
---|
2015 | }
|
---|
2016 | }
|
---|
2017 |
|
---|
2018 | cs_log_dbg(D_DVBAPI, "Read %d entries from %s", count, cs_prio);
|
---|
2019 |
|
---|
2020 | ret = fclose(fp);
|
---|
2021 | if(ret < 0) { cs_log("ERROR: Could not close oscam.dvbapi fd (errno=%d %s)", errno, strerror(errno)); }
|
---|
2022 | return;
|
---|
2023 | }
|
---|
2024 |
|
---|
2025 | void dvbapi_resort_ecmpids(int32_t demux_index)
|
---|
2026 | {
|
---|
2027 | int32_t n, cache = 0, prio = 1, highest_prio = 0, matching_done = 0, found = -1;
|
---|
2028 | uint16_t btun_caid = 0;
|
---|
2029 | struct timeb start,end;
|
---|
2030 | cs_ftime(&start);
|
---|
2031 | for(n = 0; n < demux[demux_index].ECMpidcount; n++)
|
---|
2032 | {
|
---|
2033 | demux[demux_index].ECMpids[n].status = 0;
|
---|
2034 | demux[demux_index].ECMpids[n].checked = 0;
|
---|
2035 | }
|
---|
2036 |
|
---|
2037 | demux[demux_index].max_status = 0;
|
---|
2038 | demux[demux_index].curindex = -1;
|
---|
2039 | demux[demux_index].pidindex = -1;
|
---|
2040 |
|
---|
2041 | struct s_channel_cache *c = NULL;
|
---|
2042 |
|
---|
2043 | for(n = 0; n < demux[demux_index].ECMpidcount; n++)
|
---|
2044 | {
|
---|
2045 | c = dvbapi_find_channel_cache(demux_index, n, 0); // find exact channel match
|
---|
2046 | if(c != NULL)
|
---|
2047 | {
|
---|
2048 | found = n;
|
---|
2049 | cache = 2; //found cache entry with higher priority
|
---|
2050 | demux[demux_index].ECMpids[n].status = prio * 2; // prioritize CAIDs which already decoded same caid:provid:srvid
|
---|
2051 | if(c->chid < 0x10000) { demux[demux_index].ECMpids[n].CHID = c->chid; } // if chid registered in cache -> use it!
|
---|
2052 | cs_log_dbg(D_DVBAPI, "Demuxer %d prio ecmpid %d %04X:%06X:%04X (found caid/provid/srvid in cache - weight: %d)", demux_index, n,
|
---|
2053 | demux[demux_index].ECMpids[n].CAID, demux[demux_index].ECMpids[n].PROVID, demux[demux_index].ECMpids[n].ECM_PID, demux[demux_index].ECMpids[n].status);
|
---|
2054 | break;
|
---|
2055 | }
|
---|
2056 | }
|
---|
2057 |
|
---|
2058 | if(found == -1)
|
---|
2059 | {
|
---|
2060 | // prioritize CAIDs which already decoded same caid:provid
|
---|
2061 | for(n = 0; n < demux[demux_index].ECMpidcount; n++)
|
---|
2062 | {
|
---|
2063 | c = dvbapi_find_channel_cache(demux_index, n, 1);
|
---|
2064 | if(c != NULL)
|
---|
2065 | {
|
---|
2066 | cache = 1; //found cache entry
|
---|
2067 | demux[demux_index].ECMpids[n].status = prio;
|
---|
2068 | cs_log_dbg(D_DVBAPI, "Demuxer %d prio ecmpid %d %04X:%06X:%04X (found caid/provid in cache - weight: %d)", demux_index, n,
|
---|
2069 | demux[demux_index].ECMpids[n].CAID, demux[demux_index].ECMpids[n].PROVID, demux[demux_index].ECMpids[n].ECM_PID, demux[demux_index].ECMpids[n].status);
|
---|
2070 | }
|
---|
2071 | }
|
---|
2072 | }
|
---|
2073 |
|
---|
2074 | // prioritize & ignore according to oscam.dvbapi and cfg.preferlocalcards
|
---|
2075 | if(!dvbapi_priority) { cs_log_dbg(D_DVBAPI, "Demuxer %d no oscam.dvbapi found or no valid rules are parsed!", demux_index); }
|
---|
2076 |
|
---|
2077 | if(dvbapi_priority)
|
---|
2078 | {
|
---|
2079 | struct s_reader *rdr;
|
---|
2080 | ECM_REQUEST *er;
|
---|
2081 | if(!cs_malloc(&er, sizeof(ECM_REQUEST)))
|
---|
2082 | { return; }
|
---|
2083 |
|
---|
2084 | int32_t add_prio = 0; // make sure that p: values overrule cache
|
---|
2085 | if(cache == 1)
|
---|
2086 | { add_prio = prio; }
|
---|
2087 | else if(cache == 2)
|
---|
2088 | { add_prio = prio * 2; }
|
---|
2089 |
|
---|
2090 | // reverse order! makes sure that user defined p: values are in the right order
|
---|
2091 | int32_t p_order = demux[demux_index].ECMpidcount;
|
---|
2092 |
|
---|
2093 | highest_prio = (prio * demux[demux_index].ECMpidcount) + p_order;
|
---|
2094 |
|
---|
2095 | struct s_dvbapi_priority *p;
|
---|
2096 | for(p = dvbapi_priority; p != NULL; p = p->next)
|
---|
2097 | {
|
---|
2098 | if(p->type != 'p' && p->type != 'i')
|
---|
2099 | { continue; }
|
---|
2100 | for(n = 0; n < demux[demux_index].ECMpidcount; n++)
|
---|
2101 | {
|
---|
2102 | if(!cache && demux[demux_index].ECMpids[n].status != 0)
|
---|
2103 | { continue; }
|
---|
2104 | else if(cache == 1 && (demux[demux_index].ECMpids[n].status < 0 || demux[demux_index].ECMpids[n].status > prio))
|
---|
2105 | { continue; }
|
---|
2106 | else if(cache == 2 && (demux[demux_index].ECMpids[n].status < 0 || demux[demux_index].ECMpids[n].status > prio * 2))
|
---|
2107 | { continue; }
|
---|
2108 |
|
---|
2109 | er->caid = er->ocaid = demux[demux_index].ECMpids[n].CAID;
|
---|
2110 | er->prid = demux[demux_index].ECMpids[n].PROVID;
|
---|
2111 | er->pid = demux[demux_index].ECMpids[n].ECM_PID;
|
---|
2112 | er->srvid = demux[demux_index].program_number;
|
---|
2113 | er->client = cur_client();
|
---|
2114 |
|
---|
2115 | btun_caid = chk_on_btun(SRVID_MASK, er->client, er);
|
---|
2116 | if(p->type == 'p' && btun_caid)
|
---|
2117 | { er->caid = btun_caid; }
|
---|
2118 |
|
---|
2119 | if(p->caid && p->caid != er->caid)
|
---|
2120 | { continue; }
|
---|
2121 | if(p->provid && p->provid != er->prid)
|
---|
2122 | { continue; }
|
---|
2123 | if(p->ecmpid && p->ecmpid != er->pid)
|
---|
2124 | { continue; }
|
---|
2125 | if(p->srvid && p->srvid != er->srvid)
|
---|
2126 | { continue; }
|
---|
2127 | if (p->pidx && p->pidx-1 != n)
|
---|
2128 | { continue; }
|
---|
2129 |
|
---|
2130 | if(p->type == 'i') // check if ignored by dvbapi
|
---|
2131 | {
|
---|
2132 | if(p->chid == 0x10000) // ignore all? disable pid
|
---|
2133 | {
|
---|
2134 | demux[demux_index].ECMpids[n].status = -1;
|
---|
2135 | }
|
---|
2136 | cs_log_dbg(D_DVBAPI, "Demuxer %d ignore ecmpid %d %04X:%06X:%04X:%04X (file)", demux_index, n, demux[demux_index].ECMpids[n].CAID,
|
---|
2137 | demux[demux_index].ECMpids[n].PROVID, demux[demux_index].ECMpids[n].ECM_PID, (uint16_t) p->chid);
|
---|
2138 | continue;
|
---|
2139 | }
|
---|
2140 |
|
---|
2141 | if(p->type == 'p')
|
---|
2142 | {
|
---|
2143 | if(demux[demux_index].ECMpids[n].status == -1) //skip ignores
|
---|
2144 | { continue; }
|
---|
2145 |
|
---|
2146 | matching_done = 1;
|
---|
2147 | for(rdr = first_active_reader; rdr ; rdr = rdr->next)
|
---|
2148 | {
|
---|
2149 | if(cfg.preferlocalcards && !is_network_reader(rdr)
|
---|
2150 | && rdr->card_status == CARD_INSERTED) // cfg.preferlocalcards = 1 local reader
|
---|
2151 | {
|
---|
2152 |
|
---|
2153 | if(matching_reader(er, rdr))
|
---|
2154 | {
|
---|
2155 | if(cache == 2 && demux[demux_index].ECMpids[n].status == 1)
|
---|
2156 | { demux[demux_index].ECMpids[n].status++; }
|
---|
2157 | else if(cache && !demux[demux_index].ECMpids[n].status)
|
---|
2158 | { demux[demux_index].ECMpids[n].status += add_prio; }
|
---|
2159 | //priority*ECMpidcount should overrule network reader
|
---|
2160 | demux[demux_index].ECMpids[n].status += (prio * demux[demux_index].ECMpidcount) + (p_order--);
|
---|
2161 | cs_log_dbg(D_DVBAPI, "Demuxer %d prio ecmpid %d %04X:%06X:%04X:%04X (localrdr: %s weight: %d)", demux_index,
|
---|
2162 | n, demux[demux_index].ECMpids[n].CAID, demux[demux_index].ECMpids[n].PROVID,
|
---|
2163 | demux[demux_index].ECMpids[n].ECM_PID, (uint16_t) p->chid, rdr->label,
|
---|
2164 | demux[demux_index].ECMpids[n].status);
|
---|
2165 | break;
|
---|
2166 | }
|
---|
2167 | }
|
---|
2168 | else // cfg.preferlocalcards = 0 or cfg.preferlocalcards = 1 and no local reader
|
---|
2169 | {
|
---|
2170 | if(matching_reader(er, rdr))
|
---|
2171 | {
|
---|
2172 | if(cache == 2 && demux[demux_index].ECMpids[n].status == 1)
|
---|
2173 | { demux[demux_index].ECMpids[n].status++; }
|
---|
2174 | else if(cache && !demux[demux_index].ECMpids[n].status)
|
---|
2175 | { demux[demux_index].ECMpids[n].status += add_prio; }
|
---|
2176 | demux[demux_index].ECMpids[n].status += prio + (p_order--);
|
---|
2177 | cs_log_dbg(D_DVBAPI, "Demuxer %d prio ecmpid %d %04X:%06X:%04X:%04X (rdr: %s weight: %d)", demux_index,
|
---|
2178 | n, demux[demux_index].ECMpids[n].CAID, demux[demux_index].ECMpids[n].PROVID,
|
---|
2179 | demux[demux_index].ECMpids[n].ECM_PID, (uint16_t) p->chid, rdr->label,
|
---|
2180 | demux[demux_index].ECMpids[n].status);
|
---|
2181 | break;
|
---|
2182 | }
|
---|
2183 | }
|
---|
2184 | }
|
---|
2185 | }
|
---|
2186 | }
|
---|
2187 | }
|
---|
2188 | NULLFREE(er);
|
---|
2189 | }
|
---|
2190 |
|
---|
2191 | if(!matching_done) //works if there is no oscam.dvbapi or if there is oscam.dvbapi but not p rules in it
|
---|
2192 | {
|
---|
2193 | if(dvbapi_priority && !matching_done)
|
---|
2194 | { cs_log_dbg(D_DVBAPI, "Demuxer %d no prio rules in oscam.dvbapi matches!", demux_index); }
|
---|
2195 |
|
---|
2196 | struct s_reader *rdr;
|
---|
2197 | ECM_REQUEST *er;
|
---|
2198 | if(!cs_malloc(&er, sizeof(ECM_REQUEST)))
|
---|
2199 | { return; }
|
---|
2200 |
|
---|
2201 | highest_prio = prio * 2;
|
---|
2202 |
|
---|
2203 | for(n = 0; n < demux[demux_index].ECMpidcount; n++)
|
---|
2204 | {
|
---|
2205 | if(demux[demux_index].ECMpids[n].status == -1) //skip ignores
|
---|
2206 | { continue; }
|
---|
2207 |
|
---|
2208 | er->caid = er->ocaid = demux[demux_index].ECMpids[n].CAID;
|
---|
2209 | er->prid = demux[demux_index].ECMpids[n].PROVID;
|
---|
2210 | er->pid = demux[demux_index].ECMpids[n].ECM_PID;
|
---|
2211 | er->srvid = demux[demux_index].program_number;
|
---|
2212 | er->client = cur_client();
|
---|
2213 |
|
---|
2214 | btun_caid = chk_on_btun(SRVID_MASK, er->client, er);
|
---|
2215 | if(btun_caid)
|
---|
2216 | { er->caid = btun_caid; }
|
---|
2217 |
|
---|
2218 | for(rdr = first_active_reader; rdr ; rdr = rdr->next)
|
---|
2219 | {
|
---|
2220 | if(cfg.preferlocalcards
|
---|
2221 | && !is_network_reader(rdr)
|
---|
2222 | && rdr->card_status == CARD_INSERTED) // cfg.preferlocalcards = 1 local reader
|
---|
2223 | {
|
---|
2224 | if(matching_reader(er, rdr))
|
---|
2225 | {
|
---|
2226 | demux[demux_index].ECMpids[n].status += prio * 2;
|
---|
2227 | cs_log_dbg(D_DVBAPI, "Demuxer %d prio ecmpid %d %04X:%06X:%04X (localrdr: %s weight: %d)", demux_index,
|
---|
2228 | n, demux[demux_index].ECMpids[n].CAID, demux[demux_index].ECMpids[n].PROVID,
|
---|
2229 | demux[demux_index].ECMpids[n].ECM_PID, rdr->label,
|
---|
2230 | demux[demux_index].ECMpids[n].status);
|
---|
2231 | break;
|
---|
2232 | }
|
---|
2233 | }
|
---|
2234 | else // cfg.preferlocalcards = 0 or cfg.preferlocalcards = 1 and no local reader
|
---|
2235 | {
|
---|
2236 | if(matching_reader(er, rdr))
|
---|
2237 | {
|
---|
2238 | demux[demux_index].ECMpids[n].status += prio;
|
---|
2239 | cs_log_dbg(D_DVBAPI, "Demuxer %d prio ecmpid %d %04X:%06X:%04X (rdr: %s weight: %d)", demux_index,
|
---|
2240 | n, demux[demux_index].ECMpids[n].CAID, demux[demux_index].ECMpids[n].PROVID,
|
---|
2241 | demux[demux_index].ECMpids[n].ECM_PID, rdr->label, demux[demux_index].ECMpids[n].status);
|
---|
2242 | break;
|
---|
2243 | }
|
---|
2244 | }
|
---|
2245 | }
|
---|
2246 | }
|
---|
2247 | NULLFREE(er);
|
---|
2248 | }
|
---|
2249 |
|
---|
2250 | if(cache == 1)
|
---|
2251 | { highest_prio += prio; }
|
---|
2252 | else if(cache == 2)
|
---|
2253 | { highest_prio += prio * 2; };
|
---|
2254 |
|
---|
2255 | highest_prio++;
|
---|
2256 |
|
---|
2257 | for(n = 0; n < demux[demux_index].ECMpidcount; n++)
|
---|
2258 | {
|
---|
2259 | int32_t nr;
|
---|
2260 | SIDTAB *sidtab;
|
---|
2261 | ECM_REQUEST er;
|
---|
2262 | er.caid = demux[demux_index].ECMpids[n].CAID;
|
---|
2263 | er.prid = demux[demux_index].ECMpids[n].PROVID;
|
---|
2264 | er.srvid = demux[demux_index].program_number;
|
---|
2265 |
|
---|
2266 | for(nr = 0, sidtab = cfg.sidtab; sidtab; sidtab = sidtab->next, nr++)
|
---|
2267 | {
|
---|
2268 | if(sidtab->num_caid | sidtab->num_provid | sidtab->num_srvid)
|
---|
2269 | {
|
---|
2270 | if((cfg.dvbapi_sidtabs.no & ((SIDTABBITS)1 << nr)) && (chk_srvid_match(&er, sidtab)))
|
---|
2271 | {
|
---|
2272 | demux[demux_index].ECMpids[n].status = -1; //ignore
|
---|
2273 | cs_log_dbg(D_DVBAPI, "Demuxer %d ignore ecmpid %d %04X:%06X:%04X (service %s) pos %d", demux_index,
|
---|
2274 | n, demux[demux_index].ECMpids[n].CAID, demux[demux_index].ECMpids[n].PROVID,
|
---|
2275 | demux[demux_index].ECMpids[n].ECM_PID, sidtab->label, nr);
|
---|
2276 | }
|
---|
2277 | if((cfg.dvbapi_sidtabs.ok & ((SIDTABBITS)1 << nr)) && (chk_srvid_match(&er, sidtab)))
|
---|
2278 | {
|
---|
2279 | demux[demux_index].ECMpids[n].status = highest_prio++; //priority
|
---|
2280 | cs_log_dbg(D_DVBAPI, "Demuxer %d prio ecmpid %d %04X:%06X:%04X (service: %s position: %d)", demux_index,
|
---|
2281 | n, demux[demux_index].ECMpids[n].CAID, demux[demux_index].ECMpids[n].PROVID,
|
---|
2282 | demux[demux_index].ECMpids[n].ECM_PID, sidtab->label,
|
---|
2283 | demux[demux_index].ECMpids[n].status);
|
---|
2284 | }
|
---|
2285 | }
|
---|
2286 | }
|
---|
2287 | }
|
---|
2288 |
|
---|
2289 | struct s_reader *rdr;
|
---|
2290 | ECM_REQUEST *er;
|
---|
2291 | if(!cs_malloc(&er, sizeof(ECM_REQUEST)))
|
---|
2292 | { return; }
|
---|
2293 |
|
---|
2294 | for(n = 0; n < demux[demux_index].ECMpidcount; n++)
|
---|
2295 | {
|
---|
2296 | er->caid = er->ocaid = demux[demux_index].ECMpids[n].CAID;
|
---|
2297 | er->prid = demux[demux_index].ECMpids[n].PROVID;
|
---|
2298 | er->pid = demux[demux_index].ECMpids[n].ECM_PID;
|
---|
2299 | er->srvid = demux[demux_index].program_number;
|
---|
2300 | er->client = cur_client();
|
---|
2301 | btun_caid = chk_on_btun(SRVID_MASK, er->client, er);
|
---|
2302 | if(btun_caid)
|
---|
2303 | {
|
---|
2304 | er->caid = btun_caid;
|
---|
2305 | }
|
---|
2306 |
|
---|
2307 | int32_t match = 0;
|
---|
2308 | for(rdr = first_active_reader; rdr ; rdr = rdr->next)
|
---|
2309 | {
|
---|
2310 | if(matching_reader(er, rdr))
|
---|
2311 | {
|
---|
2312 | match++;
|
---|
2313 | }
|
---|
2314 | }
|
---|
2315 | if (match == 0)
|
---|
2316 | {
|
---|
2317 | cs_log_dbg(D_DVBAPI, "Demuxer %d ignore ecmpid %d %04X:%06X:%04X:%04X (no matching reader)", demux_index, n, demux[demux_index].ECMpids[n].CAID,
|
---|
2318 | demux[demux_index].ECMpids[n].PROVID, demux[demux_index].ECMpids[n].ECM_PID, demux[demux_index].ECMpids[n].CHID);
|
---|
2319 | demux[demux_index].ECMpids[n].status = -1;
|
---|
2320 | }
|
---|
2321 | }
|
---|
2322 | NULLFREE(er);
|
---|
2323 |
|
---|
2324 | highest_prio = 0;
|
---|
2325 | int32_t highest_priopid = -1;
|
---|
2326 | for(n = 0; n < demux[demux_index].ECMpidcount; n++)
|
---|
2327 | {
|
---|
2328 | if(demux[demux_index].ECMpids[n].status > highest_prio) // find highest prio pid
|
---|
2329 | {
|
---|
2330 | highest_prio = demux[demux_index].ECMpids[n].status;
|
---|
2331 | highest_priopid = n;
|
---|
2332 | }
|
---|
2333 | if(demux[demux_index].ECMpids[n].status == 0) { demux[demux_index].ECMpids[n].checked = 2; } // set pids with no status to no prio run
|
---|
2334 | }
|
---|
2335 |
|
---|
2336 | struct s_dvbapi_priority *match;
|
---|
2337 | for(match = dvbapi_priority; match != NULL; match = match->next)
|
---|
2338 | {
|
---|
2339 | if(match->type != 'p')
|
---|
2340 | { continue; }
|
---|
2341 | if(!match || !match->force) // only evaluate forced prio's
|
---|
2342 | { continue; }
|
---|
2343 | for(n = 0; n < demux[demux_index].ECMpidcount; n++)
|
---|
2344 | {
|
---|
2345 | if(match->caid && match->caid != demux[demux_index].ECMpids[n].CAID) { continue; }
|
---|
2346 | if(match->provid && match->provid != demux[demux_index].ECMpids[n].PROVID) { continue; }
|
---|
2347 | if(match->srvid && match->srvid != demux[demux_index].program_number) { continue; }
|
---|
2348 | if(match->ecmpid && match->ecmpid != demux[demux_index].ECMpids[n].ECM_PID) { continue; }
|
---|
2349 | if(match->pidx && match->pidx-1 != n) { continue; }
|
---|
2350 | if(match->chid < 0x10000) { demux[demux_index].ECMpids[n].CHID = match->chid; }
|
---|
2351 | demux[demux_index].ECMpids[n].status = ++highest_prio;
|
---|
2352 | cs_log_dbg(D_DVBAPI, "Demuxer %d forced ecmpid %d %04X:%06X:%04X:%04X", demux_index, n, demux[demux_index].ECMpids[n].CAID,
|
---|
2353 | demux[demux_index].ECMpids[n].PROVID, demux[demux_index].ECMpids[n].ECM_PID, (uint16_t) match->chid);
|
---|
2354 | demux[demux_index].max_status = highest_prio; // register maxstatus
|
---|
2355 | demux[demux_index].ECMpids[n].checked = 0; // set forced pid to prio run
|
---|
2356 | return; // we only accept one forced pid!
|
---|
2357 | }
|
---|
2358 | }
|
---|
2359 | demux[demux_index].max_status = highest_prio; // register maxstatus
|
---|
2360 | if(highest_priopid != -1 && found == highest_priopid) // Found in cache
|
---|
2361 | {
|
---|
2362 | for(n = 0; n < demux[demux_index].ECMpidcount; n++)
|
---|
2363 | {
|
---|
2364 | if(n != found)
|
---|
2365 | {
|
---|
2366 | // disable non matching pid
|
---|
2367 | demux[demux_index].ECMpids[n].status = -1;
|
---|
2368 | }
|
---|
2369 | else
|
---|
2370 | {
|
---|
2371 | demux[demux_index].ECMpids[n].status = 1;
|
---|
2372 | }
|
---|
2373 | }
|
---|
2374 | demux[demux_index].max_emm_filter = maxfilter - 1;
|
---|
2375 | demux[demux_index].max_status = 1;
|
---|
2376 | cs_log("Demuxer %d found channel in cache and matching prio -> start descrambling ecmpid %d ", demux_index, found);
|
---|
2377 | }
|
---|
2378 | cs_ftime(&end);
|
---|
2379 | int64_t gone = comp_timeb(&end, &start);
|
---|
2380 | cs_log_dbg(D_DVBAPI, "Demuxer %d sorting the ecmpids took %"PRId64" ms", demux_index, gone);
|
---|
2381 | return;
|
---|
2382 | }
|
---|
2383 |
|
---|
2384 | void dvbapi_parse_descriptor(int32_t demux_id, uint32_t info_length, unsigned char *buffer)
|
---|
2385 | {
|
---|
2386 | // int32_t ca_pmt_cmd_id = buffer[i + 5];
|
---|
2387 | uint32_t descriptor_length = 0;
|
---|
2388 | uint32_t j, u;
|
---|
2389 |
|
---|
2390 | if(info_length < 1)
|
---|
2391 | { return; }
|
---|
2392 |
|
---|
2393 | if(buffer[0] == 0x01)
|
---|
2394 | {
|
---|
2395 | buffer = buffer + 1;
|
---|
2396 | info_length--;
|
---|
2397 | }
|
---|
2398 |
|
---|
2399 | for(j = 0; j < info_length; j += descriptor_length + 2)
|
---|
2400 | {
|
---|
2401 | descriptor_length = buffer[j + 1];
|
---|
2402 |
|
---|
2403 | if(buffer[j] == 0x81 && descriptor_length == 8) // private descriptor of length 8, assume enigma/tvh
|
---|
2404 | {
|
---|
2405 | demux[demux_id].enigma_namespace = b2i(4, buffer + j + 2);
|
---|
2406 | demux[demux_id].tsid = b2i(2, buffer + j + 6);
|
---|
2407 | demux[demux_id].onid = b2i(2, buffer + j + 8);
|
---|
2408 | cs_log_dbg(D_DVBAPI, "Demuxer %d found pmt type: %02x length: %d (assuming enigma private descriptor: namespace %04x tsid %02x onid %02x)", demux_id,
|
---|
2409 | buffer[j], descriptor_length, demux[demux_id].enigma_namespace, demux[demux_id].tsid, demux[demux_id].onid);
|
---|
2410 | }
|
---|
2411 | else if (descriptor_length !=0)
|
---|
2412 | {
|
---|
2413 | cs_log_dbg(D_TRACE, "Demuxer %d found pmt type: %02x length: %d", demux_id, buffer[j], descriptor_length);
|
---|
2414 | }
|
---|
2415 |
|
---|
2416 | if(buffer[j] != 0x09) { continue; }
|
---|
2417 |
|
---|
2418 | if(demux[demux_id].ECMpidcount >= ECM_PIDS) { break; }
|
---|
2419 |
|
---|
2420 | int32_t descriptor_ca_system_id = b2i(2, buffer + j + 2);
|
---|
2421 | int32_t descriptor_ca_pid = b2i(2, buffer + j + 4)&0x1FFF;
|
---|
2422 | int32_t descriptor_ca_provider = 0;
|
---|
2423 |
|
---|
2424 | if(descriptor_ca_system_id >> 8 == 0x01)
|
---|
2425 | {
|
---|
2426 | for(u = 2; u < descriptor_length; u += 15)
|
---|
2427 | {
|
---|
2428 | descriptor_ca_pid = b2i(2, buffer + j + u + 2)&0x1FFF;
|
---|
2429 | descriptor_ca_provider = b2i(2, buffer + j + u + 4);
|
---|
2430 | dvbapi_add_ecmpid(demux_id, descriptor_ca_system_id, descriptor_ca_pid, descriptor_ca_provider);
|
---|
2431 | }
|
---|
2432 | }
|
---|
2433 | else
|
---|
2434 | {
|
---|
2435 | if(caid_is_viaccess(descriptor_ca_system_id) && descriptor_length == 0x0F && buffer[j + 12] == 0x14)
|
---|
2436 | { descriptor_ca_provider = b2i(3, buffer + j + 14) &0xFFFFF0; }
|
---|
2437 |
|
---|
2438 | if(caid_is_nagra(descriptor_ca_system_id) && descriptor_length == 0x07)
|
---|
2439 | { descriptor_ca_provider = b2i(2, buffer + j + 7); }
|
---|
2440 |
|
---|
2441 | if(descriptor_ca_system_id >> 8 == 0x4A && descriptor_length == 0x05)
|
---|
2442 | { descriptor_ca_provider = buffer[j + 6]; }
|
---|
2443 |
|
---|
2444 | dvbapi_add_ecmpid(demux_id, descriptor_ca_system_id, descriptor_ca_pid, descriptor_ca_provider);
|
---|
2445 |
|
---|
2446 | }
|
---|
2447 | }
|
---|
2448 |
|
---|
2449 | // Apply mapping:
|
---|
2450 | if(dvbapi_priority)
|
---|
2451 | {
|
---|
2452 | struct s_dvbapi_priority *mapentry;
|
---|
2453 | for(j = 0; (int32_t)j < demux[demux_id].ECMpidcount; j++)
|
---|
2454 | {
|
---|
2455 | mapentry = dvbapi_check_prio_match(demux_id, j, 'm');
|
---|
2456 | if(mapentry)
|
---|
2457 | {
|
---|
2458 | cs_log_dbg(D_DVBAPI, "Demuxer %d mapping ecmpid %d from %04X:%06X to %04X:%06X", demux_id, j,
|
---|
2459 | demux[demux_id].ECMpids[j].CAID, demux[demux_id].ECMpids[j].PROVID,
|
---|
2460 | mapentry->mapcaid, mapentry->mapprovid);
|
---|
2461 | demux[demux_id].ECMpids[j].CAID = mapentry->mapcaid;
|
---|
2462 | demux[demux_id].ECMpids[j].PROVID = mapentry->mapprovid;
|
---|
2463 | }
|
---|
2464 | }
|
---|
2465 | }
|
---|
2466 | }
|
---|
2467 |
|
---|
2468 | void request_cw(struct s_client *client, ECM_REQUEST *er, int32_t demux_id, uint8_t delayed_ecm_check)
|
---|
2469 | {
|
---|
2470 | int32_t filternum = dvbapi_set_section_filter(demux_id, er, -1); // set ecm filter to odd -> even and visaversa
|
---|
2471 |
|
---|
2472 | if(!USE_OPENXCAS && filternum < 0)
|
---|
2473 | {
|
---|
2474 | cs_log_dbg(D_DVBAPI, "Demuxer %d not requesting cw -> ecm filter was killed!", demux_id);
|
---|
2475 | return;
|
---|
2476 | }
|
---|
2477 |
|
---|
2478 | cs_log_dbg(D_DVBAPI, "Demuxer %d get controlword!", demux_id);
|
---|
2479 | get_cw(client, er);
|
---|
2480 |
|
---|
2481 | if (!USE_OPENXCAS) {
|
---|
2482 | if(delayed_ecm_check) { memcpy(demux[demux_id].demux_fd[filternum].ecmd5, er->ecmd5, CS_ECMSTORESIZE); } // register this ecm as latest request for this filter
|
---|
2483 | else { memset(demux[demux_id].demux_fd[filternum].ecmd5, 0, CS_ECMSTORESIZE); } // zero out ecmcheck!
|
---|
2484 | }
|
---|
2485 |
|
---|
2486 | #ifdef WITH_DEBUG
|
---|
2487 | char buf[ECM_FMT_LEN];
|
---|
2488 | format_ecm(er, buf, ECM_FMT_LEN);
|
---|
2489 | cs_log_dbg(D_DVBAPI, "Demuxer %d request controlword for ecm %s", demux_id, buf);
|
---|
2490 | #endif
|
---|
2491 | }
|
---|
2492 |
|
---|
2493 | void dvbapi_try_next_caid(int32_t demux_id, int8_t checked)
|
---|
2494 | {
|
---|
2495 |
|
---|
2496 | int32_t n, j, found = -1, started = 0;
|
---|
2497 |
|
---|
2498 | int32_t status = demux[demux_id].max_status;
|
---|
2499 |
|
---|
2500 | for(j = status; j >= 0; j--) // largest status first!
|
---|
2501 | {
|
---|
2502 |
|
---|
2503 | for(n = 0; n < demux[demux_id].ECMpidcount; n++)
|
---|
2504 | {
|
---|
2505 | //cs_log_dbg(D_DVBAPI,"Demuxer %d PID %d checked = %d status = %d (searching for pid with status = %d)", demux_id, n,
|
---|
2506 | // demux[demux_id].ECMpids[n].checked, demux[demux_id].ECMpids[n].status, j);
|
---|
2507 | if(demux[demux_id].ECMpids[n].checked == checked && demux[demux_id].ECMpids[n].status == j)
|
---|
2508 | {
|
---|
2509 | found = n;
|
---|
2510 |
|
---|
2511 | openxcas_set_provid(demux[demux_id].ECMpids[found].PROVID);
|
---|
2512 | openxcas_set_caid(demux[demux_id].ECMpids[found].CAID);
|
---|
2513 | openxcas_set_ecm_pid(demux[demux_id].ECMpids[found].ECM_PID);
|
---|
2514 |
|
---|
2515 | // fixup for cas that need emm first!
|
---|
2516 | if(caid_is_irdeto(demux[demux_id].ECMpids[found].CAID)) { demux[demux_id].emmstart.time = 0; }
|
---|
2517 | started = dvbapi_start_descrambling(demux_id, found, checked);
|
---|
2518 | if(cfg.dvbapi_requestmode == 0 && started == 1) { return; } // in requestmode 0 we only start 1 ecm request at the time
|
---|
2519 | }
|
---|
2520 | }
|
---|
2521 | }
|
---|
2522 |
|
---|
2523 | if(found == -1 && demux[demux_id].pidindex == -1)
|
---|
2524 | {
|
---|
2525 | cs_log("Demuxer %d no suitable readers found that can be used for decoding!", demux_id);
|
---|
2526 | return;
|
---|
2527 | }
|
---|
2528 | }
|
---|
2529 |
|
---|
2530 | static void getDemuxOptions(int32_t demux_id, unsigned char *buffer, uint16_t *ca_mask, uint16_t *demux_index, uint16_t *adapter_index, uint16_t *pmtpid)
|
---|
2531 | {
|
---|
2532 | *ca_mask = 0x01, *demux_index = 0x00, *adapter_index = 0x00, *pmtpid = 0x00;
|
---|
2533 |
|
---|
2534 | if(buffer[17] == 0x82 && buffer[18] == 0x02)
|
---|
2535 | {
|
---|
2536 | // enigma2
|
---|
2537 | *ca_mask = buffer[19];
|
---|
2538 | uint32_t demuxid = buffer[20];
|
---|
2539 | if (demuxid == 0xff) demuxid = 0; // tryfix prismcube (0xff -> "demux-1" = error! )
|
---|
2540 | *demux_index = demuxid;
|
---|
2541 | if (buffer[21]==0x84 && buffer[22]==0x02) *pmtpid = b2i(2, buffer+23);
|
---|
2542 | if (buffer[25]==0x83 && buffer[26]==0x01) *adapter_index=buffer[27]; // from code cahandler.cpp 0x83 index of adapter
|
---|
2543 | }
|
---|
2544 |
|
---|
2545 | if(cfg.dvbapi_boxtype == BOXTYPE_IPBOX_PMT)
|
---|
2546 | {
|
---|
2547 | *ca_mask = demux_id + 1;
|
---|
2548 | *demux_index = demux_id;
|
---|
2549 | }
|
---|
2550 |
|
---|
2551 | if(cfg.dvbapi_boxtype == BOXTYPE_QBOXHD && buffer[17] == 0x82 && buffer[18] == 0x03)
|
---|
2552 | {
|
---|
2553 | // ca_mask = buffer[19]; // with STONE 1.0.4 always 0x01
|
---|
2554 | *demux_index = buffer[20]; // with STONE 1.0.4 always 0x00
|
---|
2555 | *adapter_index = buffer[21]; // with STONE 1.0.4 adapter index can be 0,1,2
|
---|
2556 | *ca_mask = (1 << *adapter_index); // use adapter_index as ca_mask (used as index for ca_fd[] array)
|
---|
2557 | }
|
---|
2558 |
|
---|
2559 | if((cfg.dvbapi_boxtype == BOXTYPE_PC || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX) && buffer[7] == 0x82 && buffer[8] == 0x02)
|
---|
2560 | {
|
---|
2561 | *demux_index = buffer[9]; // it is always 0 but you never know
|
---|
2562 | *adapter_index = buffer[10]; // adapter index can be 0,1,2
|
---|
2563 | *ca_mask = (1 << *adapter_index); // use adapter_index as ca_mask (used as index for ca_fd[] array)
|
---|
2564 | }
|
---|
2565 | }
|
---|
2566 |
|
---|
2567 | static void dvbapi_capmt_notify(struct demux_s *dmx)
|
---|
2568 | {
|
---|
2569 | struct s_client *cl;
|
---|
2570 | for(cl = first_client->next; cl ; cl = cl->next)
|
---|
2571 | {
|
---|
2572 | if((cl->typ == 'p' || cl->typ == 'r') && cl->reader && cl->reader->ph.c_capmt)
|
---|
2573 | {
|
---|
2574 | struct demux_s *curdemux;
|
---|
2575 | if(cs_malloc(&curdemux, sizeof(struct demux_s)))
|
---|
2576 | {
|
---|
2577 | memcpy(curdemux, dmx, sizeof(struct demux_s));
|
---|
2578 | add_job(cl, ACTION_READER_CAPMT_NOTIFY, curdemux, sizeof(struct demux_s));
|
---|
2579 | }
|
---|
2580 | }
|
---|
2581 | }
|
---|
2582 | }
|
---|
2583 |
|
---|
2584 | int32_t dvbapi_parse_capmt(unsigned char *buffer, uint32_t length, int32_t connfd, char *pmtfile)
|
---|
2585 | {
|
---|
2586 | uint32_t i = 0, start_descrambling = 0;
|
---|
2587 | int32_t j = 0;
|
---|
2588 | int32_t demux_id = -1;
|
---|
2589 | uint16_t ca_mask, demux_index, adapter_index, pmtpid;
|
---|
2590 |
|
---|
2591 | #define LIST_MORE 0x00 //*CA application should append a 'MORE' CAPMT object to the list and start receiving the next object
|
---|
2592 | #define LIST_FIRST 0x01 //*CA application should clear the list when a 'FIRST' CAPMT object is received, and start receiving the next object
|
---|
2593 | #define LIST_LAST 0x02 //*CA application should append a 'LAST' CAPMT object to the list and start working with the list
|
---|
2594 | #define LIST_ONLY 0x03 //*CA application should clear the list when an 'ONLY' CAPMT object is received, and start working with the object
|
---|
2595 | #define LIST_ADD 0x04 //*CA application should append an 'ADD' CAPMT object to the current list and start working with the updated list
|
---|
2596 | #define LIST_UPDATE 0x05 //*CA application should replace an entry in the list with an 'UPDATE' CAPMT object, and start working with the updated list
|
---|
2597 |
|
---|
2598 | #ifdef WITH_COOLAPI
|
---|
2599 | int32_t ca_pmt_list_management = LIST_ONLY;
|
---|
2600 | #else
|
---|
2601 | int32_t ca_pmt_list_management = buffer[0];
|
---|
2602 | #endif
|
---|
2603 | uint32_t program_number = b2i(2, buffer + 1);
|
---|
2604 | uint32_t program_info_length = b2i(2, buffer + 4) &0xFFF;
|
---|
2605 |
|
---|
2606 | cs_log_dump_dbg(D_DVBAPI, buffer, length, "capmt:");
|
---|
2607 | cs_log_dbg(D_DVBAPI, "Receiver sends PMT command %d for channel %04X", ca_pmt_list_management, program_number);
|
---|
2608 |
|
---|
2609 | if(!pmt_stopmarking && (ca_pmt_list_management == LIST_FIRST || ca_pmt_list_management == LIST_ONLY))
|
---|
2610 | {
|
---|
2611 | for(i = 0; i < MAX_DEMUX; i++)
|
---|
2612 | {
|
---|
2613 | if(demux[i].program_number == 0) { continue; } // skip empty demuxers
|
---|
2614 | if(demux[i].socket_fd != connfd) { continue; } // skip demuxers belonging to other ca pmt connection
|
---|
2615 | demux[i].stopdescramble = 1; // Mark for deletion if not used again by following pmt objects.
|
---|
2616 | cs_log_dbg(D_DVBAPI, "Marked demuxer %d/%d (srvid = %04X fd = %d) to stop decoding", i, MAX_DEMUX, demux[i].program_number, connfd);
|
---|
2617 | }
|
---|
2618 | pmt_stopmarking = 1; // only stop demuxing for first pmt record
|
---|
2619 | }
|
---|
2620 |
|
---|
2621 | getDemuxOptions(i, buffer, &ca_mask, &demux_index, &adapter_index, &pmtpid);
|
---|
2622 | cs_log_dbg(D_DVBAPI,"Receiver wants to demux srvid %04X on adapter %04X camask %04X index %04X pmtpid %04X",
|
---|
2623 | program_number, adapter_index, ca_mask, demux_index, pmtpid);
|
---|
2624 |
|
---|
2625 | for(i = 0; i < MAX_DEMUX; i++) // search current demuxers for running the same program as the one we received in this PMT object
|
---|
2626 | {
|
---|
2627 | if(demux[i].program_number == 0) { continue; }
|
---|
2628 | if(cfg.dvbapi_boxtype == BOXTYPE_IPBOX_PMT) demux_index = i; // fixup for ipbox
|
---|
2629 |
|
---|
2630 | bool full_check = 1, matched = 0;
|
---|
2631 | if (config_enabled(WITH_COOLAPI) || is_samygo)
|
---|
2632 | full_check = 0;
|
---|
2633 |
|
---|
2634 | if (full_check)
|
---|
2635 | matched = (connfd > 0 && demux[i].socket_fd == connfd) && demux[i].program_number == program_number;
|
---|
2636 | else
|
---|
2637 | matched = connfd > 0 && demux[i].program_number == program_number;
|
---|
2638 |
|
---|
2639 | if(matched)
|
---|
2640 | {
|
---|
2641 | if (full_check) {
|
---|
2642 | if (demux[i].adapter_index != adapter_index) continue; // perhaps next demuxer matches?
|
---|
2643 | if (demux[i].ca_mask != ca_mask) continue; // perhaps next demuxer matches?
|
---|
2644 | if (demux[i].demux_index != demux_index) continue; // perhaps next demuxer matches?
|
---|
2645 | }
|
---|
2646 | if(ca_pmt_list_management == LIST_UPDATE){
|
---|
2647 | cs_log("Demuxer %d PMT update for decoding of SRVID %04X! ", i, program_number);
|
---|
2648 | }
|
---|
2649 |
|
---|
2650 | demux_id = i;
|
---|
2651 |
|
---|
2652 | cs_log("Demuxer %d continue decoding of SRVID %04X", i, demux[i].program_number);
|
---|
2653 |
|
---|
2654 | openxcas_set_sid(program_number);
|
---|
2655 |
|
---|
2656 | demux[i].stopdescramble = 0; // dont stop current demuxer!
|
---|
2657 | break; // no need to explore other demuxers since we have a found!
|
---|
2658 | }
|
---|
2659 | }
|
---|
2660 |
|
---|
2661 | // start using the new list
|
---|
2662 | if(ca_pmt_list_management != LIST_FIRST && ca_pmt_list_management != LIST_MORE)
|
---|
2663 | {
|
---|
2664 | for(j = 0; j < MAX_DEMUX; j++)
|
---|
2665 | {
|
---|
2666 | if(demux[j].program_number == 0) { continue; }
|
---|
2667 | if(demux[j].stopdescramble == 1) { dvbapi_stop_descrambling(j); } // Stop descrambling and remove all demuxer entries not in new PMT.
|
---|
2668 | }
|
---|
2669 | start_descrambling = 1; // flag that demuxer descrambling is to be executed!
|
---|
2670 | pmt_stopmarking = 0; // flag that demuxers may be marked for stop decoding again
|
---|
2671 | }
|
---|
2672 |
|
---|
2673 | if(demux_id == -1)
|
---|
2674 | {
|
---|
2675 | for(demux_id = 0; demux_id < MAX_DEMUX && demux[demux_id].program_number > 0; demux_id++) { ; }
|
---|
2676 | }
|
---|
2677 |
|
---|
2678 | if(demux_id >= MAX_DEMUX)
|
---|
2679 | {
|
---|
2680 | cs_log("ERROR: No free id (MAX_DEMUX)");
|
---|
2681 | return -1;
|
---|
2682 | }
|
---|
2683 |
|
---|
2684 | demux[demux_id].program_number = program_number; // do this early since some prio items use them!
|
---|
2685 |
|
---|
2686 | demux[demux_id].enigma_namespace = 0;
|
---|
2687 | demux[demux_id].tsid = 0;
|
---|
2688 | demux[demux_id].onid = 0;
|
---|
2689 | demux[demux_id].pmtpid = pmtpid;
|
---|
2690 |
|
---|
2691 | if(pmtfile)
|
---|
2692 | {
|
---|
2693 | cs_strncpy(demux[demux_id].pmt_file, pmtfile, sizeof(demux[demux_id].pmt_file));
|
---|
2694 | }
|
---|
2695 |
|
---|
2696 | for(j = 0; j < demux[demux_id].ECMpidcount; j++) // cleanout demuxer from possible stale info
|
---|
2697 | {
|
---|
2698 | demux[demux_id].ECMpids[j].streams = 0; // reset streams of each ecmpid!
|
---|
2699 | }
|
---|
2700 | demux[demux_id].STREAMpidcount = 0; // reset number of streams
|
---|
2701 | demux[demux_id].ECMpidcount = 0; // reset number of ecmpids
|
---|
2702 |
|
---|
2703 | if(program_info_length > 1 && program_info_length < length)
|
---|
2704 | {
|
---|
2705 | dvbapi_parse_descriptor(demux_id, program_info_length - 1, buffer + 7);
|
---|
2706 | }
|
---|
2707 |
|
---|
2708 | uint32_t es_info_length = 0, vpid = 0;
|
---|
2709 | struct s_dvbapi_priority *addentry;
|
---|
2710 |
|
---|
2711 | const char *stream_in_text = NULL;
|
---|
2712 |
|
---|
2713 | for(i = program_info_length + 6; i < length; i += es_info_length + 5)
|
---|
2714 | {
|
---|
2715 | uint32_t stream_type = buffer[i];
|
---|
2716 | uint16_t elementary_pid = b2i(2, buffer + i + 1)&0x1FFF;
|
---|
2717 | es_info_length = b2i(2, buffer + i +3)&0x0FFF;
|
---|
2718 | if(stream_type < (sizeof(streamtxt) / sizeof(const char *)))
|
---|
2719 | {
|
---|
2720 | stream_in_text = streamtxt[stream_type];
|
---|
2721 | }
|
---|
2722 | else
|
---|
2723 | {
|
---|
2724 | stream_in_text = "";
|
---|
2725 | }
|
---|
2726 | cs_log_dbg(D_DVBAPI, "Demuxer %d stream %s(type: %02x pid: %04x length: %d)", demux_id, stream_in_text, stream_type, elementary_pid, es_info_length);
|
---|
2727 |
|
---|
2728 | if(demux[demux_id].STREAMpidcount >= ECM_PIDS)
|
---|
2729 | {
|
---|
2730 | break;
|
---|
2731 | }
|
---|
2732 |
|
---|
2733 | demux[demux_id].STREAMpids[demux[demux_id].STREAMpidcount++] = elementary_pid;
|
---|
2734 | // find and register videopid
|
---|
2735 | if(!vpid && (stream_type == 01 || stream_type == 02 || stream_type == 0x10 || stream_type == 0x1B)) { vpid = elementary_pid; }
|
---|
2736 |
|
---|
2737 | if(es_info_length != 0 && es_info_length < length)
|
---|
2738 | {
|
---|
2739 | dvbapi_parse_descriptor(demux_id, es_info_length, buffer + i + 5);
|
---|
2740 | }
|
---|
2741 | else
|
---|
2742 | {
|
---|
2743 | for(addentry = dvbapi_priority; addentry != NULL; addentry = addentry->next)
|
---|
2744 | {
|
---|
2745 | if(addentry->type != 'a'
|
---|
2746 | || (addentry->ecmpid && pmtpid && addentry->ecmpid != pmtpid) // ecmpid is misused to hold pmtpid in case of A: rule
|
---|
2747 | || (addentry->ecmpid && !pmtpid && addentry->ecmpid != vpid) // some receivers dont forward pmtpid, use vpid instead
|
---|
2748 | || (addentry->srvid != demux[demux_id].program_number))
|
---|
2749 | { continue; }
|
---|
2750 | cs_log_dbg(D_DVBAPI, "Demuxer %d fake ecmpid %04X:%06x:%04x for unencrypted stream on srvid %04X", demux_id, addentry->mapcaid, addentry->mapprovid,
|
---|
2751 | addentry->mapecmpid, demux[demux_id].program_number);
|
---|
2752 | dvbapi_add_ecmpid(demux_id, addentry->mapcaid, addentry->mapecmpid, addentry->mapprovid);
|
---|
2753 | break;
|
---|
2754 | }
|
---|
2755 | }
|
---|
2756 | }
|
---|
2757 | for(j = 0; j < demux[demux_id].ECMpidcount; j++)
|
---|
2758 | {
|
---|
2759 | demux[demux_id].ECMpids[j].VPID = vpid; // register found vpid on all ecmpids of this demuxer
|
---|
2760 | }
|
---|
2761 | cs_log("Demuxer %d found %d ECMpids and %d STREAMpids in PMT", demux_id, demux[demux_id].ECMpidcount, demux[demux_id].STREAMpidcount);
|
---|
2762 |
|
---|
2763 | getDemuxOptions(demux_id, buffer, &ca_mask, &demux_index, &adapter_index, &pmtpid);
|
---|
2764 | char channame[32];
|
---|
2765 | get_servicename(dvbapi_client, demux[demux_id].program_number, demux[demux_id].ECMpidcount > 0 ? demux[demux_id].ECMpids[0].CAID : NO_CAID_VALUE, channame);
|
---|
2766 | cs_log("Demuxer %d serving srvid %04X (%s) on adapter %04X camask %04X index %04X pmtpid %04X", demux_id,
|
---|
2767 | demux[demux_id].program_number, channame, adapter_index, ca_mask, demux_index, pmtpid);
|
---|
2768 |
|
---|
2769 | demux[demux_id].adapter_index = adapter_index;
|
---|
2770 | demux[demux_id].ca_mask = ca_mask;
|
---|
2771 | demux[demux_id].rdr = NULL;
|
---|
2772 | demux[demux_id].demux_index = demux_index;
|
---|
2773 | demux[demux_id].socket_fd = connfd;
|
---|
2774 | demux[demux_id].stopdescramble = 0; // remove deletion mark!
|
---|
2775 |
|
---|
2776 | // remove from unassoc_fd when necessary
|
---|
2777 | for (j = 0; j < MAX_DEMUX; j++)
|
---|
2778 | if (unassoc_fd[j] == connfd)
|
---|
2779 | unassoc_fd[j] = 0;
|
---|
2780 |
|
---|
2781 | dvbapi_capmt_notify(&demux[demux_id]);
|
---|
2782 |
|
---|
2783 | struct s_dvbapi_priority *xtraentry;
|
---|
2784 | int32_t k, l, m, xtra_demux_id;
|
---|
2785 |
|
---|
2786 | for(xtraentry = dvbapi_priority; xtraentry != NULL; xtraentry = xtraentry->next)
|
---|
2787 | {
|
---|
2788 | if(xtraentry->type != 'x') { continue; }
|
---|
2789 |
|
---|
2790 | for(j = 0; j <= demux[demux_id].ECMpidcount; ++j)
|
---|
2791 | {
|
---|
2792 | if((xtraentry->caid && xtraentry->caid != demux[demux_id].ECMpids[j].CAID)
|
---|
2793 | || (xtraentry->provid && xtraentry->provid != demux[demux_id].ECMpids[j].PROVID)
|
---|
2794 | || (xtraentry->ecmpid && xtraentry->ecmpid != demux[demux_id].ECMpids[j].ECM_PID)
|
---|
2795 | || (xtraentry->srvid && xtraentry->srvid != demux[demux_id].program_number))
|
---|
2796 | { continue; }
|
---|
2797 |
|
---|
2798 | cs_log("Mapping ecmpid %04X:%06X:%04X:%04X to xtra demuxer/ca-devices", xtraentry->caid, xtraentry->provid, xtraentry->ecmpid, xtraentry->srvid);
|
---|
2799 |
|
---|
2800 | for(xtra_demux_id = 0; xtra_demux_id < MAX_DEMUX && demux[xtra_demux_id].program_number > 0; xtra_demux_id++)
|
---|
2801 | { ; }
|
---|
2802 |
|
---|
2803 | if(xtra_demux_id >= MAX_DEMUX)
|
---|
2804 | {
|
---|
2805 | cs_log("Found no free demux device for xtra streams.");
|
---|
2806 | continue;
|
---|
2807 | }
|
---|
2808 | // copy to new demuxer
|
---|
2809 | getDemuxOptions(demux_id, buffer, &ca_mask, &demux_index, &adapter_index, &pmtpid);
|
---|
2810 | demux[xtra_demux_id].ECMpids[0] = demux[demux_id].ECMpids[j];
|
---|
2811 | demux[xtra_demux_id].ECMpidcount = 1;
|
---|
2812 | demux[xtra_demux_id].STREAMpidcount = 0;
|
---|
2813 | demux[xtra_demux_id].program_number = demux[demux_id].program_number;
|
---|
2814 | demux[xtra_demux_id].pmtpid = demux[demux_id].pmtpid;
|
---|
2815 | demux[xtra_demux_id].demux_index = demux_index;
|
---|
2816 | demux[xtra_demux_id].adapter_index = adapter_index;
|
---|
2817 | demux[xtra_demux_id].ca_mask = ca_mask;
|
---|
2818 | demux[xtra_demux_id].socket_fd = connfd;
|
---|
2819 | demux[xtra_demux_id].stopdescramble = 0; // remove deletion mark!
|
---|
2820 | demux[xtra_demux_id].rdr = NULL;
|
---|
2821 | demux[xtra_demux_id].curindex = -1;
|
---|
2822 |
|
---|
2823 | // add streams to xtra demux
|
---|
2824 | for(k = 0; k < demux[demux_id].STREAMpidcount; ++k)
|
---|
2825 | {
|
---|
2826 | if(!demux[demux_id].ECMpids[j].streams || demux[demux_id].ECMpids[j].streams & (1 << k))
|
---|
2827 | {
|
---|
2828 | demux[xtra_demux_id].ECMpids[0].streams |= (1 << demux[xtra_demux_id].STREAMpidcount);
|
---|
2829 | demux[xtra_demux_id].STREAMpids[demux[xtra_demux_id].STREAMpidcount] = demux[demux_id].STREAMpids[k];
|
---|
2830 | ++demux[xtra_demux_id].STREAMpidcount;
|
---|
2831 |
|
---|
2832 | // shift stream associations in normal demux because we will remove the stream entirely
|
---|
2833 | for(l = 0; l < demux[demux_id].ECMpidcount; ++l)
|
---|
2834 | {
|
---|
2835 | for(m = k; m < demux[demux_id].STREAMpidcount - 1; ++m)
|
---|
2836 | {
|
---|
2837 | if(demux[demux_id].ECMpids[l].streams & (1 << (m + 1)))
|
---|
2838 | {
|
---|
2839 | demux[demux_id].ECMpids[l].streams |= (1 << m);
|
---|
2840 | }
|
---|
2841 | else
|
---|
2842 | {
|
---|
2843 | demux[demux_id].ECMpids[l].streams &= ~(1 << m);
|
---|
2844 | }
|
---|
2845 | }
|
---|
2846 | }
|
---|
2847 |
|
---|
2848 | // remove stream association from normal demux device
|
---|
2849 | for(l = k; l < demux[demux_id].STREAMpidcount - 1; ++l)
|
---|
2850 | {
|
---|
2851 | demux[demux_id].STREAMpids[l] = demux[demux_id].STREAMpids[l + 1];
|
---|
2852 | }
|
---|
2853 | --demux[demux_id].STREAMpidcount;
|
---|
2854 | --k;
|
---|
2855 | }
|
---|
2856 | }
|
---|
2857 |
|
---|
2858 | // remove ecmpid from normal demuxer
|
---|
2859 | for(k = j; k < demux[demux_id].ECMpidcount; ++k)
|
---|
2860 | {
|
---|
2861 | demux[demux_id].ECMpids[k] = demux[demux_id].ECMpids[k + 1];
|
---|
2862 | }
|
---|
2863 | --demux[demux_id].ECMpidcount;
|
---|
2864 | --j;
|
---|
2865 |
|
---|
2866 | if(demux[xtra_demux_id].STREAMpidcount <= 0)
|
---|
2867 | {
|
---|
2868 | cs_log("Found no streams for xtra demuxer. Not starting additional decoding on it.");
|
---|
2869 | demux[xtra_demux_id].program_number = 0;
|
---|
2870 | demux[xtra_demux_id].stopdescramble = 1;
|
---|
2871 | }
|
---|
2872 |
|
---|
2873 | if(demux[demux_id].STREAMpidcount < 1)
|
---|
2874 | {
|
---|
2875 | cs_log("Found no streams for normal demuxer. Not starting additional decoding on it.");
|
---|
2876 | }
|
---|
2877 | }
|
---|
2878 | }
|
---|
2879 |
|
---|
2880 | if(cfg.dvbapi_au > 0 && demux[demux_id].EMMpidcount == 0) // only do emm setup if au enabled and not running!
|
---|
2881 | {
|
---|
2882 | demux[demux_id].emm_filter = -1; // to register first run emmfilter start
|
---|
2883 | if(demux[demux_id].emmstart.time == 1) // irdeto fetch emm cat direct!
|
---|
2884 | {
|
---|
2885 | cs_ftime(&demux[demux_id].emmstart); // trick to let emm fetching start after 30 seconds to speed up zapping
|
---|
2886 | dvbapi_start_filter(demux_id, demux[demux_id].pidindex, 0x001, 0x001, 0x01, 0x01, 0xFF, 0, TYPE_EMM); //CAT
|
---|
2887 | }
|
---|
2888 | else { cs_ftime(&demux[demux_id].emmstart); } // for all other caids delayed start!
|
---|
2889 | }
|
---|
2890 |
|
---|
2891 | if(start_descrambling)
|
---|
2892 | {
|
---|
2893 | for(j = 0; j < MAX_DEMUX; j++)
|
---|
2894 | {
|
---|
2895 | if(demux[j].program_number == 0) { continue; }
|
---|
2896 |
|
---|
2897 | if(demux[j].running) disable_unused_streampids(j); // disable all streampids not in use anymore
|
---|
2898 |
|
---|
2899 | if(demux[j].running == 0 && demux[j].ECMpidcount != 0 ) // only start demuxer if it wasnt running
|
---|
2900 | {
|
---|
2901 | cs_log_dbg(D_DVBAPI, "Demuxer %d/%d lets start descrambling (srvid = %04X fd = %d ecmpids = %d)", j, MAX_DEMUX,
|
---|
2902 | demux[j].program_number, connfd, demux[j].ECMpidcount);
|
---|
2903 | demux[j].running = 1; // mark channel as running
|
---|
2904 | openxcas_set_sid(demux[j].program_number);
|
---|
2905 | demux[j].decodingtries = -1;
|
---|
2906 | dvbapi_resort_ecmpids(j);
|
---|
2907 | dvbapi_try_next_caid(j, 0);
|
---|
2908 | cs_sleepms(1);
|
---|
2909 | }
|
---|
2910 | else if(demux[j].ECMpidcount == 0) //fta do logging and part of ecmhandler since there will be no ecms asked!
|
---|
2911 | {
|
---|
2912 | cs_log_dbg(D_DVBAPI, "Demuxer %d/%d no descrambling needed (srvid = %04X fd = %d ecmpids = %d)", j, MAX_DEMUX,
|
---|
2913 | demux[j].program_number, connfd, demux[j].ECMpidcount);
|
---|
2914 | demux[j].running = 0; // reset running flag
|
---|
2915 | demux[demux_id].pidindex = -1; // reset ecmpid used for descrambling
|
---|
2916 | dvbapi_stop_filter(j, TYPE_ECM);
|
---|
2917 | if(cfg.usrfileflag) { cs_statistics(dvbapi_client);} // add to user log previous channel + time on channel
|
---|
2918 | dvbapi_client->last_srvid = demux[demux_id].program_number; // set new channel srvid
|
---|
2919 | dvbapi_client->last_caid = NO_CAID_VALUE; // FTA channels have no caid!
|
---|
2920 | dvbapi_client->lastswitch = dvbapi_client->last = time((time_t *)0); // reset idle-Time & last switch
|
---|
2921 | }
|
---|
2922 | }
|
---|
2923 | }
|
---|
2924 | return demux_id;
|
---|
2925 | }
|
---|
2926 |
|
---|
2927 |
|
---|
2928 | void dvbapi_handlesockmsg(unsigned char *buffer, uint32_t len, int32_t connfd)
|
---|
2929 | {
|
---|
2930 | uint32_t val = 0, size = 0, i, k;
|
---|
2931 |
|
---|
2932 | for(k = 0; k < len; k += 3 + size + val)
|
---|
2933 | {
|
---|
2934 | if(buffer[0 + k] != 0x9F || buffer[1 + k] != 0x80)
|
---|
2935 | {
|
---|
2936 | cs_log_dbg(D_DVBAPI, "Received unknown PMT command: %02x", buffer[0 + k]);
|
---|
2937 | break;
|
---|
2938 | }
|
---|
2939 |
|
---|
2940 | if(k > 0)
|
---|
2941 | cs_log_dump_dbg(D_DVBAPI, buffer + k, len - k, "Parsing next PMT object:");
|
---|
2942 |
|
---|
2943 | if(buffer[3 + k] & 0x80)
|
---|
2944 | {
|
---|
2945 | val = 0;
|
---|
2946 | size = buffer[3 + k] & 0x7F;
|
---|
2947 | for(i = 0; i < size; i++)
|
---|
2948 | { val = (val << 8) | buffer[i + 1 + 3 + k]; }
|
---|
2949 | size++;
|
---|
2950 | }
|
---|
2951 | else
|
---|
2952 | {
|
---|
2953 | val = buffer[3 + k] & 0x7F;
|
---|
2954 | size = 1;
|
---|
2955 | }
|
---|
2956 | switch(buffer[2 + k])
|
---|
2957 | {
|
---|
2958 | case 0x32:
|
---|
2959 | dvbapi_parse_capmt(buffer + size + 3 + k, val, connfd, NULL);
|
---|
2960 | break;
|
---|
2961 | case 0x3f:
|
---|
2962 | // 9F 80 3f 04 83 02 00 <demux index>
|
---|
2963 | cs_log_dump_dbg(D_DVBAPI, buffer, len, "capmt 3f:");
|
---|
2964 | // ipbox fix
|
---|
2965 | if(cfg.dvbapi_boxtype == BOXTYPE_IPBOX || cfg.dvbapi_listenport)
|
---|
2966 | {
|
---|
2967 | int32_t demux_index = buffer[7 + k];
|
---|
2968 | for(i = 0; i < MAX_DEMUX; i++)
|
---|
2969 | {
|
---|
2970 | // 0xff demux_index is a wildcard => close all related demuxers
|
---|
2971 | if (demux_index == 0xff)
|
---|
2972 | {
|
---|
2973 | if (demux[i].socket_fd == connfd)
|
---|
2974 | dvbapi_stop_descrambling(i);
|
---|
2975 | }
|
---|
2976 | else if (demux[i].demux_index == demux_index)
|
---|
2977 | {
|
---|
2978 | dvbapi_stop_descrambling(i);
|
---|
2979 | break;
|
---|
2980 | }
|
---|
2981 | }
|
---|
2982 | if (cfg.dvbapi_boxtype == BOXTYPE_IPBOX)
|
---|
2983 | {
|
---|
2984 | // check do we have any demux running on this fd
|
---|
2985 | int16_t execlose = 1;
|
---|
2986 | for(i = 0; i < MAX_DEMUX; i++)
|
---|
2987 | {
|
---|
2988 | if(demux[i].socket_fd == connfd)
|
---|
2989 | {
|
---|
2990 | execlose = 0;
|
---|
2991 | break;
|
---|
2992 | }
|
---|
2993 | }
|
---|
2994 | if(execlose)
|
---|
2995 | {
|
---|
2996 | int32_t ret = close(connfd);
|
---|
2997 | if(ret < 0) { cs_log("ERROR: Could not close PMT fd (errno=%d %s)", errno, strerror(errno)); }
|
---|
2998 | }
|
---|
2999 | }
|
---|
3000 | }
|
---|
3001 | else
|
---|
3002 | {
|
---|
3003 | if(cfg.dvbapi_pmtmode != 6)
|
---|
3004 | {
|
---|
3005 | int32_t ret = close(connfd);
|
---|
3006 | if(ret < 0) { cs_log("ERROR: Could not close PMT fd (errno=%d %s)", errno, strerror(errno)); }
|
---|
3007 | }
|
---|
3008 | }
|
---|
3009 | break;
|
---|
3010 | default:
|
---|
3011 | cs_log_dbg(D_DVBAPI, "handlesockmsg() unknown command");
|
---|
3012 | cs_log_dump(buffer, len, "unknown command:");
|
---|
3013 | break;
|
---|
3014 | }
|
---|
3015 | }
|
---|
3016 | }
|
---|
3017 |
|
---|
3018 | int32_t dvbapi_init_listenfd(void)
|
---|
3019 | {
|
---|
3020 | int32_t clilen, listenfd;
|
---|
3021 | struct sockaddr_un servaddr;
|
---|
3022 |
|
---|
3023 | memset(&servaddr, 0, sizeof(struct sockaddr_un));
|
---|
3024 | servaddr.sun_family = AF_UNIX;
|
---|
3025 | cs_strncpy(servaddr.sun_path, devices[selected_box].cam_socket_path, sizeof(servaddr.sun_path));
|
---|
3026 | clilen = sizeof(servaddr.sun_family) + strlen(servaddr.sun_path);
|
---|
3027 |
|
---|
3028 | if((unlink(devices[selected_box].cam_socket_path) < 0) && (errno != ENOENT))
|
---|
3029 | { return 0; }
|
---|
3030 | if((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
---|
3031 | { return 0; }
|
---|
3032 | if(bind(listenfd, (struct sockaddr *)&servaddr, clilen) < 0)
|
---|
3033 | { return 0; }
|
---|
3034 | if(listen(listenfd, 5) < 0)
|
---|
3035 | { return 0; }
|
---|
3036 |
|
---|
3037 | // change the access right on the camd.socket
|
---|
3038 | // this will allow oscam to run as root if needed
|
---|
3039 | // and still allow non root client to connect to the socket
|
---|
3040 | chmod(devices[selected_box].cam_socket_path, S_IRWXU | S_IRWXG | S_IRWXO);
|
---|
3041 |
|
---|
3042 | return listenfd;
|
---|
3043 | }
|
---|
3044 |
|
---|
3045 | int32_t dvbapi_net_init_listenfd(void)
|
---|
3046 | {
|
---|
3047 | int32_t listenfd;
|
---|
3048 | struct SOCKADDR servaddr;
|
---|
3049 |
|
---|
3050 | memset(&servaddr, 0, sizeof(servaddr));
|
---|
3051 | SIN_GET_FAMILY(servaddr) = DEFAULT_AF;
|
---|
3052 | SIN_GET_ADDR(servaddr) = ADDR_ANY;
|
---|
3053 | SIN_GET_PORT(servaddr) = htons((uint16_t)cfg.dvbapi_listenport);
|
---|
3054 |
|
---|
3055 | if((listenfd = socket(DEFAULT_AF, SOCK_STREAM, 0)) < 0)
|
---|
3056 | { return 0; }
|
---|
3057 |
|
---|
3058 | int32_t opt = 0;
|
---|
3059 | #ifdef IPV6SUPPORT
|
---|
3060 | // set the server socket option to listen on IPv4 and IPv6 simultaneously
|
---|
3061 | setsockopt(listenfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&opt, sizeof(opt));
|
---|
3062 | #endif
|
---|
3063 |
|
---|
3064 | opt = 1;
|
---|
3065 | setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(opt));
|
---|
3066 | set_so_reuseport(listenfd);
|
---|
3067 |
|
---|
3068 | if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
|
---|
3069 | { return 0; }
|
---|
3070 | if(listen(listenfd, 5) < 0)
|
---|
3071 | { return 0; }
|
---|
3072 |
|
---|
3073 | return listenfd;
|
---|
3074 | }
|
---|
3075 |
|
---|
3076 | static pthread_mutex_t event_handler_lock;
|
---|
3077 |
|
---|
3078 | void event_handler(int32_t UNUSED(signal))
|
---|
3079 | {
|
---|
3080 | struct stat pmt_info;
|
---|
3081 | char dest[1024];
|
---|
3082 | DIR *dirp;
|
---|
3083 | struct dirent entry, *dp = NULL;
|
---|
3084 | int32_t i, pmt_fd;
|
---|
3085 | uchar mbuf[2048]; // dirty fix: larger buffer needed for CA PMT mode 6 with many parallel channels to decode
|
---|
3086 | if(dvbapi_client != cur_client()) { return; }
|
---|
3087 |
|
---|
3088 | pthread_mutex_lock(&event_handler_lock);
|
---|
3089 |
|
---|
3090 | if(cfg.dvbapi_boxtype == BOXTYPE_PC || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX)
|
---|
3091 | { pausecam = 0; }
|
---|
3092 | else
|
---|
3093 | {
|
---|
3094 | int32_t standby_fd = open(STANDBY_FILE, O_RDONLY);
|
---|
3095 | pausecam = (standby_fd > 0) ? 1 : 0;
|
---|
3096 | if(standby_fd > 0)
|
---|
3097 | {
|
---|
3098 | int32_t ret = close(standby_fd);
|
---|
3099 | if(ret < 0) { cs_log("ERROR: Could not close standby fd (errno=%d %s)", errno, strerror(errno)); }
|
---|
3100 | }
|
---|
3101 | }
|
---|
3102 |
|
---|
3103 | if(cfg.dvbapi_boxtype == BOXTYPE_IPBOX || cfg.dvbapi_pmtmode == 1)
|
---|
3104 | {
|
---|
3105 | pthread_mutex_unlock(&event_handler_lock);
|
---|
3106 | return;
|
---|
3107 | }
|
---|
3108 |
|
---|
3109 | for(i = 0; i < MAX_DEMUX; i++)
|
---|
3110 | {
|
---|
3111 | if(demux[i].pmt_file[0] != 0)
|
---|
3112 | {
|
---|
3113 | snprintf(dest, sizeof(dest), "%s%s", TMPDIR, demux[i].pmt_file);
|
---|
3114 | pmt_fd = open(dest, O_RDONLY);
|
---|
3115 | if(pmt_fd > 0)
|
---|
3116 | {
|
---|
3117 | if(fstat(pmt_fd, &pmt_info) != 0)
|
---|
3118 | {
|
---|
3119 | int32_t ret = close(pmt_fd);
|
---|
3120 | if(ret < 0) { cs_log("ERROR: Could not close PMT fd (errno=%d %s)", errno, strerror(errno)); }
|
---|
3121 | continue;
|
---|
3122 | }
|
---|
3123 |
|
---|
3124 | if((time_t)pmt_info.st_mtime != demux[i].pmt_time)
|
---|
3125 | {
|
---|
3126 | dvbapi_stop_descrambling(i);
|
---|
3127 | }
|
---|
3128 |
|
---|
3129 | int32_t ret = close(pmt_fd);
|
---|
3130 | if(ret < 0) { cs_log("ERROR: Could not close PMT fd (errno=%d %s)", errno, strerror(errno)); }
|
---|
3131 | continue;
|
---|
3132 | }
|
---|
3133 | else
|
---|
3134 | {
|
---|
3135 | cs_log("Demuxer %d Unable to open PMT file %s -> stop descrambling!", i, dest);
|
---|
3136 | dvbapi_stop_descrambling(i);
|
---|
3137 | }
|
---|
3138 | }
|
---|
3139 | }
|
---|
3140 |
|
---|
3141 | if(disable_pmt_files)
|
---|
3142 | {
|
---|
3143 | pthread_mutex_unlock(&event_handler_lock);
|
---|
3144 | return;
|
---|
3145 | }
|
---|
3146 |
|
---|
3147 | dirp = opendir(TMPDIR);
|
---|
3148 | if(!dirp)
|
---|
3149 | {
|
---|
3150 | cs_log_dbg(D_DVBAPI, "opendir failed (errno=%d %s)", errno, strerror(errno));
|
---|
3151 | pthread_mutex_unlock(&event_handler_lock);
|
---|
3152 | return;
|
---|
3153 | }
|
---|
3154 |
|
---|
3155 | while(!cs_readdir_r(dirp, &entry, &dp))
|
---|
3156 | {
|
---|
3157 | if(!dp) { break; }
|
---|
3158 |
|
---|
3159 | if(strlen(dp->d_name) < 7)
|
---|
3160 | { continue; }
|
---|
3161 | if(strncmp(dp->d_name, "pmt", 3) != 0 || strncmp(dp->d_name + strlen(dp->d_name) - 4, ".tmp", 4) != 0)
|
---|
3162 | { continue; }
|
---|
3163 | #ifdef WITH_STAPI
|
---|
3164 | struct s_dvbapi_priority *p;
|
---|
3165 | for(p = dvbapi_priority; p != NULL; p = p->next) // stapi: check if there is a device connected to this pmt file!
|
---|
3166 | {
|
---|
3167 | if(p->type != 's') { continue; } // stapi rule?
|
---|
3168 | if(strcmp(dp->d_name, p->pmtfile) != 0) { continue; } // same file?
|
---|
3169 | break; // found match!
|
---|
3170 | }
|
---|
3171 | if(p == NULL)
|
---|
3172 | {
|
---|
3173 | cs_log_dbg(D_DVBAPI, "No matching S: line in oscam.dvbapi for pmtfile %s -> skip!", dp->d_name);
|
---|
3174 | continue;
|
---|
3175 | }
|
---|
3176 | #endif
|
---|
3177 | snprintf(dest, sizeof(dest), "%s%s", TMPDIR, dp->d_name);
|
---|
3178 | pmt_fd = open(dest, O_RDONLY);
|
---|
3179 | if(pmt_fd < 0)
|
---|
3180 | { continue; }
|
---|
3181 |
|
---|
3182 | if(fstat(pmt_fd, &pmt_info) != 0)
|
---|
3183 | {
|
---|
3184 | int32_t ret = close(pmt_fd);
|
---|
3185 | if(ret < 0) { cs_log("ERROR: Could not close PMT fd (errno=%d %s)", errno, strerror(errno)); }
|
---|
3186 | continue;
|
---|
3187 | }
|
---|
3188 |
|
---|
3189 | int32_t found = 0;
|
---|
3190 | for(i = 0; i < MAX_DEMUX; i++)
|
---|
3191 | {
|
---|
3192 | if(strcmp(demux[i].pmt_file, dp->d_name) == 0)
|
---|
3193 | {
|
---|
3194 | if((time_t)pmt_info.st_mtime == demux[i].pmt_time)
|
---|
3195 | {
|
---|
3196 | found = 1;
|
---|
3197 | continue;
|
---|
3198 | }
|
---|
3199 | dvbapi_stop_descrambling(i);
|
---|
3200 | }
|
---|
3201 | }
|
---|
3202 | if(found)
|
---|
3203 | {
|
---|
3204 | int32_t ret = close(pmt_fd);
|
---|
3205 | if(ret < 0) { cs_log("ERROR: Could not close PMT fd (errno=%d %s)", errno, strerror(errno)); }
|
---|
3206 | continue;
|
---|
3207 | }
|
---|
3208 |
|
---|
3209 | cs_log_dbg(D_DVBAPI, "found pmt file %s", dest);
|
---|
3210 | cs_sleepms(100);
|
---|
3211 |
|
---|
3212 | uint32_t len = read(pmt_fd, mbuf, sizeof(mbuf));
|
---|
3213 | int32_t ret = close(pmt_fd);
|
---|
3214 | if(ret < 0) { cs_log("ERROR: Could not close PMT fd (errno=%d %s)", errno, strerror(errno)); }
|
---|
3215 |
|
---|
3216 | if(len < 1)
|
---|
3217 | {
|
---|
3218 | cs_log_dbg(D_DVBAPI, "pmt file %s have invalid len!", dest);
|
---|
3219 | continue;
|
---|
3220 | }
|
---|
3221 |
|
---|
3222 | int32_t pmt_id;
|
---|
3223 |
|
---|
3224 | #ifdef QBOXHD
|
---|
3225 | uint32_t j1, j2;
|
---|
3226 | // QboxHD pmt.tmp is the full capmt written as a string of hex values
|
---|
3227 | // pmt.tmp must be longer than 3 bytes (6 hex chars) and even length
|
---|
3228 | if((len < 6) || ((len % 2) != 0) || ((len / 2) > sizeof(dest)))
|
---|
3229 | {
|
---|
3230 | cs_log_dbg(D_DVBAPI, "error parsing QboxHD pmt.tmp, incorrect length");
|
---|
3231 | continue;
|
---|
3232 | }
|
---|
3233 |
|
---|
3234 | for(j2 = 0, j1 = 0; j2 < len; j2 += 2, j1++)
|
---|
3235 | {
|
---|
3236 | unsigned int tmp;
|
---|
3237 | if(sscanf((char *)mbuf + j2, "%02X", &tmp) != 1)
|
---|
3238 | {
|
---|
3239 | cs_log_dbg(D_DVBAPI, "error parsing QboxHD pmt.tmp, data not valid in position %d", j2);
|
---|
3240 | pthread_mutex_unlock(&event_handler_lock);
|
---|
3241 | return;
|
---|
3242 | }
|
---|
3243 | else
|
---|
3244 | {
|
---|
3245 | memcpy(dest + j1, &tmp, 4);
|
---|
3246 | }
|
---|
3247 | }
|
---|
3248 |
|
---|
3249 | cs_log_dump_dbg(D_DVBAPI, (unsigned char *)dest, len / 2, "QboxHD pmt.tmp:");
|
---|
3250 | pmt_id = dvbapi_parse_capmt((unsigned char *)dest + 4, (len / 2) - 4, -1, dp->d_name);
|
---|
3251 | #else
|
---|
3252 | if(len > sizeof(dest))
|
---|
3253 | {
|
---|
3254 | cs_log_dbg(D_DVBAPI, "event_handler() dest buffer is to small for pmt data!");
|
---|
3255 | continue;
|
---|
3256 | }
|
---|
3257 | if(len < 16)
|
---|
3258 | {
|
---|
3259 | cs_log_dbg(D_DVBAPI, "event_handler() received pmt is too small! (%d < 16 bytes!)", len);
|
---|
3260 | continue;
|
---|
3261 | }
|
---|
3262 | cs_log_dump_dbg(D_DVBAPI, mbuf, len, "pmt:");
|
---|
3263 |
|
---|
3264 | dest[0] = 0x03;
|
---|
3265 | dest[1] = mbuf[3];
|
---|
3266 | dest[2] = mbuf[4];
|
---|
3267 | uint32_t pmt_program_length = b2i(2, mbuf + 10)&0xFFF;
|
---|
3268 | i2b_buf(2, pmt_program_length + 1, (uchar *) dest + 4);
|
---|
3269 | dest[6] = 0;
|
---|
3270 |
|
---|
3271 | memcpy(dest + 7, mbuf + 12, len - 12 - 4);
|
---|
3272 |
|
---|
3273 | pmt_id = dvbapi_parse_capmt((uchar *)dest, 7 + len - 12 - 4, -1, dp->d_name);
|
---|
3274 | #endif
|
---|
3275 |
|
---|
3276 | if(pmt_id >= 0)
|
---|
3277 | {
|
---|
3278 | cs_strncpy(demux[pmt_id].pmt_file, dp->d_name, sizeof(demux[pmt_id].pmt_file));
|
---|
3279 | demux[pmt_id].pmt_time = (time_t)pmt_info.st_mtime;
|
---|
3280 | }
|
---|
3281 |
|
---|
3282 | if(cfg.dvbapi_pmtmode == 3)
|
---|
3283 | {
|
---|
3284 | disable_pmt_files = 1;
|
---|
3285 | break;
|
---|
3286 | }
|
---|
3287 | }
|
---|
3288 | closedir(dirp);
|
---|
3289 | pthread_mutex_unlock(&event_handler_lock);
|
---|
3290 | }
|
---|
3291 |
|
---|
3292 | void *dvbapi_event_thread(void *cli)
|
---|
3293 | {
|
---|
3294 | struct s_client *client = (struct s_client *) cli;
|
---|
3295 | pthread_setspecific(getclient, client);
|
---|
3296 | set_thread_name(__func__);
|
---|
3297 | while(1)
|
---|
3298 | {
|
---|
3299 | cs_sleepms(750);
|
---|
3300 | event_handler(0);
|
---|
3301 | }
|
---|
3302 |
|
---|
3303 | return NULL;
|
---|
3304 | }
|
---|
3305 |
|
---|
3306 | void dvbapi_process_input(int32_t demux_id, int32_t filter_num, uchar *buffer, int32_t len)
|
---|
3307 | {
|
---|
3308 | int32_t pid = demux[demux_id].demux_fd[filter_num].pidindex;
|
---|
3309 | struct s_ecmpids *curpid = NULL;
|
---|
3310 | if(pid != -1)
|
---|
3311 | {
|
---|
3312 | curpid = &demux[demux_id].ECMpids[pid];
|
---|
3313 | }
|
---|
3314 | uint32_t chid = 0x10000;
|
---|
3315 | uint32_t ecmlen = (b2i(2, buffer + 1)&0xFFF)+3;
|
---|
3316 | ECM_REQUEST *er;
|
---|
3317 |
|
---|
3318 | if(demux[demux_id].demux_fd[filter_num].type == TYPE_ECM)
|
---|
3319 | {
|
---|
3320 | if(len != 0) // len = 0 receiver encountered an internal bufferoverflow!
|
---|
3321 | {
|
---|
3322 | cs_log_dbg(D_DVBAPI, "Demuxer %d Filter %d fetched ECM data (ecmlength = %03X)", demux_id, filter_num + 1, ecmlen);
|
---|
3323 | if((uint) len < ecmlen) // invalid CAT length
|
---|
3324 | {
|
---|
3325 | cs_log_dbg(D_DVBAPI, "Received data with total length %03X but ECM length is %03X -> invalid CAT length!", len, ecmlen);
|
---|
3326 | return;
|
---|
3327 | }
|
---|
3328 |
|
---|
3329 | if(!(buffer[0] == 0x80 || buffer[0] == 0x81))
|
---|
3330 | {
|
---|
3331 | cs_log_dbg(D_DVBAPI, "Received an ECM with invalid ecmtable ID %02X -> ignoring!", buffer[0]);
|
---|
3332 | return;
|
---|
3333 | }
|
---|
3334 |
|
---|
3335 | if(curpid->table == buffer[0] && !caid_is_irdeto(curpid->CAID)) // wait for odd / even ecm change (only not for irdeto!)
|
---|
3336 | {
|
---|
3337 |
|
---|
3338 | if(!(er = get_ecmtask()))
|
---|
3339 | {
|
---|
3340 | return;
|
---|
3341 | }
|
---|
3342 |
|
---|
3343 | er->srvid = demux[demux_id].program_number;
|
---|
3344 |
|
---|
3345 | er->tsid = demux[demux_id].tsid;
|
---|
3346 | er->onid = demux[demux_id].onid;
|
---|
3347 | er->pmtpid = demux[demux_id].pmtpid;
|
---|
3348 | er->ens = demux[demux_id].enigma_namespace;
|
---|
3349 |
|
---|
3350 | er->caid = curpid->CAID;
|
---|
3351 | er->pid = curpid->ECM_PID;
|
---|
3352 | er->prid = curpid->PROVID;
|
---|
3353 | er->vpid = curpid->VPID;
|
---|
3354 | er->ecmlen = ecmlen;
|
---|
3355 | memcpy(er->ecm, buffer, er->ecmlen);
|
---|
3356 | chid = get_subid(er); // fetch chid or fake chid
|
---|
3357 | er->chid = chid;
|
---|
3358 | dvbapi_set_section_filter(demux_id, er, filter_num);
|
---|
3359 | NULLFREE(er);
|
---|
3360 | return;
|
---|
3361 | }
|
---|
3362 |
|
---|
3363 | if(caid_is_irdeto(curpid->CAID))
|
---|
3364 | {
|
---|
3365 | // 80 70 39 53 04 05 00 88
|
---|
3366 | // 81 70 41 41 01 06 00 13 00 06 80 38 1F 52 93 D2
|
---|
3367 | //if (buffer[5]>20) return;
|
---|
3368 | if(curpid->irdeto_maxindex != buffer[5]) //6, register max irdeto index
|
---|
3369 | {
|
---|
3370 | cs_log_dbg(D_DVBAPI, "Found %d IRDETO ECM CHIDs", buffer[5] + 1);
|
---|
3371 | curpid->irdeto_maxindex = buffer[5]; // numchids = 7 (0..6)
|
---|
3372 | }
|
---|
3373 | }
|
---|
3374 | }
|
---|
3375 |
|
---|
3376 | if(!(er = get_ecmtask()))
|
---|
3377 | {
|
---|
3378 | return;
|
---|
3379 | }
|
---|
3380 |
|
---|
3381 | er->srvid = demux[demux_id].program_number;
|
---|
3382 |
|
---|
3383 | er->tsid = demux[demux_id].tsid;
|
---|
3384 | er->onid = demux[demux_id].onid;
|
---|
3385 | er->pmtpid = demux[demux_id].pmtpid;
|
---|
3386 | er->ens = demux[demux_id].enigma_namespace;
|
---|
3387 |
|
---|
3388 | er->caid = curpid->CAID;
|
---|
3389 | er->pid = curpid->ECM_PID;
|
---|
3390 | er->prid = curpid->PROVID;
|
---|
3391 | er->vpid = curpid->VPID;
|
---|
3392 | er->ecmlen = ecmlen;
|
---|
3393 | memcpy(er->ecm, buffer, er->ecmlen);
|
---|
3394 |
|
---|
3395 | chid = get_subid(er); // fetch chid or fake chid
|
---|
3396 | er->chid = chid;
|
---|
3397 |
|
---|
3398 | if(len == 0) // only used on receiver internal bufferoverflow to get quickly fresh ecm filterdata otherwise freezing!
|
---|
3399 | {
|
---|
3400 | curpid->table = 0;
|
---|
3401 | dvbapi_set_section_filter(demux_id, er, filter_num);
|
---|
3402 | NULLFREE(er);
|
---|
3403 | return;
|
---|
3404 | }
|
---|
3405 |
|
---|
3406 | if(caid_is_irdeto(curpid->CAID))
|
---|
3407 | {
|
---|
3408 |
|
---|
3409 | if(curpid->irdeto_curindex != buffer[4]) // old style wrong irdeto index
|
---|
3410 | {
|
---|
3411 | if(curpid->irdeto_curindex == 0xFE) // check if this ecmfilter just started up
|
---|
3412 | {
|
---|
3413 | curpid->irdeto_curindex = buffer[4]; // on startup set the current index to the irdeto index of the ecm
|
---|
3414 | }
|
---|
3415 | else // we are already running and not interested in this ecm
|
---|
3416 | {
|
---|
3417 | if(curpid->table != buffer[0]) curpid->table = 0; // fix for receivers not supporting section filtering
|
---|
3418 | dvbapi_set_section_filter(demux_id, er, filter_num); // set ecm filter to odd + even since this ecm doesnt match with current irdeto index
|
---|
3419 | NULLFREE(er);
|
---|
3420 | return;
|
---|
3421 | }
|
---|
3422 | }
|
---|
3423 | else //fix for receivers not supporting section filtering
|
---|
3424 | {
|
---|
3425 | if(curpid->table == buffer[0]){
|
---|
3426 | NULLFREE(er);
|
---|
3427 | return;
|
---|
3428 | }
|
---|
3429 | }
|
---|
3430 | cs_log_dbg(D_DVBAPI, "Demuxer %d ECMTYPE %02X CAID %04X PROVID %06X ECMPID %04X IRDETO INDEX %02X MAX INDEX %02X CHID %04X CYCLE %02X VPID %04X", demux_id, er->ecm[0], er->caid, er->prid, er->pid, er->ecm[4], er->ecm[5], er->chid, curpid->irdeto_cycle, er->vpid);
|
---|
3431 | }
|
---|
3432 | else
|
---|
3433 | {
|
---|
3434 | cs_log_dbg(D_DVBAPI, "Demuxer %d ECMTYPE %02X CAID %04X PROVID %06X ECMPID %04X FAKECHID %04X (unique part in ecm)",
|
---|
3435 | demux_id, er->ecm[0], er->caid, er->prid, er->pid, er->chid);
|
---|
3436 | }
|
---|
3437 |
|
---|
3438 | // check for matching chid (unique ecm part in case of non-irdeto cas) + added fix for seca2 monthly changing fakechid
|
---|
3439 | if((curpid->CHID < 0x10000) && !((chid == curpid->CHID) || ((curpid->CAID >> 8 == 0x01) && (chid&0xF0FF) == (curpid->CHID&0xF0FF)) ) )
|
---|
3440 | {
|
---|
3441 | if(caid_is_irdeto(curpid->CAID))
|
---|
3442 | {
|
---|
3443 |
|
---|
3444 | if((curpid->irdeto_cycle < 0xFE) && (curpid->irdeto_cycle == curpid->irdeto_curindex)) // if same: we cycled all indexes but no luck!
|
---|
3445 | {
|
---|
3446 | struct s_dvbapi_priority *forceentry = dvbapi_check_prio_match(demux_id, pid, 'p');
|
---|
3447 | if(!forceentry || !forceentry->force) // forced pid? keep trying the forced ecmpid, no force kill ecm filter
|
---|
3448 | {
|
---|
3449 | if(curpid->checked == 2) { curpid->checked = 4; }
|
---|
3450 | if(curpid->checked == 1)
|
---|
3451 | {
|
---|
3452 | curpid->checked = 2;
|
---|
3453 | curpid->CHID = 0x10000;
|
---|
3454 | }
|
---|
3455 | dvbapi_stop_filternum(demux_id, filter_num); // stop this ecm filter!
|
---|
3456 | NULLFREE(er);
|
---|
3457 | return;
|
---|
3458 | }
|
---|
3459 | }
|
---|
3460 |
|
---|
3461 | curpid->irdeto_curindex++; // set check on next index
|
---|
3462 | if(curpid->irdeto_cycle == 0xFE) curpid->irdeto_cycle = buffer[4]; // on startup set to current irdeto index
|
---|
3463 | if(curpid->irdeto_curindex > curpid->irdeto_maxindex) { curpid->irdeto_curindex = 0; } // check if we reached max irdeto index, if so reset to 0
|
---|
3464 |
|
---|
3465 | curpid->table = 0;
|
---|
3466 | dvbapi_set_section_filter(demux_id, er, filter_num); // set ecm filter to odd + even since this ecm doesnt match with current irdeto index
|
---|
3467 | NULLFREE(er);
|
---|
3468 | return;
|
---|
3469 | }
|
---|
3470 | else // all nonirdeto cas systems
|
---|
3471 | {
|
---|
3472 | struct s_dvbapi_priority *forceentry = dvbapi_check_prio_match(demux_id, pid, 'p');
|
---|
3473 | curpid->table = 0;
|
---|
3474 | dvbapi_set_section_filter(demux_id, er, filter_num); // set ecm filter to odd + even since this ecm doesnt match with current irdeto index
|
---|
3475 | if(forceentry && forceentry->force)
|
---|
3476 | {
|
---|
3477 | NULLFREE(er);
|
---|
3478 | return; // forced pid? keep trying the forced ecmpid!
|
---|
3479 | }
|
---|
3480 | if(curpid->checked == 2) { curpid->checked = 4; }
|
---|
3481 | if(curpid->checked == 1)
|
---|
3482 | {
|
---|
3483 | curpid->checked = 2;
|
---|
3484 | curpid->CHID = 0x10000;
|
---|
3485 | }
|
---|
3486 | dvbapi_stop_filternum(demux_id, filter_num); // stop this ecm filter!
|
---|
3487 | NULLFREE(er);
|
---|
3488 | return;
|
---|
3489 | }
|
---|
3490 | }
|
---|
3491 |
|
---|
3492 | struct s_dvbapi_priority *p;
|
---|
3493 |
|
---|
3494 | for(p = dvbapi_priority; p != NULL; p = p->next)
|
---|
3495 | {
|
---|
3496 | if(p->type != 'l'
|
---|
3497 | || (p->caid && p->caid != curpid->CAID)
|
---|
3498 | || (p->provid && p->provid != curpid->PROVID)
|
---|
3499 | || (p->ecmpid && p->ecmpid != curpid->ECM_PID)
|
---|
3500 | || (p->srvid && p->srvid != demux[demux_id].program_number))
|
---|
3501 | { continue; }
|
---|
3502 |
|
---|
3503 | if((uint)p->delay == ecmlen && p->force < 6)
|
---|
3504 | {
|
---|
3505 | p->force++;
|
---|
3506 | NULLFREE(er);
|
---|
3507 | return;
|
---|
3508 | }
|
---|
3509 | if(p->force >= 6)
|
---|
3510 | { p->force = 0; }
|
---|
3511 | }
|
---|
3512 |
|
---|
3513 | if(!curpid->PROVID)
|
---|
3514 | { curpid->PROVID = chk_provid(buffer, curpid->CAID); }
|
---|
3515 |
|
---|
3516 | if(caid_is_irdeto(curpid->CAID)) // irdeto: wait for the correct index
|
---|
3517 | {
|
---|
3518 | if(buffer[4] != curpid->irdeto_curindex)
|
---|
3519 | {
|
---|
3520 | curpid->table = 0;
|
---|
3521 | dvbapi_set_section_filter(demux_id, er, filter_num); // set ecm filter to odd + even since this ecm doesnt match with current irdeto index
|
---|
3522 | NULLFREE(er);
|
---|
3523 | return;
|
---|
3524 | }
|
---|
3525 | }
|
---|
3526 | // we have an ecm with the correct irdeto index (or fakechid)
|
---|
3527 | for(p = dvbapi_priority; p != NULL ; p = p->next) // check for ignore!
|
---|
3528 | {
|
---|
3529 | if((p->type != 'i')
|
---|
3530 | || (p->caid && p->caid != curpid->CAID)
|
---|
3531 | || (p->provid && p->provid != curpid->PROVID)
|
---|
3532 | || (p->ecmpid && p->ecmpid != curpid->ECM_PID)
|
---|
3533 | || (p->pidx && p->pidx-1 != pid)
|
---|
3534 | || (p->srvid && p->srvid != demux[demux_id].program_number))
|
---|
3535 | { continue; }
|
---|
3536 |
|
---|
3537 | if(p->type == 'i' && (p->chid < 0x10000 && p->chid == chid)) // found a ignore chid match with current ecm -> ignoring this irdeto index
|
---|
3538 | {
|
---|
3539 | curpid->irdeto_curindex++;
|
---|
3540 | if(curpid->irdeto_cycle == 0xFE) curpid->irdeto_cycle = buffer[4]; // on startup set to current irdeto index
|
---|
3541 | if(curpid->irdeto_curindex > curpid->irdeto_maxindex) // check if curindex is over the max
|
---|
3542 | {
|
---|
3543 | curpid->irdeto_curindex = 0;
|
---|
3544 | }
|
---|
3545 | curpid->table = 0;
|
---|
3546 | if(caid_is_irdeto(curpid->CAID) && (curpid->irdeto_cycle != curpid->irdeto_curindex)) // irdeto: wait for the correct index + check if we cycled all
|
---|
3547 | {
|
---|
3548 | dvbapi_set_section_filter(demux_id, er, filter_num); // set ecm filter to odd + even since this chid has to be ignored!
|
---|
3549 | }
|
---|
3550 | else // this fakechid has to be ignored, kill this filter!
|
---|
3551 | {
|
---|
3552 | if(curpid->checked == 2) { curpid->checked = 4; }
|
---|
3553 | if(curpid->checked == 1)
|
---|
3554 | {
|
---|
3555 | curpid->checked = 2;
|
---|
3556 | curpid->CHID = 0x10000;
|
---|
3557 | }
|
---|
3558 | dvbapi_stop_filternum(demux_id, filter_num); // stop this ecm filter!
|
---|
3559 | }
|
---|
3560 | NULLFREE(er);
|
---|
3561 | return;
|
---|
3562 | }
|
---|
3563 | }
|
---|
3564 |
|
---|
3565 | if(er)
|
---|
3566 | {
|
---|
3567 | curpid->table = er->ecm[0];
|
---|
3568 | }
|
---|
3569 |
|
---|
3570 | request_cw(dvbapi_client, er, demux_id, 1); // register this ecm for delayed ecm response check
|
---|
3571 | return; // end of ecm filterhandling!
|
---|
3572 | }
|
---|
3573 |
|
---|
3574 | if(demux[demux_id].demux_fd[filter_num].type == TYPE_EMM && len != 0) // len = 0 receiver encountered an internal bufferoverflow!
|
---|
3575 | {
|
---|
3576 | if(demux[demux_id].demux_fd[filter_num].pid == 0x01) // CAT
|
---|
3577 | {
|
---|
3578 | cs_log_dbg(D_DVBAPI, "receiving cat");
|
---|
3579 | dvbapi_parse_cat(demux_id, buffer, len);
|
---|
3580 |
|
---|
3581 | dvbapi_stop_filternum(demux_id, filter_num);
|
---|
3582 | return;
|
---|
3583 | }
|
---|
3584 | dvbapi_process_emm(demux_id, filter_num, buffer, len);
|
---|
3585 | }
|
---|
3586 | }
|
---|
3587 |
|
---|
3588 | static void *dvbapi_main_local(void *cli)
|
---|
3589 | {
|
---|
3590 | int32_t i, j;
|
---|
3591 | struct s_client *client = (struct s_client *) cli;
|
---|
3592 | client->thread = pthread_self();
|
---|
3593 | pthread_setspecific(getclient, cli);
|
---|
3594 |
|
---|
3595 | dvbapi_client = cli;
|
---|
3596 |
|
---|
3597 | int32_t maxpfdsize = (MAX_DEMUX * maxfilter) + MAX_DEMUX + 2;
|
---|
3598 | struct pollfd pfd2[maxpfdsize];
|
---|
3599 | struct timeb start, end; // start time poll, end time poll
|
---|
3600 | #define PMT_SERVER_SOCKET "/tmp/.listen.camd.socket"
|
---|
3601 | struct sockaddr_un saddr;
|
---|
3602 | saddr.sun_family = AF_UNIX;
|
---|
3603 | strncpy(saddr.sun_path, PMT_SERVER_SOCKET, 107);
|
---|
3604 | saddr.sun_path[107] = '\0';
|
---|
3605 |
|
---|
3606 | int32_t rc, pfdcount, g, connfd, clilen;
|
---|
3607 | int32_t ids[maxpfdsize], fdn[maxpfdsize], type[maxpfdsize];
|
---|
3608 | struct SOCKADDR servaddr;
|
---|
3609 | ssize_t len = 0;
|
---|
3610 | uchar mbuf[1024];
|
---|
3611 |
|
---|
3612 | struct s_auth *account;
|
---|
3613 | int32_t ok = 0;
|
---|
3614 | for(account = cfg.account; account != NULL; account = account->next)
|
---|
3615 | {
|
---|
3616 | if((ok = is_dvbapi_usr(account->usr)))
|
---|
3617 | { break; }
|
---|
3618 | }
|
---|
3619 | cs_auth_client(client, ok ? account : (struct s_auth *)(-1), "dvbapi");
|
---|
3620 |
|
---|
3621 | memset(demux, 0, sizeof(struct demux_s) * MAX_DEMUX);
|
---|
3622 | memset(ca_fd, 0, sizeof(ca_fd));
|
---|
3623 | memset(unassoc_fd, 0, sizeof(unassoc_fd));
|
---|
3624 |
|
---|
3625 | dvbapi_read_priority();
|
---|
3626 | dvbapi_load_channel_cache();
|
---|
3627 | dvbapi_detect_api();
|
---|
3628 |
|
---|
3629 | if(selected_box == -1 || selected_api == -1)
|
---|
3630 | {
|
---|
3631 | cs_log("ERROR: Could not detect DVBAPI version.");
|
---|
3632 | return NULL;
|
---|
3633 | }
|
---|
3634 |
|
---|
3635 | if(cfg.dvbapi_pmtmode == 1)
|
---|
3636 | { disable_pmt_files = 1; }
|
---|
3637 |
|
---|
3638 | int32_t listenfd = -1;
|
---|
3639 | if(cfg.dvbapi_boxtype != BOXTYPE_IPBOX_PMT && cfg.dvbapi_pmtmode != 2 && cfg.dvbapi_pmtmode != 5 && cfg.dvbapi_pmtmode != 6)
|
---|
3640 | {
|
---|
3641 | if (!cfg.dvbapi_listenport)
|
---|
3642 | listenfd = dvbapi_init_listenfd();
|
---|
3643 | else
|
---|
3644 | listenfd = dvbapi_net_init_listenfd();
|
---|
3645 | if(listenfd < 1)
|
---|
3646 | {
|
---|
3647 | cs_log("ERROR: Could not init socket: (errno=%d: %s)", errno, strerror(errno));
|
---|
3648 | return NULL;
|
---|
3649 | }
|
---|
3650 | }
|
---|
3651 |
|
---|
3652 | pthread_mutex_init(&event_handler_lock, NULL);
|
---|
3653 |
|
---|
3654 | for(i = 0; i < MAX_DEMUX; i++) // init all demuxers!
|
---|
3655 | {
|
---|
3656 | demux[i].pidindex = -1;
|
---|
3657 | demux[i].curindex = -1;
|
---|
3658 | }
|
---|
3659 |
|
---|
3660 | if(cfg.dvbapi_pmtmode != 4 && cfg.dvbapi_pmtmode != 5 && cfg.dvbapi_pmtmode != 6)
|
---|
3661 | {
|
---|
3662 | struct sigaction signal_action;
|
---|
3663 | signal_action.sa_handler = event_handler;
|
---|
3664 | sigemptyset(&signal_action.sa_mask);
|
---|
3665 | signal_action.sa_flags = SA_RESTART;
|
---|
3666 | sigaction(SIGRTMIN + 1, &signal_action, NULL);
|
---|
3667 |
|
---|
3668 | dir_fd = open(TMPDIR, O_RDONLY);
|
---|
3669 | if(dir_fd >= 0)
|
---|
3670 | {
|
---|
3671 | fcntl(dir_fd, F_SETSIG, SIGRTMIN + 1);
|
---|
3672 | fcntl(dir_fd, F_NOTIFY, DN_MODIFY | DN_CREATE | DN_DELETE | DN_MULTISHOT);
|
---|
3673 | event_handler(SIGRTMIN + 1);
|
---|
3674 | }
|
---|
3675 | }
|
---|
3676 | else
|
---|
3677 | {
|
---|
3678 | pthread_t event_thread;
|
---|
3679 | int32_t ret = pthread_create(&event_thread, NULL, dvbapi_event_thread, (void *) dvbapi_client);
|
---|
3680 | if(ret)
|
---|
3681 | {
|
---|
3682 | cs_log("ERROR: Can't create dvbapi event thread (errno=%d %s)", ret, strerror(ret));
|
---|
3683 | return NULL;
|
---|
3684 | }
|
---|
3685 | else
|
---|
3686 | { pthread_detach(event_thread); }
|
---|
3687 | }
|
---|
3688 |
|
---|
3689 | if(listenfd != -1)
|
---|
3690 | {
|
---|
3691 | pfd2[0].fd = listenfd;
|
---|
3692 | pfd2[0].events = (POLLIN | POLLPRI);
|
---|
3693 | type[0] = 1;
|
---|
3694 | }
|
---|
3695 |
|
---|
3696 | #ifdef WITH_COOLAPI
|
---|
3697 | system("pzapit -rz");
|
---|
3698 | #endif
|
---|
3699 | cs_ftime(&start); // register start time
|
---|
3700 | while(1)
|
---|
3701 | {
|
---|
3702 | if(pausecam) // for dbox2, STAPI or PC in standby mode dont parse any ecm/emm or try to start next filter
|
---|
3703 | { continue; }
|
---|
3704 |
|
---|
3705 | if(cfg.dvbapi_pmtmode == 6)
|
---|
3706 | {
|
---|
3707 | if(listenfd < 0)
|
---|
3708 | {
|
---|
3709 | cs_log("PMT6: Trying connect to enigma CA PMT listen socket...");
|
---|
3710 | /* socket init */
|
---|
3711 | if((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
---|
3712 | {
|
---|
3713 |
|
---|
3714 | cs_log("socket error (errno=%d %s)", errno, strerror(errno));
|
---|
3715 | listenfd = -1;
|
---|
3716 | }
|
---|
3717 | else if(connect(listenfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
|
---|
3718 | {
|
---|
3719 | cs_log("socket connect error (errno=%d %s)", errno, strerror(errno));
|
---|
3720 | close(listenfd);
|
---|
3721 | listenfd = -1;
|
---|
3722 | }
|
---|
3723 | else
|
---|
3724 | {
|
---|
3725 | pfd2[0].fd = listenfd;
|
---|
3726 | pfd2[0].events = (POLLIN | POLLPRI);
|
---|
3727 | type[0] = 1;
|
---|
3728 | cs_log("PMT6 CA PMT Server connected on fd %d!", listenfd);
|
---|
3729 | }
|
---|
3730 | }
|
---|
3731 |
|
---|
3732 | }
|
---|
3733 | pfdcount = (listenfd > -1) ? 1 : 0;
|
---|
3734 |
|
---|
3735 | for(i = 0; i < MAX_DEMUX; i++)
|
---|
3736 | {
|
---|
3737 | // add client fd's which are not yet associated with the demux but needs to be polled for data
|
---|
3738 | if (unassoc_fd[i]) {
|
---|
3739 | pfd2[pfdcount].fd = unassoc_fd[i];
|
---|
3740 | pfd2[pfdcount].events = (POLLIN | POLLPRI);
|
---|
3741 | type[pfdcount++] = 1;
|
---|
3742 | }
|
---|
3743 |
|
---|
3744 | if(demux[i].program_number == 0) { continue; } // only evalutate demuxers that have channels assigned
|
---|
3745 |
|
---|
3746 | uint32_t ecmcounter = 0, emmcounter = 0;
|
---|
3747 | for(g = 0; g < maxfilter; g++)
|
---|
3748 | {
|
---|
3749 | if(demux[i].demux_fd[g].fd <= 0) continue; // deny obvious invalid fd!
|
---|
3750 |
|
---|
3751 | if(!cfg.dvbapi_listenport && cfg.dvbapi_boxtype != BOXTYPE_PC_NODMX && selected_api != STAPI && selected_api != COOLAPI)
|
---|
3752 | {
|
---|
3753 | pfd2[pfdcount].fd = demux[i].demux_fd[g].fd;
|
---|
3754 | pfd2[pfdcount].events = (POLLIN | POLLPRI);
|
---|
3755 | ids[pfdcount] = i;
|
---|
3756 | fdn[pfdcount] = g;
|
---|
3757 | type[pfdcount++] = 0;
|
---|
3758 | }
|
---|
3759 | if(demux[i].demux_fd[g].type == TYPE_ECM) { ecmcounter++; } // count ecm filters to see if demuxing is possible anyway
|
---|
3760 | if(demux[i].demux_fd[g].type == TYPE_EMM) { emmcounter++; } // count emm filters also
|
---|
3761 | }
|
---|
3762 | if(ecmcounter != demux[i].old_ecmfiltercount || emmcounter != demux[i].old_emmfiltercount) // only produce log if something changed
|
---|
3763 | {
|
---|
3764 | cs_log_dbg(D_DVBAPI, "Demuxer %d has %d ecmpids, %d streampids, %d ecmfilters and %d of max %d emmfilters", i, demux[i].ECMpidcount,
|
---|
3765 | demux[i].STREAMpidcount, ecmcounter, emmcounter, demux[i].max_emm_filter);
|
---|
3766 | demux[i].old_ecmfiltercount = ecmcounter; // save new amount of ecmfilters
|
---|
3767 | demux[i].old_emmfiltercount = emmcounter; // save new amount of emmfilters
|
---|
3768 | }
|
---|
3769 |
|
---|
3770 | // delayed emm start for non irdeto caids, start emm cat if not already done for this demuxer!
|
---|
3771 |
|
---|
3772 | struct timeb now;
|
---|
3773 | cs_ftime(&now);
|
---|
3774 |
|
---|
3775 | if(cfg.dvbapi_au > 0 && demux[i].emm_filter == -1 && demux[i].EMMpidcount == 0 && emmcounter == 0)
|
---|
3776 | {
|
---|
3777 | int64_t gone = comp_timeb(&now, &demux[i].emmstart);
|
---|
3778 | if(gone > 30*1000){
|
---|
3779 | cs_ftime(&demux[i].emmstart); // trick to let emm fetching start after 30 seconds to speed up zapping
|
---|
3780 | dvbapi_start_filter(i, demux[i].pidindex, 0x001, 0x001, 0x01, 0x01, 0xFF, 0, TYPE_EMM); //CAT
|
---|
3781 | }
|
---|
3782 | }
|
---|
3783 |
|
---|
3784 | //early start for irdeto since they need emm before ecm (pmt emmstart = 1 if detected caid 0x06)
|
---|
3785 | int32_t emmstarted = demux[i].emm_filter;
|
---|
3786 | if(cfg.dvbapi_au && demux[i].EMMpidcount > 0) // check every time since share readers might give us new filters due to hexserial change
|
---|
3787 | {
|
---|
3788 | if(!emmcounter && emmstarted == -1)
|
---|
3789 | {
|
---|
3790 | demux[i].emmstart = now;
|
---|
3791 | dvbapi_start_emm_filter(i); // start emmfiltering if emmpids are found
|
---|
3792 | }
|
---|
3793 | else
|
---|
3794 | {
|
---|
3795 | int64_t gone = comp_timeb(&now, &demux[i].emmstart);
|
---|
3796 | if(gone > 30*1000)
|
---|
3797 | {
|
---|
3798 | demux[i].emmstart = now;
|
---|
3799 | dvbapi_start_emm_filter(i); // start emmfiltering delayed if filters already were running
|
---|
3800 | rotate_emmfilter(i); // rotate active emmfilters
|
---|
3801 | }
|
---|
3802 | }
|
---|
3803 | }
|
---|
3804 |
|
---|
3805 | if(ecmcounter == 0 && demux[i].ECMpidcount > 0) // Restart decoding all caids we have ecmpids but no ecm filters!
|
---|
3806 | {
|
---|
3807 |
|
---|
3808 | int32_t started = 0;
|
---|
3809 |
|
---|
3810 | for(g = 0; g < demux[i].ECMpidcount; g++) // avoid race: not all pids are asked and checked out yet!
|
---|
3811 | {
|
---|
3812 | if(demux[i].ECMpids[g].checked == 0 && demux[i].ECMpids[g].status >= 0) // check if prio run is done
|
---|
3813 | {
|
---|
3814 | dvbapi_try_next_caid(i, 0); // not done, so start next prio pid
|
---|
3815 | started = 1;
|
---|
3816 | break;
|
---|
3817 | }
|
---|
3818 | }
|
---|
3819 | if(started) { continue; } // if started a filter proceed with next demuxer
|
---|
3820 |
|
---|
3821 | if(g == demux[i].ECMpidcount) // all usable pids (with prio) are tried, lets start over again without prio!
|
---|
3822 | {
|
---|
3823 | for(g = 0; g < demux[i].ECMpidcount; g++) // avoid race: not all pids are asked and checked out yet!
|
---|
3824 | {
|
---|
3825 | if(demux[i].ECMpids[g].checked == 2 && demux[i].ECMpids[g].status >= 0) // check if noprio run is done
|
---|
3826 | {
|
---|
3827 | demux[i].ECMpids[g].irdeto_curindex = 0xFE;
|
---|
3828 | demux[i].ECMpids[g].irdeto_maxindex = 0;
|
---|
3829 | demux[i].ECMpids[g].irdeto_cycle = 0xFE;
|
---|
3830 | demux[i].ECMpids[g].tries = 0xFE;
|
---|
3831 | demux[i].ECMpids[g].table = 0;
|
---|
3832 | demux[i].ECMpids[g].CHID = 0x10000; // remove chid prio
|
---|
3833 | dvbapi_try_next_caid(i, 2); // not done, so start next no prio pid
|
---|
3834 | started = 1;
|
---|
3835 | break;
|
---|
3836 | }
|
---|
3837 | }
|
---|
3838 | }
|
---|
3839 | if(started) { continue; } // if started a filter proceed with next demuxer
|
---|
3840 |
|
---|
3841 | if(g == demux[i].ECMpidcount) // all usable pids are tried, lets start over again!
|
---|
3842 | {
|
---|
3843 | if(demux[i].decodingtries == -1) // first redecoding attempt?
|
---|
3844 | {
|
---|
3845 | cs_ftime(&demux[i].decstart);
|
---|
3846 | for(g = 0; g < demux[i].ECMpidcount; g++) // reinit some used things from second run (without prio)
|
---|
3847 | {
|
---|
3848 | demux[i].ECMpids[g].checked = 0;
|
---|
3849 | demux[i].ECMpids[g].irdeto_curindex = 0xFE;
|
---|
3850 | demux[i].ECMpids[g].irdeto_maxindex = 0;
|
---|
3851 | demux[i].ECMpids[g].irdeto_cycle = 0xFE;
|
---|
3852 | demux[i].ECMpids[g].table = 0;
|
---|
3853 | demux[i].decodingtries = 0;
|
---|
3854 | dvbapi_edit_channel_cache(i, g, 0); // remove this pid from channelcache since we had no founds on any ecmpid!
|
---|
3855 | }
|
---|
3856 | }
|
---|
3857 | uint8_t number_of_enabled_pids = 0;
|
---|
3858 | demux[i].decodingtries++;
|
---|
3859 | dvbapi_resort_ecmpids(i);
|
---|
3860 |
|
---|
3861 | for(g = 0; g < demux[i].ECMpidcount; g++) // count number of enabled pids!
|
---|
3862 | {
|
---|
3863 | if(demux[i].ECMpids[g].status >= 0) number_of_enabled_pids++;
|
---|
3864 | }
|
---|
3865 | if(!number_of_enabled_pids)
|
---|
3866 | {
|
---|
3867 | if(demux[i].decodingtries == 10)
|
---|
3868 | {
|
---|
3869 | demux[i].decodingtries = 0;
|
---|
3870 | cs_log("Demuxer %d no enabled matching ecmpids -> decoding is waiting for matching readers!",i);
|
---|
3871 | }
|
---|
3872 | }
|
---|
3873 | else
|
---|
3874 | {
|
---|
3875 | cs_ftime(&demux[i].decend);
|
---|
3876 | demux[i].decodingtries = -1; // reset to first run again!
|
---|
3877 | int64_t gone = comp_timeb(&demux[i].decend, &demux[i].decstart);
|
---|
3878 | cs_log("Demuxer %d restarting decodingrequests after %"PRId64" ms with %d enabled and %d disabled ecmpids!", i, gone, number_of_enabled_pids,
|
---|
3879 | (demux[i].ECMpidcount-number_of_enabled_pids));
|
---|
3880 | dvbapi_try_next_caid(i, 0);
|
---|
3881 | }
|
---|
3882 | }
|
---|
3883 | }
|
---|
3884 |
|
---|
3885 | if(demux[i].socket_fd > 0 && cfg.dvbapi_pmtmode != 6)
|
---|
3886 | {
|
---|
3887 | rc = 0;
|
---|
3888 | for(j = 0; j < pfdcount; j++)
|
---|
3889 | {
|
---|
3890 | if(pfd2[j].fd == demux[i].socket_fd)
|
---|
3891 | {
|
---|
3892 | rc = 1;
|
---|
3893 | break;
|
---|
3894 | }
|
---|
3895 | }
|
---|
3896 | if(rc == 1) { continue; }
|
---|
3897 |
|
---|
3898 | pfd2[pfdcount].fd = demux[i].socket_fd;
|
---|
3899 | pfd2[pfdcount].events = (POLLIN | POLLPRI);
|
---|
3900 | ids[pfdcount] = i;
|
---|
3901 | type[pfdcount++] = 1;
|
---|
3902 | }
|
---|
3903 | }
|
---|
3904 |
|
---|
3905 | while(1)
|
---|
3906 | {
|
---|
3907 | rc = poll(pfd2, pfdcount, 300);
|
---|
3908 | if(listenfd == -1 && cfg.dvbapi_pmtmode == 6) { break; }
|
---|
3909 | if(rc < 0)
|
---|
3910 | { continue; }
|
---|
3911 | break;
|
---|
3912 | }
|
---|
3913 |
|
---|
3914 | if(rc > 0)
|
---|
3915 | {
|
---|
3916 | cs_ftime(&end); // register end time
|
---|
3917 | int64_t timeout = comp_timeb(&end, &start);
|
---|
3918 | if (timeout < 0) {
|
---|
3919 | cs_log("*** WARNING: BAD TIME AFFECTING WHOLE OSCAM ECM HANDLING ****");
|
---|
3920 | }
|
---|
3921 | cs_log_dbg(D_TRACE, "New events occurred on %d of %d handlers after %"PRId64" ms inactivity", rc, pfdcount, timeout);
|
---|
3922 | cs_ftime(&start); // register new start time for next poll
|
---|
3923 | }
|
---|
3924 |
|
---|
3925 | for(i = 0; i < pfdcount && rc > 0; i++)
|
---|
3926 | {
|
---|
3927 | if(pfd2[i].revents == 0) { continue; } // skip sockets with no changes
|
---|
3928 | rc--; //event handled!
|
---|
3929 | cs_log_dbg(D_TRACE, "Now handling fd %d that reported event %d", pfd2[i].fd, pfd2[i].revents);
|
---|
3930 |
|
---|
3931 | if(pfd2[i].revents & (POLLHUP | POLLNVAL | POLLERR))
|
---|
3932 | {
|
---|
3933 | if(type[i] == 1)
|
---|
3934 | {
|
---|
3935 | for(j = 0; j < MAX_DEMUX; j++)
|
---|
3936 | {
|
---|
3937 | if(demux[j].socket_fd == pfd2[i].fd) // if listenfd closes stop all assigned decoding!
|
---|
3938 | {
|
---|
3939 | dvbapi_stop_descrambling(j);
|
---|
3940 | }
|
---|
3941 | }
|
---|
3942 | int32_t ret = close(pfd2[i].fd);
|
---|
3943 | if(ret < 0 && errno != 9) { cs_log("ERROR: Could not close demuxer socket fd (errno=%d %s)", errno, strerror(errno)); }
|
---|
3944 | if(pfd2[i].fd == listenfd && cfg.dvbapi_pmtmode == 6)
|
---|
3945 | {
|
---|
3946 | listenfd = -1;
|
---|
3947 | }
|
---|
3948 | }
|
---|
3949 | else // type = 0
|
---|
3950 | {
|
---|
3951 | int32_t demux_index = ids[i];
|
---|
3952 | int32_t n = fdn[i];
|
---|
3953 | dvbapi_stop_filternum(demux_index, n); // stop filter since its giving errors and wont return anything good.
|
---|
3954 | }
|
---|
3955 | continue; // continue with other events
|
---|
3956 | }
|
---|
3957 |
|
---|
3958 | if(pfd2[i].revents & (POLLIN | POLLPRI))
|
---|
3959 | {
|
---|
3960 | if(type[i] == 1 && pmthandling == 0)
|
---|
3961 | {
|
---|
3962 | pmthandling = 1; // pmthandling in progress!
|
---|
3963 | connfd = -1; // initially no socket to read from
|
---|
3964 | int add_to_poll = 0; // we may need to additionally poll this socket when no PMT data comes in
|
---|
3965 |
|
---|
3966 | if (pfd2[i].fd == listenfd)
|
---|
3967 | {
|
---|
3968 | if (cfg.dvbapi_pmtmode == 6) {
|
---|
3969 | connfd = listenfd;
|
---|
3970 | disable_pmt_files = 1;
|
---|
3971 | } else {
|
---|
3972 | clilen = sizeof(servaddr);
|
---|
3973 | connfd = accept(listenfd, (struct sockaddr *)&servaddr, (socklen_t *)&clilen);
|
---|
3974 | cs_log_dbg(D_DVBAPI, "new socket connection fd: %d", connfd);
|
---|
3975 | if (cfg.dvbapi_listenport)
|
---|
3976 | {
|
---|
3977 | //update webif data
|
---|
3978 | client->ip = SIN_GET_ADDR(servaddr);
|
---|
3979 | client->port = ntohs(SIN_GET_PORT(servaddr));
|
---|
3980 | }
|
---|
3981 | add_to_poll = 1;
|
---|
3982 |
|
---|
3983 | if(cfg.dvbapi_pmtmode == 3 || cfg.dvbapi_pmtmode == 0) { disable_pmt_files = 1; }
|
---|
3984 |
|
---|
3985 | if(connfd <= 0)
|
---|
3986 | cs_log_dbg(D_DVBAPI, "accept() returns error on fd event %d (errno=%d %s)", pfd2[i].revents, errno, strerror(errno));
|
---|
3987 | }
|
---|
3988 | }
|
---|
3989 | else
|
---|
3990 | {
|
---|
3991 | cs_log_dbg(D_DVBAPI, "PMT Update on socket %d.", pfd2[i].fd);
|
---|
3992 | connfd = pfd2[i].fd;
|
---|
3993 | }
|
---|
3994 |
|
---|
3995 | //reading and completing data from socket
|
---|
3996 | if (connfd > 0) {
|
---|
3997 | uint32_t pmtlen = 0, chunks_processed = 0;
|
---|
3998 |
|
---|
3999 | int tries = 100;
|
---|
4000 | do {
|
---|
4001 | len = recv(connfd, mbuf + pmtlen, sizeof(mbuf) - pmtlen, MSG_DONTWAIT);
|
---|
4002 | if (len > 0)
|
---|
4003 | pmtlen += len;
|
---|
4004 | if ((cfg.dvbapi_listenport || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX) &&
|
---|
4005 | (len == 0 || (len == -1 && (errno != EINTR && errno != EAGAIN))))
|
---|
4006 | {
|
---|
4007 | //client disconnects, stop all assigned decoding
|
---|
4008 | cs_log_dbg(D_DVBAPI, "Socket %d reported connection close", connfd);
|
---|
4009 | int active_conn = 0; //other active connections counter
|
---|
4010 | for (j = 0; j < MAX_DEMUX; j++)
|
---|
4011 | {
|
---|
4012 | if (demux[j].socket_fd == connfd)
|
---|
4013 | dvbapi_stop_descrambling(j);
|
---|
4014 | else if (demux[j].socket_fd)
|
---|
4015 | active_conn++;
|
---|
4016 | // remove from unassoc_fd when necessary
|
---|
4017 | if (unassoc_fd[j] == connfd)
|
---|
4018 | unassoc_fd[j] = 0;
|
---|
4019 | }
|
---|
4020 | close(connfd);
|
---|
4021 | connfd = -1;
|
---|
4022 | add_to_poll = 0;
|
---|
4023 | if (!active_conn) //last connection closed
|
---|
4024 | {
|
---|
4025 | client_proto_version = 0;
|
---|
4026 | if (client_name)
|
---|
4027 | {
|
---|
4028 | free(client_name);
|
---|
4029 | client_name = NULL;
|
---|
4030 | }
|
---|
4031 | if (cfg.dvbapi_listenport)
|
---|
4032 | {
|
---|
4033 | //update webif data
|
---|
4034 | client->ip = get_null_ip();
|
---|
4035 | client->port = 0;
|
---|
4036 | }
|
---|
4037 | }
|
---|
4038 | break;
|
---|
4039 | }
|
---|
4040 | if (pmtlen >= 8) //if we received less then 8 bytes, than it's not complete for sure
|
---|
4041 | {
|
---|
4042 | // check and try to process complete PMT objects and filter data by chunks to avoid PMT buffer overflows
|
---|
4043 | uint32_t opcode_ptr;
|
---|
4044 | memcpy(&opcode_ptr, &mbuf[0], 4); //used only to silent compiler warning about dereferencing type-punned pointer
|
---|
4045 | uint32_t opcode = ntohl(opcode_ptr); //get the client opcode (4 bytes)
|
---|
4046 | uint32_t chunksize = 0; //size of complete chunk in the buffer (an opcode with the data)
|
---|
4047 | uint32_t data_len = 0; //variable for internal data length (eg. for the filter data size, PMT len)
|
---|
4048 |
|
---|
4049 | //detect the opcode, its size (chunksize) and its internal data size (data_len)
|
---|
4050 | if ((opcode & 0xFFFFF000) == DVBAPI_AOT_CA)
|
---|
4051 | {
|
---|
4052 | // parse packet size (ASN.1)
|
---|
4053 | uint32_t size = 0;
|
---|
4054 | if (mbuf[3] & 0x80)
|
---|
4055 | {
|
---|
4056 | data_len = 0;
|
---|
4057 | size = mbuf[3] & 0x7F;
|
---|
4058 | if (pmtlen > 4 + size)
|
---|
4059 | {
|
---|
4060 | uint32_t k;
|
---|
4061 | for (k = 0; k < size; k++)
|
---|
4062 | data_len = (data_len << 8) | mbuf[3 + 1 + k];
|
---|
4063 | size++;
|
---|
4064 | }
|
---|
4065 | }
|
---|
4066 | else
|
---|
4067 | {
|
---|
4068 | data_len = mbuf[3] & 0x7F;
|
---|
4069 | size = 1;
|
---|
4070 | }
|
---|
4071 | chunksize = 3 + size + data_len;
|
---|
4072 | }
|
---|
4073 | else switch (opcode)
|
---|
4074 | {
|
---|
4075 | case DVBAPI_FILTER_DATA:
|
---|
4076 | {
|
---|
4077 | data_len = b2i(2, mbuf + 7) & 0x0FFF;
|
---|
4078 | chunksize = 6 + 3 + data_len;
|
---|
4079 | break;
|
---|
4080 | }
|
---|
4081 | case DVBAPI_CLIENT_INFO:
|
---|
4082 | {
|
---|
4083 | data_len = mbuf[6];
|
---|
4084 | chunksize = 6 + 1 + data_len;
|
---|
4085 | break;
|
---|
4086 | }
|
---|
4087 | default:
|
---|
4088 | cs_log("Unknown socket command received: 0x%08X", opcode);
|
---|
4089 | }
|
---|
4090 |
|
---|
4091 | //processing the complete data according to type
|
---|
4092 | if (chunksize < sizeof(mbuf) && chunksize <= pmtlen) // only handle if we fetched a complete chunksize!
|
---|
4093 | {
|
---|
4094 | chunks_processed++;
|
---|
4095 | if ((opcode & 0xFFFFF000) == DVBAPI_AOT_CA)
|
---|
4096 | {
|
---|
4097 | cs_log_dump_dbg(D_DVBAPI, mbuf, chunksize, "Parsing PMT object %d:", chunks_processed);
|
---|
4098 | dvbapi_handlesockmsg(mbuf, chunksize, connfd);
|
---|
4099 | add_to_poll = 0;
|
---|
4100 | if (cfg.dvbapi_listenport && opcode == DVBAPI_AOT_CA_STOP)
|
---|
4101 | add_to_poll = 1;
|
---|
4102 | }
|
---|
4103 | else switch (opcode)
|
---|
4104 | {
|
---|
4105 | case DVBAPI_FILTER_DATA:
|
---|
4106 | {
|
---|
4107 | int32_t demux_index = mbuf[4];
|
---|
4108 | int32_t filter_num = mbuf[5];
|
---|
4109 | dvbapi_process_input(demux_index, filter_num, mbuf + 6, data_len + 3);
|
---|
4110 | break;
|
---|
4111 | }
|
---|
4112 | case DVBAPI_CLIENT_INFO:
|
---|
4113 | {
|
---|
4114 | uint16_t client_proto_ptr;
|
---|
4115 | memcpy(&client_proto_ptr, &mbuf[4], 2);
|
---|
4116 | uint16_t client_proto = ntohs(client_proto_ptr);
|
---|
4117 | if (client_name)
|
---|
4118 | free(client_name);
|
---|
4119 | if (cs_malloc(&client_name, data_len + 1))
|
---|
4120 | {
|
---|
4121 | memcpy(client_name, &mbuf[7], data_len);
|
---|
4122 | client_name[data_len] = 0;
|
---|
4123 | cs_log("Client connected: '%s' (protocol version = %d)", client_name, client_proto);
|
---|
4124 | }
|
---|
4125 | client_proto_version = client_proto; //setting the global var according to the client
|
---|
4126 |
|
---|
4127 | // as a response we are sending our info to the client:
|
---|
4128 | dvbapi_net_send(DVBAPI_SERVER_INFO, connfd, -1, -1, NULL, NULL, NULL);
|
---|
4129 | break;
|
---|
4130 | }
|
---|
4131 | }
|
---|
4132 |
|
---|
4133 | if (pmtlen == chunksize) // if we fetched and handled the exact chunksize reset buffer counter!
|
---|
4134 | pmtlen = 0;
|
---|
4135 |
|
---|
4136 | // if we read more data then processed, move it to beginning
|
---|
4137 | if (pmtlen > chunksize)
|
---|
4138 | {
|
---|
4139 | memmove(mbuf, mbuf + chunksize, pmtlen - chunksize);
|
---|
4140 | pmtlen -= chunksize;
|
---|
4141 | }
|
---|
4142 | continue;
|
---|
4143 | }
|
---|
4144 | }
|
---|
4145 | if (len <= 0) {
|
---|
4146 | if (pmtlen > 0 || chunks_processed > 0) //all data read
|
---|
4147 | break;
|
---|
4148 | else { //wait for data become available and try again
|
---|
4149 |
|
---|
4150 | // remove from unassoc_fd if the socket fd is invalid
|
---|
4151 | if (errno == EBADF)
|
---|
4152 | for (j = 0; j < MAX_DEMUX; j++)
|
---|
4153 | if (unassoc_fd[j] == connfd)
|
---|
4154 | unassoc_fd[j] = 0;
|
---|
4155 | cs_sleepms(20);
|
---|
4156 | continue;
|
---|
4157 | }
|
---|
4158 | }
|
---|
4159 | } while (pmtlen < sizeof(mbuf) && tries--);
|
---|
4160 |
|
---|
4161 | // if the connection is new and we read no PMT data, then add it to the poll,
|
---|
4162 | // otherwise this socket will not be checked with poll when data arives
|
---|
4163 | // because fd it is not yet assigned with the demux
|
---|
4164 | if (add_to_poll) {
|
---|
4165 | for (j = 0; j < MAX_DEMUX; j++) {
|
---|
4166 | if (!unassoc_fd[j]) {
|
---|
4167 | unassoc_fd[j] = connfd;
|
---|
4168 | break;
|
---|
4169 | }
|
---|
4170 | }
|
---|
4171 | }
|
---|
4172 |
|
---|
4173 | if (pmtlen > 0) {
|
---|
4174 | if (pmtlen < 3)
|
---|
4175 | cs_log_dbg(D_DVBAPI, "CA PMT server message too short!");
|
---|
4176 | else {
|
---|
4177 | if (pmtlen >= sizeof(mbuf))
|
---|
4178 | cs_log("***** WARNING: PMT BUFFER OVERFLOW, PLEASE REPORT! ****** ");
|
---|
4179 | cs_log_dump_dbg(D_DVBAPI, mbuf, pmtlen, "New PMT info from socket (total size: %d)", pmtlen);
|
---|
4180 | dvbapi_handlesockmsg(mbuf, pmtlen, connfd);
|
---|
4181 | }
|
---|
4182 | }
|
---|
4183 | }
|
---|
4184 | pmthandling = 0; // pmthandling done!
|
---|
4185 | continue; // continue with other events!
|
---|
4186 | }
|
---|
4187 | else // type==0
|
---|
4188 | {
|
---|
4189 | int32_t demux_index = ids[i];
|
---|
4190 | int32_t n = fdn[i];
|
---|
4191 |
|
---|
4192 | if((int)demux[demux_index].demux_fd[n].fd != pfd2[i].fd) { continue; } // filter already killed, no need to process this data!
|
---|
4193 |
|
---|
4194 | len = dvbapi_read_device(pfd2[i].fd, mbuf, sizeof(mbuf));
|
---|
4195 | if(len < 0) // serious filterdata read error
|
---|
4196 | {
|
---|
4197 | dvbapi_stop_filternum(demux_index, n); // stop filter since its giving errors and wont return anything good.
|
---|
4198 | maxfilter--; // lower maxfilters to avoid this with new filter setups!
|
---|
4199 | continue;
|
---|
4200 | }
|
---|
4201 | if(!len) // receiver internal filterbuffer overflow
|
---|
4202 | {
|
---|
4203 | memset(mbuf, 0, sizeof(mbuf));
|
---|
4204 | }
|
---|
4205 |
|
---|
4206 | dvbapi_process_input(demux_index, n, mbuf, len);
|
---|
4207 | }
|
---|
4208 | continue; // continue with other events!
|
---|
4209 | }
|
---|
4210 | }
|
---|
4211 | }
|
---|
4212 | return NULL;
|
---|
4213 | }
|
---|
4214 |
|
---|
4215 | void dvbapi_write_cw(int32_t demux_id, uchar *cw, int32_t pid)
|
---|
4216 | {
|
---|
4217 | int32_t n;
|
---|
4218 | int8_t cwEmpty = 0;
|
---|
4219 | unsigned char nullcw[8];
|
---|
4220 | memset(nullcw, 0, 8);
|
---|
4221 | ca_descr_t ca_descr;
|
---|
4222 |
|
---|
4223 | memset(&ca_descr, 0, sizeof(ca_descr));
|
---|
4224 |
|
---|
4225 | if(memcmp(demux[demux_id].lastcw[0], nullcw, 8) == 0
|
---|
4226 | && memcmp(demux[demux_id].lastcw[1], nullcw, 8) == 0)
|
---|
4227 | { cwEmpty = 1; } // to make sure that both cws get written on constantcw
|
---|
4228 |
|
---|
4229 |
|
---|
4230 | for(n = 0; n < 2; n++)
|
---|
4231 | {
|
---|
4232 | char lastcw[9 * 3];
|
---|
4233 | char newcw[9 * 3];
|
---|
4234 | cs_hexdump(0, demux[demux_id].lastcw[n], 8, lastcw, sizeof(lastcw));
|
---|
4235 | cs_hexdump(0, cw + (n * 8), 8, newcw, sizeof(newcw));
|
---|
4236 |
|
---|
4237 | if((memcmp(cw + (n * 8), demux[demux_id].lastcw[n], 8) != 0 || cwEmpty)
|
---|
4238 | && memcmp(cw + (n * 8), nullcw, 8) != 0) // check if already delivered and new cw part is valid!
|
---|
4239 | {
|
---|
4240 | int32_t idx = dvbapi_ca_setpid(demux_id, pid); // prepare ca
|
---|
4241 | if (idx == -1) return; // return on no index!
|
---|
4242 |
|
---|
4243 | #ifdef WITH_COOLAPI
|
---|
4244 | ca_descr.index = idx;
|
---|
4245 | ca_descr.parity = n;
|
---|
4246 | memcpy(demux[demux_id].lastcw[n], cw + (n * 8), 8);
|
---|
4247 | memcpy(ca_descr.cw, cw + (n * 8), 8);
|
---|
4248 | cs_log_dbg(D_DVBAPI, "Demuxer %d write cw%d index: %d (ca_mask %d)", demux_id, n, ca_descr.index, demux[demux_id].ca_mask);
|
---|
4249 | coolapi_write_cw(demux[demux_id].ca_mask, demux[demux_id].STREAMpids, demux[demux_id].STREAMpidcount, &ca_descr);
|
---|
4250 | #else
|
---|
4251 | int32_t i,j, write_cw = 0;
|
---|
4252 | for(i = 0; i < MAX_DEMUX; i++)
|
---|
4253 | {
|
---|
4254 | if(!(demux[demux_id].ca_mask & (1 << i))) continue; // ca not in use by this demuxer!
|
---|
4255 |
|
---|
4256 | for(j = 0; j < demux[demux_id].STREAMpidcount; j++)
|
---|
4257 | {
|
---|
4258 | if(!demux[demux_id].ECMpids[pid].streams || ((demux[demux_id].ECMpids[pid].streams & (1 << j)) == (uint) (1 << j)))
|
---|
4259 | {
|
---|
4260 | int32_t usedidx = is_ca_used(i, demux[demux_id].STREAMpids[j]);
|
---|
4261 | if(idx != usedidx)
|
---|
4262 | {
|
---|
4263 | cs_log_dbg(D_DVBAPI,"Demuxer %d ca%d is using index %d for streampid %04X -> skip!", demux_id, i, usedidx, demux[demux_id].STREAMpids[j]);
|
---|
4264 | continue; // if not used for descrambling -> skip!
|
---|
4265 | }
|
---|
4266 | else
|
---|
4267 | {
|
---|
4268 | cs_log_dbg(D_DVBAPI,"Demuxer %d ca%d is using index %d for streampid %04X -> write!", demux_id, i, usedidx, demux[demux_id].STREAMpids[j]);
|
---|
4269 | write_cw = 1;
|
---|
4270 | }
|
---|
4271 | }
|
---|
4272 | }
|
---|
4273 | if(!write_cw) { continue; } // no need to write the cw since this ca isnt using it!
|
---|
4274 |
|
---|
4275 | ca_descr.index = idx;
|
---|
4276 | ca_descr.parity = n;
|
---|
4277 | memcpy(demux[demux_id].lastcw[n], cw + (n * 8), 8);
|
---|
4278 | memcpy(ca_descr.cw, cw + (n * 8), 8);
|
---|
4279 | cs_log_dbg(D_DVBAPI, "Demuxer %d writing %s part (%s) of controlword, replacing expired (%s)", demux_id, (n == 1 ? "even" : "odd"), newcw, lastcw);
|
---|
4280 | cs_log_dbg(D_DVBAPI, "Demuxer %d write cw%d index: %d (ca%d)", demux_id, n, ca_descr.index, i);
|
---|
4281 |
|
---|
4282 | if(cfg.dvbapi_boxtype == BOXTYPE_PC || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX)
|
---|
4283 | dvbapi_net_send(DVBAPI_CA_SET_DESCR, demux[demux_id].socket_fd, demux_id, -1 /*unused*/, (unsigned char *) &ca_descr, NULL, NULL);
|
---|
4284 | else
|
---|
4285 | {
|
---|
4286 | if(ca_fd[i] <= 0)
|
---|
4287 | {
|
---|
4288 | ca_fd[i] = dvbapi_open_device(1, i, demux[demux_id].adapter_index);
|
---|
4289 | if(ca_fd[i] <= 0) { continue; }
|
---|
4290 | }
|
---|
4291 | if (dvbapi_ioctl(ca_fd[i], CA_SET_DESCR, &ca_descr) < 0)
|
---|
4292 | {
|
---|
4293 | cs_log("ERROR: ioctl(CA_SET_DESCR): %s", strerror(errno));
|
---|
4294 | }
|
---|
4295 | }
|
---|
4296 | }
|
---|
4297 | #endif
|
---|
4298 | }
|
---|
4299 | }
|
---|
4300 | }
|
---|
4301 |
|
---|
4302 | void delayer(ECM_REQUEST *er)
|
---|
4303 | {
|
---|
4304 | if(cfg.dvbapi_delayer <= 0) { return; }
|
---|
4305 |
|
---|
4306 | struct timeb tpe;
|
---|
4307 | cs_ftime(&tpe);
|
---|
4308 | int64_t gone = comp_timeb(&tpe, &er->tps);
|
---|
4309 | if( gone < cfg.dvbapi_delayer)
|
---|
4310 | {
|
---|
4311 | cs_log_dbg(D_DVBAPI, "delayer: gone=%"PRId64" ms, cfg=%d ms -> delay=%"PRId64" ms", gone, cfg.dvbapi_delayer, cfg.dvbapi_delayer - gone);
|
---|
4312 | cs_sleepms(cfg.dvbapi_delayer - gone);
|
---|
4313 | }
|
---|
4314 | }
|
---|
4315 |
|
---|
4316 | void dvbapi_send_dcw(struct s_client *client, ECM_REQUEST *er)
|
---|
4317 | {
|
---|
4318 | int32_t i, j, handled = 0;
|
---|
4319 |
|
---|
4320 | for(i = 0; i < MAX_DEMUX; i++)
|
---|
4321 | {
|
---|
4322 | uint32_t nocw_write = 0; // 0 = write cw, 1 = dont write cw to hardware demuxer
|
---|
4323 | if(demux[i].program_number == 0) { continue; } // ignore empty demuxers
|
---|
4324 | if(demux[i].program_number != er->srvid) { continue; } // skip ecm response for other srvid
|
---|
4325 | demux[i].rdr = er->selected_reader;
|
---|
4326 | for(j = 0; j < demux[i].ECMpidcount; j++) // check for matching ecmpid
|
---|
4327 | {
|
---|
4328 | if((demux[i].ECMpids[j].CAID == er->caid || demux[i].ECMpids[j].CAID == er->ocaid)
|
---|
4329 | && demux[i].ECMpids[j].ECM_PID == er->pid
|
---|
4330 | && demux[i].ECMpids[j].PROVID == er->prid
|
---|
4331 | && demux[i].ECMpids[j].VPID == er->vpid)
|
---|
4332 | { break; }
|
---|
4333 | }
|
---|
4334 | if(j == demux[i].ECMpidcount) { continue; } // ecm response srvid ok but no matching ecmpid, perhaps this for other demuxer
|
---|
4335 |
|
---|
4336 | cs_log_dbg(D_DVBAPI, "Demuxer %d %scontrolword received for PID %d CAID %04X PROVID %06X ECMPID %04X CHID %04X VPID %04X", i,
|
---|
4337 | (er->rc >= E_NOTFOUND ? "no " : ""), j, er->caid, er->prid, er->pid, er->chid, er->vpid);
|
---|
4338 |
|
---|
4339 | uint32_t status = dvbapi_check_ecm_delayed_delivery(i, er);
|
---|
4340 |
|
---|
4341 | uint32_t comparecw0 = 0, comparecw1 = 0;
|
---|
4342 | char ecmd5[17 * 3];
|
---|
4343 | cs_hexdump(0, er->ecmd5, 16, ecmd5, sizeof(ecmd5));
|
---|
4344 |
|
---|
4345 | if(status == 1 && er->rc) // wrong ecmhash
|
---|
4346 | {
|
---|
4347 | cs_log_dbg(D_DVBAPI, "Demuxer %d not interested in response ecmhash %s (requested different one)", i, ecmd5);
|
---|
4348 | continue;
|
---|
4349 | }
|
---|
4350 | if(status == 2) // no filter
|
---|
4351 | {
|
---|
4352 | cs_log_dbg(D_DVBAPI, "Demuxer %d not interested in response ecmhash %s (filter already killed)", i, ecmd5);
|
---|
4353 | continue;
|
---|
4354 | }
|
---|
4355 | if(status == 5) // empty cw
|
---|
4356 | {
|
---|
4357 | cs_log_dbg(D_DVBAPI, "Demuxer %d not interested in response ecmhash %s (delivered cw is empty!)", i, ecmd5);
|
---|
4358 | nocw_write = 1;
|
---|
4359 | if(er->rc < E_NOTFOUND) { er->rc = E_NOTFOUND; }
|
---|
4360 | }
|
---|
4361 |
|
---|
4362 | if((status == 0 || status == 3 || status == 4) && er->rc < E_NOTFOUND) // 0=matching ecm hash, 2=no filter, 3=table reset, 4=cache-ex response
|
---|
4363 | {
|
---|
4364 | if(memcmp(er->cw, demux[i].lastcw[0], 8) == 0 && memcmp(er->cw + 8, demux[i].lastcw[1], 8) == 0) // check for matching controlword
|
---|
4365 | {
|
---|
4366 | comparecw0 = 1;
|
---|
4367 | }
|
---|
4368 | else if(memcmp(er->cw, demux[i].lastcw[1], 8) == 0 && memcmp(er->cw + 8, demux[i].lastcw[0], 8) == 0) // check for matching controlword
|
---|
4369 | {
|
---|
4370 | comparecw1 = 1;
|
---|
4371 | }
|
---|
4372 | if(comparecw0 == 1 || comparecw1 == 1)
|
---|
4373 | {
|
---|
4374 | cs_log_dbg(D_DVBAPI, "Demuxer %d duplicate controlword ecm response hash %s (duplicate controlword!)", i, ecmd5);
|
---|
4375 | nocw_write = 1;
|
---|
4376 | }
|
---|
4377 | }
|
---|
4378 |
|
---|
4379 | if(status == 3) // table reset
|
---|
4380 | {
|
---|
4381 | cs_log_dbg(D_DVBAPI, "Demuxer %d luckyshot new controlword ecm response hash %s (ecm table reset)", i, ecmd5);
|
---|
4382 | }
|
---|
4383 |
|
---|
4384 | if(status == 4) // no check on cache-ex responses!
|
---|
4385 | {
|
---|
4386 | cs_log_dbg(D_DVBAPI, "Demuxer %d new controlword from cache-ex reader (no ecmhash check possible)", i);
|
---|
4387 | }
|
---|
4388 |
|
---|
4389 | handled = 1; // mark this ecm response as handled
|
---|
4390 | if(er->rc < E_NOTFOUND && cfg.dvbapi_requestmode == 0 && (demux[i].pidindex == -1) && er->caid != 0)
|
---|
4391 | {
|
---|
4392 | demux[i].ECMpids[j].tries = 0xFE; // reset timeout retry flag
|
---|
4393 | demux[i].ECMpids[j].irdeto_cycle = 0xFE; // reset irdetocycle
|
---|
4394 | demux[i].pidindex = j; // set current index as *the* pid to descramble
|
---|
4395 | demux[i].ECMpids[j].checked = 4;
|
---|
4396 | cs_log_dbg(D_DVBAPI, "Demuxer %d descrambling PID %d CAID %04X PROVID %06X ECMPID %04X CHID %02X VPID %04X",
|
---|
4397 | i, demux[i].pidindex, er->caid, er->prid, er->pid, er->chid, er->vpid);
|
---|
4398 | }
|
---|
4399 |
|
---|
4400 | if(er->rc < E_NOTFOUND && cfg.dvbapi_requestmode == 1 && er->caid != 0) // FOUND
|
---|
4401 | {
|
---|
4402 | pthread_mutex_lock(&demux[i].answerlock); // only process one ecm answer
|
---|
4403 | if(demux[i].ECMpids[j].checked != 4)
|
---|
4404 | {
|
---|
4405 |
|
---|
4406 | int32_t t, o, ecmcounter = 0;
|
---|
4407 | int32_t oldpidindex = demux[i].pidindex;
|
---|
4408 | demux[i].pidindex = j; // set current ecmpid as the new pid to descramble
|
---|
4409 | if(oldpidindex != -1) demux[i].ECMpids[j].index = demux[i].ECMpids[oldpidindex].index; // swap index with lower status pid that was descrambling
|
---|
4410 | for(t = 0; t < demux[i].ECMpidcount; t++) //check this pid with controlword FOUND for higher status:
|
---|
4411 | {
|
---|
4412 | if(t != j && demux[i].ECMpids[j].status >= demux[i].ECMpids[t].status)
|
---|
4413 | {
|
---|
4414 | for(o = 0; o < maxfilter; o++) // check if ecmfilter is in use & stop all ecmfilters of lower status pids
|
---|
4415 | {
|
---|
4416 | if(demux[i].demux_fd[o].fd > 0 && demux[i].demux_fd[o].type == TYPE_ECM && (demux[i].demux_fd[o].pidindex == t))
|
---|
4417 | {
|
---|
4418 | dvbapi_stop_filternum(i, o); // ecmfilter belongs to lower status pid -> kill!
|
---|
4419 | }
|
---|
4420 | }
|
---|
4421 | dvbapi_edit_channel_cache(i, t, 0); // remove lowerstatus pid from channelcache
|
---|
4422 | demux[i].ECMpids[t].checked = 4; // mark index t as low status
|
---|
4423 | }
|
---|
4424 | }
|
---|
4425 |
|
---|
4426 |
|
---|
4427 | for(o = 0; o < maxfilter; o++) if(demux[i].demux_fd[o].type == TYPE_ECM) { ecmcounter++; } // count all ecmfilters
|
---|
4428 |
|
---|
4429 | demux[i].ECMpids[j].tries = 0xFE; // reset timeout retry flag
|
---|
4430 | demux[i].ECMpids[j].irdeto_cycle = 0xFE; // reset irdetocycle
|
---|
4431 |
|
---|
4432 | if(ecmcounter == 1) // if total found running ecmfilters is 1 -> we found the "best" pid
|
---|
4433 | {
|
---|
4434 | dvbapi_edit_channel_cache(i, j, 1);
|
---|
4435 | demux[i].ECMpids[j].checked = 4; // mark best pid last ;)
|
---|
4436 | }
|
---|
4437 |
|
---|
4438 | cs_log_dbg(D_DVBAPI, "Demuxer %d descrambling PID %d CAID %04X PROVID %06X ECMPID %04X CHID %02X VPID %04X",
|
---|
4439 | i, demux[i].pidindex, er->caid, er->prid, er->pid, er->chid, er->vpid);
|
---|
4440 | }
|
---|
4441 | pthread_mutex_unlock(&demux[i].answerlock); // and release it!
|
---|
4442 | }
|
---|
4443 |
|
---|
4444 | if(er->rc >= E_NOTFOUND) // not found on requestmode 0 + 1
|
---|
4445 | {
|
---|
4446 | if(er->rc == E_SLEEPING)
|
---|
4447 | {
|
---|
4448 | dvbapi_stop_descrambling(i);
|
---|
4449 | return;
|
---|
4450 | }
|
---|
4451 |
|
---|
4452 | struct s_dvbapi_priority *forceentry = dvbapi_check_prio_match(i, j, 'p');
|
---|
4453 |
|
---|
4454 | if(forceentry && forceentry->force) // forced pid? keep trying the forced ecmpid!
|
---|
4455 | {
|
---|
4456 | if(!caid_is_irdeto(er->caid) || forceentry->chid < 0x10000) //all cas or irdeto cas with forced prio chid
|
---|
4457 | {
|
---|
4458 | demux[i].ECMpids[j].table = 0;
|
---|
4459 | dvbapi_set_section_filter(i, er, -1);
|
---|
4460 | continue;
|
---|
4461 | }
|
---|
4462 | else // irdeto cas without chid prio forced
|
---|
4463 | {
|
---|
4464 | if(demux[i].ECMpids[j].irdeto_curindex == 0xFE) { demux[i].ECMpids[j].irdeto_curindex = 0x00; } // init irdeto current index to first one
|
---|
4465 | if(!(demux[i].ECMpids[j].irdeto_curindex + 1 > demux[i].ECMpids[j].irdeto_maxindex)) // check for last / max chid
|
---|
4466 | {
|
---|
4467 | cs_log_dbg(D_DVBAPI, "Demuxer %d trying next irdeto chid of FORCED PID %d CAID %04X PROVID %06X ECMPID %04X", i,
|
---|
4468 | j, er->caid, er->prid, er->pid);
|
---|
4469 | demux[i].ECMpids[j].irdeto_curindex++; // irdeto index one up
|
---|
4470 | demux[i].ECMpids[j].table = 0;
|
---|
4471 | dvbapi_set_section_filter(i, er, -1);
|
---|
4472 | continue;
|
---|
4473 | }
|
---|
4474 | }
|
---|
4475 | }
|
---|
4476 |
|
---|
4477 | // in case of timeout or fatal LB event give this pid another try but no more than 1 try
|
---|
4478 | if((er->rc == E_TIMEOUT || (er->rcEx && er->rcEx <= E2_CCCAM_NOCARD)) && demux[i].ECMpids[j].tries == 0xFE)
|
---|
4479 | {
|
---|
4480 | demux[i].ECMpids[j].tries = 1;
|
---|
4481 | demux[i].ECMpids[j].table = 0;
|
---|
4482 | dvbapi_set_section_filter(i, er, -1);
|
---|
4483 | continue;
|
---|
4484 | }
|
---|
4485 | else // all not found responses exception: first timeout response and first fatal loadbalancer response
|
---|
4486 | {
|
---|
4487 | demux[i].ECMpids[j].CHID = 0x10000; // get rid of this prio chid since it failed!
|
---|
4488 | demux[i].ECMpids[j].tries = 0xFE; // reset timeout retry
|
---|
4489 | }
|
---|
4490 |
|
---|
4491 | if(caid_is_irdeto(er->caid))
|
---|
4492 | {
|
---|
4493 | if(demux[i].ECMpids[j].irdeto_curindex == 0xFE) { demux[i].ECMpids[j].irdeto_curindex = 0x00; } // init irdeto current index to first one
|
---|
4494 | if(!(demux[i].ECMpids[j].irdeto_curindex + 1 > demux[i].ECMpids[j].irdeto_maxindex)) // check for last / max chid
|
---|
4495 | {
|
---|
4496 | cs_log_dbg(D_DVBAPI, "Demuxer %d trying next irdeto chid of PID %d CAID %04X PROVID %06X ECMPID %04X VPID %04X", i,
|
---|
4497 | j, er->caid, er->prid, er->pid, er->vpid);
|
---|
4498 | demux[i].ECMpids[j].irdeto_curindex++; // irdeto index one up
|
---|
4499 | demux[i].ECMpids[j].table = 0;
|
---|
4500 | dvbapi_set_section_filter(i, er, -1);
|
---|
4501 | continue;
|
---|
4502 | }
|
---|
4503 | }
|
---|
4504 |
|
---|
4505 | dvbapi_edit_channel_cache(i, j, 0); // remove this pid from channelcache
|
---|
4506 | if(demux[i].pidindex == j)
|
---|
4507 | {
|
---|
4508 | demux[i].pidindex = -1; // current pid delivered a notfound so this pid isnt being used to descramble any longer-> clear pidindex
|
---|
4509 | }
|
---|
4510 | demux[i].ECMpids[j].irdeto_maxindex = 0;
|
---|
4511 | demux[i].ECMpids[j].irdeto_curindex = 0xFE;
|
---|
4512 | demux[i].ECMpids[j].tries = 0xFE; // reset timeout retry flag
|
---|
4513 | demux[i].ECMpids[j].irdeto_cycle = 0xFE; // reset irdetocycle
|
---|
4514 | demux[i].ECMpids[j].table = 0;
|
---|
4515 | demux[i].ECMpids[j].checked = 4; // flag ecmpid as checked
|
---|
4516 | demux[i].ECMpids[j].status = -1; // flag ecmpid as unusable
|
---|
4517 | int32_t found = 1; // setup for first run
|
---|
4518 | int32_t filternum = -1;
|
---|
4519 |
|
---|
4520 | while(found > 0) // disable all ecm + emm filters for this notfound
|
---|
4521 | {
|
---|
4522 | found = 0;
|
---|
4523 | filternum = dvbapi_get_filternum(i, er, TYPE_ECM); // get ecm filternumber
|
---|
4524 | if(filternum > -1) // in case valid filter found
|
---|
4525 | {
|
---|
4526 | int32_t fd = demux[i].demux_fd[filternum].fd;
|
---|
4527 | if(fd > 0) // in case valid fd
|
---|
4528 | {
|
---|
4529 | dvbapi_stop_filternum(i, filternum); // stop ecmfilter
|
---|
4530 | found = 1;
|
---|
4531 | }
|
---|
4532 | }
|
---|
4533 | if(caid_is_irdeto(er->caid)) // in case irdeto cas stop old emm filters
|
---|
4534 | {
|
---|
4535 | filternum = dvbapi_get_filternum(i, er, TYPE_EMM); // get emm filternumber
|
---|
4536 | if(filternum > -1) // in case valid filter found
|
---|
4537 | {
|
---|
4538 | int32_t fd = demux[i].demux_fd[filternum].fd;
|
---|
4539 | if(fd > 0) // in case valid fd
|
---|
4540 | {
|
---|
4541 | dvbapi_stop_filternum(i, filternum); // stop emmfilter
|
---|
4542 | found = 1;
|
---|
4543 | }
|
---|
4544 | }
|
---|
4545 | }
|
---|
4546 | }
|
---|
4547 |
|
---|
4548 | continue;
|
---|
4549 | }
|
---|
4550 |
|
---|
4551 |
|
---|
4552 | // below this should be only run in case of ecm answer is found
|
---|
4553 |
|
---|
4554 | uint32_t chid = get_subid(er); // derive current chid in case of irdeto, or a unique part of ecm on other cas systems
|
---|
4555 | demux[i].ECMpids[j].CHID = (chid != 0 ? chid : 0x10000); // if not zero apply, otherwise use no chid value 0x10000
|
---|
4556 | dvbapi_edit_channel_cache(i, j, 1); // do it here to here after the right CHID is registered
|
---|
4557 |
|
---|
4558 | //dvbapi_set_section_filter(i, er); is not needed anymore (unsure)
|
---|
4559 | demux[i].ECMpids[j].tries = 0xFE; // reset timeout retry flag
|
---|
4560 | demux[i].ECMpids[j].irdeto_cycle = 0xFE; // reset irdeto cycle
|
---|
4561 |
|
---|
4562 | if(nocw_write || demux[i].pidindex != j) { continue; } // cw was already written by another filter or current pid isnt pid used to descramble so it ends here!
|
---|
4563 |
|
---|
4564 | struct s_dvbapi_priority *delayentry = dvbapi_check_prio_match(i, demux[i].pidindex, 'd');
|
---|
4565 | if(delayentry)
|
---|
4566 | {
|
---|
4567 | if(delayentry->delay < 1000)
|
---|
4568 | {
|
---|
4569 | cs_log_dbg(D_DVBAPI, "wait %d ms", delayentry->delay);
|
---|
4570 | cs_sleepms(delayentry->delay);
|
---|
4571 | }
|
---|
4572 | }
|
---|
4573 |
|
---|
4574 | delayer(er);
|
---|
4575 |
|
---|
4576 | switch(selected_api)
|
---|
4577 | {
|
---|
4578 | #ifdef WITH_STAPI
|
---|
4579 | case STAPI:
|
---|
4580 | stapi_write_cw(i, er->cw, demux[i].STREAMpids, demux[i].STREAMpidcount, demux[i].pmt_file);
|
---|
4581 | break;
|
---|
4582 | #endif
|
---|
4583 | default:
|
---|
4584 | dvbapi_write_cw(i, er->cw, j);
|
---|
4585 | break;
|
---|
4586 | }
|
---|
4587 |
|
---|
4588 | // reset idle-Time
|
---|
4589 | client->last = time((time_t *)0); // ********* TO BE FIXED LATER ON ******
|
---|
4590 |
|
---|
4591 | FILE *ecmtxt = NULL;
|
---|
4592 | if (cfg.dvbapi_listenport && client_proto_version >= 2)
|
---|
4593 | dvbapi_net_send(DVBAPI_ECM_INFO, demux[i].socket_fd, i, 0, NULL, client, er);
|
---|
4594 | else if (!cfg.dvbapi_listenport && cfg.dvbapi_boxtype != BOXTYPE_PC_NODMX)
|
---|
4595 | ecmtxt = fopen(ECMINFO_FILE, "w");
|
---|
4596 | if(ecmtxt != NULL && er->rc < E_NOTFOUND)
|
---|
4597 | {
|
---|
4598 | char tmp[25];
|
---|
4599 | fprintf(ecmtxt, "caid: 0x%04X\npid: 0x%04X\nprov: 0x%06X\n", er->caid, er->pid, (uint) er->prid);
|
---|
4600 | switch(er->rc)
|
---|
4601 | {
|
---|
4602 | case E_FOUND:
|
---|
4603 | if(er->selected_reader)
|
---|
4604 | {
|
---|
4605 | fprintf(ecmtxt, "reader: %s\n", er->selected_reader->label);
|
---|
4606 | if(is_network_reader(er->selected_reader))
|
---|
4607 | { fprintf(ecmtxt, "from: %s\n", er->selected_reader->device); }
|
---|
4608 | else
|
---|
4609 | { fprintf(ecmtxt, "from: local\n"); }
|
---|
4610 | fprintf(ecmtxt, "protocol: %s\n", reader_get_type_desc(er->selected_reader, 1));
|
---|
4611 | fprintf(ecmtxt, "hops: %d\n", er->selected_reader->currenthops);
|
---|
4612 | }
|
---|
4613 | break;
|
---|
4614 |
|
---|
4615 | case E_CACHE1:
|
---|
4616 | fprintf(ecmtxt, "reader: Cache\n");
|
---|
4617 | fprintf(ecmtxt, "from: cache1\n");
|
---|
4618 | fprintf(ecmtxt, "protocol: none\n");
|
---|
4619 | break;
|
---|
4620 |
|
---|
4621 | case E_CACHE2:
|
---|
4622 | fprintf(ecmtxt, "reader: Cache\n");
|
---|
4623 | fprintf(ecmtxt, "from: cache2\n");
|
---|
4624 | fprintf(ecmtxt, "protocol: none\n");
|
---|
4625 | break;
|
---|
4626 |
|
---|
4627 | case E_CACHEEX:
|
---|
4628 | fprintf(ecmtxt, "reader: Cache\n");
|
---|
4629 | fprintf(ecmtxt, "from: cache3\n");
|
---|
4630 | fprintf(ecmtxt, "protocol: none\n");
|
---|
4631 | break;
|
---|
4632 | }
|
---|
4633 | fprintf(ecmtxt, "ecm time: %.3f\n", (float) client->cwlastresptime / 1000);
|
---|
4634 | fprintf(ecmtxt, "cw0: %s\n", cs_hexdump(1, demux[i].lastcw[0], 8, tmp, sizeof(tmp)));
|
---|
4635 | fprintf(ecmtxt, "cw1: %s\n", cs_hexdump(1, demux[i].lastcw[1], 8, tmp, sizeof(tmp)));
|
---|
4636 | }
|
---|
4637 | if(ecmtxt)
|
---|
4638 | {
|
---|
4639 | int32_t ret = fclose(ecmtxt);
|
---|
4640 | if(ret < 0) { cs_log("ERROR: Could not close ecmtxt fd (errno=%d %s)", errno, strerror(errno)); }
|
---|
4641 | ecmtxt = NULL;
|
---|
4642 | }
|
---|
4643 |
|
---|
4644 | }
|
---|
4645 | if(handled == 0)
|
---|
4646 | {
|
---|
4647 | cs_log_dbg(D_DVBAPI, "Unhandled ECM response received for CAID %04X PROVID %06X ECMPID %04X CHID %04X VPID %04X",
|
---|
4648 | er->caid, er->prid, er->pid, er->chid, er->vpid);
|
---|
4649 | }
|
---|
4650 |
|
---|
4651 | }
|
---|
4652 |
|
---|
4653 | void *dvbapi_start_handler(struct s_client *cl, uchar *UNUSED(mbuf), int32_t module_idx, void * (*_main_func)(void *))
|
---|
4654 | {
|
---|
4655 | // cs_log("dvbapi loaded fd=%d", idx);
|
---|
4656 | if(cfg.dvbapi_enabled == 1)
|
---|
4657 | {
|
---|
4658 | cl = create_client(get_null_ip());
|
---|
4659 | cl->module_idx = module_idx;
|
---|
4660 | cl->typ = 'c';
|
---|
4661 | int32_t ret = pthread_create(&cl->thread, NULL, _main_func, (void *) cl);
|
---|
4662 | if(ret)
|
---|
4663 | {
|
---|
4664 | cs_log("ERROR: Can't create dvbapi handler thread (errno=%d %s)", ret, strerror(ret));
|
---|
4665 | return NULL;
|
---|
4666 | }
|
---|
4667 | else
|
---|
4668 | { pthread_detach(cl->thread); }
|
---|
4669 | }
|
---|
4670 |
|
---|
4671 | return NULL;
|
---|
4672 | }
|
---|
4673 |
|
---|
4674 | void *dvbapi_handler(struct s_client *cl, uchar *mbuf, int32_t module_idx)
|
---|
4675 | {
|
---|
4676 | return dvbapi_start_handler(cl, mbuf, module_idx, dvbapi_main_local);
|
---|
4677 | }
|
---|
4678 |
|
---|
4679 | int32_t dvbapi_set_section_filter(int32_t demux_index, ECM_REQUEST *er, int32_t n)
|
---|
4680 | {
|
---|
4681 | if(!er) { return -1; }
|
---|
4682 |
|
---|
4683 | if(selected_api != DVBAPI_3 && selected_api != DVBAPI_1 && selected_api != STAPI) // only valid for dvbapi3, dvbapi1 and STAPI
|
---|
4684 | {
|
---|
4685 | return 0;
|
---|
4686 | }
|
---|
4687 |
|
---|
4688 | if(n == -1)
|
---|
4689 | {
|
---|
4690 | n = dvbapi_get_filternum(demux_index, er, TYPE_ECM);
|
---|
4691 | }
|
---|
4692 |
|
---|
4693 | if(n < 0) { return -1; } // in case no valid filter found;
|
---|
4694 |
|
---|
4695 | int32_t fd = demux[demux_index].demux_fd[n].fd;
|
---|
4696 | if(fd < 1) { return -1 ; } // in case no valid fd
|
---|
4697 |
|
---|
4698 | uchar filter[16];
|
---|
4699 | uchar mask[16];
|
---|
4700 | memset(filter, 0, 16);
|
---|
4701 | memset(mask, 0, 16);
|
---|
4702 |
|
---|
4703 | struct s_ecmpids *curpid = NULL;
|
---|
4704 | int32_t pid = demux[demux_index].demux_fd[n].pidindex;
|
---|
4705 | if(pid != -1)
|
---|
4706 | {
|
---|
4707 | curpid = &demux[demux_index].ECMpids[pid];
|
---|
4708 | }
|
---|
4709 | if(curpid->table != er->ecm[0] && curpid->table != 0) { return -1; } // if current ecmtype differs from latest requested ecmtype do not apply section filtering!
|
---|
4710 | uint8_t ecmfilter = 0;
|
---|
4711 |
|
---|
4712 | if(er->ecm[0] == 0x80) { ecmfilter = 0x81; } // current processed ecm is even, next will be filtered for odd
|
---|
4713 | else { ecmfilter = 0x80; } // current processed ecm is odd, next will be filtered for even
|
---|
4714 |
|
---|
4715 | if(curpid->table != 0) // cycle ecmtype from odd to even or even to odd
|
---|
4716 | {
|
---|
4717 | filter[0] = ecmfilter; // only accept new ecms (if previous odd, filter for even and visaversa)
|
---|
4718 | mask[0] = 0xFF;
|
---|
4719 | cs_log_dbg(D_DVBAPI, "Demuxer %d Filter %d set ecmtable to %s (CAID %04X PROVID %06X FD %d)", demux_index, n + 1,
|
---|
4720 | (ecmfilter == 0x80 ? "EVEN" : "ODD"), curpid->CAID, curpid->PROVID, fd);
|
---|
4721 | }
|
---|
4722 | else // not decoding right now so we are interessted in all ecmtypes!
|
---|
4723 | {
|
---|
4724 | filter[0] = 0x80; // set filter to wait for any ecms
|
---|
4725 | mask[0] = 0xF0;
|
---|
4726 | cs_log_dbg(D_DVBAPI, "Demuxer %d Filter %d set ecmtable to ODD+EVEN (CAID %04X PROVID %06X FD %d)", demux_index, n + 1,
|
---|
4727 | curpid->CAID, curpid->PROVID, fd);
|
---|
4728 | }
|
---|
4729 | uint32_t offset = 0, extramask = 0xFF;
|
---|
4730 |
|
---|
4731 | struct s_dvbapi_priority *forceentry = dvbapi_check_prio_match(demux_index, pid, 'p');
|
---|
4732 | //cs_log("**** curpid->CHID %04X, checked = %d, er->chid = %04X *****", curpid->CHID, curpid->checked, er->chid);
|
---|
4733 | // checked 4 to make sure we dont set chid filter and no such ecm in dvbstream except for forced pids!
|
---|
4734 | if(curpid->CHID < 0x10000 && (curpid->checked == 4 || (forceentry && forceentry->force)))
|
---|
4735 | {
|
---|
4736 |
|
---|
4737 | switch(er->caid >> 8)
|
---|
4738 | {
|
---|
4739 | case 0x01:
|
---|
4740 | offset = 7;
|
---|
4741 | extramask = 0xF0;
|
---|
4742 | break; // seca
|
---|
4743 | case 0x05:
|
---|
4744 | offset = 8;
|
---|
4745 | break; // viaccess
|
---|
4746 | case 0x06:
|
---|
4747 | offset = 6;
|
---|
4748 | break; // irdeto
|
---|
4749 | case 0x09:
|
---|
4750 | offset = 11;
|
---|
4751 | break; // videoguard
|
---|
4752 | case 0x4A: // DRE-Crypt, Bulcrypt,Tongang and others?
|
---|
4753 | if(!caid_is_bulcrypt(er->caid))
|
---|
4754 | { offset = 6; }
|
---|
4755 | break;
|
---|
4756 | }
|
---|
4757 | }
|
---|
4758 |
|
---|
4759 | int32_t irdetomatch = 1; // check if wanted irdeto index is the one the delivers current chid!
|
---|
4760 | if(caid_is_irdeto(curpid->CAID))
|
---|
4761 | {
|
---|
4762 | if(curpid->irdeto_curindex == er->ecm[4]) { irdetomatch = 1; } // ok apply chid filtering
|
---|
4763 | else { irdetomatch = 0; } // skip chid filtering but apply irdeto index filtering
|
---|
4764 | }
|
---|
4765 |
|
---|
4766 | if(offset && irdetomatch) // we have a cas with chid or unique part in checked ecm
|
---|
4767 | {
|
---|
4768 | i2b_buf(2, curpid->CHID, filter + (offset - 2));
|
---|
4769 | mask[(offset - 2)] = 0xFF&extramask; // additional mask seca2 chid can be FC10 or FD10 varies each month so only apply F?10
|
---|
4770 | mask[(offset - 1)] = 0xFF;
|
---|
4771 | cs_log_dbg(D_DVBAPI, "Demuxer %d Filter %d set chid to %04X on fd %d", demux_index, n + 1, curpid->CHID, fd);
|
---|
4772 | }
|
---|
4773 | else
|
---|
4774 | {
|
---|
4775 | if(caid_is_irdeto(curpid->CAID) && (curpid->irdeto_curindex < 0xFE)) // on irdeto we can always apply irdeto index filtering!
|
---|
4776 | {
|
---|
4777 | filter[2] = curpid->irdeto_curindex;
|
---|
4778 | mask[2] = 0xFF;
|
---|
4779 | cs_log_dbg(D_DVBAPI, "Demuxer %d Filter %d set irdetoindex to %d on fd %d", demux_index, n + 1, curpid->irdeto_curindex, fd);
|
---|
4780 | }
|
---|
4781 | else // all other cas systems also cas systems without chid or unique ecm part
|
---|
4782 | {
|
---|
4783 | cs_log_dbg(D_DVBAPI, "Demuxer %d Filter %d set chid to ANY CHID on fd %d", demux_index, n + 1, fd);
|
---|
4784 | }
|
---|
4785 | }
|
---|
4786 |
|
---|
4787 | int32_t ret = dvbapi_activate_section_filter(demux_index, n, fd, curpid->ECM_PID, filter, mask);
|
---|
4788 | if(ret < 0) // something went wrong setting filter!
|
---|
4789 | {
|
---|
4790 | cs_log("Demuxer %d Filter %d (fd %d) error setting section filtering -> stop filter!", demux_index, n + 1, fd);
|
---|
4791 | ret = dvbapi_stop_filternum(demux_index, n);
|
---|
4792 | if(ret == -1)
|
---|
4793 | {
|
---|
4794 | cs_log("Demuxer %d Filter %d (fd %d) stopping filter failed -> kill all filters of this demuxer!", demux_index, n + 1, fd);
|
---|
4795 | dvbapi_stop_filter(demux_index, TYPE_EMM);
|
---|
4796 | dvbapi_stop_filter(demux_index, TYPE_ECM);
|
---|
4797 | }
|
---|
4798 | return -1;
|
---|
4799 | }
|
---|
4800 | return n;
|
---|
4801 | }
|
---|
4802 |
|
---|
4803 | int32_t dvbapi_activate_section_filter(int32_t demux_index, int32_t num, int32_t fd, int32_t pid, uchar *filter, uchar *mask)
|
---|
4804 | {
|
---|
4805 |
|
---|
4806 | int32_t ret = -1;
|
---|
4807 |
|
---|
4808 | switch(selected_api)
|
---|
4809 | {
|
---|
4810 | case DVBAPI_3:
|
---|
4811 | {
|
---|
4812 | struct dmx_sct_filter_params sFP2;
|
---|
4813 | memset(&sFP2, 0, sizeof(sFP2));
|
---|
4814 | sFP2.pid = pid;
|
---|
4815 | sFP2.timeout = 0;
|
---|
4816 | sFP2.flags = DMX_IMMEDIATE_START;
|
---|
4817 | if(cfg.dvbapi_boxtype == BOXTYPE_NEUMO)
|
---|
4818 | {
|
---|
4819 | //DeepThought: on dgs/cubestation and neumo images, perhaps others
|
---|
4820 | //the following code is needed to descramble
|
---|
4821 | sFP2.filter.filter[0] = filter[0];
|
---|
4822 | sFP2.filter.mask[0] = mask[0];
|
---|
4823 | sFP2.filter.filter[1] = 0;
|
---|
4824 | sFP2.filter.mask[1] = 0;
|
---|
4825 | sFP2.filter.filter[2] = 0;
|
---|
4826 | sFP2.filter.mask[2] = 0;
|
---|
4827 | memcpy(sFP2.filter.filter + 3, filter + 1, 16 - 3);
|
---|
4828 | memcpy(sFP2.filter.mask + 3, mask + 1, 16 - 3);
|
---|
4829 | //DeepThought: in the drivers of the dgs/cubestation and neumo images,
|
---|
4830 | //dvbapi 1 and 3 are somehow mixed. In the kernel drivers, the DMX_SET_FILTER
|
---|
4831 | //ioctl expects to receive a dmx_sct_filter_params structure (DVBAPI 3) but
|
---|
4832 | //due to a bug its sets the "positive mask" wrongly (they should be all 0).
|
---|
4833 | //On the other hand, the DMX_SET_FILTER1 ioctl also uses the dmx_sct_filter_params
|
---|
4834 | //structure, which is incorrect (it should be dmxSctFilterParams).
|
---|
4835 | //The only way to get it right is to call DMX_SET_FILTER1 with the argument
|
---|
4836 | //expected by DMX_SET_FILTER. Otherwise, the timeout parameter is not passed correctly.
|
---|
4837 | ret = dvbapi_ioctl(fd, DMX_SET_FILTER1, &sFP2);
|
---|
4838 | }
|
---|
4839 | else
|
---|
4840 | {
|
---|
4841 | memcpy(sFP2.filter.filter, filter, 16);
|
---|
4842 | memcpy(sFP2.filter.mask, mask, 16);
|
---|
4843 | if (cfg.dvbapi_listenport || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX)
|
---|
4844 | ret = dvbapi_net_send(DVBAPI_DMX_SET_FILTER, demux[demux_index].socket_fd, demux_index, num, (unsigned char *) &sFP2, NULL, NULL);
|
---|
4845 | else
|
---|
4846 | ret = dvbapi_ioctl(fd, DMX_SET_FILTER, &sFP2);
|
---|
4847 | }
|
---|
4848 | break;
|
---|
4849 | }
|
---|
4850 |
|
---|
4851 | case DVBAPI_1:
|
---|
4852 | {
|
---|
4853 | struct dmxSctFilterParams sFP1;
|
---|
4854 | memset(&sFP1, 0, sizeof(sFP1));
|
---|
4855 | sFP1.pid = pid;
|
---|
4856 | sFP1.timeout = 0;
|
---|
4857 | sFP1.flags = DMX_IMMEDIATE_START;
|
---|
4858 | memcpy(sFP1.filter.filter, filter, 16);
|
---|
4859 | memcpy(sFP1.filter.mask, mask, 16);
|
---|
4860 | ret = dvbapi_ioctl(fd, DMX_SET_FILTER1, &sFP1);
|
---|
4861 | break;
|
---|
4862 | }
|
---|
4863 | #ifdef WITH_STAPI
|
---|
4864 | case STAPI:
|
---|
4865 | {
|
---|
4866 | ret = stapi_activate_section_filter(fd, filter, mask);
|
---|
4867 | break;
|
---|
4868 | }
|
---|
4869 | #endif
|
---|
4870 | /*#ifdef WITH_COOLAPI ******* NOT IMPLEMENTED YET ********
|
---|
4871 | case COOLAPI: {
|
---|
4872 | coolapi_set_filter(demux[demux_id].demux_fd[n].fd, n, pid, filter, mask, TYPE_ECM);
|
---|
4873 | break;
|
---|
4874 | }
|
---|
4875 | #endif
|
---|
4876 | */
|
---|
4877 | default:
|
---|
4878 | break;
|
---|
4879 | }
|
---|
4880 | return ret;
|
---|
4881 | }
|
---|
4882 |
|
---|
4883 |
|
---|
4884 | int32_t dvbapi_check_ecm_delayed_delivery(int32_t demux_index, ECM_REQUEST *er)
|
---|
4885 | {
|
---|
4886 | char nullcw[CS_ECMSTORESIZE];
|
---|
4887 | memset(nullcw, 0, CS_ECMSTORESIZE);
|
---|
4888 | if(memcmp(er->cw, nullcw, 8) == 0 && memcmp(er->cw+8, nullcw, 8) == 0) {return 5;} // received a null cw -> not usable!
|
---|
4889 | int32_t filternum = dvbapi_get_filternum(demux_index, er, TYPE_ECM);
|
---|
4890 | if(filternum < 0) { return 2; } // if no matching filter act like ecm response is delayed
|
---|
4891 | struct s_ecmpids *curpid = NULL;
|
---|
4892 | int32_t pid = demux[demux_index].demux_fd[filternum].pidindex;
|
---|
4893 | if(pid !=-1)
|
---|
4894 | {
|
---|
4895 | curpid = &demux[demux_index].ECMpids[pid];
|
---|
4896 | if(curpid->table == 0) { return 3; } // on change table act like ecm response is found
|
---|
4897 | }
|
---|
4898 |
|
---|
4899 | if(er->rc == E_CACHEEX) { return 4; } // on cache-ex response act like ecm response is found
|
---|
4900 |
|
---|
4901 | if(memcmp(demux[demux_index].demux_fd[filternum].ecmd5, nullcw, CS_ECMSTORESIZE))
|
---|
4902 | {
|
---|
4903 | char ecmd5[17 * 3];
|
---|
4904 | cs_hexdump(0, demux[demux_index].demux_fd[filternum].ecmd5, 16, ecmd5, sizeof(ecmd5));
|
---|
4905 | cs_log_dbg(D_DVBAPI, "Demuxer %d requested controlword for ecm %s on fd %d", demux_index, ecmd5, demux[demux_index].demux_fd[filternum].fd);
|
---|
4906 | return memcmp(demux[demux_index].demux_fd[filternum].ecmd5, er->ecmd5, CS_ECMSTORESIZE); // 1 = no response on the ecm we request last for this fd!
|
---|
4907 | }
|
---|
4908 | else { return 0; }
|
---|
4909 | }
|
---|
4910 |
|
---|
4911 | int32_t dvbapi_get_filternum(int32_t demux_index, ECM_REQUEST *er, int32_t type)
|
---|
4912 | {
|
---|
4913 | if(!er) { return -1; }
|
---|
4914 |
|
---|
4915 | int32_t n;
|
---|
4916 | int32_t fd = -1;
|
---|
4917 |
|
---|
4918 | for(n = 0; n < maxfilter; n++) // determine fd
|
---|
4919 | {
|
---|
4920 | if(demux[demux_index].demux_fd[n].fd > 0 && demux[demux_index].demux_fd[n].type == type) // check for valid and right type (ecm or emm)
|
---|
4921 | {
|
---|
4922 | if(type == TYPE_ECM && er->srvid != demux[demux_index].program_number) continue;
|
---|
4923 | if((demux[demux_index].demux_fd[n].pid == er->pid) &&
|
---|
4924 | ((demux[demux_index].demux_fd[n].provid == er->prid) || demux[demux_index].demux_fd[n].provid == 0 || er->prid == 0) &&
|
---|
4925 | ((demux[demux_index].demux_fd[n].caid == er->caid) || (demux[demux_index].demux_fd[n].caid == er->ocaid))) // current ecm pid?
|
---|
4926 | {
|
---|
4927 | fd = demux[demux_index].demux_fd[n].fd; // found!
|
---|
4928 | break;
|
---|
4929 | }
|
---|
4930 | }
|
---|
4931 | }
|
---|
4932 | if(fd > 0 && demux[demux_index].demux_fd[n].provid == 0) { demux[demux_index].demux_fd[n].provid = er->prid; } // hack to fill in provid into demuxer
|
---|
4933 |
|
---|
4934 | return (fd > 0 ? n : fd); // return -1(fd) on not found, on found return filternumber(n)
|
---|
4935 | }
|
---|
4936 |
|
---|
4937 | int32_t dvbapi_ca_setpid(int32_t demux_index, int32_t pid)
|
---|
4938 | {
|
---|
4939 | int32_t idx = -1, n;
|
---|
4940 | if(pid == -1 || pid > demux[demux_index].ECMpidcount) return -1;
|
---|
4941 |
|
---|
4942 | idx = demux[demux_index].ECMpids[pid].index;
|
---|
4943 |
|
---|
4944 | if(!idx) // if no indexer for this pid get one!
|
---|
4945 | {
|
---|
4946 | idx = dvbapi_get_descindex(demux_index);
|
---|
4947 | demux[demux_index].ECMpids[pid].index = idx;
|
---|
4948 | cs_log_dbg(D_DVBAPI, "Demuxer %d PID: %d CAID: %04X ECMPID: %04X is using index %d", demux_index, pid,
|
---|
4949 | demux[demux_index].ECMpids[pid].CAID, demux[demux_index].ECMpids[pid].ECM_PID, idx - 1);
|
---|
4950 | }
|
---|
4951 |
|
---|
4952 | for(n = 0; n < demux[demux_index].STREAMpidcount; n++)
|
---|
4953 | {
|
---|
4954 | if(!demux[demux_index].ECMpids[pid].streams || ((demux[demux_index].ECMpids[pid].streams & (1 << n)) == (uint) (1 << n))){
|
---|
4955 | dvbapi_set_pid(demux_index, n, idx - 1, true); // enable streampid
|
---|
4956 | }
|
---|
4957 | else{
|
---|
4958 | dvbapi_set_pid(demux_index, n, idx - 1, false); // disable streampid
|
---|
4959 | }
|
---|
4960 | }
|
---|
4961 |
|
---|
4962 | return idx - 1; // return caindexer
|
---|
4963 | }
|
---|
4964 |
|
---|
4965 | int8_t update_streampid_list(uint8_t cadevice, uint16_t pid, int32_t idx)
|
---|
4966 | {
|
---|
4967 | struct s_streampid *listitem, *newlistitem;
|
---|
4968 | if(!ll_activestreampids)
|
---|
4969 | { ll_activestreampids = ll_create("ll_activestreampids"); }
|
---|
4970 | LL_ITER itr;
|
---|
4971 | if(ll_count(ll_activestreampids) > 0)
|
---|
4972 | {
|
---|
4973 | itr = ll_iter_create(ll_activestreampids);
|
---|
4974 | while((listitem = ll_iter_next(&itr)))
|
---|
4975 | {
|
---|
4976 | if (cadevice == listitem->cadevice && pid == listitem->streampid){
|
---|
4977 | if((listitem->activeindexers & (1 << idx)) == (uint) (1 << idx)){
|
---|
4978 | return FOUND_STREAMPID_INDEX; // match found
|
---|
4979 | }else{
|
---|
4980 | listitem->activeindexers|=(1 << idx); // ca + pid found but not this index -> add this index
|
---|
4981 | cs_log_dbg(D_DVBAPI, "Added existing streampid %04X with new index %d to ca%d", pid, idx, cadevice);
|
---|
4982 | return ADDED_STREAMPID_INDEX;
|
---|
4983 | }
|
---|
4984 | }
|
---|
4985 | }
|
---|
4986 | }
|
---|
4987 | if(!cs_malloc(&newlistitem, sizeof(struct s_streampid)))
|
---|
4988 | { return FIRST_STREAMPID_INDEX; }
|
---|
4989 | newlistitem->cadevice = cadevice;
|
---|
4990 | newlistitem->streampid = pid;
|
---|
4991 | newlistitem->activeindexers = (1 << idx);
|
---|
4992 | newlistitem->caindex = idx; // set this index as used to decode on ca device
|
---|
4993 | ll_append(ll_activestreampids, newlistitem);
|
---|
4994 | cs_log_dbg(D_DVBAPI, "Added new streampid %04X with index %d to ca%d", pid, idx, cadevice);
|
---|
4995 | return FIRST_STREAMPID_INDEX;
|
---|
4996 | }
|
---|
4997 |
|
---|
4998 | int8_t remove_streampid_from_list(uint8_t cadevice, uint16_t pid, int32_t idx)
|
---|
4999 | {
|
---|
5000 | if(!ll_activestreampids) return NO_STREAMPID_LISTED;
|
---|
5001 |
|
---|
5002 | struct s_streampid *listitem;
|
---|
5003 | int8_t removed = 0;
|
---|
5004 |
|
---|
5005 | LL_ITER itr;
|
---|
5006 | if(ll_count(ll_activestreampids) > 0)
|
---|
5007 | {
|
---|
5008 | itr = ll_iter_create(ll_activestreampids);
|
---|
5009 | while((listitem = ll_iter_next(&itr)))
|
---|
5010 | {
|
---|
5011 | if (cadevice == listitem->cadevice && pid == listitem->streampid)
|
---|
5012 | {
|
---|
5013 | if(idx == -1){ // idx -1 means disable all!
|
---|
5014 | listitem->activeindexers = 0;
|
---|
5015 | removed = 1;
|
---|
5016 | }
|
---|
5017 | else if((listitem->activeindexers & (1 << idx)) == (uint) (1 << idx))
|
---|
5018 | {
|
---|
5019 | listitem->activeindexers &= ~(1 << idx); // flag it as disabled for this index
|
---|
5020 | removed = 1;
|
---|
5021 | }
|
---|
5022 |
|
---|
5023 | if(removed)
|
---|
5024 | {
|
---|
5025 | cs_log_dbg(D_DVBAPI, "Remove streampid %04X using indexer %d from ca%d", pid, idx, cadevice);
|
---|
5026 | }
|
---|
5027 | if (listitem->activeindexers == 0 && removed == 1) // all indexers disabled? -> remove pid from list!
|
---|
5028 | {
|
---|
5029 | ll_iter_remove_data(&itr);
|
---|
5030 | cs_log_dbg(D_DVBAPI, "Removed last indexer of streampid %04X from ca%d", pid, cadevice);
|
---|
5031 | return REMOVED_STREAMPID_LASTINDEX;
|
---|
5032 | }
|
---|
5033 | else if(removed == 1)
|
---|
5034 | {
|
---|
5035 | if (idx > 0 && (uint) idx != listitem->caindex)
|
---|
5036 | {
|
---|
5037 | return REMOVED_STREAMPID_INDEX;
|
---|
5038 | }
|
---|
5039 | else
|
---|
5040 | {
|
---|
5041 | listitem->caindex = 0xFFFF;
|
---|
5042 | cs_log_dbg(D_DVBAPI, "Streampid %04X index %d was used for decoding on ca%d", pid, idx, cadevice);
|
---|
5043 | return REMOVED_DECODING_STREAMPID_INDEX;
|
---|
5044 | }
|
---|
5045 | }
|
---|
5046 | }
|
---|
5047 | }
|
---|
5048 | }
|
---|
5049 | return NO_STREAMPID_LISTED;
|
---|
5050 | }
|
---|
5051 |
|
---|
5052 | void disable_unused_streampids(int16_t demux_id)
|
---|
5053 | {
|
---|
5054 | if(!ll_activestreampids) return;
|
---|
5055 | if(ll_count(ll_activestreampids) == 0) return; // no items in list?
|
---|
5056 |
|
---|
5057 | int32_t ecmpid = demux[demux_id].pidindex;
|
---|
5058 | if (ecmpid == -1) return; // no active ecmpid!
|
---|
5059 |
|
---|
5060 | int32_t idx = demux[demux_id].ECMpids[ecmpid].index;
|
---|
5061 | int32_t i,n;
|
---|
5062 | struct s_streampid *listitem;
|
---|
5063 | // search for old enabled streampids on all ca devices that have to be disabled, index 0 is skipped as it belongs to fta!
|
---|
5064 | for(i = 0; i < MAX_DEMUX && idx; i++){
|
---|
5065 | if(!((demux[demux_id].ca_mask & (1 << i)) == (uint) (1 << i))) continue; // continue if ca is unused by this demuxer
|
---|
5066 |
|
---|
5067 | LL_ITER itr;
|
---|
5068 | itr = ll_iter_create(ll_activestreampids);
|
---|
5069 | while((listitem = ll_iter_next(&itr)))
|
---|
5070 | {
|
---|
5071 | if (i != listitem->cadevice) continue; // ca doesnt match
|
---|
5072 | if (!((listitem->activeindexers & (1 << (idx-1))) == (uint) (1 << (idx-1)))) continue; // index doesnt match
|
---|
5073 | for(n = 0; n < demux[demux_id].STREAMpidcount; n++){
|
---|
5074 | if (listitem->streampid == demux[demux_id].STREAMpids[n]){ // check if pid matches with current streampid on demuxer
|
---|
5075 | break;
|
---|
5076 | }
|
---|
5077 | }
|
---|
5078 | if (n == demux[demux_id].STREAMpidcount){
|
---|
5079 | demux[demux_id].STREAMpids[n] = listitem->streampid; // put it temp here!
|
---|
5080 | dvbapi_set_pid(demux_id, n, idx - 1, false); // no match found so disable this now unused streampid
|
---|
5081 | demux[demux_id].STREAMpids[n] = 0; // remove temp!
|
---|
5082 | }
|
---|
5083 | }
|
---|
5084 | }
|
---|
5085 | }
|
---|
5086 |
|
---|
5087 |
|
---|
5088 | int8_t is_ca_used(uint8_t cadevice, int32_t pid)
|
---|
5089 | {
|
---|
5090 | if(!ll_activestreampids) return CA_IS_CLEAR;
|
---|
5091 |
|
---|
5092 | struct s_streampid *listitem;
|
---|
5093 |
|
---|
5094 | LL_ITER itr;
|
---|
5095 | if(ll_count(ll_activestreampids) > 0)
|
---|
5096 | {
|
---|
5097 | itr = ll_iter_create(ll_activestreampids);
|
---|
5098 | while((listitem = ll_iter_next(&itr)))
|
---|
5099 | {
|
---|
5100 | if(listitem->cadevice != cadevice) continue;
|
---|
5101 | if(pid && listitem->streampid != pid) continue;
|
---|
5102 | uint32_t i = 0;
|
---|
5103 | int32_t newindex = -1;
|
---|
5104 | if(listitem->caindex != 0xFFFF)
|
---|
5105 | {
|
---|
5106 | newindex = listitem->caindex;
|
---|
5107 | }
|
---|
5108 | while(newindex == -1)
|
---|
5109 | {
|
---|
5110 | if((listitem->activeindexers&(1 << i)) == (uint)(1 << i))
|
---|
5111 | {
|
---|
5112 | newindex = i;
|
---|
5113 | }
|
---|
5114 | i++;
|
---|
5115 | }
|
---|
5116 | if(listitem->caindex == 0xFFFF) // check if this pid has active index for ca device (0xFFFF means no active index!)
|
---|
5117 | {
|
---|
5118 |
|
---|
5119 | listitem->caindex = newindex; // set fresh one
|
---|
5120 | cs_log_dbg(D_DVBAPI, "Streampid %04X is now using index %d for decoding on ca%d", pid, newindex, cadevice);
|
---|
5121 | }
|
---|
5122 | return newindex;
|
---|
5123 | }
|
---|
5124 | }
|
---|
5125 | return CA_IS_CLEAR; // no indexer found for this pid!
|
---|
5126 | }
|
---|
5127 |
|
---|
5128 | const char *dvbapi_get_client_name(void)
|
---|
5129 | {
|
---|
5130 | return client_name;
|
---|
5131 | }
|
---|
5132 |
|
---|
5133 | void check_add_emmpid(int32_t demux_index, uchar *filter, int32_t l, int32_t emmtype)
|
---|
5134 | {
|
---|
5135 | if (l<0) return;
|
---|
5136 |
|
---|
5137 | uint32_t typtext_idx = 0;
|
---|
5138 | int32_t ret = -1;
|
---|
5139 | const char *typtext[] = { "UNIQUE", "SHARED", "GLOBAL", "UNKNOWN" };
|
---|
5140 |
|
---|
5141 | while(((emmtype >> typtext_idx) & 0x01) == 0 && typtext_idx < sizeof(typtext) / sizeof(const char *))
|
---|
5142 | {
|
---|
5143 | ++typtext_idx;
|
---|
5144 | }
|
---|
5145 |
|
---|
5146 | //filter already in list?
|
---|
5147 | if(is_emmfilter_in_list(filter, demux[demux_index].EMMpids[l].PID, demux[demux_index].EMMpids[l].PROVID, demux[demux_index].EMMpids[l].CAID))
|
---|
5148 | {
|
---|
5149 | cs_log_dbg(D_DVBAPI, "Demuxer %d duplicate emm filter type %s, emmpid: 0x%04X, emmcaid: %04X, emmprovid: %06X -> SKIPPED!", demux_index,
|
---|
5150 | typtext[typtext_idx], demux[demux_index].EMMpids[l].PID, demux[demux_index].EMMpids[l].CAID, demux[demux_index].EMMpids[l].PROVID);
|
---|
5151 | return;
|
---|
5152 | }
|
---|
5153 |
|
---|
5154 | if(demux[demux_index].emm_filter < demux[demux_index].max_emm_filter) // can this filter be started?
|
---|
5155 | {
|
---|
5156 | // try to activate this emmfilter
|
---|
5157 | ret = dvbapi_set_filter(demux_index, selected_api, demux[demux_index].EMMpids[l].PID, demux[demux_index].EMMpids[l].CAID,
|
---|
5158 | demux[demux_index].EMMpids[l].PROVID, filter, filter + 16, 0, demux[demux_index].pidindex, TYPE_EMM, 1);
|
---|
5159 | }
|
---|
5160 |
|
---|
5161 | if(ret != -1) // -1 if maxfilter reached or filter start error!
|
---|
5162 | {
|
---|
5163 | if(demux[demux_index].emm_filter == -1) // -1: first run of emm filtering on this demuxer
|
---|
5164 | {
|
---|
5165 | demux[demux_index].emm_filter = 0;
|
---|
5166 | }
|
---|
5167 | demux[demux_index].emm_filter++; // increase total active filters
|
---|
5168 | cs_log_dump_dbg(D_DVBAPI, filter, 32, "Demuxer %d started emm filter type %s, pid: 0x%04X", demux_index, typtext[typtext_idx], demux[demux_index].EMMpids[l].PID);
|
---|
5169 | return;
|
---|
5170 | }
|
---|
5171 | else // not set successful, so add it to the list for try again later on!
|
---|
5172 | {
|
---|
5173 | add_emmfilter_to_list(demux_index, filter, demux[demux_index].EMMpids[l].CAID, demux[demux_index].EMMpids[l].PROVID, demux[demux_index].EMMpids[l].PID, 0, false);
|
---|
5174 | cs_log_dump_dbg(D_DVBAPI, filter, 32, "Demuxer %d added inactive emm filter type %s, pid: 0x%04X", demux_index, typtext[typtext_idx], demux[demux_index].EMMpids[l].PID);
|
---|
5175 | }
|
---|
5176 | return;
|
---|
5177 | }
|
---|
5178 |
|
---|
5179 | void rotate_emmfilter(int32_t demux_id)
|
---|
5180 | {
|
---|
5181 | // emm filter iteration
|
---|
5182 | if(!ll_emm_active_filter)
|
---|
5183 | { ll_emm_active_filter = ll_create("ll_emm_active_filter"); }
|
---|
5184 |
|
---|
5185 | if(!ll_emm_inactive_filter)
|
---|
5186 | { ll_emm_inactive_filter = ll_create("ll_emm_inactive_filter"); }
|
---|
5187 |
|
---|
5188 | if(!ll_emm_pending_filter)
|
---|
5189 | { ll_emm_pending_filter = ll_create("ll_emm_pending_filter"); }
|
---|
5190 |
|
---|
5191 | uint32_t filter_count = ll_count(ll_emm_active_filter) + ll_count(ll_emm_inactive_filter);
|
---|
5192 |
|
---|
5193 | if(demux[demux_id].max_emm_filter > 0
|
---|
5194 | && ll_count(ll_emm_inactive_filter) > 0
|
---|
5195 | && filter_count > demux[demux_id].max_emm_filter)
|
---|
5196 | {
|
---|
5197 |
|
---|
5198 | int32_t filter_queue = ll_count(ll_emm_inactive_filter);
|
---|
5199 | int32_t stopped = 0, started = 0;
|
---|
5200 | struct timeb now;
|
---|
5201 | cs_ftime(&now);
|
---|
5202 |
|
---|
5203 | struct s_emm_filter *filter_item;
|
---|
5204 | LL_ITER itr;
|
---|
5205 | itr = ll_iter_create(ll_emm_active_filter);
|
---|
5206 |
|
---|
5207 | while((filter_item = ll_iter_next(&itr)) != NULL)
|
---|
5208 | {
|
---|
5209 | if(!ll_count(ll_emm_inactive_filter) || started == filter_queue)
|
---|
5210 | { break; }
|
---|
5211 | int64_t gone = comp_timeb(&now, &filter_item->time_started);
|
---|
5212 | if( gone > 45*1000)
|
---|
5213 | {
|
---|
5214 | struct s_dvbapi_priority *forceentry = dvbapi_check_prio_match_emmpid(filter_item->demux_id, filter_item->caid,
|
---|
5215 | filter_item->provid, 'p');
|
---|
5216 |
|
---|
5217 | if(!forceentry || (forceentry && !forceentry->force))
|
---|
5218 | {
|
---|
5219 | // stop active filter and add to pending list
|
---|
5220 | dvbapi_stop_filternum(filter_item->demux_id, filter_item->num - 1);
|
---|
5221 | ll_iter_remove_data(&itr);
|
---|
5222 | add_emmfilter_to_list(filter_item->demux_id, filter_item->filter, filter_item->caid,
|
---|
5223 | filter_item->provid, filter_item->pid, -1, false);
|
---|
5224 | stopped++;
|
---|
5225 | }
|
---|
5226 | }
|
---|
5227 |
|
---|
5228 | int32_t ret;
|
---|
5229 | if(stopped > started) // we have room for new filters, try to start an inactive emmfilter!
|
---|
5230 | {
|
---|
5231 | struct s_emm_filter *filter_item2;
|
---|
5232 | LL_ITER itr2 = ll_iter_create(ll_emm_inactive_filter);
|
---|
5233 |
|
---|
5234 | while((filter_item2 = ll_iter_next(&itr2)))
|
---|
5235 | {
|
---|
5236 | ret = dvbapi_set_filter(filter_item2->demux_id, selected_api, filter_item2->pid, filter_item2->caid,
|
---|
5237 | filter_item2->provid, filter_item2->filter, filter_item2->filter + 16, 0,
|
---|
5238 | demux[filter_item2->demux_id].pidindex, TYPE_EMM, 1);
|
---|
5239 | if(ret != -1)
|
---|
5240 | {
|
---|
5241 | ll_iter_remove_data(&itr2);
|
---|
5242 | started++;
|
---|
5243 | break;
|
---|
5244 | }
|
---|
5245 | }
|
---|
5246 | }
|
---|
5247 | }
|
---|
5248 |
|
---|
5249 | itr = ll_iter_create(ll_emm_pending_filter);
|
---|
5250 |
|
---|
5251 | while((filter_item = ll_iter_next(&itr)) != NULL) // move pending filters to inactive
|
---|
5252 | {
|
---|
5253 | add_emmfilter_to_list(filter_item->demux_id, filter_item->filter, filter_item->caid, filter_item->provid, filter_item->pid, 0, false);
|
---|
5254 | ll_iter_remove_data(&itr);
|
---|
5255 | }
|
---|
5256 | }
|
---|
5257 | }
|
---|
5258 |
|
---|
5259 | uint16_t dvbapi_get_client_proto_version(void)
|
---|
5260 | {
|
---|
5261 | return client_proto_version;
|
---|
5262 | }
|
---|
5263 |
|
---|
5264 | /*
|
---|
5265 | * protocol structure
|
---|
5266 | */
|
---|
5267 |
|
---|
5268 | void module_dvbapi(struct s_module *ph)
|
---|
5269 | {
|
---|
5270 | ph->desc = "dvbapi";
|
---|
5271 | ph->type = MOD_CONN_SERIAL;
|
---|
5272 | ph->listenertype = LIS_DVBAPI;
|
---|
5273 | #if defined(WITH_AZBOX)
|
---|
5274 | ph->s_handler = azbox_handler;
|
---|
5275 | ph->send_dcw = azbox_send_dcw;
|
---|
5276 | #elif defined(WITH_MCA)
|
---|
5277 | ph->s_handler = mca_handler;
|
---|
5278 | ph->send_dcw = mca_send_dcw;
|
---|
5279 | selected_box = selected_api = 0; // HACK: This fixes incorrect warning about out of bounds array access in functionas that are not even called when WITH_MCA is defined
|
---|
5280 | #else
|
---|
5281 | ph->s_handler = dvbapi_handler;
|
---|
5282 | ph->send_dcw = dvbapi_send_dcw;
|
---|
5283 | #endif
|
---|
5284 | }
|
---|
5285 | #endif // HAVE_DVBAPI
|
---|