revert breaks some stupid old compilers
[oscam.git] / module-cccam-cacheex.c
blob7a1a76ea46bf392073985c95a94fff5eb33429cd
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 //minimal size, keep it <= 512 for max UDP packet size without fragmentation
32 int32_t size = 482;
33 uint8_t buf[482];
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;
46 else {
47 return;
50 i2b_buf(2, filter->cevnum, buf + i);
51 i += 2;
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);
60 i += 4;
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);
69 i += 4;
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);
78 i += 4;
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);
87 i += 4;
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;
97 int i = 0, j;
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;
112 else {
113 return;
116 cecspvaluetab_clear(filter);
117 i += 2;
119 int32_t max_filters = 30;
120 for(j=0; j<max_filters; j++)
122 caid = b2i(4, buf + i);
123 if(caid > 0){
124 CECSPVALUETAB_DATA d;
125 memset(&d, 0, sizeof(d));
126 d.caid = b2i(4, buf + i);
127 cecspvaluetab_add(filter, &d);
129 i += 4;
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];
137 d->cmask = cmask;
139 i += 4;
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];
147 d->prid = provid;
149 i += 4;
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];
157 d->srvid = srvid;
159 i += 4;
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!");
171 return 0;
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));
177 return 0;
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);
184 uint8_t *node;
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)
190 break;
193 ll_li_destroy(li);
195 //node found, so we got it from there, do not push:
196 if(node)
198 cs_log_dbg(D_CACHEEX,
199 "cacheex: node %" PRIu64 "X found in list => skip push!", cacheex_node_id(node));
200 return 0;
203 if(!cl->cc)
205 if(cl->reader && !cl->reader->tcp_connected)
207 cc_cli_connect(cl);
211 if(!cc || !cl->udp_fd)
213 cs_log_dbg(D_CACHEEX, "cacheex: not connected %s -> no push", username(cl));
214 return 0;
217 //check if cw is already pushed
218 if(check_is_pushed(er->cw_cache, cl))
219 { return 0; }
221 return 1;
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
229 if(cl->reader)
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));
239 return (-1);
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;
245 unsigned char *buf;
246 if(!cs_malloc(&buf, size + 20)) //camd35_send() adds +20
247 { return -1; }
249 // build ecm message
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;
260 //buf[12] = 0;
261 //buf[13] = 0;
262 buf[14] = rc;
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))
277 { cl->cwc_info++; }
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;
285 //write oscam ecmd5:
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);
291 ofs += 4;
293 //write cw:
294 memcpy(ofs, er->cw, sizeof(er->cw)); //16
295 ofs += sizeof(er->cw);
297 //write node count:
298 *ofs = ll_count(er->csp_lastnodes) + 1;
299 ofs++;
301 //write own node:
302 memcpy(ofs, cc->node_id, 8);
303 ofs += 8;
305 //write other nodes:
306 LL_LOCKITER *li = ll_li_create(er->csp_lastnodes, 0);
307 uint8_t *node;
308 while((node = ll_li_next(li)))
310 memcpy(ofs, node, 8);
311 ofs += 8;
313 ll_li_destroy(li);
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!
318 if(cl->reader)
319 { cl->reader->last_s = cl->reader->last_g = time((time_t *)0); } // correct
320 if(cl) { cl->last = time(NULL); }
322 NULLFREE(buf);
323 return res;
326 void cc_cacheex_push_in(struct s_client *cl, uchar *buf)
328 struct cc_data *cc = cl->cc;
329 ECM_REQUEST *er;
330 if(!cc) { return; }
332 if(cl->reader)
333 { cl->reader->last_s = cl->reader->last_g = time((time_t *)0); }
334 if(cl) { cl->last = time(NULL); }
336 int8_t rc = buf[14];
337 if(rc != E_FOUND && rc != E_UNHANDLED) //Maybe later we could support other rcs
338 { return; }
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));
343 return;
345 if(!(er = get_ecmtask()))
346 { return; }
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
352 er->rc = rc;
354 er->ecmlen = 0;
356 if(buf[18])
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;
363 else
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))
375 { cl->cwc_info++; }
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;
381 //Read ecmd5
382 memcpy(er->ecmd5, ofs, sizeof(er->ecmd5)); //16
383 ofs += sizeof(er->ecmd5);
385 if(!check_cacheex_filter(cl, er))
386 { return; }
388 //Read csp_hash:
389 er->csp_hash = CSP_HASH_SWAP(b2i(4, ofs));
390 ofs += 4;
392 //Read cw:
393 memcpy(er->cw, ofs, sizeof(er->cw)); //16
394 ofs += sizeof(er->cw);
396 //Read lastnode count:
397 uint8_t count = *ofs;
398 ofs++;
400 //check max nodes:
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));
404 NULLFREE(er);
405 return;
407 cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes %s", (int32_t)count, username(cl));
408 //Read lastnodes:
409 uint8_t *data;
410 if (er){
411 er->csp_lastnodes = ll_create("csp_lastnodes");
413 while(count)
415 if(!cs_malloc(&data, 8))
416 { break; }
417 memcpy(data, ofs, 8);
418 ofs += 8;
419 ll_append(er->csp_lastnodes, data);
420 count--;
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))
428 { return; }
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;
443 #endif