update wiki URL
[oscam.git] / module-cccam-cacheex.c
blob04370a6110db1e5f4240678ec6eff4ae6463eb42
1 #define MODULE_LOG_PREFIX "cccam"
3 #include "globals.h"
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;
29 int i = 0, j;
30 CECSPVALUETAB *filter;
31 int32_t size = 482; // minimal size, keep it <= 512 for max UDP packet size without fragmentation
32 uint8_t buf[482];
33 memset(buf, 0, sizeof(buf));
35 if(rdr && rdr->cacheex.mode == 2) // mode == 2 send filters from rdr
37 filter = &rdr->cacheex.filter_caidtab;
39 else if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode == 3) // mode == 3 send filters from acc
41 filter = &cl->account->cacheex.filter_caidtab;
43 else
45 return;
48 i2b_buf(2, filter->cevnum, buf + i);
49 i += 2;
51 int32_t max_filters = 30;
52 for(j = 0; j < max_filters; j++)
54 if(filter->cevnum > j)
56 CECSPVALUETAB_DATA *d = &filter->cevdata[j];
57 i2b_buf(4, d->caid, buf + i);
59 i += 4;
62 for(j = 0; j < max_filters; j++)
64 if(filter->cevnum > j)
66 CECSPVALUETAB_DATA *d = &filter->cevdata[j];
67 i2b_buf(4, d->cmask, buf + i);
69 i += 4;
72 for(j = 0; j < max_filters; j++)
74 if(filter->cevnum > j)
76 CECSPVALUETAB_DATA *d = &filter->cevdata[j];
77 i2b_buf(4, d->prid, buf + i);
79 i += 4;
82 for(j = 0; j < max_filters; j++)
84 if(filter->cevnum > j)
86 CECSPVALUETAB_DATA *d = &filter->cevdata[j];
87 i2b_buf(4, d->srvid, buf + i);
89 i += 4;
92 cs_log_dbg(D_CACHEEX, "cacheex: sending push filter request to %s", username(cl));
93 cc_cmd_send(cl, buf, size, MSG_CACHE_FILTER);
96 void cc_cacheex_filter_in(struct s_client *cl, uint8_t *buf)
98 struct s_reader *rdr = (cl->typ == 'c') ? NULL : cl->reader;
99 int i = 0, j;
100 int32_t caid, cmask, provid, srvid;
101 CECSPVALUETAB *filter;
103 // mode == 2 write filters to acc
104 if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode == 2 && cl->account->cacheex.allow_filter == 1)
106 filter = &cl->account->cacheex.filter_caidtab;
108 else if(rdr && rdr->cacheex.mode == 3 && rdr->cacheex.allow_filter == 1) // mode == 3 write filters to rdr
110 filter = &rdr->cacheex.filter_caidtab;
112 else
114 return;
117 cecspvaluetab_clear(filter);
118 i += 2;
120 int32_t max_filters = 30;
121 for(j = 0; j < max_filters; j++)
123 caid = b2i(4, buf + i);
124 if(caid > 0)
126 CECSPVALUETAB_DATA d;
127 memset(&d, 0, sizeof(d));
128 d.caid = b2i(4, buf + i);
129 cecspvaluetab_add(filter, &d);
131 i += 4;
134 for(j = 0; j < max_filters; j++)
136 cmask = b2i(4, buf + i);
137 if(j < filter->cevnum)
139 CECSPVALUETAB_DATA *d = &filter->cevdata[j];
140 d->cmask = cmask;
142 i += 4;
145 for(j = 0; j < max_filters; j++)
147 provid = b2i(4, buf + i);
148 if(j < filter->cevnum)
150 CECSPVALUETAB_DATA *d = &filter->cevdata[j];
151 d->prid = provid;
153 i += 4;
156 for(j = 0; j < max_filters; j++)
158 srvid = b2i(4, buf + i);
159 if(j < filter->cevnum)
161 CECSPVALUETAB_DATA *d = &filter->cevdata[j];
162 d->srvid = srvid;
164 i += 4;
167 cs_log_dbg(D_CACHEEX, "cacheex: received push filter request from %s", username(cl));
170 static int32_t cc_cacheex_push_chk(struct s_client *cl, struct ecm_request_t *er)
172 struct cc_data *cc = cl->cc;
173 if(chk_is_null_nodeid(cc->peer_node_id,8))
175 cs_log_dbg(D_CACHEEX, "cacheex: NO peer_node_id got yet, skip!");
176 return 0;
179 if(ll_count(er->csp_lastnodes) >= cacheex_maxhop(cl)) // check max 10 nodes to push
181 cs_log_dbg(D_CACHEEX, "cacheex: nodelist reached %d nodes, no push", cacheex_maxhop(cl));
182 return 0;
185 uint8_t *remote_node = cc->peer_node_id;
187 // search existing peer nodes
188 LL_LOCKITER *li = ll_li_create(er->csp_lastnodes, 0);
189 uint8_t *node;
190 while((node = ll_li_next(li)))
192 cs_log_dbg(D_CACHEEX, "cacheex: check node %" PRIu64 "X == %" PRIu64 "X ?",
193 cacheex_node_id(node), cacheex_node_id(remote_node));
195 if(memcmp(node, remote_node, 8) == 0)
197 break;
200 ll_li_destroy(li);
202 // node found, so we got it from there, do not push
203 if(node)
205 cs_log_dbg(D_CACHEEX, "cacheex: node %" PRIu64 "X found in list => skip push!", cacheex_node_id(node));
206 return 0;
209 if(!cl->cc)
211 if(cl->reader && !cl->reader->tcp_connected)
213 cc_cli_connect(cl);
217 if(!cc || !cl->udp_fd)
219 cs_log_dbg(D_CACHEEX, "cacheex: not connected %s -> no push", username(cl));
220 return 0;
223 // check if cw is already pushed
224 if(check_is_pushed(er->cw_cache, cl))
226 return 0;
229 return 1;
232 static int32_t cc_cacheex_push_out(struct s_client *cl, struct ecm_request_t *er)
234 int8_t rc = (er->rc < E_NOTFOUND) ? E_FOUND : er->rc;
236 if(rc != E_FOUND && rc != E_UNHANDLED)
238 return -1; // Maybe later we could support other rcs
241 if(cl->reader)
243 if(!cl->reader->tcp_connected)
245 cc_cli_connect(cl);
249 struct cc_data *cc = cl->cc;
250 if(!cc || !cl->udp_fd)
252 cs_log_dbg(D_CACHEEX, "cacheex: not connected %s -> no push", username(cl));
253 return (-1);
256 uint32_t size = sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw) + sizeof(uint8_t) +
257 (ll_count(er->csp_lastnodes) + 1) * 8;
259 uint8_t *buf;
260 if(!cs_malloc(&buf, size + 20)) // camd35_send() adds +20
262 return -1;
265 // build ecm message
266 //buf[0] = er->caid >> 8;
267 //buf[1] = er->caid & 0xff;
268 //buf[2] = er->prid >> 24;
269 //buf[3] = er->prid >> 16;
270 //buf[4] = er->prid >> 8;
271 //buf[5] = er->prid & 0xff;
272 //buf[10] = er->srvid >> 8;
273 //buf[11] = er->srvid & 0xff;
274 buf[12] = (sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw)) & 0xff;
275 buf[13] = (sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw)) >> 8;
276 //buf[12] = 0;
277 //buf[13] = 0;
278 buf[14] = rc;
280 i2b_buf(2, er->caid, buf + 0);
281 i2b_buf(4, er->prid, buf + 2);
282 i2b_buf(2, er->srvid, buf + 10);
284 if(er->cwc_cycletime && er->cwc_next_cw_cycle < 2)
286 buf[18] = er->cwc_cycletime; // contains cwc stage3 cycletime
288 if(er->cwc_next_cw_cycle == 1)
290 buf[18] = (buf[18] | 0x80); // set bit 8 to high
293 if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode)
295 cl->account->cwc_info++;
297 else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode))
299 cl->cwc_info++;
302 cs_log_dbg(D_CWC, "CWC (CE) push to %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X",
303 username(cl), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid);
306 buf[19] = er->ecm[0] != 0x80 && er->ecm[0] != 0x81 ? 0 : er->ecm[0];
308 uint8_t *ofs = buf + 20;
310 // write oscam ecmd5
311 memcpy(ofs, er->ecmd5, sizeof(er->ecmd5)); // 16
312 ofs += sizeof(er->ecmd5);
314 // write csp hashcode
315 i2b_buf(4, CSP_HASH_SWAP(er->csp_hash), ofs);
316 ofs += 4;
318 // write cw
319 memcpy(ofs, er->cw, sizeof(er->cw)); // 16
320 ofs += sizeof(er->cw);
322 // write node count
323 *ofs = ll_count(er->csp_lastnodes) + 1;
324 ofs++;
326 // write own node
327 memcpy(ofs, cc->node_id, 8);
328 ofs += 8;
330 // write other nodes
331 LL_LOCKITER *li = ll_li_create(er->csp_lastnodes, 0);
332 uint8_t *node;
333 while((node = ll_li_next(li)))
335 memcpy(ofs, node, 8);
336 ofs += 8;
338 ll_li_destroy(li);
340 int32_t res = cc_cmd_send(cl, buf, size + 20, MSG_CACHE_PUSH);
341 if(res > 0) // cache-ex is pushing out, so no receive but last_g should be updated otherwise disconnect!
343 if(cl->reader)
345 cl->reader->last_s = cl->reader->last_g = time((time_t *)0); // correct
348 if(cl)
350 cl->last = time(NULL);
354 NULLFREE(buf);
355 return res;
358 void cc_cacheex_push_in(struct s_client *cl, uint8_t *buf)
360 struct cc_data *cc = cl->cc;
361 ECM_REQUEST *er;
363 if(!cc)
365 return;
368 if(cl->reader)
370 cl->reader->last_s = cl->reader->last_g = time((time_t *)0);
373 if(cl)
375 cl->last = time(NULL);
378 int8_t rc = buf[14];
379 if(rc != E_FOUND && rc != E_UNHANDLED) // Maybe later we could support other rcs
381 return;
384 uint16_t size = buf[12] | (buf[13] << 8);
385 if(size != sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw))
387 cs_log_dbg(D_CACHEEX, "cacheex: %s received old cash-push format! data ignored!", username(cl));
388 return;
391 if(!(er = get_ecmtask()))
393 return;
396 er->caid = b2i(2, buf + 0);
397 er->prid = b2i(4, buf + 2);
398 er->srvid = b2i(2, buf + 10);
399 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
400 er->rc = rc;
402 er->ecmlen = 0;
404 if(buf[18])
406 if(buf[18] & (0x01 << 7))
408 er->cwc_cycletime = (buf[18] & 0x7F); // remove bit 8 to get cycletime
409 er->cwc_next_cw_cycle = 1;
411 else
413 er->cwc_cycletime = buf[18];
414 er->cwc_next_cw_cycle = 0;
418 if (er->cwc_cycletime && er->cwc_next_cw_cycle < 2)
420 if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode)
422 cl->account->cwc_info++;
424 else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode))
426 cl->cwc_info++;
429 cs_log_dbg(D_CWC, "CWC (CE) received from %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X",
430 username(cl), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid);
433 uint8_t *ofs = buf + 20;
435 // Read ecmd5
436 memcpy(er->ecmd5, ofs, sizeof(er->ecmd5)); // 16
437 ofs += sizeof(er->ecmd5);
439 if(!check_cacheex_filter(cl, er))
441 return;
444 // Read csp_hash
445 er->csp_hash = CSP_HASH_SWAP(b2i(4, ofs));
446 ofs += 4;
448 // Read cw
449 memcpy(er->cw, ofs, sizeof(er->cw)); // 16
450 ofs += sizeof(er->cw);
452 // Read lastnode count
453 uint8_t count = *ofs;
454 ofs++;
456 // check max nodes
457 if(count > cacheex_maxhop(cl))
459 cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes (max=%d), ignored! %s",
460 (int32_t)count, cacheex_maxhop(cl), username(cl));
462 NULLFREE(er);
463 return;
466 cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes %s", (int32_t)count, username(cl));
468 // Read lastnodes
469 uint8_t *data;
470 if (er)
472 er->csp_lastnodes = ll_create("csp_lastnodes");
475 while(count)
477 if(!cs_malloc(&data, 8))
479 break;
482 memcpy(data, ofs, 8);
483 ofs += 8;
484 ll_append(er->csp_lastnodes, data);
485 count--;
487 cs_log_dbg(D_CACHEEX, "cacheex: received node %" PRIu64 "X %s", cacheex_node_id(data), username(cl));
490 // for compatibility: add peer node if no node received
491 if(!ll_count(er->csp_lastnodes))
493 if(!cs_malloc(&data, 8))
495 return;
498 memcpy(data, cc->peer_node_id, 8);
499 ll_append(er->csp_lastnodes, data);
500 cs_log_dbg(D_CACHEEX, "cacheex: added missing remote node id %" PRIu64 "X", cacheex_node_id(data));
503 cacheex_add_to_cache(cl, er);
506 void cc_cacheex_module_init(struct s_module *ph)
508 ph->c_cache_push = cc_cacheex_push_out;
509 ph->c_cache_push_chk = cc_cacheex_push_chk;
512 #endif