source: trunk/oscam-reader.c@ 70

Last change on this file since 70 was 70, checked in by rorothetroll, 12 years ago

csctapi/io_serial.c : fix the serial port read/write wait routine to use select instead of poll

This make them compatible with Mac OS X and now oscamd works on OS X. The same code off course
still works on linux and other unix platforms. I let that code ran for 24h before commiting this code.
If you have any issue let me know and I'llr evert to poll for non compatible machines.

all the others : fix all the warning due to sign difference (mostly uchar versus char). This make the code compile

with -Werror on the more strict version of gcc (which is the case on OS X). I also noticed that in a lot of places
the code use a buffer defined as an uchar * ... and use strings functions (strnXXXX) where some memcpy/memcmp .. function
would have been preferable as we're suposedly manipulation a binary buffer. Anyway I fixed all of them and it now compile
without any warning or error on linux and OS X (and also probably on all the other unices but we will have to try before
adding -Werror on the other platform).

File size: 12.6 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 int val;
24 char txt[256];
25
26 va_list params;
27 va_start(params, fmt);
28 vsprintf(txt, fmt, params);
29 va_end(params);
30 cs_log("%s", txt);
31#ifdef CS_RDR_INIT_HIST
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
81void network_tcp_connection_close(int fd)
82{
83 cs_debug("tcp_conn_close(): fd=%d, is_server=%d", fd, is_server);
84 close(fd);
85 client[cs_idx].udp_fd = 0;
86
87 if (!is_server)
88 {
89 int i;
90 pfd=0;
91 reader[ridx].tcp_connected = 0;
92
93 for (i=0; i<CS_MAXPENDING; i++)
94 {
95 ecmtask[i].idx=0;
96 ecmtask[i].rc=0;
97 }
98
99 if (reader[ridx].ph.c_init())
100 {
101 cs_debug("network_tcp_connection_close() exit(1);");
102 cs_exit(1);
103 }
104
105 cs_resolve();
106 reader[ridx].ncd_msgid=0;
107 reader[ridx].last_s=reader[ridx].last_g=0;
108// cs_log("last_s=%d, last_g=%d", reader[ridx].last_s, reader[ridx].last_g);
109 }
110}
111
112static void casc_do_sock_log()
113{
114 int i, idx;
115 ushort caid, srvid;
116 ulong provid;
117
118 idx=reader[ridx].ph.c_recv_log(&caid, &provid, &srvid);
119 client[cs_idx].last=time((time_t)0);
120 if (idx<0) return; // no dcw-msg received
121
122 for (i=1; i<CS_MAXPENDING; i++)
123 {
124 if ( (ecmtask[i].rc>=10)
125 && (ecmtask[i].idx==idx)
126 && (ecmtask[i].caid==caid)
127 && (ecmtask[i].prid==provid)
128 && (ecmtask[i].srvid==srvid))
129 {
130 casc_check_dcw(i, 0, ecmtask[i].cw); // send "not found"
131 break;
132 }
133 }
134}
135
136static void casc_do_sock(int w)
137{
138 int i, n, idx, rc, j;
139 uchar buf[1024];
140 uchar dcw[16];
141
142 if ((n=casc_recv_timer(buf, sizeof(buf), w))<=0)
143 {
144 if (reader[ridx].ph.type==MOD_CONN_TCP)
145 {
146 cs_debug("casc_do_sock: close connection");
147 network_tcp_connection_close(client[cs_idx].udp_fd);
148 }
149 return;
150 }
151 client[cs_idx].last=time((time_t)0);
152 idx=reader[ridx].ph.c_recv_chk(dcw, &rc, buf, n);
153 if (idx<0) return; // no dcw received
154 reader[ridx].last_g=time((time_t*)0); // for reconnect timeout
155//cs_log("casc_do_sock: last_s=%d, last_g=%d", reader[ridx].last_s, reader[ridx].last_g);
156 if (!idx) idx=last_idx;
157 j=0;
158 for (i=1; i<CS_MAXPENDING; i++)
159 {
160
161 if (ecmtask[i].idx==idx)
162 {
163 casc_check_dcw(i, rc, dcw);
164 j=1;
165 break;
166 }
167 }
168}
169
170static void casc_get_dcw(int n)
171{
172 int w;
173 struct timeb tps, tpe;
174 tpe=ecmtask[n].tps;
175 //tpe.millitm+=1500; // TODO: timeout of 1500 should be config
176 tpe.millitm+=cfg->srtimeout;
177 tpe.time+=(tpe.millitm/1000);
178 tpe.millitm%=1000;
179
180 cs_ftime(&tps);
181 while (((w=1000*(tpe.time-tps.time)+tpe.millitm-tps.millitm)>0)
182 && (ecmtask[n].rc>=10))
183 {
184 casc_do_sock(w);
185 cs_ftime(&tps);
186 }
187 if (ecmtask[n].rc>=10)
188 casc_check_dcw(n, 0, ecmtask[n].cw); // simulate "not found"
189}
190
191
192
193int casc_process_ecm(ECM_REQUEST *er)
194{
195 int rc, n, i, sflag;
196 time_t t;//, tls;
197
198 uchar buf[512];
199
200 t=time((time_t *)0);
201 for (n=0, i=sflag=1; i<CS_MAXPENDING; i++)
202 {
203 if ((t-ecmtask[i].tps.time>cfg->ctimeout+1) &&
204 (ecmtask[i].rc>=10)) // drop timeouts
205 {
206 ecmtask[i].rc=0;
207 }
208 if ((!n) && (ecmtask[i].rc<10)) // free slot found
209 n=i;
210 if ((ecmtask[i].rc>=10) && // ecm already pending
211 (!memcmp(er->ecmd5, ecmtask[i].ecmd5, CS_ECMSTORESIZE)) &&
212 (er->level<=ecmtask[i].level)) // ... this level at least
213 sflag=0;
214 }
215 if (!n)
216 {
217 cs_log("WARNING: ecm pending table overflow !!");
218 return(-2);
219 }
220 memcpy(&ecmtask[n], er, sizeof(ECM_REQUEST));
221 if( reader[ridx].typ == R_NEWCAMD )
222 ecmtask[n].idx=(reader[ridx].ncd_msgid==0)?2:reader[ridx].ncd_msgid+1;
223 else
224 ecmtask[n].idx=idx++;
225 ecmtask[n].rc=10;
226 cs_debug("---- ecm_task %d, idx %d, sflag=%d, level=%d",
227 n, ecmtask[n].idx, sflag, er->level);
228
229 if( reader[ridx].ph.type==MOD_CONN_TCP && reader[ridx].tcp_rto )
230 {
231 int rto = abs(reader[ridx].last_s - reader[ridx].last_g);
232 if (rto >= reader[ridx].tcp_rto)
233 {
234 cs_debug("rto=%d", rto);
235 network_tcp_connection_close(client[cs_idx].udp_fd);
236 }
237 }
238
239 if (cfg->show_ecm_dw && !client[cs_idx].dbglvl)
240 cs_dump(er->ecm, er->l, 0);
241 rc=0;
242 if (sflag)
243 {
244 if (!client[cs_idx].udp_sa.sin_addr.s_addr) // once resolved at least
245 cs_resolve();
246
247 if ((rc=reader[ridx].ph.c_send_ecm(&ecmtask[n], buf)))
248 casc_check_dcw(n, 0, ecmtask[n].cw); // simulate "not found"
249 else
250 last_idx = ecmtask[n].idx;
251 reader[ridx].last_s = t; // used for inactive_timeout and reconnect_timeout in TCP reader
252
253 if (!reader[ridx].ph.c_multi)
254 casc_get_dcw(n);
255 }
256
257//cs_log("casc_process_ecm 1: last_s=%d, last_g=%d", reader[ridx].last_s, reader[ridx].last_g);
258
259 if (idx>0x1ffe) idx=1;
260 return(rc);
261}
262
263static int reader_store_emm(uchar *emm, uchar type)
264{
265 static int rotate=0;
266 int rc;
267 memcpy(emmcache[rotate].emm, emm, emm[2]);
268 emmcache[rotate].type=type;
269 emmcache[rotate].count=1;
270// cs_debug("EMM stored (index %d)", rotate);
271 rc=rotate;
272 rotate=(rotate+1) % CS_EMMCACHESIZE;
273 return(rc);
274}
275
276static void reader_get_ecm(ECM_REQUEST *er)
277{
278 //cs_log("hallo idx:%d rc:%d caid:%04X",er->idx,er->rc,er->caid);
279 if ((er->rc<10) )
280 {
281 send_dcw(er);
282 return;
283 }
284 er->ocaid=er->caid;
285 if (!chk_bcaid(er, &reader[ridx].ctab))
286 {
287 cs_debug("caid %04X filtered", er->caid);
288 er->rcEx=E2_CAID;
289 er->rc=0;
290 write_ecm_answer(fd_c2m, er);
291 return;
292 }
293 if (check_ecmcache(er, client[er->cidx].grp))
294 {
295 er->rc=2;
296 write_ecm_answer(fd_c2m, er);
297 return;
298 }
299 if (proxy)
300 {
301 client[cs_idx].last_srvid=er->srvid;
302 client[cs_idx].last_caid=er->caid;
303 casc_process_ecm(er);
304 return;
305 }
306 er->rc=reader_ecm(er);
307 write_ecm_answer(fd_c2m, er);
308 //if(reader[ridx].typ=='r') reader[ridx].qlen--;
309}
310
311static void reader_send_DCW(ECM_REQUEST *er)
312{
313 if ((er->rc<10) )
314 {
315 send_dcw(er);
316 }
317}
318
319static int reader_do_emm(EMM_PACKET *ep)
320{
321 int i, no, rc, ecs;
322 char *rtxt[]={ "error", "written", "skipped" };
323 struct timeb tps, tpe;
324
325 cs_ftime(&tps);
326
327 if (memcmp(ep->hexserial, reader[ridx].hexserial, 8))
328 return(3);
329
330 no=0;
331 for (i=ecs=0; (i<CS_EMMCACHESIZE) && (!ecs); i++)
332 if (!memcmp(emmcache[i].emm, ep->emm, ep->emm[2]))
333 {
334 if (reader[ridx].cachemm)
335 ecs=(reader[ridx].rewritemm > emmcache[i].count) ? 1 : 2;
336 else
337 ecs=1;
338 no=++emmcache[i].count;
339 i--;
340 }
341
342 if ((rc=ecs)<2)
343 {
344 rc=(proxy) ? 0 : reader_emm(ep);
345 if (!ecs)
346 {
347 i=reader_store_emm(ep->emm, ep->type);
348 no=1;
349 }
350 }
351 if (rc) client[cs_idx].lastemm=time((time_t)0);
352
353 if (reader[ridx].logemm>=rc)
354 {
355 cs_ftime(&tpe);
356// cs_log("%s type=%02x, len=%d, idx=%d, cnt=%d: %s (%d ms)",
357// cs_inet_ntoa(client[ep->cidx].ip), emmcache[i].type, ep->emm[2],
358// i, no, rtxt[rc], 1000*(tpe.time-tps.time)+tpe.millitm-tps.millitm);
359 cs_log("%s type=%02x, len=%d, idx=%d, cnt=%d: %s (%d ms)",
360 username(ep->cidx), emmcache[i].type, ep->emm[2],
361 i, no, rtxt[rc], 1000*(tpe.time-tps.time)+tpe.millitm-tps.millitm);
362 }
363 return(rc);
364}
365
366static int reader_listen(int fd1, int fd2)
367{
368 int fdmax, tcp_toflag, use_tv=(!proxy);
369 int is_tcp=(reader[ridx].ph.type==MOD_CONN_TCP);
370 fd_set fds;
371 struct timeval tv;
372
373 if(reader[ridx].typ==R_GBOX){
374 struct timeb tpe;
375 int ms,x;
376 cs_ftime(&tpe);
377 for(x=0;x<CS_MAXPENDING;x++){
378 ms=1000*(tpe.time-ecmtask[x].tps.time)+tpe.millitm-ecmtask[x].tps.millitm;
379 if(ecmtask[x].rc==10&& ms>(cfg->ctimeout*1000)&&ridx==ecmtask[x].gbxRidx){
380 //cs_log("hello rc=%d idx:%d x:%d ridx%d ridx:%d",ecmtask[x].rc,ecmtask[x].idx,x,ridx,ecmtask[x].gbxRidx);
381 ecmtask[x].rc=5;
382 send_dcw(&ecmtask[x]);
383
384 }
385 }
386 }
387
388 if (master_pid!=getppid()) cs_exit(0);
389 tcp_toflag=(fd2 && is_tcp && reader[ridx].tcp_ito && reader[ridx].tcp_connected);
390 tv.tv_sec = 0;
391 tv.tv_usec = 100000L;
392 if (tcp_toflag)
393 {
394 tv.tv_sec = reader[ridx].tcp_ito*60;
395 tv.tv_usec = 0;
396 use_tv = 1;
397 }
398 FD_ZERO(&fds);
399 FD_SET(fd1, &fds);
400 if (fd2) FD_SET(fd2, &fds);
401 if (logfd) FD_SET(logfd, &fds);
402 fdmax=(fd1>fd2) ? fd1 : fd2;
403 fdmax=(fdmax>logfd) ? fdmax : logfd;
404 if (select(fdmax+1, &fds, 0, 0, (use_tv) ? &tv : 0)<0) return(0);
405 if (master_pid!=getppid()) cs_exit(0);
406
407 if ((logfd) && (FD_ISSET(logfd, &fds)))
408 {
409 cs_debug("select: log-socket ist set");
410 return(3);
411 }
412
413 if ((fd2) && (FD_ISSET(fd2, &fds)))
414 {
415 cs_debug("select: socket is set");
416 return(2);
417 }
418
419 if (FD_ISSET(fd1, &fds))
420 {
421 if (tcp_toflag)
422 {
423 time_t now;
424 int time_diff;
425 time(&now);
426 time_diff = abs(now-reader[ridx].last_s);
427 if (time_diff>(reader[ridx].tcp_ito*60))
428 {
429 cs_debug("%s inactive_timeout (%d), close connection (fd=%d)",
430 reader[ridx].ph.desc, time_diff, fd2);
431 network_tcp_connection_close(fd2);
432 }
433 }
434 cs_debug("select: pipe is set");
435 return(1);
436 }
437
438 if (tcp_toflag)
439 {
440 cs_debug("%s inactive_timeout (%d), close connection (fd=%d)",
441 reader[ridx].ph.desc, tv.tv_sec, fd2);
442 network_tcp_connection_close(fd2);
443 return(0);
444 }
445
446 if (!proxy) reader_checkhealth();
447 return(0);
448}
449
450static void reader_do_pipe()
451{
452 uchar *ptr;
453 switch(read_from_pipe(fd_m2c, &ptr, 0))
454 {
455 case PIP_ID_ECM:
456 reader_get_ecm((ECM_REQUEST *)ptr);
457 break;
458 case PIP_ID_DCW:
459 reader_send_DCW((ECM_REQUEST *)ptr);
460 break;
461 case PIP_ID_EMM:
462 reader_do_emm((EMM_PACKET *)ptr);
463 break;
464 case PIP_ID_CIN:
465 reader_card_info();
466 break;
467 }
468}
469
470static void reader_main()
471{
472 while (1)
473 {
474 switch(reader_listen(fd_m2c, pfd))
475 {
476 case 1: reader_do_pipe() ; break;
477 case 2: casc_do_sock(0) ; break;
478 case 3: casc_do_sock_log(); break;
479 }
480 }
481}
482
483void start_cardreader()
484{
485 cs_ptyp=D_READER;
486
487 if ((proxy=reader[ridx].typ & R_IS_CASCADING))
488 {
489 client[cs_idx].typ='p';
490 client[cs_idx].port=reader[ridx].r_port;
491 strcpy(client[cs_idx].usr, reader[ridx].r_usr);
492 switch(reader[ridx].typ)
493 {
494 case R_CAMD33 : module_camd33(&reader[ridx].ph); break;
495 case R_CAMD35 : module_camd35(&reader[ridx].ph); break;
496 case R_NEWCAMD : module_newcamd(&reader[ridx].ph); break;
497 case R_RADEGAST: module_radegast(&reader[ridx].ph); break;
498 case R_SERIAL : module_oscam_ser(&reader[ridx].ph); break;
499 case R_CS378X : module_camd35_tcp(&reader[ridx].ph); break;
500#ifdef CS_WITH_GBOX
501 case R_GBOX : module_gbox(&reader[ridx].ph);strcpy(client[cs_idx].usr, reader[ridx].label); break;
502#endif
503 }
504 if (!(reader[ridx].ph.c_init))
505 {
506 cs_log("FATAL: %s-protocol not supporting cascading", reader[ridx].ph.desc);
507 sleep(1);
508 cs_exit(1);
509 }
510 if (reader[ridx].ph.c_init())
511 cs_exit(1);
512 if ((reader[ridx].log_port) && (reader[ridx].ph.c_init_log))
513 reader[ridx].ph.c_init_log();
514 }
515 else
516 {
517 client[cs_idx].ip=cs_inet_addr("127.0.0.1");
518 if (reader_device_init(reader[ridx].device, reader[ridx].typ))
519 cs_exit(1);
520 }
521
522 emmcache=(struct s_emm *)malloc(CS_EMMCACHESIZE*(sizeof(struct s_emm)));
523 if (!emmcache)
524 {
525 cs_log("Cannot allocate memory (errno=%d)", errno);
526 cs_exit(1);
527 }
528 memset(emmcache, 0, CS_EMMCACHESIZE*(sizeof(struct s_emm)));
529
530 ecmtask=(ECM_REQUEST *)malloc(CS_MAXPENDING*(sizeof(ECM_REQUEST)));
531 if (!ecmtask)
532 {
533 cs_log("Cannot allocate memory (errno=%d)", errno);
534 cs_exit(1);
535 }
536 memset(ecmtask, 0, CS_MAXPENDING*(sizeof(ECM_REQUEST)));
537
538 reader_main();
539 cs_exit(0);
540}
Note: See TracBrowser for help on using the repository browser.