1 #define MODULE_LOG_PREFIX "cccam"
4 #include "oscam-array.h"
6 #if defined(CS_CACHEEX) && defined(MODULE_CCCAM)
8 #include "module-cacheex.h"
9 #include "module-cccam-data.h"
10 #include "module-cccam-cacheex.h"
11 #include "oscam-cache.h"
12 #include "oscam-client.h"
13 #include "oscam-ecm.h"
14 #include "oscam-string.h"
15 #include "oscam-chk.h"
16 #include "oscam-reader.h"
18 #define CSP_HASH_SWAP(n) (((((uint32_t)(n) & 0xFF)) << 24) | \
19 ((((uint32_t)(n) & 0xFF00)) << 8) | \
20 ((((uint32_t)(n) & 0xFF0000)) >> 8) | \
21 ((((uint32_t)(n) & 0xFF000000)) >> 24))
23 extern int32_t cc_cli_connect(struct s_client
*cl
);
24 extern int32_t cc_cmd_send(struct s_client
*cl
, uint8_t *buf
, int32_t len
, cc_msg_type_t cmd
);
26 void cc_cacheex_filter_out(struct s_client
*cl
)
28 struct s_reader
*rdr
= (cl
->typ
== 'c') ? NULL
: cl
->reader
;
30 CECSPVALUETAB
*filter
;
31 //minimal size, keep it <= 512 for max UDP packet size without fragmentation
34 memset(buf
, 0, sizeof(buf
));
36 //mode==2 send filters from rdr
37 if(rdr
&& rdr
->cacheex
.mode
== 2)
39 filter
= &rdr
->cacheex
.filter_caidtab
;
41 //mode==3 send filters from acc
42 else if(cl
->typ
== 'c' && cl
->account
&& cl
->account
->cacheex
.mode
== 3)
44 filter
= &cl
->account
->cacheex
.filter_caidtab
;
50 i2b_buf(2, filter
->cevnum
, buf
+ i
);
53 int32_t max_filters
= 30;
54 for(j
=0; j
<max_filters
; j
++)
56 if(filter
->cevnum
> j
){
57 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
58 i2b_buf(4, d
->caid
, buf
+ i
);
63 for(j
=0; j
<max_filters
; j
++)
65 if(filter
->cevnum
> j
){
66 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
67 i2b_buf(4, d
->cmask
, buf
+ i
);
72 for(j
=0; j
<max_filters
; j
++)
74 if(filter
->cevnum
> j
){
75 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
76 i2b_buf(4, d
->prid
, buf
+ i
);
81 for(j
=0; j
<max_filters
; j
++)
83 if(filter
->cevnum
> j
){
84 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
85 i2b_buf(4, d
->srvid
, buf
+ i
);
90 cs_log_dbg(D_CACHEEX
, "cacheex: sending push filter request to %s", username(cl
));
91 cc_cmd_send(cl
, buf
, size
, MSG_CACHE_FILTER
);
94 void cc_cacheex_filter_in(struct s_client
*cl
, uchar
*buf
)
96 struct s_reader
*rdr
= (cl
->typ
== 'c') ? NULL
: cl
->reader
;
98 int32_t caid
, cmask
, provid
, srvid
;
99 CECSPVALUETAB
*filter
;
101 //mode==2 write filters to acc
102 if(cl
->typ
== 'c' && cl
->account
&& cl
->account
->cacheex
.mode
== 2
103 && cl
->account
->cacheex
.allow_filter
== 1)
105 filter
= &cl
->account
->cacheex
.filter_caidtab
;
107 //mode==3 write filters to rdr
108 else if(rdr
&& rdr
->cacheex
.mode
== 3 && rdr
->cacheex
.allow_filter
== 1)
110 filter
= &rdr
->cacheex
.filter_caidtab
;
116 cecspvaluetab_clear(filter
);
119 int32_t max_filters
= 30;
120 for(j
=0; j
<max_filters
; j
++)
122 caid
= b2i(4, buf
+ i
);
124 CECSPVALUETAB_DATA d
;
125 memset(&d
, 0, sizeof(d
));
126 d
.caid
= b2i(4, buf
+ i
);
127 cecspvaluetab_add(filter
, &d
);
132 for(j
=0; j
<max_filters
; j
++)
134 cmask
= b2i(4, buf
+ i
);
135 if(j
<filter
->cevnum
){
136 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
142 for(j
=0; j
<max_filters
; j
++)
144 provid
= b2i(4, buf
+ i
);
145 if(j
<filter
->cevnum
){
146 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
152 for(j
=0; j
<max_filters
; j
++)
154 srvid
= b2i(4, buf
+ i
);
155 if(j
<filter
->cevnum
){
156 CECSPVALUETAB_DATA
*d
= &filter
->cevdata
[j
];
162 cs_log_dbg(D_CACHEEX
, "cacheex: received push filter request from %s", username(cl
));
165 static int32_t cc_cacheex_push_chk(struct s_client
*cl
, struct ecm_request_t
*er
)
167 struct cc_data
*cc
= cl
->cc
;
168 if(chk_is_null_nodeid(cc
->peer_node_id
,8))
170 cs_log_dbg(D_CACHEEX
, "cacheex: NO peer_node_id got yet, skip!");
174 if(ll_count(er
->csp_lastnodes
) >= cacheex_maxhop(cl
)) //check max 10 nodes to push:
176 cs_log_dbg(D_CACHEEX
, "cacheex: nodelist reached %d nodes, no push", cacheex_maxhop(cl
));
180 uint8_t *remote_node
= cc
->peer_node_id
;
182 //search existing peer nodes:
183 LL_LOCKITER
*li
= ll_li_create(er
->csp_lastnodes
, 0);
185 while((node
= ll_li_next(li
)))
187 cs_log_dbg(D_CACHEEX
, "cacheex: check node %" PRIu64
"X == %" PRIu64
"X ?", cacheex_node_id(node
), cacheex_node_id(remote_node
));
188 if(memcmp(node
, remote_node
, 8) == 0)
195 //node found, so we got it from there, do not push:
198 cs_log_dbg(D_CACHEEX
,
199 "cacheex: node %" PRIu64
"X found in list => skip push!", cacheex_node_id(node
));
205 if(cl
->reader
&& !cl
->reader
->tcp_connected
)
211 if(!cc
|| !cl
->udp_fd
)
213 cs_log_dbg(D_CACHEEX
, "cacheex: not connected %s -> no push", username(cl
));
217 //check if cw is already pushed
218 if(check_is_pushed(er
->cw_cache
, cl
))
224 static int32_t cc_cacheex_push_out(struct s_client
*cl
, struct ecm_request_t
*er
)
226 int8_t rc
= (er
->rc
< E_NOTFOUND
) ? E_FOUND
: er
->rc
;
227 if(rc
!= E_FOUND
&& rc
!= E_UNHANDLED
) { return -1; } //Maybe later we could support other rcs
231 if(!cl
->reader
->tcp_connected
)
232 { cc_cli_connect(cl
); }
235 struct cc_data
*cc
= cl
->cc
;
236 if(!cc
|| !cl
->udp_fd
)
238 cs_log_dbg(D_CACHEEX
, "cacheex: not connected %s -> no push", username(cl
));
242 uint32_t size
= sizeof(er
->ecmd5
) + sizeof(er
->csp_hash
) + sizeof(er
->cw
) + sizeof(uint8_t) +
243 (ll_count(er
->csp_lastnodes
) + 1) * 8;
246 if(!cs_malloc(&buf
, size
+ 20)) //camd35_send() adds +20
250 //buf[0] = er->caid >> 8;
251 //buf[1] = er->caid & 0xff;
252 //buf[2] = er->prid >> 24;
253 //buf[3] = er->prid >> 16;
254 //buf[4] = er->prid >> 8;
255 //buf[5] = er->prid & 0xff;
256 //buf[10] = er->srvid >> 8;
257 //buf[11] = er->srvid & 0xff;
258 buf
[12] = (sizeof(er
->ecmd5
) + sizeof(er
->csp_hash
) + sizeof(er
->cw
)) & 0xff;
259 buf
[13] = (sizeof(er
->ecmd5
) + sizeof(er
->csp_hash
) + sizeof(er
->cw
)) >> 8;
264 i2b_buf(2, er
->caid
, buf
+ 0);
265 i2b_buf(4, er
->prid
, buf
+ 2);
266 i2b_buf(2, er
->srvid
, buf
+ 10);
268 if(er
->cwc_cycletime
&& er
->cwc_next_cw_cycle
< 2)
270 buf
[18] = er
->cwc_cycletime
; // contains cwc stage3 cycletime
271 if(er
->cwc_next_cw_cycle
== 1)
272 { buf
[18] = (buf
[18] | 0x80); } // set bit 8 to high
274 if(cl
->typ
== 'c' && cl
->account
&& cl
->account
->cacheex
.mode
)
275 { cl
->account
->cwc_info
++; }
276 else if((cl
->typ
== 'p' || cl
->typ
== 'r') && (cl
->reader
&& cl
->reader
->cacheex
.mode
))
278 cs_log_dbg(D_CWC
, "CWC (CE) push to %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl
), er
->cwc_cycletime
, er
->cwc_next_cw_cycle
, er
->caid
, er
->prid
, er
->srvid
);
281 buf
[19] = er
->ecm
[0] != 0x80 && er
->ecm
[0] != 0x81 ? 0 : er
->ecm
[0];
283 uint8_t *ofs
= buf
+ 20;
286 memcpy(ofs
, er
->ecmd5
, sizeof(er
->ecmd5
)); //16
287 ofs
+= sizeof(er
->ecmd5
);
289 //write csp hashcode:
290 i2b_buf(4, CSP_HASH_SWAP(er
->csp_hash
), ofs
);
294 memcpy(ofs
, er
->cw
, sizeof(er
->cw
)); //16
295 ofs
+= sizeof(er
->cw
);
298 *ofs
= ll_count(er
->csp_lastnodes
) + 1;
302 memcpy(ofs
, cc
->node_id
, 8);
306 LL_LOCKITER
*li
= ll_li_create(er
->csp_lastnodes
, 0);
308 while((node
= ll_li_next(li
)))
310 memcpy(ofs
, node
, 8);
315 int32_t res
= cc_cmd_send(cl
, buf
, size
+ 20, MSG_CACHE_PUSH
);
316 if(res
> 0) // cache-ex is pushing out, so no receive but last_g should be updated otherwise disconnect!
319 { cl
->reader
->last_s
= cl
->reader
->last_g
= time((time_t *)0); } // correct
320 if(cl
) { cl
->last
= time(NULL
); }
326 void cc_cacheex_push_in(struct s_client
*cl
, uchar
*buf
)
328 struct cc_data
*cc
= cl
->cc
;
333 { cl
->reader
->last_s
= cl
->reader
->last_g
= time((time_t *)0); }
334 if(cl
) { cl
->last
= time(NULL
); }
337 if(rc
!= E_FOUND
&& rc
!= E_UNHANDLED
) //Maybe later we could support other rcs
339 uint16_t size
= buf
[12] | (buf
[13] << 8);
340 if(size
!= sizeof(er
->ecmd5
) + sizeof(er
->csp_hash
) + sizeof(er
->cw
))
342 cs_log_dbg(D_CACHEEX
, "cacheex: %s received old cash-push format! data ignored!", username(cl
));
345 if(!(er
= get_ecmtask()))
348 er
->caid
= b2i(2, buf
+ 0);
349 er
->prid
= b2i(4, buf
+ 2);
350 er
->srvid
= b2i(2, buf
+ 10);
351 er
->ecm
[0] = buf
[19]!=0x80 && buf
[19]!=0x81 ? 0 : buf
[19]; //odd/even byte, usefull to send it over CSP and to check cw for swapping
358 if(buf
[18] & (0x01 << 7))
360 er
->cwc_cycletime
= (buf
[18] & 0x7F); // remove bit 8 to get cycletime
361 er
->cwc_next_cw_cycle
= 1;
365 er
->cwc_cycletime
= buf
[18];
366 er
->cwc_next_cw_cycle
= 0;
370 if (er
->cwc_cycletime
&& er
->cwc_next_cw_cycle
< 2)
372 if(cl
->typ
== 'c' && cl
->account
&& cl
->account
->cacheex
.mode
)
373 { cl
->account
->cwc_info
++; }
374 else if((cl
->typ
== 'p' || cl
->typ
== 'r') && (cl
->reader
&& cl
->reader
->cacheex
.mode
))
376 cs_log_dbg(D_CWC
, "CWC (CE) received from %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl
), er
->cwc_cycletime
, er
->cwc_next_cw_cycle
, er
->caid
, er
->prid
, er
->srvid
);
379 uint8_t *ofs
= buf
+ 20;
382 memcpy(er
->ecmd5
, ofs
, sizeof(er
->ecmd5
)); //16
383 ofs
+= sizeof(er
->ecmd5
);
385 if(!check_cacheex_filter(cl
, er
))
389 er
->csp_hash
= CSP_HASH_SWAP(b2i(4, ofs
));
393 memcpy(er
->cw
, ofs
, sizeof(er
->cw
)); //16
394 ofs
+= sizeof(er
->cw
);
396 //Read lastnode count:
397 uint8_t count
= *ofs
;
401 if(count
> cacheex_maxhop(cl
))
403 cs_log_dbg(D_CACHEEX
, "cacheex: received %d nodes (max=%d), ignored! %s", (int32_t)count
, cacheex_maxhop(cl
), username(cl
));
407 cs_log_dbg(D_CACHEEX
, "cacheex: received %d nodes %s", (int32_t)count
, username(cl
));
411 er
->csp_lastnodes
= ll_create("csp_lastnodes");
415 if(!cs_malloc(&data
, 8))
417 memcpy(data
, ofs
, 8);
419 ll_append(er
->csp_lastnodes
, data
);
421 cs_log_dbg(D_CACHEEX
, "cacheex: received node %" PRIu64
"X %s", cacheex_node_id(data
), username(cl
));
424 //for compatibility: add peer node if no node received:
425 if(!ll_count(er
->csp_lastnodes
))
427 if(!cs_malloc(&data
, 8))
429 memcpy(data
, cc
->peer_node_id
, 8);
430 ll_append(er
->csp_lastnodes
, data
);
431 cs_log_dbg(D_CACHEEX
, "cacheex: added missing remote node id %" PRIu64
"X", cacheex_node_id(data
));
434 cacheex_add_to_cache(cl
, er
);
437 void cc_cacheex_module_init(struct s_module
*ph
)
439 ph
->c_cache_push
= cc_cacheex_push_out
;
440 ph
->c_cache_push_chk
= cc_cacheex_push_chk
;