source: trunk/oscam-reader.c@ 1691

Last change on this file since 1691 was 1691, checked in by merek, 11 years ago

Merge Webinterface into Trunk - Use -DWEBIF=1 with cmake to build with Webinterface - For make add -DWEBIF to target in Makefile to build with Webinterface for, thanks to Alno and Streamboard community

File size: 15.5 KB
Line 
1#include "globals.h"
2
3int ridx=0, logfd=0;
4
5static int proxy;
6static struct s_emm *emmcache;
7static int last_idx=1;
8static ushort idx=1;
9
10void cs_ri_brk(int flag)
11{
12#ifdef CS_RDR_INIT_HIST
13 static int brk_pos=0;
14 if (flag)
15 brk_pos=reader[ridx].init_history_pos;
16 else
17 reader[ridx].init_history_pos=brk_pos;
18#endif
19}
20
21void cs_ri_log(char *fmt,...)
22{
23 char txt[256];
24
25 va_list params;
26 va_start(params, fmt);
27 vsprintf(txt, fmt, params);
28 va_end(params);
29 cs_log("%s", txt);
30#ifdef CS_RDR_INIT_HIST
31 int val;
32 val=sizeof(reader[ridx].init_history)-reader[ridx].init_history_pos-1;
33 if (val>0)
34 snprintf((char *) reader[ridx].init_history+reader[ridx].init_history_pos, val, "%s", txt);
35 reader[ridx].init_history_pos+=strlen(txt)+1;
36#endif
37}
38
39static void casc_check_dcw(int idx, int rc, uchar *cw)
40{
41 int i;
42 for (i=1; i<CS_MAXPENDING; i++)
43 {
44 if ((ecmtask[i].rc>=10) &&
45 (!memcmp(ecmtask[i].ecmd5, ecmtask[idx].ecmd5, CS_ECMSTORESIZE)))
46 {
47 if (rc)
48 {
49 ecmtask[i].rc=(i==idx) ? 1 : 2;
50 if(ecmtask[i].gbxRidx)ecmtask[i].rc=0;
51 memcpy(ecmtask[i].cw, cw, 16);
52 }
53 else
54 ecmtask[i].rc=0;
55 write_ecm_answer(fd_c2m, &ecmtask[i]);
56 ecmtask[i].idx=0;
57 }
58 }
59}
60
61static int casc_recv_timer(uchar *buf, int l, int msec)
62{
63 struct timeval tv;
64 fd_set fds;
65 int rc;
66
67 if (!pfd) return(-1);
68 tv.tv_sec = msec/1000;
69 tv.tv_usec = (msec%1000)*1000;
70 FD_ZERO(&fds);
71 FD_SET(pfd, &fds);
72 select(pfd+1, &fds, 0, 0, &tv);
73 rc=0;
74 if (FD_ISSET(pfd, &fds))
75 if (!(rc=reader[ridx].ph.recv(buf, l)))
76 rc=-1;
77
78 return(rc);
79}
80
81static int connect_nonb(int sockfd, const struct sockaddr *saptr, socklen_t salen, int nsec)
82{
83 int flags, n, error;
84 socklen_t len;
85 fd_set rset, wset;
86 struct timeval tval;
87
88 flags = fcntl(sockfd, F_GETFL, 0);
89 fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
90
91 error = 0;
92 cs_debug("conn_nb 1 (fd=%d)", sockfd);
93
94 if ( (n = connect(sockfd, saptr, salen)) < 0) {
95 if( errno==EALREADY ) {
96 cs_debug("conn_nb in progress, errno=%d", errno);
97 return(-1);
98 }
99 else if( errno==EISCONN ) {
100 cs_debug("conn_nb already connected, errno=%d", errno);
101 goto done;
102 }
103 cs_debug("conn_nb 2 (fd=%d)", sockfd);
104 if (errno != EINPROGRESS) {
105 cs_debug("conn_nb 3 (fd=%d)", sockfd);
106 return(-1);
107 }
108 }
109
110 cs_debug("n = %d\n", n);
111
112 /* Do whatever we want while the connect is taking place. */
113 if (n == 0)
114 goto done; /* connect completed immediately */
115
116 FD_ZERO(&rset);
117 FD_SET(sockfd, &rset);
118 wset = rset;
119 tval.tv_sec = nsec;
120 tval.tv_usec = 0;
121
122 if ( (n = select(sockfd+1, &rset, &wset, 0, nsec ? &tval : 0)) == 0) {
123 //close(sockfd); // timeout
124 cs_debug("conn_nb 4 (fd=%d)", sockfd);
125 errno = ETIMEDOUT;
126 return(-1);
127 }
128
129 cs_debug("conn_nb 5 (fd=%d)", sockfd);
130
131 if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
132 cs_debug("conn_nb 6 (fd=%d)", sockfd);
133 len = sizeof(error);
134 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
135 cs_debug("conn_nb 7 (fd=%d)", sockfd);
136 return(-1); // Solaris pending error
137 }
138 } else {
139 cs_debug("conn_nb 8 (fd=%d)", sockfd);
140 return -2;
141 }
142
143done:
144cs_debug("conn_nb 9 (fd=%d)", sockfd);
145 fcntl(sockfd, F_SETFL, flags); /* restore file status flags */
146
147 if (error) {
148 cs_debug("cccam: conn_nb 10 (fd=%d)", sockfd);
149 //close(sockfd); /* just in case */
150 errno = error;
151 return(-1);
152 }
153 return(0);
154}
155
156int network_tcp_connection_open()
157{
158 int flags;
159 if( connect_nonb(client[cs_idx].udp_fd,
160 (struct sockaddr *)&client[cs_idx].udp_sa,
161 sizeof(client[cs_idx].udp_sa), 5) < 0)
162 {
163 cs_log("connect(fd=%d) failed: (errno=%d)", client[cs_idx].udp_fd, errno);
164 return -1;
165 }
166 flags = fcntl(client[cs_idx].udp_fd, F_GETFL, 0);
167 flags &=~ O_NONBLOCK;
168 fcntl(client[cs_idx].udp_fd, F_SETFL, flags );
169
170 return client[cs_idx].udp_fd;
171}
172
173void network_tcp_connection_close(int fd)
174{
175 cs_debug("tcp_conn_close(): fd=%d, is_server=%d", fd, is_server);
176 close(fd);
177 client[cs_idx].udp_fd = 0;
178
179 if (!is_server)
180 {
181 int i;
182 pfd=0;
183 reader[ridx].tcp_connected = 0;
184
185 for (i=0; i<CS_MAXPENDING; i++)
186 {
187 ecmtask[i].idx=0;
188 ecmtask[i].rc=0;
189 }
190
191 reader[ridx].ncd_msgid=0;
192 reader[ridx].last_s=reader[ridx].last_g=0;
193
194 if (reader[ridx].ph.c_init())
195 {
196 cs_debug("network_tcp_connection_close() exit(1);");
197 cs_exit(1);
198 }
199
200 cs_resolve();
201// cs_log("last_s=%d, last_g=%d", reader[ridx].last_s, reader[ridx].last_g);
202 }
203}
204
205static void casc_do_sock_log()
206{
207 int i, idx;
208 ushort caid, srvid;
209 ulong provid;
210
211 idx=reader[ridx].ph.c_recv_log(&caid, &provid, &srvid);
212 client[cs_idx].last=time((time_t)0);
213 if (idx<0) return; // no dcw-msg received
214
215 for (i=1; i<CS_MAXPENDING; i++)
216 {
217 if ( (ecmtask[i].rc>=10)
218 && (ecmtask[i].idx==idx)
219 && (ecmtask[i].caid==caid)
220 && (ecmtask[i].prid==provid)
221 && (ecmtask[i].srvid==srvid))
222 {
223 casc_check_dcw(i, 0, ecmtask[i].cw); // send "not found"
224 break;
225 }
226 }
227}
228
229static void casc_do_sock(int w)
230{
231 int i, n, idx, rc, j;
232 uchar buf[1024];
233 uchar dcw[16];
234
235 if ((n=casc_recv_timer(buf, sizeof(buf), w))<=0)
236 {
237 if (reader[ridx].ph.type==MOD_CONN_TCP && reader[ridx].typ != R_RADEGAST)
238 {
239 cs_debug("casc_do_sock: close connection");
240 network_tcp_connection_close(client[cs_idx].udp_fd);
241 }
242 return;
243 }
244 client[cs_idx].last=time((time_t)0);
245 idx=reader[ridx].ph.c_recv_chk(dcw, &rc, buf, n);
246
247 if (idx<0) return; // no dcw received
248 reader[ridx].last_g=time((time_t*)0); // for reconnect timeout
249//cs_log("casc_do_sock: last_s=%d, last_g=%d", reader[ridx].last_s, reader[ridx].last_g);
250 if (!idx) idx=last_idx;
251 j=0;
252 for (i=1; i<CS_MAXPENDING; i++)
253 {
254
255 if (ecmtask[i].idx==idx)
256 {
257 casc_check_dcw(i, rc, dcw);
258 j=1;
259 break;
260 }
261 }
262}
263
264static void casc_get_dcw(int n)
265{
266 int w;
267 struct timeb tps, tpe;
268 tpe=ecmtask[n].tps;
269 //tpe.millitm+=1500; // TODO: timeout of 1500 should be config
270 tpe.millitm+=cfg->srtimeout;
271 tpe.time+=(tpe.millitm/1000);
272 tpe.millitm%=1000;
273
274 cs_ftime(&tps);
275 while (((w=1000*(tpe.time-tps.time)+tpe.millitm-tps.millitm)>0)
276 && (ecmtask[n].rc>=10))
277 {
278 casc_do_sock(w);
279 cs_ftime(&tps);
280 }
281 if (ecmtask[n].rc>=10)
282 casc_check_dcw(n, 0, ecmtask[n].cw); // simulate "not found"
283}
284
285
286
287int casc_process_ecm(ECM_REQUEST *er)
288{
289 int rc, n, i, sflag;
290 time_t t;//, tls;
291
292 uchar buf[512];
293
294 t=time((time_t *)0);
295 for (n=0, i=sflag=1; i<CS_MAXPENDING; i++)
296 {
297 if ((t-(ulong)ecmtask[i].tps.time > ((cfg->ctimeout + 500) / 1000) + 1) &&
298 (ecmtask[i].rc>=10)) // drop timeouts
299 {
300 ecmtask[i].rc=0;
301 }
302 if ((!n) && (ecmtask[i].rc<10)) // free slot found
303 n=i;
304 if ((ecmtask[i].rc>=10) && // ecm already pending
305 (!memcmp(er->ecmd5, ecmtask[i].ecmd5, CS_ECMSTORESIZE)) &&
306 (er->level<=ecmtask[i].level)) // ... this level at least
307 sflag=0;
308 }
309 if (!n)
310 {
311 cs_log("WARNING: ecm pending table overflow !!");
312 return(-2);
313 }
314 memcpy(&ecmtask[n], er, sizeof(ECM_REQUEST));
315 if( reader[ridx].typ == R_NEWCAMD )
316 ecmtask[n].idx=(reader[ridx].ncd_msgid==0)?2:reader[ridx].ncd_msgid+1;
317 else
318 ecmtask[n].idx=idx++;
319 ecmtask[n].rc=10;
320 cs_debug("---- ecm_task %d, idx %d, sflag=%d, level=%d",
321 n, ecmtask[n].idx, sflag, er->level);
322
323 if( reader[ridx].ph.type==MOD_CONN_TCP && reader[ridx].tcp_rto )
324 {
325 int rto = abs(reader[ridx].last_s - reader[ridx].last_g);
326 if (rto >= (reader[ridx].tcp_rto*60))
327 {
328 cs_debug("rto=%d", rto);
329 network_tcp_connection_close(client[cs_idx].udp_fd);
330 }
331 }
332
333 cs_ddump_mask(D_ATR, er->ecm, er->l, "casc ecm:");
334 rc=0;
335 if (sflag)
336 {
337 if (!client[cs_idx].udp_sa.sin_addr.s_addr) // once resolved at least
338 cs_resolve();
339
340 if ((rc=reader[ridx].ph.c_send_ecm(&ecmtask[n], buf)))
341 casc_check_dcw(n, 0, ecmtask[n].cw); // simulate "not found"
342 else
343 last_idx = ecmtask[n].idx;
344 reader[ridx].last_s = t; // used for inactive_timeout and reconnect_timeout in TCP reader
345
346 if (!reader[ridx].ph.c_multi)
347 casc_get_dcw(n);
348 }
349
350//cs_log("casc_process_ecm 1: last_s=%d, last_g=%d", reader[ridx].last_s, reader[ridx].last_g);
351
352 if (idx>0x1ffe) idx=1;
353 return(rc);
354}
355
356static int reader_store_emm(uchar *emm, uchar type)
357{
358 static int rotate=0;
359 int rc;
360 memcpy(emmcache[rotate].emm, emm, emm[2]);
361 emmcache[rotate].type=type;
362 emmcache[rotate].count=1;
363// cs_debug("EMM stored (index %d)", rotate);
364 rc=rotate;
365 rotate=(rotate+1) % CS_EMMCACHESIZE;
366 return(rc);
367}
368
369static void reader_get_ecm(ECM_REQUEST *er)
370{
371 //cs_log("hallo idx:%d rc:%d caid:%04X",er->idx,er->rc,er->caid);
372 if ((er->rc<10) )
373 {
374 send_dcw(er);
375 return;
376 }
377 er->ocaid=er->caid;
378 if (!chk_bcaid(er, &reader[ridx].ctab))
379 {
380 cs_debug("caid %04X filtered", er->caid);
381 er->rcEx=E2_CAID;
382 er->rc=0;
383 write_ecm_answer(fd_c2m, er);
384 return;
385 }
386 if (check_ecmcache(er, client[er->cidx].grp))
387 {
388 er->rc=2;
389 write_ecm_answer(fd_c2m, er);
390 return;
391 }
392 if (proxy)
393 {
394 client[cs_idx].last_srvid=er->srvid;
395 client[cs_idx].last_caid=er->caid;
396 casc_process_ecm(er);
397 return;
398 }
399 cs_ddump_mask(D_ATR, er->ecm, er->l, "ecm:");
400 er->rc=reader_ecm(er);
401 write_ecm_answer(fd_c2m, er);
402 reader_post_process();
403 //if(reader[ridx].typ=='r') reader[ridx].qlen--;
404 //printf("queue: %d\n",reader[ridx].qlen);
405}
406
407static void reader_send_DCW(ECM_REQUEST *er)
408{
409 if ((er->rc<10) )
410 {
411 send_dcw(er);
412 }
413}
414
415static int reader_do_emm(EMM_PACKET *ep)
416{
417 int i, no, rc, ecs;
418 char *rtxt[] = { "error", "written", "skipped", "blocked" };
419 struct timeb tps, tpe;
420
421 cs_ftime(&tps);
422
423 if (memcmp(ep->hexserial, reader[ridx].hexserial, 8))
424 return(3);
425
426 no=0;
427 for (i=ecs=0; (i<CS_EMMCACHESIZE) && (!ecs); i++)
428 if (!memcmp(emmcache[i].emm, ep->emm, ep->emm[2]))
429 {
430 if (reader[ridx].cachemm)
431 ecs=(reader[ridx].rewritemm > emmcache[i].count) ? 1 : 2;
432 else
433 ecs=1;
434 no=++emmcache[i].count;
435 i--;
436 }
437
438 if ((rc=ecs)<2)
439 {
440 rc=(proxy) ? 0 : reader_emm(ep);
441 if (!ecs)
442 {
443 i=reader_store_emm(ep->emm, ep->type);
444 no=1;
445 }
446 }
447 if (rc) client[cs_idx].lastemm=time((time_t)0);
448
449 if (reader[ridx].logemm>=rc)
450 {
451 cs_ftime(&tpe);
452// cs_log("%s type=%02x, len=%d, idx=%d, cnt=%d: %s (%d ms)",
453// cs_inet_ntoa(client[ep->cidx].ip), emmcache[i].type, ep->emm[2],
454// i, no, rtxt[rc], 1000*(tpe.time-tps.time)+tpe.millitm-tps.millitm);
455 cs_log("%s type=%02x, len=%d, idx=%d, cnt=%d: %s (%d ms)",
456 username(ep->cidx), emmcache[i].type, ep->emm[2],
457 i, no, rtxt[rc], 1000*(tpe.time-tps.time)+tpe.millitm-tps.millitm);
458 }
459
460 //counting results
461 switch(rc){
462 case 0:
463 reader[ridx].emmerror++;
464 break;
465 case 1:
466 reader[ridx].emmwritten++;
467 break;
468 case 2:
469 reader[ridx].emmskipped++;
470 break;
471 case 3:
472 reader[ridx].emmblocked++;
473 break;
474 }
475
476 return(rc);
477}
478
479static int reader_listen(int fd1, int fd2)
480{
481 int fdmax, tcp_toflag, use_tv=(!proxy);
482 int is_tcp=(reader[ridx].ph.type==MOD_CONN_TCP);
483 fd_set fds;
484 struct timeval tv;
485
486#ifdef CS_WITH_GBOX
487 if(reader[ridx].typ==R_GBOX) {
488 struct timeb tpe;
489 int x;
490 ulong ms;
491 cs_ftime(&tpe);
492 for(x=0;x<CS_MAXPENDING;x++){
493 ms=1000*(tpe.time-ecmtask[x].tps.time)+tpe.millitm-ecmtask[x].tps.millitm;
494 if(ecmtask[x].rc == 10 && ms > cfg->ctimeout && ridx == ecmtask[x].gbxRidx) {
495 //cs_log("hello rc=%d idx:%d x:%d ridx%d ridx:%d",ecmtask[x].rc,ecmtask[x].idx,x,ridx,ecmtask[x].gbxRidx);
496 ecmtask[x].rc=5;
497 send_dcw(&ecmtask[x]);
498 }
499 }
500 }
501#endif
502
503 if (master_pid!=getppid()) cs_exit(0);
504 tcp_toflag=(fd2 && is_tcp && reader[ridx].tcp_ito && reader[ridx].tcp_connected);
505 tv.tv_sec = 0;
506 tv.tv_usec = 100000L;
507 if (tcp_toflag)
508 {
509 tv.tv_sec = reader[ridx].tcp_ito*60;
510 tv.tv_usec = 0;
511 use_tv = 1;
512 }
513 FD_ZERO(&fds);
514 FD_SET(fd1, &fds);
515 if (fd2) FD_SET(fd2, &fds);
516 if (logfd) FD_SET(logfd, &fds);
517 fdmax=(fd1>fd2) ? fd1 : fd2;
518 fdmax=(fdmax>logfd) ? fdmax : logfd;
519 if (select(fdmax+1, &fds, 0, 0, (use_tv) ? &tv : 0)<0) return(0);
520 if (master_pid!=getppid()) cs_exit(0);
521
522 if ((logfd) && (FD_ISSET(logfd, &fds)))
523 {
524 cs_debug("select: log-socket ist set");
525 return(3);
526 }
527
528 if ((fd2) && (FD_ISSET(fd2, &fds)))
529 {
530 cs_debug("select: socket is set");
531 return(2);
532 }
533
534 if (FD_ISSET(fd1, &fds))
535 {
536 if (tcp_toflag)
537 {
538 time_t now;
539 int time_diff;
540 time(&now);
541 time_diff = abs(now-reader[ridx].last_s);
542 if (time_diff>(reader[ridx].tcp_ito*60))
543 {
544 cs_debug("%s inactive_timeout (%d), close connection (fd=%d)",
545 reader[ridx].ph.desc, time_diff, fd2);
546 network_tcp_connection_close(fd2);
547 }
548 }
549 cs_debug("select: pipe is set");
550 return(1);
551 }
552
553 if (tcp_toflag)
554 {
555 cs_debug("%s inactive_timeout (%d), close connection (fd=%d)",
556 reader[ridx].ph.desc, tv.tv_sec, fd2);
557 network_tcp_connection_close(fd2);
558 return(0);
559 }
560
561 if (!proxy) reader_checkhealth();
562 return(0);
563}
564
565static void reader_do_pipe()
566{
567 uchar *ptr;
568 switch(read_from_pipe(fd_m2c, &ptr, 0))
569 {
570 case PIP_ID_ECM:
571 reader_get_ecm((ECM_REQUEST *)ptr);
572 break;
573 case PIP_ID_DCW:
574 reader_send_DCW((ECM_REQUEST *)ptr);
575 break;
576 case PIP_ID_EMM:
577 reader_do_emm((EMM_PACKET *)ptr);
578 break;
579 case PIP_ID_CIN:
580 reader_card_info();
581 break;
582 }
583}
584
585static void reader_main()
586{
587 while (1)
588 {
589 switch(reader_listen(fd_m2c, pfd))
590 {
591 case 1: reader_do_pipe() ; break;
592 case 2: casc_do_sock(0) ; break;
593 case 3: casc_do_sock_log(); break;
594 }
595 }
596}
597
598void start_cardreader()
599{
600 cs_ptyp=D_READER;
601
602 if ((proxy=reader[ridx].typ & R_IS_CASCADING))
603 {
604 client[cs_idx].typ='p';
605 client[cs_idx].port=reader[ridx].r_port;
606 strcpy(client[cs_idx].usr, reader[ridx].r_usr);
607 switch(reader[ridx].typ)
608 {
609 case R_CAMD33 : module_camd33(&reader[ridx].ph); break;
610 case R_CAMD35 : module_camd35(&reader[ridx].ph); break;
611 case R_NEWCAMD : module_newcamd(&reader[ridx].ph); break;
612 case R_RADEGAST: module_radegast(&reader[ridx].ph); break;
613 case R_SERIAL : module_oscam_ser(&reader[ridx].ph); break;
614 case R_CS378X : module_camd35_tcp(&reader[ridx].ph); break;
615 case R_CCCAM : module_cccam(&reader[ridx].ph); break;
616#ifdef CS_WITH_GBOX
617 case R_GBOX : module_gbox(&reader[ridx].ph);strcpy(client[cs_idx].usr, reader[ridx].label); break;
618#endif
619 }
620 if (!(reader[ridx].ph.c_init))
621 {
622 cs_log("FATAL: %s-protocol not supporting cascading", reader[ridx].ph.desc);
623 cs_sleepms(1000);
624 cs_exit(1);
625 }
626 if (reader[ridx].ph.c_init())
627 cs_exit(1);
628 if ((reader[ridx].log_port) && (reader[ridx].ph.c_init_log))
629 reader[ridx].ph.c_init_log();
630 }
631 else
632 {
633 client[cs_idx].ip=cs_inet_addr("127.0.0.1");
634 while (reader_device_init(reader[ridx].device)==2)
635 cs_sleepms(60000); // wait 60 secs and try again
636 }
637
638 emmcache=(struct s_emm *)malloc(CS_EMMCACHESIZE*(sizeof(struct s_emm)));
639 if (!emmcache)
640 {
641 cs_log("Cannot allocate memory (errno=%d)", errno);
642 cs_exit(1);
643 }
644 memset(emmcache, 0, CS_EMMCACHESIZE*(sizeof(struct s_emm)));
645
646 ecmtask=(ECM_REQUEST *)malloc(CS_MAXPENDING*(sizeof(ECM_REQUEST)));
647 if (!ecmtask)
648 {
649 cs_log("Cannot allocate memory (errno=%d)", errno);
650 cs_exit(1);
651 }
652 memset(ecmtask, 0, CS_MAXPENDING*(sizeof(ECM_REQUEST)));
653
654 reader_main();
655 cs_exit(0);
656}
Note: See TracBrowser for help on using the repository browser.