| 1 | #define MODULE_LOG_PREFIX "ecm"
|
|---|
| 2 |
|
|---|
| 3 | #include "globals.h"
|
|---|
| 4 | #include "cscrypt/md5.h"
|
|---|
| 5 | #include "module-anticasc.h"
|
|---|
| 6 | #include "module-cacheex.h"
|
|---|
| 7 | #include "module-led.h"
|
|---|
| 8 | #include "module-stat.h"
|
|---|
| 9 | #include "module-webif.h"
|
|---|
| 10 | #include "module-ird-guess.h"
|
|---|
| 11 | #include "module-cw-cycle-check.h"
|
|---|
| 12 | #include "module-gbox.h"
|
|---|
| 13 | #include "oscam-cache.h"
|
|---|
| 14 | #include "oscam-chk.h"
|
|---|
| 15 | #include "oscam-client.h"
|
|---|
| 16 | #include "oscam-config.h"
|
|---|
| 17 | #include "oscam-ecm.h"
|
|---|
| 18 | #include "oscam-garbage.h"
|
|---|
| 19 | #include "oscam-failban.h"
|
|---|
| 20 | #include "oscam-net.h"
|
|---|
| 21 | #include "oscam-time.h"
|
|---|
| 22 | #include "oscam-lock.h"
|
|---|
| 23 | #include "oscam-string.h"
|
|---|
| 24 | #include "oscam-work.h"
|
|---|
| 25 | #include "reader-common.h"
|
|---|
| 26 | #include "module-cccam-data.h"
|
|---|
| 27 | #ifdef CS_CACHEEX_AIO
|
|---|
| 28 | #include "oscam-hashtable.h"
|
|---|
| 29 | #endif
|
|---|
| 30 |
|
|---|
| 31 | extern CS_MUTEX_LOCK ecmcache_lock;
|
|---|
| 32 | extern struct ecm_request_t *ecmcwcache;
|
|---|
| 33 | extern uint16_t len4caid[256];
|
|---|
| 34 | extern uint32_t ecmcwcache_size;
|
|---|
| 35 | extern int32_t exit_oscam;
|
|---|
| 36 |
|
|---|
| 37 | extern CS_MUTEX_LOCK ecm_pushed_deleted_lock;
|
|---|
| 38 | extern struct ecm_request_t *ecm_pushed_deleted;
|
|---|
| 39 |
|
|---|
| 40 | static pthread_mutex_t cw_process_sleep_cond_mutex;
|
|---|
| 41 | static pthread_cond_t cw_process_sleep_cond;
|
|---|
| 42 | static int cw_process_wakeups;
|
|---|
| 43 | int64_t ecmc_next, cache_next, msec_wait = 3000;
|
|---|
| 44 |
|
|---|
| 45 | #ifdef CS_CACHEEX_AIO
|
|---|
| 46 | // ecm-cache
|
|---|
| 47 | typedef struct ecm_cache
|
|---|
| 48 | {
|
|---|
| 49 | struct timeb first_recv_time;// time of first cw received
|
|---|
| 50 | struct timeb upd_time; // updated time. Update time at each cw got
|
|---|
| 51 | uint32_t csp_hash;
|
|---|
| 52 | node ht_node;
|
|---|
| 53 | node ll_node;
|
|---|
| 54 | } ECM_CACHE;
|
|---|
| 55 |
|
|---|
| 56 | static pthread_rwlock_t ecm_cache_lock;
|
|---|
| 57 | static hash_table ht_ecm_cache;
|
|---|
| 58 | static list ll_ecm_cache;
|
|---|
| 59 | static int8_t ecm_cache_init_done = 0;
|
|---|
| 60 |
|
|---|
| 61 | void free_ecm_cache(void)
|
|---|
| 62 | {
|
|---|
| 63 | deinitialize_hash_table(&ht_ecm_cache);
|
|---|
| 64 | pthread_rwlock_destroy(&ecm_cache_lock);
|
|---|
| 65 | }
|
|---|
| 66 |
|
|---|
| 67 | void init_ecm_cache(void)
|
|---|
| 68 | {
|
|---|
| 69 | #ifdef CS_CACHEEX
|
|---|
| 70 | if(cfg.cw_cache_size > 0 || cfg.cw_cache_memory > 0)
|
|---|
| 71 | {
|
|---|
| 72 | init_hash_table(&ht_ecm_cache, &ll_ecm_cache);
|
|---|
| 73 | if (pthread_rwlock_init(&ecm_cache_lock,NULL) != 0)
|
|---|
| 74 | { cs_log("Error creating lock ecm_cache_lock!"); }
|
|---|
| 75 | else
|
|---|
| 76 | { ecm_cache_init_done = 1; }
|
|---|
| 77 | }
|
|---|
| 78 | #endif
|
|---|
| 79 | }
|
|---|
| 80 |
|
|---|
| 81 | static uint8_t time_sort(ECM_CACHE *a, ECM_CACHE *b)
|
|---|
| 82 | {
|
|---|
| 83 | if (((int64_t)(a->upd_time.time) * 1000ull + (int64_t) a->upd_time.millitm) == ((int64_t)(b->upd_time.time) * 1000ull + (int64_t) b->upd_time.millitm)) return 0;
|
|---|
| 84 | return (((int64_t)(a->upd_time.time) * 1000ull + (int64_t) a->upd_time.millitm) > ((int64_t)(b->upd_time.time) * 1000ull + (int64_t) b->upd_time.millitm)) ? -1 : 1;
|
|---|
| 85 | }
|
|---|
| 86 |
|
|---|
| 87 | static int compare_csp_hash_ecmcache(const void *arg, const void *obj)
|
|---|
| 88 | {
|
|---|
| 89 | uint32_t h = ((const ECM_CACHE*)obj)->csp_hash;
|
|---|
| 90 | return memcmp(arg, &h, 4);
|
|---|
| 91 | }
|
|---|
| 92 |
|
|---|
| 93 | void ecm_cache_cleanup(bool force)
|
|---|
| 94 | {
|
|---|
| 95 | if(!ecm_cache_init_done)
|
|---|
| 96 | { return; }
|
|---|
| 97 |
|
|---|
| 98 | SAFE_RWLOCK_WRLOCK(&ecm_cache_lock);
|
|---|
| 99 |
|
|---|
| 100 | ECM_CACHE *ecm_cache;
|
|---|
| 101 | node *i, *i_next;
|
|---|
| 102 | uint32_t ll_c = 0;
|
|---|
| 103 | uint32_t ll_ten_percent = (uint)tommy_list_count(&ll_ecm_cache)*0.1; // 10 percent of cache
|
|---|
| 104 |
|
|---|
| 105 | if(!force)
|
|---|
| 106 | sort_list(&ll_ecm_cache, time_sort);
|
|---|
| 107 |
|
|---|
| 108 | i = get_first_node_list(&ll_ecm_cache);
|
|---|
| 109 | while(i)
|
|---|
| 110 | {
|
|---|
| 111 | i_next = i->next;
|
|---|
| 112 |
|
|---|
| 113 | ecm_cache = get_data_from_node(i);
|
|---|
| 114 |
|
|---|
| 115 | if(!ecm_cache)
|
|---|
| 116 | {
|
|---|
| 117 | i = i_next;
|
|---|
| 118 | continue;
|
|---|
| 119 | }
|
|---|
| 120 | if(!force)
|
|---|
| 121 | {
|
|---|
| 122 | ++ll_c;
|
|---|
| 123 |
|
|---|
| 124 | if(ll_c < ll_ten_percent)
|
|---|
| 125 | {
|
|---|
| 126 | remove_elem_list(&ll_ecm_cache, &ecm_cache->ll_node);
|
|---|
| 127 | remove_elem_hash_table(&ht_ecm_cache, &ecm_cache->ht_node);
|
|---|
| 128 | NULLFREE(ecm_cache);
|
|---|
| 129 | }
|
|---|
| 130 | else{
|
|---|
| 131 | break;
|
|---|
| 132 | }
|
|---|
| 133 | }
|
|---|
| 134 | else{
|
|---|
| 135 | remove_elem_list(&ll_ecm_cache, &ecm_cache->ll_node);
|
|---|
| 136 | remove_elem_hash_table(&ht_ecm_cache, &ecm_cache->ht_node);
|
|---|
| 137 | NULLFREE(ecm_cache);
|
|---|
| 138 | }
|
|---|
| 139 | i = i_next;
|
|---|
| 140 | }
|
|---|
| 141 |
|
|---|
| 142 | SAFE_RWLOCK_UNLOCK(&ecm_cache_lock);
|
|---|
| 143 | }
|
|---|
| 144 | #endif
|
|---|
| 145 |
|
|---|
| 146 | void fallback_timeout(ECM_REQUEST *er)
|
|---|
| 147 | {
|
|---|
| 148 | if(er->rc >= E_UNHANDLED && er->stage < 4)
|
|---|
| 149 | {
|
|---|
| 150 | cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} fallback timeout! (stage: %d)", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid, er->stage);
|
|---|
| 151 | debug_ecm(D_TRACE, "fallback for %s %s", username(er->client), buf);
|
|---|
| 152 | while(er->stage < 4) // if preferlocalcards=1 and no answer from locals, initial stage will be 2! We need to reach stage=4 to call fallback's.
|
|---|
| 153 | {
|
|---|
| 154 | request_cw_from_readers(er, 0);
|
|---|
| 155 | }
|
|---|
| 156 | }
|
|---|
| 157 | }
|
|---|
| 158 |
|
|---|
| 159 | void ecm_timeout(ECM_REQUEST *er)
|
|---|
| 160 | {
|
|---|
| 161 | if(!er->readers_timeout_check)
|
|---|
| 162 | {
|
|---|
| 163 | er->readers_timeout_check = 1;
|
|---|
| 164 |
|
|---|
| 165 | if(check_client(er->client) && er->rc >= E_UNHANDLED)
|
|---|
| 166 | {
|
|---|
| 167 | debug_ecm(D_TRACE, "timeout for %s %s", username(er->client), buf);
|
|---|
| 168 |
|
|---|
| 169 | // set timeout for readers not answering
|
|---|
| 170 | struct s_ecm_answer *ea_list;
|
|---|
| 171 | for(ea_list = er->matching_rdr; ea_list; ea_list = ea_list->next)
|
|---|
| 172 | {
|
|---|
| 173 | if((ea_list->status & (REQUEST_SENT | REQUEST_ANSWERED)) == REQUEST_SENT) // Request sent, but no answer!
|
|---|
| 174 | {
|
|---|
| 175 | write_ecm_answer(ea_list->reader, er, E_TIMEOUT, 0, NULL, NULL, 0, NULL); // set timeout for readers not answered!
|
|---|
| 176 | }
|
|---|
| 177 | }
|
|---|
| 178 |
|
|---|
| 179 | // send timeout to client!
|
|---|
| 180 | cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} client timeout! ", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid);
|
|---|
| 181 | er->rc = E_TIMEOUT;
|
|---|
| 182 | er->rcEx = 0;
|
|---|
| 183 | send_dcw(er->client, er);
|
|---|
| 184 | }
|
|---|
| 185 | }
|
|---|
| 186 | }
|
|---|
| 187 |
|
|---|
| 188 | void increment_n_request(struct s_client *cl)
|
|---|
| 189 | {
|
|---|
| 190 | if(check_client(cl))
|
|---|
| 191 | {
|
|---|
| 192 | cl->n_request[1]++;
|
|---|
| 193 | first_client->n_request[1]++;
|
|---|
| 194 | }
|
|---|
| 195 | }
|
|---|
| 196 |
|
|---|
| 197 | uint8_t checkCWpart(uint8_t *cw, int8_t part)
|
|---|
| 198 | {
|
|---|
| 199 | uint8_t eo = part ? 8 : 0;
|
|---|
| 200 | int8_t i;
|
|---|
| 201 | for(i = 0; i < 8; i++)
|
|---|
| 202 | if(cw[i + eo]) { return 1; }
|
|---|
| 203 | return 0;
|
|---|
| 204 | }
|
|---|
| 205 |
|
|---|
| 206 | void update_n_request(void)
|
|---|
| 207 | {
|
|---|
| 208 | struct s_client *cl;
|
|---|
| 209 |
|
|---|
| 210 | cs_readlock(__func__, &clientlist_lock);
|
|---|
| 211 | for(cl = first_client->next; cl; cl = cl->next)
|
|---|
| 212 | {
|
|---|
| 213 | #ifdef CS_CACHEEX
|
|---|
| 214 | if(check_client(cl) && get_module(cl)->num != R_CSP && cl->typ == 'c' && !cl->dup && cl->account && cl->account->cacheex.mode<=1) //no cacheex 2/3 client
|
|---|
| 215 | #else
|
|---|
| 216 | if(check_client(cl) && get_module(cl)->num != R_CSP && cl->typ == 'c' && !cl->dup)
|
|---|
| 217 | #endif
|
|---|
| 218 | {
|
|---|
| 219 | cl->n_request[0] = cl->n_request[1];
|
|---|
| 220 | cl->n_request[1] = 0;
|
|---|
| 221 | }
|
|---|
| 222 | else
|
|---|
| 223 | {
|
|---|
| 224 | cl->n_request[0] = 0;
|
|---|
| 225 | cl->n_request[1] = 0;
|
|---|
| 226 | }
|
|---|
| 227 | }
|
|---|
| 228 |
|
|---|
| 229 | first_client->n_request[0] = first_client->n_request[1];
|
|---|
| 230 | first_client->n_request[1] = 0;
|
|---|
| 231 |
|
|---|
| 232 | cs_readunlock(__func__, &clientlist_lock);
|
|---|
| 233 | }
|
|---|
| 234 |
|
|---|
| 235 | static void *cw_process(void)
|
|---|
| 236 | {
|
|---|
| 237 | set_thread_name(__func__);
|
|---|
| 238 | int64_t time_to_check_fbtimeout, time_to_check_ctimeout, next_check, n_request_next;
|
|---|
| 239 | struct timeb t_now, tbc, ecmc_time, cache_time, n_request_time;
|
|---|
| 240 | ECM_REQUEST *er = NULL;
|
|---|
| 241 | time_t ecm_maxcachetime;
|
|---|
| 242 |
|
|---|
| 243 | #ifdef CS_CACHEEX
|
|---|
| 244 | int64_t time_to_check_cacheex_wait_time;
|
|---|
| 245 | int64_t time_to_check_cacheex_mode1_delay;
|
|---|
| 246 | #endif
|
|---|
| 247 |
|
|---|
| 248 | cs_pthread_cond_init(__func__, &cw_process_sleep_cond_mutex, &cw_process_sleep_cond);
|
|---|
| 249 |
|
|---|
| 250 | #ifdef CS_ANTICASC
|
|---|
| 251 | int32_t ac_next;
|
|---|
| 252 | struct timeb ac_time;
|
|---|
| 253 | cs_ftime(&ac_time);
|
|---|
| 254 | add_ms_to_timeb(&ac_time, cfg.ac_stime * 60 * 1000);
|
|---|
| 255 | #endif
|
|---|
| 256 |
|
|---|
| 257 | cs_ftime(&ecmc_time);
|
|---|
| 258 | add_ms_to_timeb(&ecmc_time, 1000);
|
|---|
| 259 | cs_ftime(&cache_time);
|
|---|
| 260 | add_ms_to_timeb(&cache_time, 3000);
|
|---|
| 261 | cs_ftime(&n_request_time);
|
|---|
| 262 | add_ms_to_timeb(&n_request_time, 60 * 1000);
|
|---|
| 263 |
|
|---|
| 264 | while(!exit_oscam)
|
|---|
| 265 | {
|
|---|
| 266 | if(cw_process_wakeups == 0) // No waiting wakeups, proceed to sleep
|
|---|
| 267 | {
|
|---|
| 268 | sleepms_on_cond(__func__, &cw_process_sleep_cond_mutex, &cw_process_sleep_cond, msec_wait);
|
|---|
| 269 | }
|
|---|
| 270 | cw_process_wakeups = 0; // We've been woken up, reset the counter
|
|---|
| 271 | if(exit_oscam)
|
|---|
| 272 | { break; }
|
|---|
| 273 |
|
|---|
| 274 | next_check = 0;
|
|---|
| 275 | #ifdef CS_ANTICASC
|
|---|
| 276 | ac_next = 0;
|
|---|
| 277 | #endif
|
|---|
| 278 | ecmc_next = 0;
|
|---|
| 279 | cache_next = 0;
|
|---|
| 280 | msec_wait = 0;
|
|---|
| 281 |
|
|---|
| 282 | cs_ftime(&t_now);
|
|---|
| 283 | cs_readlock(__func__, &ecmcache_lock);
|
|---|
| 284 | for(er = ecmcwcache; er; er = er->next)
|
|---|
| 285 | {
|
|---|
| 286 |
|
|---|
| 287 | if((er->from_cacheex || er->from_csp) // ignore ecms from cacheex/csp
|
|---|
| 288 | || er->readers_timeout_check // ignore already checked
|
|---|
| 289 | || !check_client(er->client)) // ignore ecm of killed clients
|
|---|
| 290 | {
|
|---|
| 291 | continue;
|
|---|
| 292 | }
|
|---|
| 293 |
|
|---|
| 294 | if(er->rc >= E_UNHANDLED)
|
|---|
| 295 | {
|
|---|
| 296 | #ifdef CS_CACHEEX
|
|---|
| 297 | // cacheex_wait_time
|
|---|
| 298 | if(er->cacheex_wait_time && !er->cacheex_wait_time_expired)
|
|---|
| 299 | {
|
|---|
| 300 | tbc = er->tps;
|
|---|
| 301 | time_to_check_cacheex_mode1_delay = 0;
|
|---|
| 302 | time_to_check_cacheex_wait_time = add_ms_to_timeb_diff(&tbc, lb_auto_timeout(er, er->cacheex_wait_time));
|
|---|
| 303 |
|
|---|
| 304 | if(comp_timeb(&t_now, &tbc) >= 0)
|
|---|
| 305 | {
|
|---|
| 306 | add_job(er->client, ACTION_CACHEEX_TIMEOUT, (void *)er, 0);
|
|---|
| 307 | time_to_check_cacheex_wait_time = 0;
|
|---|
| 308 |
|
|---|
| 309 | }
|
|---|
| 310 | else if(er->cacheex_mode1_delay && !er->stage && er->cacheex_reader_count>0)
|
|---|
| 311 | {
|
|---|
| 312 | // check for cacheex_mode1_delay
|
|---|
| 313 | tbc = er->tps;
|
|---|
| 314 | time_to_check_cacheex_mode1_delay = add_ms_to_timeb_diff(&tbc, lb_auto_timeout(er, er->cacheex_mode1_delay));
|
|---|
| 315 |
|
|---|
| 316 | if(comp_timeb(&t_now, &tbc) >= 0)
|
|---|
| 317 | {
|
|---|
| 318 | add_job(er->client, ACTION_CACHEEX1_DELAY, (void *)er, 0);
|
|---|
| 319 | time_to_check_cacheex_mode1_delay = 0;
|
|---|
| 320 | }
|
|---|
| 321 | }
|
|---|
| 322 |
|
|---|
| 323 | if(!next_check || (time_to_check_cacheex_wait_time > 0 && time_to_check_cacheex_wait_time < next_check))
|
|---|
| 324 | { next_check = time_to_check_cacheex_wait_time; }
|
|---|
| 325 |
|
|---|
| 326 | if(!next_check || (time_to_check_cacheex_mode1_delay > 0 && time_to_check_cacheex_mode1_delay < next_check))
|
|---|
| 327 | { next_check = time_to_check_cacheex_mode1_delay; }
|
|---|
| 328 | }
|
|---|
| 329 | #endif
|
|---|
| 330 | if(er->stage < 4)
|
|---|
| 331 | {
|
|---|
| 332 | // fbtimeout
|
|---|
| 333 | tbc = er->tps;
|
|---|
| 334 | time_to_check_fbtimeout = add_ms_to_timeb_diff(&tbc, lb_auto_timeout(er, get_fallbacktimeout(er->caid)));
|
|---|
| 335 |
|
|---|
| 336 | if(comp_timeb(&t_now, &tbc) >= 0)
|
|---|
| 337 | {
|
|---|
| 338 | add_job(er->client, ACTION_FALLBACK_TIMEOUT, (void *)er, 0);
|
|---|
| 339 | time_to_check_fbtimeout = 0;
|
|---|
| 340 | }
|
|---|
| 341 |
|
|---|
| 342 | if(!next_check || (time_to_check_fbtimeout > 0 && time_to_check_fbtimeout < next_check))
|
|---|
| 343 | { next_check = time_to_check_fbtimeout; }
|
|---|
| 344 | }
|
|---|
| 345 | }
|
|---|
| 346 |
|
|---|
| 347 | // clienttimeout
|
|---|
| 348 | if(!er->readers_timeout_check) // ecm stays in cache at least ctimeout+2seconds!
|
|---|
| 349 | {
|
|---|
| 350 | tbc = er->tps;
|
|---|
| 351 | time_to_check_ctimeout = add_ms_to_timeb_diff(&tbc, lb_auto_timeout(er, cfg.ctimeout));
|
|---|
| 352 |
|
|---|
| 353 | if(comp_timeb(&t_now, &tbc) >= 0)
|
|---|
| 354 | {
|
|---|
| 355 | add_job(er->client, ACTION_CLIENT_TIMEOUT, (void *)er, 0);
|
|---|
| 356 | time_to_check_ctimeout = 0;
|
|---|
| 357 | }
|
|---|
| 358 |
|
|---|
| 359 | if(!next_check || (time_to_check_ctimeout > 0 && time_to_check_ctimeout < next_check))
|
|---|
| 360 | { next_check = time_to_check_ctimeout; }
|
|---|
| 361 | }
|
|---|
| 362 | }
|
|---|
| 363 | cs_readunlock(__func__, &ecmcache_lock);
|
|---|
| 364 | #ifdef CS_ANTICASC
|
|---|
| 365 | if(cfg.ac_enabled && (ac_next = comp_timeb(&ac_time, &t_now)) <= 10)
|
|---|
| 366 | {
|
|---|
| 367 | ac_do_stat();
|
|---|
| 368 | cs_ftime(&ac_time);
|
|---|
| 369 | ac_next = add_ms_to_timeb_diff(&ac_time, cfg.ac_stime * 60 * 1000);
|
|---|
| 370 | }
|
|---|
| 371 | #endif
|
|---|
| 372 | if((ecmc_next = comp_timeb(&ecmc_time, &t_now)) <= 10)
|
|---|
| 373 | {
|
|---|
| 374 | uint32_t count = 0;
|
|---|
| 375 | struct ecm_request_t *ecm, *ecmt = NULL, *prv;
|
|---|
| 376 |
|
|---|
| 377 | cs_readlock(__func__, &ecmcache_lock);
|
|---|
| 378 | for(ecm = ecmcwcache, prv = NULL; ecm; prv = ecm, ecm = ecm->next, count++)
|
|---|
| 379 | {
|
|---|
| 380 | ecm_maxcachetime = t_now.time - ((cfg.ctimeout + 500) / 1000 + 3); // to be sure no more access er!
|
|---|
| 381 |
|
|---|
| 382 | if(ecm->tps.time < ecm_maxcachetime)
|
|---|
| 383 | {
|
|---|
| 384 | cs_readunlock(__func__, &ecmcache_lock);
|
|---|
| 385 | cs_writelock(__func__, &ecmcache_lock);
|
|---|
| 386 | ecmt = ecm;
|
|---|
| 387 | if(prv)
|
|---|
| 388 | { prv->next = NULL; }
|
|---|
| 389 | else
|
|---|
| 390 | { ecmcwcache = NULL; }
|
|---|
| 391 | cs_writeunlock(__func__, &ecmcache_lock);
|
|---|
| 392 | break;
|
|---|
| 393 | }
|
|---|
| 394 | }
|
|---|
| 395 | if(!ecmt)
|
|---|
| 396 | { cs_readunlock(__func__, &ecmcache_lock); }
|
|---|
| 397 | ecmcwcache_size = count;
|
|---|
| 398 |
|
|---|
| 399 | while(ecmt)
|
|---|
| 400 | {
|
|---|
| 401 | ecm = ecmt->next;
|
|---|
| 402 | free_ecm(ecmt);
|
|---|
| 403 | ecmt = ecm;
|
|---|
| 404 | }
|
|---|
| 405 |
|
|---|
| 406 | #ifdef CS_CACHEEX
|
|---|
| 407 | ecmt=NULL;
|
|---|
| 408 | cs_readlock(__func__, &ecm_pushed_deleted_lock);
|
|---|
| 409 | for(ecm = ecm_pushed_deleted, prv = NULL; ecm; prv = ecm, ecm = ecm->next)
|
|---|
| 410 | {
|
|---|
| 411 | ecm_maxcachetime = t_now.time - ((cfg.ctimeout + 500) / 1000 + 3);
|
|---|
| 412 | if(ecm->tps.time < ecm_maxcachetime)
|
|---|
| 413 | {
|
|---|
| 414 | cs_readunlock(__func__, &ecm_pushed_deleted_lock);
|
|---|
| 415 | cs_writelock(__func__, &ecm_pushed_deleted_lock);
|
|---|
| 416 | ecmt = ecm;
|
|---|
| 417 | if(prv)
|
|---|
| 418 | { prv->next = NULL; }
|
|---|
| 419 | else
|
|---|
| 420 | { ecm_pushed_deleted = NULL; }
|
|---|
| 421 | cs_writeunlock(__func__, &ecm_pushed_deleted_lock);
|
|---|
| 422 | break;
|
|---|
| 423 | }
|
|---|
| 424 | }
|
|---|
| 425 | if(!ecmt)
|
|---|
| 426 | { cs_readunlock(__func__, &ecm_pushed_deleted_lock); }
|
|---|
| 427 |
|
|---|
| 428 | while(ecmt)
|
|---|
| 429 | {
|
|---|
| 430 | ecm = ecmt->next;
|
|---|
| 431 | free_push_in_ecm(ecmt);
|
|---|
| 432 | ecmt = ecm;
|
|---|
| 433 | }
|
|---|
| 434 | #endif
|
|---|
| 435 |
|
|---|
| 436 | cs_ftime(&ecmc_time);
|
|---|
| 437 | ecmc_next = add_ms_to_timeb_diff(&ecmc_time, 1000);
|
|---|
| 438 | }
|
|---|
| 439 |
|
|---|
| 440 | if((cache_next = comp_timeb(&cache_time, &t_now)) <= 10)
|
|---|
| 441 | {
|
|---|
| 442 | cleanup_cache(false);
|
|---|
| 443 | cacheex_cleanup_hitcache(false);
|
|---|
| 444 |
|
|---|
| 445 | cs_ftime(&cache_time);
|
|---|
| 446 | cache_next = add_ms_to_timeb_diff(&cache_time, 3000);
|
|---|
| 447 | }
|
|---|
| 448 |
|
|---|
| 449 | if((n_request_next = comp_timeb(&n_request_time, &t_now)) <= 10)
|
|---|
| 450 | {
|
|---|
| 451 | update_n_request();
|
|---|
| 452 | cs_ftime(&n_request_time);
|
|---|
| 453 | n_request_next = add_ms_to_timeb_diff(&n_request_time, 60 * 1000);
|
|---|
| 454 | }
|
|---|
| 455 |
|
|---|
| 456 | msec_wait = next_check;
|
|---|
| 457 | #ifdef CS_ANTICASC
|
|---|
| 458 | if(!msec_wait || (ac_next > 0 && ac_next < msec_wait))
|
|---|
| 459 | { msec_wait = ac_next; }
|
|---|
| 460 | #endif
|
|---|
| 461 | if(!msec_wait || (ecmc_next > 0 && ecmc_next < msec_wait))
|
|---|
| 462 | { msec_wait = ecmc_next; }
|
|---|
| 463 |
|
|---|
| 464 | if(!msec_wait || (cache_next > 0 && cache_next < msec_wait))
|
|---|
| 465 | { msec_wait = cache_next; }
|
|---|
| 466 |
|
|---|
| 467 | if(!msec_wait || (n_request_next > 0 && n_request_next < msec_wait))
|
|---|
| 468 | { msec_wait = n_request_next; }
|
|---|
| 469 |
|
|---|
| 470 | if(!msec_wait)
|
|---|
| 471 | { msec_wait = 3000; }
|
|---|
| 472 |
|
|---|
| 473 | cleanupcwcycle();
|
|---|
| 474 | }
|
|---|
| 475 |
|
|---|
| 476 | return NULL;
|
|---|
| 477 | }
|
|---|
| 478 |
|
|---|
| 479 | void cw_process_thread_start(void)
|
|---|
| 480 | {
|
|---|
| 481 | start_thread("cw_process", (void *) &cw_process, NULL, NULL, 1, 1);
|
|---|
| 482 | }
|
|---|
| 483 |
|
|---|
| 484 | void cw_process_thread_wakeup(void)
|
|---|
| 485 | {
|
|---|
| 486 | cw_process_wakeups++; // Do not sleep...
|
|---|
| 487 | SAFE_COND_SIGNAL(&cw_process_sleep_cond);
|
|---|
| 488 | }
|
|---|
| 489 |
|
|---|
| 490 | void convert_to_beta(struct s_client *cl, ECM_REQUEST *er, uint16_t caidto)
|
|---|
| 491 | {
|
|---|
| 492 | static uint8_t headerN3[10] = { 0xc7, 0x00, 0x00, 0x00, 0x01, 0x10, 0x10, 0x00, 0x87, 0x12 };
|
|---|
| 493 | static uint8_t headerN2[10] = { 0xc9, 0x00, 0x00, 0x00, 0x01, 0x10, 0x10, 0x00, 0x48, 0x12 };
|
|---|
| 494 |
|
|---|
| 495 | er->ocaid = er->caid;
|
|---|
| 496 | er->caid = caidto;
|
|---|
| 497 | er->prid = 0;
|
|---|
| 498 | er->ecmlen = er->ecm[2] + 3;
|
|---|
| 499 |
|
|---|
| 500 | memmove(er->ecm + 13, er->ecm + 3, er->ecmlen - 3);
|
|---|
| 501 |
|
|---|
| 502 | if(er->ecmlen > 0x88)
|
|---|
| 503 | {
|
|---|
| 504 | memcpy(er->ecm + 3, headerN3, 10);
|
|---|
| 505 | if(er->ecm[0] == 0x81)
|
|---|
| 506 | { er->ecm[12] += 1; }
|
|---|
| 507 | er->ecm[1] = 0x70;
|
|---|
| 508 | }
|
|---|
| 509 | else
|
|---|
| 510 | {
|
|---|
| 511 | memcpy(er->ecm + 3, headerN2, 10);
|
|---|
| 512 | }
|
|---|
| 513 |
|
|---|
| 514 | er->ecmlen += 10;
|
|---|
| 515 | er->ecm[2] = er->ecmlen - 3;
|
|---|
| 516 | er->btun = 1;
|
|---|
| 517 |
|
|---|
| 518 | cl->cwtun++;
|
|---|
| 519 | cl->account->cwtun++;
|
|---|
| 520 | first_client->cwtun++;
|
|---|
| 521 |
|
|---|
| 522 | cs_log_dbg(D_TRACE, "ECM converted ocaid from 0x%04X to BetaCrypt caid 0x%04X for service id 0x%04X",
|
|---|
| 523 | er->ocaid, caidto, er->srvid);
|
|---|
| 524 | }
|
|---|
| 525 |
|
|---|
| 526 | void convert_to_nagra(struct s_client *cl, ECM_REQUEST *er, uint16_t caidto)
|
|---|
| 527 | {
|
|---|
| 528 | cs_log_dbg(D_TRACE, "convert_to_nagra");
|
|---|
| 529 | er->ocaid = er->caid;
|
|---|
| 530 | er->caid = caidto;
|
|---|
| 531 | er->prid = 0;
|
|---|
| 532 | er->ecmlen = er->ecm[2] + 3;
|
|---|
| 533 |
|
|---|
| 534 | // not sure
|
|---|
| 535 | if(er->ecmlen < 0x52)
|
|---|
| 536 | { er->ecm[1] = 0x30; }
|
|---|
| 537 |
|
|---|
| 538 | memmove(er->ecm + 3, er->ecm + 13, er->ecmlen - 3);
|
|---|
| 539 |
|
|---|
| 540 | er->ecmlen -= 10;
|
|---|
| 541 | er->ecm[2] = er->ecmlen - 3;
|
|---|
| 542 | er->btun = 1;
|
|---|
| 543 |
|
|---|
| 544 | cl->cwtun++;
|
|---|
| 545 | cl->account->cwtun++;
|
|---|
| 546 | first_client->cwtun++;
|
|---|
| 547 |
|
|---|
| 548 | cs_log_dbg(D_TRACE, "ECM converted ocaid from: 0x%04X to Nagra: 0x04%X for service id:0x04%X",
|
|---|
| 549 | er->ocaid, caidto, er->srvid);
|
|---|
| 550 | }
|
|---|
| 551 |
|
|---|
| 552 | void cs_betatunnel(ECM_REQUEST *er)
|
|---|
| 553 | {
|
|---|
| 554 | int32_t i;
|
|---|
| 555 | struct s_client *cl = cur_client();
|
|---|
| 556 | uint32_t mask_all = 0xFFFF;
|
|---|
| 557 | TUNTAB *ttab = &cl->ttab;
|
|---|
| 558 |
|
|---|
| 559 | for(i = 0; i < ttab->ttnum; i++)
|
|---|
| 560 | {
|
|---|
| 561 | if((er->caid == ttab->ttdata[i].bt_caidfrom) && ((er->srvid == ttab->ttdata[i].bt_srvid) || (ttab->ttdata[i].bt_srvid) == mask_all))
|
|---|
| 562 | {
|
|---|
| 563 | if(chk_is_betatunnel_caid(er->caid) == 1 && er->ocaid == 0x0000)
|
|---|
| 564 | {
|
|---|
| 565 | convert_to_nagra(cl, er, ttab->ttdata[i].bt_caidto);
|
|---|
| 566 | }
|
|---|
| 567 | else if(er->ocaid == 0x0000)
|
|---|
| 568 | {
|
|---|
| 569 | convert_to_beta(cl, er, ttab->ttdata[i].bt_caidto);
|
|---|
| 570 | }
|
|---|
| 571 | return;
|
|---|
| 572 | }
|
|---|
| 573 | }
|
|---|
| 574 | }
|
|---|
| 575 |
|
|---|
| 576 | static void remove_ecm_from_reader(ECM_REQUEST *ecm)
|
|---|
| 577 | {
|
|---|
| 578 | int32_t i;
|
|---|
| 579 | struct s_ecm_answer *ea = ecm->matching_rdr;
|
|---|
| 580 | while(ea)
|
|---|
| 581 | {
|
|---|
| 582 | if((ea->status & REQUEST_SENT) && !(ea->status & REQUEST_ANSWERED))
|
|---|
| 583 | {
|
|---|
| 584 | // we found a outstanding reader, clean it:
|
|---|
| 585 | struct s_reader *rdr = ea->reader;
|
|---|
| 586 | if(rdr)
|
|---|
| 587 | {
|
|---|
| 588 | struct s_client *cl = rdr->client;
|
|---|
| 589 | if(check_client(cl))
|
|---|
| 590 | {
|
|---|
| 591 | ECM_REQUEST *ecmtask = cl->ecmtask;
|
|---|
| 592 | if(ecmtask)
|
|---|
| 593 | {
|
|---|
| 594 | for(i = 0; i < cfg.max_pending; ++i)
|
|---|
| 595 | {
|
|---|
| 596 | if(ecmtask[i].parent == ecm)
|
|---|
| 597 | {
|
|---|
| 598 | ecmtask[i].client = NULL;
|
|---|
| 599 | cacheex_set_csp_lastnode(&ecmtask[i]);
|
|---|
| 600 | }
|
|---|
| 601 | }
|
|---|
| 602 | }
|
|---|
| 603 | }
|
|---|
| 604 | }
|
|---|
| 605 | }
|
|---|
| 606 | ea = ea->next;
|
|---|
| 607 | }
|
|---|
| 608 | }
|
|---|
| 609 |
|
|---|
| 610 | void free_ecm(ECM_REQUEST *ecm)
|
|---|
| 611 | {
|
|---|
| 612 | struct s_ecm_answer *ea, *nxt;
|
|---|
| 613 | cacheex_free_csp_lastnodes(ecm);
|
|---|
| 614 | gbox_free_cards_pending(ecm);
|
|---|
| 615 | // remove this ecm from reader queue to avoid segfault on very late answers (when ecm is already disposed)
|
|---|
| 616 | // first check for outstanding answers:
|
|---|
| 617 | remove_ecm_from_reader(ecm);
|
|---|
| 618 | // free matching_rdr list:
|
|---|
| 619 | ea = ecm->matching_rdr;
|
|---|
| 620 | ecm->matching_rdr = NULL;
|
|---|
| 621 | while(ea)
|
|---|
| 622 | {
|
|---|
| 623 | nxt = ea->next;
|
|---|
| 624 | cs_lock_destroy(__func__, &ea->ecmanswer_lock);
|
|---|
| 625 | add_garbage(ea);
|
|---|
| 626 | ea = nxt;
|
|---|
| 627 | }
|
|---|
| 628 | if(ecm->src_data)
|
|---|
| 629 | { add_garbage(ecm->src_data); }
|
|---|
| 630 | add_garbage(ecm);
|
|---|
| 631 | }
|
|---|
| 632 |
|
|---|
| 633 |
|
|---|
| 634 | void free_push_in_ecm(ECM_REQUEST *ecm)
|
|---|
| 635 | {
|
|---|
| 636 | cacheex_free_csp_lastnodes(ecm);
|
|---|
| 637 | gbox_free_cards_pending(ecm);
|
|---|
| 638 | if(ecm->src_data)
|
|---|
| 639 | { NULLFREE(ecm->src_data); }
|
|---|
| 640 | NULLFREE(ecm);
|
|---|
| 641 | }
|
|---|
| 642 |
|
|---|
| 643 | ECM_REQUEST *get_ecmtask(void)
|
|---|
| 644 | {
|
|---|
| 645 | ECM_REQUEST *er = NULL;
|
|---|
| 646 | struct s_client *cl = cur_client();
|
|---|
| 647 | if(!cl)
|
|---|
| 648 | { return NULL; }
|
|---|
| 649 | if(!cs_malloc(&er, sizeof(ECM_REQUEST)))
|
|---|
| 650 | { return NULL; }
|
|---|
| 651 | cs_ftime(&er->tps);
|
|---|
| 652 | er->rc = E_UNHANDLED;
|
|---|
| 653 | er->client = cl;
|
|---|
| 654 | er->grp = 0; // no readers/cacheex-clients answers yet
|
|---|
| 655 | //cs_log("client %s ECMTASK %d module %s", username(cl), n, get_module(cl)->desc);
|
|---|
| 656 | return er;
|
|---|
| 657 | }
|
|---|
| 658 |
|
|---|
| 659 | void cleanup_ecmtasks(struct s_client *cl)
|
|---|
| 660 | {
|
|---|
| 661 | if(!cl) { return; }
|
|---|
| 662 |
|
|---|
| 663 | ECM_REQUEST *ecm;
|
|---|
| 664 |
|
|---|
| 665 | // remove this clients ecm from queue. because of cache, just null the client:
|
|---|
| 666 | cs_readlock(__func__, &ecmcache_lock);
|
|---|
| 667 | for(ecm = ecmcwcache; ecm && cl; ecm = ecm->next)
|
|---|
| 668 | {
|
|---|
| 669 | if(ecm->client == cl)
|
|---|
| 670 | {
|
|---|
| 671 | ecm->client = NULL;
|
|---|
| 672 | }
|
|---|
| 673 | }
|
|---|
| 674 | cs_readunlock(__func__, &ecmcache_lock);
|
|---|
| 675 |
|
|---|
| 676 | // remove client from rdr ecm-queue:
|
|---|
| 677 | cs_readlock(__func__, &readerlist_lock);
|
|---|
| 678 | struct s_reader *rdr = first_active_reader;
|
|---|
| 679 | while(rdr)
|
|---|
| 680 | {
|
|---|
| 681 | if(check_client(rdr->client) && rdr->client->ecmtask)
|
|---|
| 682 | {
|
|---|
| 683 | int i;
|
|---|
| 684 | for(i = 0; (i < cfg.max_pending) && cl; i++)
|
|---|
| 685 | {
|
|---|
| 686 | ecm = &rdr->client->ecmtask[i];
|
|---|
| 687 | if(ecm->client == cl)
|
|---|
| 688 | {
|
|---|
| 689 | ecm->client = NULL;
|
|---|
| 690 | }
|
|---|
| 691 | }
|
|---|
| 692 | }
|
|---|
| 693 | rdr = rdr->next;
|
|---|
| 694 | }
|
|---|
| 695 | cs_readunlock(__func__, &readerlist_lock);
|
|---|
| 696 |
|
|---|
| 697 | }
|
|---|
| 698 |
|
|---|
| 699 | static void add_cascade_data(struct s_client *client, ECM_REQUEST *er)
|
|---|
| 700 | {
|
|---|
| 701 | if(!client->cascadeusers)
|
|---|
| 702 | { client->cascadeusers = ll_create("cascade_data"); }
|
|---|
| 703 | LLIST *l = client->cascadeusers;
|
|---|
| 704 | LL_ITER it = ll_iter_create(l);
|
|---|
| 705 | time_t now = time(NULL);
|
|---|
| 706 | struct s_cascadeuser *cu;
|
|---|
| 707 | int8_t found = 0;
|
|---|
| 708 | while((cu = ll_iter_next(&it)))
|
|---|
| 709 | {
|
|---|
| 710 | if(er->caid == cu->caid && er->prid == cu->prid && er->srvid == cu->srvid) // found it
|
|---|
| 711 | {
|
|---|
| 712 | if(cu->time < now)
|
|---|
| 713 | { cu->cwrate = now - cu->time; }
|
|---|
| 714 | cu->time = now;
|
|---|
| 715 | found = 1;
|
|---|
| 716 | }
|
|---|
| 717 | else if(cu->time + 60 < now) // old
|
|---|
| 718 | { ll_iter_remove_data(&it); }
|
|---|
| 719 | }
|
|---|
| 720 |
|
|---|
| 721 | if(!found) // add it if not found
|
|---|
| 722 | {
|
|---|
| 723 | if(!cs_malloc(&cu, sizeof(struct s_cascadeuser)))
|
|---|
| 724 | { return; }
|
|---|
| 725 | cu->caid = er->caid;
|
|---|
| 726 | cu->prid = er->prid;
|
|---|
| 727 | cu->srvid = er->srvid;
|
|---|
| 728 | cu->time = now;
|
|---|
| 729 | ll_append(l, cu);
|
|---|
| 730 | }
|
|---|
| 731 | }
|
|---|
| 732 |
|
|---|
| 733 | static int32_t is_double_check_caid(ECM_REQUEST *er, FTAB *double_check_caid)
|
|---|
| 734 | {
|
|---|
| 735 | if(!double_check_caid->nfilts) { return 1; }
|
|---|
| 736 |
|
|---|
| 737 | int32_t i, k;
|
|---|
| 738 | for(i = 0; i < double_check_caid->nfilts; i++)
|
|---|
| 739 | {
|
|---|
| 740 | uint16_t tcaid = double_check_caid->filts[i].caid;
|
|---|
| 741 | if(tcaid && (tcaid == er->caid || (tcaid < 0x0100 && (er->caid >> 8) == tcaid))) // caid match
|
|---|
| 742 | {
|
|---|
| 743 | int32_t nprids = double_check_caid->filts[i].nprids;
|
|---|
| 744 | if(!nprids) // No Provider ->Ok
|
|---|
| 745 | { return 1; }
|
|---|
| 746 |
|
|---|
| 747 | for(k = 0; k < nprids; k++)
|
|---|
| 748 | {
|
|---|
| 749 | uint32_t prid = double_check_caid->filts[i].prids[k];
|
|---|
| 750 | if(prid == er->prid) // Provider matches
|
|---|
| 751 | { return 1; }
|
|---|
| 752 | }
|
|---|
| 753 | }
|
|---|
| 754 | }
|
|---|
| 755 |
|
|---|
| 756 | return 0;
|
|---|
| 757 | }
|
|---|
| 758 |
|
|---|
| 759 | struct s_ecm_answer *get_ecm_answer(struct s_reader *reader, ECM_REQUEST *er)
|
|---|
| 760 | {
|
|---|
| 761 | if(!er || !reader) { return NULL; }
|
|---|
| 762 |
|
|---|
| 763 | struct s_ecm_answer *ea;
|
|---|
| 764 |
|
|---|
| 765 | for(ea = er->matching_rdr; ea; ea = ea->next)
|
|---|
| 766 | {
|
|---|
| 767 | if(ea->reader == reader)
|
|---|
| 768 | {
|
|---|
| 769 | return ea;
|
|---|
| 770 | }
|
|---|
| 771 | }
|
|---|
| 772 | return NULL;
|
|---|
| 773 | }
|
|---|
| 774 |
|
|---|
| 775 | void distribute_ea(struct s_ecm_answer *ea)
|
|---|
| 776 | {
|
|---|
| 777 | struct s_ecm_answer *ea_temp;
|
|---|
| 778 |
|
|---|
| 779 | for(ea_temp = ea->pending; ea_temp; ea_temp = ea_temp->pending_next)
|
|---|
| 780 | {
|
|---|
| 781 | cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} [distribute_ea] send ea (%s) by reader %s answering for client %s", (check_client(ea_temp->er->client) ? ea_temp->er->client->account->usr : "-"), ea_temp->er->caid, ea_temp->er->prid, ea_temp->er->srvid, ea->rc==E_FOUND?"OK":"NOK", ea_temp->reader->label, (check_client(ea->er->client) ? ea->er->client->account->usr : "-"));
|
|---|
| 782 | #ifdef CS_CACHEEX_AIO
|
|---|
| 783 | if(ea->rc==E_FOUND && ea->er->localgenerated)
|
|---|
| 784 | ea_temp->er->localgenerated = 1;
|
|---|
| 785 | #endif
|
|---|
| 786 | // e.g. we cannot send timeout, because "ea_temp->er->client" could wait/ask other readers! Simply set not_found if different from E_FOUND!
|
|---|
| 787 | write_ecm_answer(ea_temp->reader, ea_temp->er, (ea->rc==E_FOUND? E_FOUND : E_NOTFOUND), ea->rcEx, ea->cw, NULL, ea->tier, &ea->cw_ex);
|
|---|
| 788 | }
|
|---|
| 789 | }
|
|---|
| 790 |
|
|---|
| 791 | int32_t send_dcw(struct s_client *client, ECM_REQUEST *er)
|
|---|
| 792 | {
|
|---|
| 793 | if(!check_client(client) || client->typ != 'c')
|
|---|
| 794 | { return 0; }
|
|---|
| 795 |
|
|---|
| 796 | cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} [send_dcw] rc %d from reader %s", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid, er->rc, er->selected_reader ? er->selected_reader->label : "-");
|
|---|
| 797 |
|
|---|
| 798 | static const char stageTxt[] = { '0', 'C', 'L', 'P', 'F', 'X' };
|
|---|
| 799 | static const char *stxt[] = { "found", "cache1", "cache2", "cache3", "not found", "timeout", "sleeping",
|
|---|
| 800 | "fake", "invalid", "corrupt", "no card", "expdate", "disabled", "stopped" };
|
|---|
| 801 |
|
|---|
| 802 | static const char *stxtEx[16] = {"", "group", "caid", "ident", "class", "chid", "queue", "peer", "sid", "", "", "", "", "", "", ""};
|
|---|
| 803 | static const char *stxtWh[16] = {"", "user ", "reader ", "server ", "lserver ", "", "", "", "", "", "", "", "" , "" , "", ""};
|
|---|
| 804 | #ifdef CS_CACHEEX_AIO
|
|---|
| 805 | char sby[100] = "", sreason[35] = "", scwcinfo[32] = "", schaninfo[CS_SERVICENAME_SIZE] = "", srealecmtime[50]="";
|
|---|
| 806 | #else
|
|---|
| 807 | char sby[100] = "", sreason[32] = "", scwcinfo[32] = "", schaninfo[CS_SERVICENAME_SIZE] = "", srealecmtime[50]="";
|
|---|
| 808 | #endif
|
|---|
| 809 | char erEx[32] = "";
|
|---|
| 810 | char usrname[38] = "";
|
|---|
| 811 | char channame[28];
|
|---|
| 812 | struct timeb tpe;
|
|---|
| 813 |
|
|---|
| 814 | snprintf(usrname, sizeof(usrname) - 1, "%s", username(client));
|
|---|
| 815 |
|
|---|
| 816 | #ifdef WITH_DEBUG
|
|---|
| 817 | if(cs_dblevel & D_CLIENTECM)
|
|---|
| 818 | {
|
|---|
| 819 | char buf[ECM_FMT_LEN];
|
|---|
| 820 | char ecmd5[17 * 3];
|
|---|
| 821 | char cwstr[17 * 3];
|
|---|
| 822 | format_ecm(er, buf, ECM_FMT_LEN);
|
|---|
| 823 | cs_hexdump(0, er->ecmd5, 16, ecmd5, sizeof(ecmd5));
|
|---|
| 824 | cs_hexdump(0, er->cw, 16, cwstr, sizeof(cwstr));
|
|---|
| 825 | #ifdef CS_CACHEEX
|
|---|
| 826 | char csphash[5 * 3];
|
|---|
| 827 | cs_hexdump(0, (void *)&er->csp_hash, 4, csphash, sizeof(csphash));
|
|---|
| 828 | cs_log_dbg(D_CLIENTECM, "Client %s csphash %s cw %s rc %d %s", username(client), csphash, cwstr, er->rc, buf);
|
|---|
| 829 | #else
|
|---|
| 830 | cs_log_dbg(D_CLIENTECM, "Client %s cw %s rc %d %s", username(client), cwstr, er->rc, buf);
|
|---|
| 831 | #endif
|
|---|
| 832 | }
|
|---|
| 833 | #endif
|
|---|
| 834 |
|
|---|
| 835 | struct s_reader *er_reader = er->selected_reader; // responding reader
|
|---|
| 836 | struct s_ecm_answer *ea_orig = get_ecm_answer(er_reader, er);
|
|---|
| 837 |
|
|---|
| 838 |
|
|---|
| 839 | // check if ecm_answer from pending's
|
|---|
| 840 | if(ea_orig && ea_orig->is_pending && er->rc == E_FOUND)
|
|---|
| 841 | { er->rc = E_CACHE2; }
|
|---|
| 842 |
|
|---|
| 843 |
|
|---|
| 844 | // check if answer from cacheex-1 reader
|
|---|
| 845 | if(er->rc == E_FOUND && er_reader && cacheex_reader(er_reader)) // so add hit to cacheex mode 1 readers
|
|---|
| 846 | {
|
|---|
| 847 | er->rc = E_CACHEEX;
|
|---|
| 848 | }
|
|---|
| 849 |
|
|---|
| 850 | // real ecm time
|
|---|
| 851 | if(ea_orig && !ea_orig->is_pending && er->rc == E_FOUND
|
|---|
| 852 | && (
|
|---|
| 853 | #ifdef CS_CACHEEX
|
|---|
| 854 | er->cacheex_wait_time ||
|
|---|
| 855 | #endif
|
|---|
| 856 | (ea_orig->status & READER_FALLBACK)))
|
|---|
| 857 | {
|
|---|
| 858 | snprintf(srealecmtime, sizeof(srealecmtime) - 1, " (real %d ms)", ea_orig->ecm_time);
|
|---|
| 859 | }
|
|---|
| 860 |
|
|---|
| 861 |
|
|---|
| 862 | if(er->rc == E_TIMEOUT)
|
|---|
| 863 | {
|
|---|
| 864 | #ifdef CS_CACHEEX
|
|---|
| 865 | if(!er->from_cacheex1_client) // cosmetic: show "by" readers only for "normal" clients
|
|---|
| 866 | {
|
|---|
| 867 | #endif
|
|---|
| 868 | struct s_ecm_answer *ea_list;
|
|---|
| 869 | int32_t ofs = 0;
|
|---|
| 870 |
|
|---|
| 871 | for(ea_list = er->matching_rdr; ea_list; ea_list = ea_list->next)
|
|---|
| 872 | {
|
|---|
| 873 | if(ea_list->reader && ofs < (int32_t)sizeof(sby) && ((ea_list->status & REQUEST_SENT) && (ea_list->rc == E_TIMEOUT || ea_list->rc >= E_99))) //Request send, but no cw answered!
|
|---|
| 874 | {
|
|---|
| 875 | ofs += snprintf(sby + ofs, sizeof(sby) - ofs - 1, "%s%s", ofs ? "," : " by ", ea_list->reader->label);
|
|---|
| 876 | }
|
|---|
| 877 | }
|
|---|
| 878 |
|
|---|
| 879 | if(er->ocaid && ofs < (int32_t)sizeof(sby))
|
|---|
| 880 | { snprintf(sby + ofs, sizeof(sby) - ofs - 1, "(btun %04X)", er->ocaid); }
|
|---|
| 881 |
|
|---|
| 882 | #ifdef CS_CACHEEX
|
|---|
| 883 | }
|
|---|
| 884 | #endif
|
|---|
| 885 | }
|
|---|
| 886 | else if(er_reader)
|
|---|
| 887 | {
|
|---|
| 888 | // add marker to reader if ECM_REQUEST was betatunneled
|
|---|
| 889 | if(er->ocaid)
|
|---|
| 890 | { snprintf(sby, sizeof(sby) - 1, " by %s(btun %04X)", er_reader->label, er->ocaid); }
|
|---|
| 891 | else
|
|---|
| 892 | { snprintf(sby, sizeof(sby) - 1, " by %s", er_reader->label); }
|
|---|
| 893 | }
|
|---|
| 894 | #ifdef CS_CACHEEX
|
|---|
| 895 | else if(er->cacheex_src) // only for cacheex mode-3 clients (no mode-1 or mode-2 because reader is set!) and csp
|
|---|
| 896 | {
|
|---|
| 897 | char *cex_name = "-";
|
|---|
| 898 | if(check_client(er->cacheex_src) && er->cacheex_src->account)
|
|---|
| 899 | {
|
|---|
| 900 | if(er->cacheex_src->account->usr[0] != '\0')
|
|---|
| 901 | cex_name = er->cacheex_src->account->usr;
|
|---|
| 902 | else
|
|---|
| 903 | cex_name = "csp";
|
|---|
| 904 | }
|
|---|
| 905 |
|
|---|
| 906 | if(er->ocaid)
|
|---|
| 907 | {
|
|---|
| 908 | snprintf(sby, sizeof(sby) - 1, " by %s(btun %04X)", cex_name, er->ocaid);
|
|---|
| 909 | }
|
|---|
| 910 | else
|
|---|
| 911 | {
|
|---|
| 912 | snprintf(sby, sizeof(sby) - 1, " by %s", cex_name);
|
|---|
| 913 | }
|
|---|
| 914 | }
|
|---|
| 915 | #endif
|
|---|
| 916 |
|
|---|
| 917 | if(er->rc < E_NOTFOUND)
|
|---|
| 918 | {
|
|---|
| 919 | er->rcEx = 0;
|
|---|
| 920 | memset(er->msglog, 0, MSGLOGSIZE); // remove reader msglog from previous requests that failed, founds never give back msglog!
|
|---|
| 921 | }
|
|---|
| 922 |
|
|---|
| 923 | if(er->rcEx)
|
|---|
| 924 | { snprintf(erEx, sizeof(erEx) - 1, "rejected %s%s", stxtWh[er->rcEx >> 4], stxtEx[er->rcEx & 0xf]); }
|
|---|
| 925 |
|
|---|
| 926 | get_servicename_or_null(client, er->srvid, er->prid, er->caid, channame, sizeof(channame));
|
|---|
| 927 | if(!channame[0])
|
|---|
| 928 | {
|
|---|
| 929 | schaninfo[0] = '\0';
|
|---|
| 930 | }
|
|---|
| 931 | else
|
|---|
| 932 | {
|
|---|
| 933 | snprintf(schaninfo, sizeof(schaninfo) - 1, " - %s", channame);
|
|---|
| 934 | }
|
|---|
| 935 |
|
|---|
| 936 | if(er->msglog[0])
|
|---|
| 937 | { snprintf(sreason, sizeof(sreason) - 1, " (%.26s)", er->msglog); }
|
|---|
| 938 | #ifdef CW_CYCLE_CHECK
|
|---|
| 939 | if(er->cwc_msg_log[0])
|
|---|
| 940 | { snprintf(scwcinfo, sizeof(scwcinfo) - 1, " (%.26s)", er->cwc_msg_log); }
|
|---|
| 941 | #endif
|
|---|
| 942 |
|
|---|
| 943 | cs_ftime(&tpe);
|
|---|
| 944 |
|
|---|
| 945 | #ifdef CS_CACHEEX
|
|---|
| 946 | int cx = 0;
|
|---|
| 947 | if(er->rc >= E_CACHEEX && er->cacheex_wait_time && er->cacheex_wait_time_expired)
|
|---|
| 948 | {
|
|---|
| 949 | cx = snprintf ( sreason, sizeof sreason, " (wait_time over)");
|
|---|
| 950 | }
|
|---|
| 951 |
|
|---|
| 952 | if(er->cw_count>1)
|
|---|
| 953 | {
|
|---|
| 954 | #ifdef CS_CACHEEX_AIO
|
|---|
| 955 | if(er->cw_count > 0x0F000000 || er->localgenerated)
|
|---|
| 956 | {
|
|---|
| 957 | uint32_t cw_count_cleaned = er->cw_count ^ 0x0F000000;
|
|---|
| 958 | if(cw_count_cleaned > 1)
|
|---|
| 959 | snprintf(sreason+cx, (sizeof sreason)-cx, " (cw count %d) (lg)", cw_count_cleaned);
|
|---|
| 960 | else
|
|---|
| 961 | snprintf(sreason+cx, (sizeof sreason)-cx, " (lg)");
|
|---|
| 962 | }
|
|---|
| 963 | else
|
|---|
| 964 | {
|
|---|
| 965 | #endif
|
|---|
| 966 |
|
|---|
| 967 | snprintf (sreason+cx, (sizeof sreason)-cx, " (cw count %d)", er->cw_count);
|
|---|
| 968 |
|
|---|
| 969 | #ifdef CS_CACHEEX_AIO
|
|---|
| 970 | }
|
|---|
| 971 |
|
|---|
| 972 | }
|
|---|
| 973 | else
|
|---|
| 974 | {
|
|---|
| 975 | if(er->localgenerated)
|
|---|
| 976 | snprintf(sreason+cx, (sizeof sreason)-cx, " (lg)");
|
|---|
| 977 | #endif
|
|---|
| 978 | }
|
|---|
| 979 |
|
|---|
| 980 | #endif
|
|---|
| 981 |
|
|---|
| 982 | client->cwlastresptime = comp_timeb(&tpe, &er->tps);
|
|---|
| 983 |
|
|---|
| 984 | time_t now = time(NULL);
|
|---|
| 985 | webif_client_add_lastresponsetime(client, client->cwlastresptime, now, er->rc); // add to ringbuffer
|
|---|
| 986 |
|
|---|
| 987 | if(er_reader)
|
|---|
| 988 | {
|
|---|
| 989 | struct s_client *er_cl = er_reader->client;
|
|---|
| 990 | if(check_client(er_cl))
|
|---|
| 991 | {
|
|---|
| 992 | er_cl->cwlastresptime = client->cwlastresptime;
|
|---|
| 993 | webif_client_add_lastresponsetime(er_cl, client->cwlastresptime, now, er->rc);
|
|---|
| 994 | er_cl->last_providptr = client->last_providptr;
|
|---|
| 995 | er_cl->last_srvidptr = client->last_srvidptr;
|
|---|
| 996 | }
|
|---|
| 997 | }
|
|---|
| 998 |
|
|---|
| 999 | webif_client_init_lastreader(client, er, er_reader, stxt);
|
|---|
| 1000 |
|
|---|
| 1001 | client->last = now;
|
|---|
| 1002 |
|
|---|
| 1003 | //cs_log_dbg(D_TRACE, "CHECK rc=%d er->cacheex_src=%s", er->rc, username(er->cacheex_src));
|
|---|
| 1004 | switch(er->rc)
|
|---|
| 1005 | {
|
|---|
| 1006 | case E_FOUND:
|
|---|
| 1007 | {
|
|---|
| 1008 | client->cwfound++;
|
|---|
| 1009 | client->account->cwfound++;
|
|---|
| 1010 | first_client->cwfound++;
|
|---|
| 1011 | break;
|
|---|
| 1012 | }
|
|---|
| 1013 | case E_CACHE1:
|
|---|
| 1014 | case E_CACHE2:
|
|---|
| 1015 | case E_CACHEEX:
|
|---|
| 1016 | {
|
|---|
| 1017 | client->cwcache++;
|
|---|
| 1018 | client->account->cwcache++;
|
|---|
| 1019 | first_client->cwcache++;
|
|---|
| 1020 | #ifdef CS_CACHEEX
|
|---|
| 1021 | if(check_client(er->cacheex_src))
|
|---|
| 1022 | {
|
|---|
| 1023 | first_client->cwcacheexhit++;
|
|---|
| 1024 | er->cacheex_src->cwcacheexhit++;
|
|---|
| 1025 | if(er->cacheex_src->account)
|
|---|
| 1026 | { er->cacheex_src->account->cwcacheexhit++; }
|
|---|
| 1027 | }
|
|---|
| 1028 | #endif
|
|---|
| 1029 | break;
|
|---|
| 1030 | }
|
|---|
| 1031 | case E_NOTFOUND:
|
|---|
| 1032 | case E_CORRUPT:
|
|---|
| 1033 | case E_NOCARD:
|
|---|
| 1034 | {
|
|---|
| 1035 | if(er->rcEx)
|
|---|
| 1036 | {
|
|---|
| 1037 | client->cwignored++;
|
|---|
| 1038 | client->account->cwignored++;
|
|---|
| 1039 | first_client->cwignored++;
|
|---|
| 1040 | }
|
|---|
| 1041 | else
|
|---|
| 1042 | {
|
|---|
| 1043 | client->cwnot++;
|
|---|
| 1044 | client->account->cwnot++;
|
|---|
| 1045 | first_client->cwnot++;
|
|---|
| 1046 | }
|
|---|
| 1047 | break;
|
|---|
| 1048 | }
|
|---|
| 1049 | case E_TIMEOUT:
|
|---|
| 1050 | {
|
|---|
| 1051 | client->cwtout++;
|
|---|
| 1052 | client->account->cwtout++;
|
|---|
| 1053 | first_client->cwtout++;
|
|---|
| 1054 | break;
|
|---|
| 1055 | }
|
|---|
| 1056 | default:
|
|---|
| 1057 | {
|
|---|
| 1058 | client->cwignored++;
|
|---|
| 1059 | client->account->cwignored++;
|
|---|
| 1060 | first_client->cwignored++;
|
|---|
| 1061 | }
|
|---|
| 1062 | }
|
|---|
| 1063 |
|
|---|
| 1064 | #ifdef CS_ANTICASC
|
|---|
| 1065 | // [zaplist] ACoSC anticascading
|
|---|
| 1066 | if(cfg.acosc_enabled)
|
|---|
| 1067 | {
|
|---|
| 1068 | int8_t max_active_sids = 0;
|
|---|
| 1069 | int8_t zap_limit = 0;
|
|---|
| 1070 | int8_t penalty = 0;
|
|---|
| 1071 | int32_t penalty_duration = 0;
|
|---|
| 1072 | int32_t delay = 0;
|
|---|
| 1073 | int8_t max_ecms_per_minute = 0;
|
|---|
| 1074 | char *info1 = NULL;
|
|---|
| 1075 | char *info2 = NULL;
|
|---|
| 1076 | char *info3 = NULL;
|
|---|
| 1077 | char *info4 = NULL;
|
|---|
| 1078 | char *info5 = NULL;
|
|---|
| 1079 | char *info6 = NULL;
|
|---|
| 1080 |
|
|---|
| 1081 | // **global or user value?
|
|---|
| 1082 | cs_writelock(__func__, &clientlist_lock);
|
|---|
| 1083 |
|
|---|
| 1084 | max_active_sids = client->account->acosc_max_active_sids == -1 ? cfg.acosc_max_active_sids : client->account->acosc_max_active_sids;
|
|---|
| 1085 | info1 = client->account->acosc_max_active_sids == -1 ? "Globalvalue" : "Uservalue";
|
|---|
| 1086 |
|
|---|
| 1087 | zap_limit = client->account->acosc_zap_limit == -1 ? cfg.acosc_zap_limit : client->account->acosc_zap_limit;
|
|---|
| 1088 | info5 = client->account->acosc_zap_limit == -1 ? "Globalvalue" : "Uservalue";
|
|---|
| 1089 |
|
|---|
| 1090 | penalty = client->account->acosc_penalty == -1 ? cfg.acosc_penalty : client->account->acosc_penalty;
|
|---|
| 1091 | info2 = client->account->acosc_penalty == -1 ? "Globalvalue" : "Uservalue";
|
|---|
| 1092 |
|
|---|
| 1093 | penalty_duration = client->account->acosc_penalty_duration == -1 ? cfg.acosc_penalty_duration : client->account->acosc_penalty_duration;
|
|---|
| 1094 | info3 = client->account->acosc_penalty_duration == -1 ? "Globalvalue" : "Uservalue";
|
|---|
| 1095 |
|
|---|
| 1096 | delay = client->account->acosc_delay == -1 ? cfg.acosc_delay : client->account->acosc_delay;
|
|---|
| 1097 | info4 = client->account->acosc_delay == -1 ? "Globalvalue" : "Uservalue";
|
|---|
| 1098 |
|
|---|
| 1099 | max_ecms_per_minute = client->account->acosc_max_ecms_per_minute == -1 ? cfg.acosc_max_ecms_per_minute : client->account->acosc_max_ecms_per_minute;
|
|---|
| 1100 | info6 = client->account->acosc_max_ecms_per_minute == -1 ? "Globalvalue" : "Uservalue";
|
|---|
| 1101 |
|
|---|
| 1102 | //**
|
|---|
| 1103 |
|
|---|
| 1104 | if((er->rc < E_NOTFOUND && max_active_sids > 0) || zap_limit > 0 || max_ecms_per_minute > 0)
|
|---|
| 1105 | {
|
|---|
| 1106 | int8_t k = 0;
|
|---|
| 1107 | int8_t active_sid_count = 0;
|
|---|
| 1108 | time_t zaptime = time(NULL);
|
|---|
| 1109 |
|
|---|
| 1110 | if(client->account->acosc_penalty_active == 4 && client->account->acosc_penalty_until <= zaptime) // reset penalty_active
|
|---|
| 1111 | {
|
|---|
| 1112 | client->account->acosc_penalty_active = 0;
|
|---|
| 1113 | client->account->acosc_penalty_until = 0;
|
|---|
| 1114 | }
|
|---|
| 1115 |
|
|---|
| 1116 | if(client->account->acosc_penalty_active == 0 && max_active_sids > 0)
|
|---|
| 1117 | {
|
|---|
| 1118 | for(k=0; k<15 ; k++)
|
|---|
| 1119 | {
|
|---|
| 1120 | if(zaptime-30 < client->client_zap_list[k].lasttime && client->client_zap_list[k].request_stage == 10)
|
|---|
| 1121 | {
|
|---|
| 1122 | cs_log_dbg(D_TRACE, "[zaplist] ACoSC for Client: %s more then 10 ECM's for %04X@%06X/%04X/%04X", username(client), client->client_zap_list[k].caid, client->client_zap_list[k].provid, client->client_zap_list[k].chid, client->client_zap_list[k].sid);
|
|---|
| 1123 | active_sid_count ++;
|
|---|
| 1124 | }
|
|---|
| 1125 | }
|
|---|
| 1126 | cs_log_dbg(D_TRACE, "[zaplist] ACoSC for Client: %s active_sid_count= %i with more than 10 followed ECM's (mas:%i (%s))", username(client), active_sid_count, max_active_sids, info1);
|
|---|
| 1127 | }
|
|---|
| 1128 |
|
|---|
| 1129 | if(client->account->acosc_penalty_active == 0 && max_active_sids > 0 && active_sid_count > max_active_sids) //max_active_sids reached
|
|---|
| 1130 | {
|
|---|
| 1131 | client->account->acosc_penalty_active = 1;
|
|---|
| 1132 | client->account->acosc_penalty_until = zaptime + penalty_duration;
|
|---|
| 1133 | }
|
|---|
| 1134 |
|
|---|
| 1135 | if(client->account->acosc_penalty_active == 0 && zap_limit > 0 && client->account->acosc_user_zap_count > zap_limit) // zap_limit reached
|
|---|
| 1136 | {
|
|---|
| 1137 | client->account->acosc_penalty_active = 2;
|
|---|
| 1138 | client->account->acosc_penalty_until = zaptime + penalty_duration;
|
|---|
| 1139 | }
|
|---|
| 1140 |
|
|---|
| 1141 | if(client->account->acosc_penalty_active == 0 && max_ecms_per_minute > 0 && client->n_request[1] >= max_ecms_per_minute && penalty != 4) // max ecms per minute reached
|
|---|
| 1142 | {
|
|---|
| 1143 | client->account->acosc_penalty_active = 3;
|
|---|
| 1144 | client->account->acosc_penalty_until = zaptime + penalty_duration;
|
|---|
| 1145 | }
|
|---|
| 1146 |
|
|---|
| 1147 | if(client->account->acosc_penalty_active == 0 && max_ecms_per_minute > 0 && client->n_request[1] > 0 && penalty == 4) // max ecms per minute with hidecards penalty
|
|---|
| 1148 | {
|
|---|
| 1149 | client->account->acosc_penalty_active = 3;
|
|---|
| 1150 | client->account->acosc_penalty_until = zaptime + penalty_duration;
|
|---|
| 1151 | }
|
|---|
| 1152 |
|
|---|
| 1153 | if(client->account->acosc_penalty_active > 0)
|
|---|
| 1154 | {
|
|---|
| 1155 | if(client->account->acosc_penalty_active == 4)
|
|---|
| 1156 | { cs_log_dbg(D_TRACE, "[zaplist] ACoSC for Client: %s penalty_duration: %ld seconds left(%s)", username(client), client->account->acosc_penalty_until - zaptime, info3); }
|
|---|
| 1157 |
|
|---|
| 1158 | int16_t lt = get_module(client)->listenertype;
|
|---|
| 1159 | switch(penalty)
|
|---|
| 1160 | {
|
|---|
| 1161 | case 1: // NULL CW
|
|---|
| 1162 | er->rc = E_FAKE; // E_FAKE give only a status fake not a NULL cw
|
|---|
| 1163 | er->rcEx = E2_WRONG_CHKSUM;
|
|---|
| 1164 | if(client->account->acosc_penalty_active == 1)
|
|---|
| 1165 | { cs_log("[zaplist] ACoSC for Client: %s max_activ_sids reached: %i:%i(%s) penalty: 1(%s) send null CW", username(client), active_sid_count, max_active_sids, info1, info2); }
|
|---|
| 1166 | if(client->account->acosc_penalty_active == 2)
|
|---|
| 1167 | { cs_log("[zaplist] ACoSC for Client: %s zap_limit reached: %i:%i(%s) penalty: 1(%s) send null CW", username(client), client->account->acosc_user_zap_count, zap_limit, info5, info2); }
|
|---|
| 1168 | if(client->account->acosc_penalty_active == 3)
|
|---|
| 1169 | { cs_log("[maxecms] ACoSC for Client: %s max_ecms_per_minute reached: ecms_last_minute=%i ecms_now=%i max=%i(%s) penalty: 1(%s) send null CW", username(client), client->n_request[0], client->n_request[1], max_ecms_per_minute, info6, info2); }
|
|---|
| 1170 | break;
|
|---|
| 1171 |
|
|---|
| 1172 | case 2: // ban
|
|---|
| 1173 | if(lt != LIS_DVBAPI)
|
|---|
| 1174 | {
|
|---|
| 1175 | if(client->account->acosc_penalty_active == 1)
|
|---|
| 1176 | { cs_log("[zaplist] ACoSC for Client: %s max_activ_sids reached: %i:%i(%s) penalty: 2(%s) BAN Client - Kill and set Client to failban list for %i sec.", username(client), active_sid_count, max_active_sids, info1, info2, penalty_duration); }
|
|---|
| 1177 | if(client->account->acosc_penalty_active == 2)
|
|---|
| 1178 | { cs_log("[zaplist] ACoSC for Client: %s zap_limit reached: %i:%i(%s) penalty: 2(%s) BAN Client - Kill and set Client to failban list for %i sec.", username(client), client->account->acosc_user_zap_count, zap_limit, info5, info2, penalty_duration); }
|
|---|
| 1179 | if(client->account->acosc_penalty_active == 3)
|
|---|
| 1180 | { cs_log("[maxecms] ACoSC for Client: %s max_ecms_per_minute reached: ecms_last_minute=%i ecms_now=%i max=%i(%s) penalty: 2(%s) BAN Client - Kill and set Client to failban list for %i sec.", username(client), client->n_request[0], client->n_request[1], max_ecms_per_minute, info6, info2, penalty_duration); }
|
|---|
| 1181 | cs_add_violation_acosc(client, client->account->usr, penalty_duration);
|
|---|
| 1182 | add_job(client, ACTION_CLIENT_KILL, NULL, 0);
|
|---|
| 1183 | }
|
|---|
| 1184 | else
|
|---|
| 1185 | {
|
|---|
| 1186 | cs_log("[zaplist] ACoSC for Client: %s %i:%i(%s) penalty: 2(%s) BAN Client - don't Ban dvbapi user only stop decoding", username(client), active_sid_count, max_active_sids, info1, info2);
|
|---|
| 1187 | }
|
|---|
| 1188 | er->rc = E_DISABLED;
|
|---|
| 1189 | break;
|
|---|
| 1190 |
|
|---|
| 1191 | case 3: // delay
|
|---|
| 1192 | if(client->account->acosc_penalty_active == 1)
|
|---|
| 1193 | { cs_log("[zaplist] ACoSC for Client: %s max_activ_sids reached: %i:%i(%s) penalty: 3(%s) delay CW: %ims(%s)", username(client), active_sid_count, max_active_sids, info1, info2, delay, info4); }
|
|---|
| 1194 | if(client->account->acosc_penalty_active == 2)
|
|---|
| 1195 | { cs_log("[zaplist] ACoSC for Client: %s zap_limit reached: %i:%i(%s) penalty: 3(%s) delay CW: %ims(%s)", username(client), client->account->acosc_user_zap_count, zap_limit, info5, info2, delay, info4); }
|
|---|
| 1196 | if(client->account->acosc_penalty_active == 3)
|
|---|
| 1197 | { cs_log("[maxecms] ACoSC for Client: %s max_ecms_per_minute reached: ecms_last_minute=%i ecms_now=%i max=%i(%s) penalty: 3(%s) delay CW: %ims(%s)", username(client), client->n_request[0], client->n_request[1], max_ecms_per_minute, info6, info2, delay, info4); }
|
|---|
| 1198 | cs_writeunlock(__func__, &clientlist_lock);
|
|---|
| 1199 | cs_sleepms(delay);
|
|---|
| 1200 | cs_writelock(__func__, &clientlist_lock);
|
|---|
| 1201 | client->cwlastresptime += delay;
|
|---|
| 1202 | snprintf(sreason, sizeof(sreason)-1, " (%d ms penalty delay)", delay);
|
|---|
| 1203 | break;
|
|---|
| 1204 | case 4: // hidecards
|
|---|
| 1205 | if(client->account->acosc_penalty_active == 3)
|
|---|
| 1206 | {
|
|---|
| 1207 | cs_log("[maxecms] ACoSC for Client: %s ecms_last_minute=%i ecms_now=%i max=%i(%s) penalty: 4(%s) hidecards - hidecards to the client for %i sec", username(client), client->n_request[0], client->n_request[1], max_ecms_per_minute, info6, info2, penalty_duration);
|
|---|
| 1208 | client->start_hidecards = 1;
|
|---|
| 1209 | }
|
|---|
| 1210 | break;
|
|---|
| 1211 | default: // logging
|
|---|
| 1212 | if(client->account->acosc_penalty_active == 1)
|
|---|
| 1213 | { cs_log("[zaplist] ACoSC for Client: %s max_activ_sids reached: %i:%i(%s) penalty: 0(%s) only logging", username(client), active_sid_count, max_active_sids, info1, info2); }
|
|---|
| 1214 | if(client->account->acosc_penalty_active == 2)
|
|---|
| 1215 | { cs_log("[zaplist] ACoSC for Client: %s zap_limit reached: %i:%i(%s) penalty: 0(%s) only logging", username(client), client->account->acosc_user_zap_count, zap_limit, info5, info2); }
|
|---|
| 1216 | if(client->account->acosc_penalty_active == 3)
|
|---|
| 1217 | { cs_log("[maxecms] ACoSC for Client: %s max_ecms_per_minute reached: ecms_last_minute=%i ecms_now=%i max=%i(%s) penalty: 0(%s) only logging", username(client), client->n_request[0], client->n_request[1], max_ecms_per_minute, info6, info2); }
|
|---|
| 1218 | break;
|
|---|
| 1219 | }
|
|---|
| 1220 | client->account->acosc_user_zap_count = 0; // we got already a penalty
|
|---|
| 1221 | client->account->acosc_penalty_active = 3;
|
|---|
| 1222 | client->account->acosc_penalty_active = 4;
|
|---|
| 1223 | }
|
|---|
| 1224 | }
|
|---|
| 1225 | cs_writeunlock(__func__, &clientlist_lock);
|
|---|
| 1226 | }
|
|---|
| 1227 | #endif
|
|---|
| 1228 |
|
|---|
| 1229 | if(cfg.double_check && er->rc <= E_CACHE2 && er->selected_reader && is_double_check_caid(er, &cfg.double_check_caid))
|
|---|
| 1230 | {
|
|---|
| 1231 | if(er->checked == 0) // First CW, save it and wait for next one
|
|---|
| 1232 | {
|
|---|
| 1233 | er->checked = 1;
|
|---|
| 1234 | er->origin_reader = er->selected_reader;
|
|---|
| 1235 | memcpy(er->cw_checked, er->cw, sizeof(er->cw));
|
|---|
| 1236 | cs_log("DOUBLE CHECK FIRST CW by %s idx %d cpti %d", er->origin_reader->label, er->idx, er->msgid);
|
|---|
| 1237 | }
|
|---|
| 1238 | else if(er->origin_reader != er->selected_reader) // Second (or third and so on) cw. We have to compare
|
|---|
| 1239 | {
|
|---|
| 1240 | if(memcmp(er->cw_checked, er->cw, sizeof(er->cw)) == 0)
|
|---|
| 1241 | {
|
|---|
| 1242 | er->checked++;
|
|---|
| 1243 | cs_log("DOUBLE CHECKED! %d. CW by %s idx %d cpti %d", er->checked, er->selected_reader->label, er->idx, er->msgid);
|
|---|
| 1244 | }
|
|---|
| 1245 | else
|
|---|
| 1246 | {
|
|---|
| 1247 | cs_log("DOUBLE CHECKED NONMATCHING! %d. CW by %s idx %d cpti %d", er->checked, er->selected_reader->label, er->idx, er->msgid);
|
|---|
| 1248 | }
|
|---|
| 1249 | }
|
|---|
| 1250 | if(er->checked < 2) // less as two same cw? mark as pending!
|
|---|
| 1251 | {
|
|---|
| 1252 | er->rc = E_UNHANDLED;
|
|---|
| 1253 | goto ESC;
|
|---|
| 1254 | }
|
|---|
| 1255 | }
|
|---|
| 1256 |
|
|---|
| 1257 | ac_chk(client, er, 1);
|
|---|
| 1258 | int32_t is_fake = 0;
|
|---|
| 1259 | if(er->rc == E_FAKE)
|
|---|
| 1260 | {
|
|---|
| 1261 | is_fake = 1;
|
|---|
| 1262 | er->rc = E_FOUND;
|
|---|
| 1263 | }
|
|---|
| 1264 |
|
|---|
| 1265 | get_module(client)->send_dcw(client, er);
|
|---|
| 1266 |
|
|---|
| 1267 | add_cascade_data(client, er);
|
|---|
| 1268 |
|
|---|
| 1269 | if(is_fake)
|
|---|
| 1270 | { er->rc = E_FAKE; }
|
|---|
| 1271 |
|
|---|
| 1272 | #ifdef CS_ANTICASC
|
|---|
| 1273 | cs_writelock(__func__, &clientlist_lock);
|
|---|
| 1274 | if(client->start_hidecards)
|
|---|
| 1275 | {
|
|---|
| 1276 | client->start_hidecards = 0;
|
|---|
| 1277 | add_job(client, ACTION_CLIENT_HIDECARDS, NULL, 0);
|
|---|
| 1278 | }
|
|---|
| 1279 | cs_writeunlock(__func__, &clientlist_lock);
|
|---|
| 1280 | #endif
|
|---|
| 1281 |
|
|---|
| 1282 | if(!(er->rc == E_SLEEPING && client->cwlastresptime == 0))
|
|---|
| 1283 | {
|
|---|
| 1284 | char buf[ECM_FMT_LEN];
|
|---|
| 1285 | format_ecm(er, buf, ECM_FMT_LEN);
|
|---|
| 1286 | if(er->reader_avail == 1 || er->stage == 0)
|
|---|
| 1287 | {
|
|---|
| 1288 | cs_log("%s (%s): %s (%d ms)%s%s%s%s", usrname, buf, er->rcEx ? erEx : stxt[er->rc],
|
|---|
| 1289 | client->cwlastresptime, sby, schaninfo, sreason, scwcinfo);
|
|---|
| 1290 | }
|
|---|
| 1291 | else
|
|---|
| 1292 | {
|
|---|
| 1293 | cs_log("%s (%s): %s (%d ms)%s (%c/%d/%d/%d)%s%s%s%s", usrname, buf, er->rcEx ? erEx : stxt[er->rc],
|
|---|
| 1294 | client->cwlastresptime, sby, stageTxt[er->stage], er->reader_requested,
|
|---|
| 1295 | (er->reader_count + er->fallback_reader_count), er->reader_avail, schaninfo,
|
|---|
| 1296 | srealecmtime, sreason, scwcinfo);
|
|---|
| 1297 | }
|
|---|
| 1298 | }
|
|---|
| 1299 |
|
|---|
| 1300 | cs_log_dump_dbg(D_ATR, er->cw, 16, "cw:");
|
|---|
| 1301 | led_status_cw_not_found(er);
|
|---|
| 1302 |
|
|---|
| 1303 | ESC:
|
|---|
| 1304 |
|
|---|
| 1305 | return 0;
|
|---|
| 1306 | }
|
|---|
| 1307 |
|
|---|
| 1308 | /*
|
|---|
| 1309 | * write_ecm_request():
|
|---|
| 1310 | */
|
|---|
| 1311 | static int32_t write_ecm_request(struct s_reader *rdr, ECM_REQUEST *er)
|
|---|
| 1312 | {
|
|---|
| 1313 | add_job(rdr->client, ACTION_READER_ECM_REQUEST, (void *)er, 0);
|
|---|
| 1314 | return 1;
|
|---|
| 1315 | }
|
|---|
| 1316 |
|
|---|
| 1317 | /**
|
|---|
| 1318 | * sends the ecm request to the readers
|
|---|
| 1319 | * ECM_REQUEST er : the ecm
|
|---|
| 1320 | * er->stage: 0 = no reader asked yet
|
|---|
| 1321 | * 2 = ask only local reader (skipped without preferlocalcards)
|
|---|
| 1322 | * 3 = ask any non fallback reader
|
|---|
| 1323 | * 4 = ask fallback reader
|
|---|
| 1324 | **/
|
|---|
| 1325 | void request_cw_from_readers(ECM_REQUEST *er, uint8_t stop_stage)
|
|---|
| 1326 | {
|
|---|
| 1327 | struct s_ecm_answer *ea;
|
|---|
| 1328 | int8_t sent = 0;
|
|---|
| 1329 |
|
|---|
| 1330 | if(er->stage >= 4) { return; }
|
|---|
| 1331 |
|
|---|
| 1332 | while(1)
|
|---|
| 1333 | {
|
|---|
| 1334 | if(stop_stage && er->stage >= stop_stage) { return; }
|
|---|
| 1335 |
|
|---|
| 1336 | er->stage++;
|
|---|
| 1337 |
|
|---|
| 1338 | #ifdef CS_CACHEEX
|
|---|
| 1339 | if(er->stage == 1 && er->preferlocalcards==2)
|
|---|
| 1340 | { er->stage++; }
|
|---|
| 1341 | #else
|
|---|
| 1342 | if(er->stage == 1)
|
|---|
| 1343 | { er->stage++; }
|
|---|
| 1344 | #endif
|
|---|
| 1345 |
|
|---|
| 1346 | if(er->stage == 2 && !er->preferlocalcards)
|
|---|
| 1347 | { er->stage++; }
|
|---|
| 1348 |
|
|---|
| 1349 | for(ea = er->matching_rdr; ea; ea = ea->next)
|
|---|
| 1350 | {
|
|---|
| 1351 | switch(er->stage)
|
|---|
| 1352 | {
|
|---|
| 1353 | #ifdef CS_CACHEEX
|
|---|
| 1354 | case 1:
|
|---|
| 1355 | {
|
|---|
| 1356 | // Cache-Exchange
|
|---|
| 1357 | if((ea->status & REQUEST_SENT) ||
|
|---|
| 1358 | (ea->status & (READER_CACHEEX | READER_ACTIVE)) != (READER_CACHEEX | READER_ACTIVE))
|
|---|
| 1359 | { continue; }
|
|---|
| 1360 | break;
|
|---|
| 1361 | }
|
|---|
| 1362 | #endif
|
|---|
| 1363 | case 2:
|
|---|
| 1364 | {
|
|---|
| 1365 | // only local reader
|
|---|
| 1366 | if((ea->status & REQUEST_SENT) ||
|
|---|
| 1367 | (ea->status & (READER_ACTIVE | READER_FALLBACK | READER_LOCAL)) != (READER_ACTIVE | READER_LOCAL))
|
|---|
| 1368 | { continue; }
|
|---|
| 1369 | break;
|
|---|
| 1370 | }
|
|---|
| 1371 | case 3:
|
|---|
| 1372 | {
|
|---|
| 1373 | // any non fallback reader not asked yet
|
|---|
| 1374 | if((ea->status & REQUEST_SENT) ||
|
|---|
| 1375 | (ea->status & (READER_ACTIVE | READER_FALLBACK)) != READER_ACTIVE)
|
|---|
| 1376 | { continue; }
|
|---|
| 1377 | break;
|
|---|
| 1378 | }
|
|---|
| 1379 | default:
|
|---|
| 1380 | {
|
|---|
| 1381 | // only fallbacks
|
|---|
| 1382 | if((ea->status & REQUEST_SENT) ||
|
|---|
| 1383 | (ea->status & (READER_ACTIVE | READER_FALLBACK)) != (READER_ACTIVE | READER_FALLBACK))
|
|---|
| 1384 | { continue; }
|
|---|
| 1385 | break;
|
|---|
| 1386 | }
|
|---|
| 1387 | }
|
|---|
| 1388 |
|
|---|
| 1389 | struct s_reader *rdr = ea->reader;
|
|---|
| 1390 | #ifdef WITH_DEBUG
|
|---|
| 1391 | if (cs_dblevel & (D_TRACE | D_CSP))
|
|---|
| 1392 | {
|
|---|
| 1393 | char ecmd5[17 * 3];
|
|---|
| 1394 | cs_hexdump(0, er->ecmd5, 16, ecmd5, sizeof(ecmd5));
|
|---|
| 1395 | cs_log_dbg(D_TRACE | D_CSP, "request_cw stage=%d to reader %s ecm hash=%s", er->stage, rdr ? rdr->label : "", ecmd5);
|
|---|
| 1396 | }
|
|---|
| 1397 | #endif
|
|---|
| 1398 | ea->status |= REQUEST_SENT;
|
|---|
| 1399 | cs_ftime(&ea->time_request_sent);
|
|---|
| 1400 |
|
|---|
| 1401 | er->reader_requested++;
|
|---|
| 1402 |
|
|---|
| 1403 | write_ecm_request(ea->reader, er);
|
|---|
| 1404 |
|
|---|
| 1405 | // set sent=1 only if reader is active/connected. If not, switch to next stage!
|
|---|
| 1406 | if(!sent && rdr)
|
|---|
| 1407 | {
|
|---|
| 1408 | struct s_client *rcl = rdr->client;
|
|---|
| 1409 | if(check_client(rcl))
|
|---|
| 1410 | {
|
|---|
| 1411 | if(rcl->typ == 'r' && rdr->card_status == CARD_INSERTED)
|
|---|
| 1412 | { sent = 1; }
|
|---|
| 1413 | else if(rcl->typ == 'p' && (rdr->card_status == CARD_INSERTED || rdr->tcp_connected))
|
|---|
| 1414 | { sent = 1; }
|
|---|
| 1415 | }
|
|---|
| 1416 | }
|
|---|
| 1417 |
|
|---|
| 1418 | cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} [write_ecm_request] reader %s --> SENT %d", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid, rdr ? ea->reader->label : "-", sent);
|
|---|
| 1419 | }
|
|---|
| 1420 |
|
|---|
| 1421 | if(sent || er->stage >= 4)
|
|---|
| 1422 | { break; }
|
|---|
| 1423 | }
|
|---|
| 1424 | }
|
|---|
| 1425 |
|
|---|
| 1426 | void add_cache_from_reader(ECM_REQUEST *er, struct s_reader *rdr, uint32_t csp_hash, uint8_t *ecmd5, uint8_t *cw, int16_t caid, int32_t prid, int16_t srvid
|
|---|
| 1427 | #ifdef CS_CACHEEX_AIO
|
|---|
| 1428 | , int32_t ecm_time
|
|---|
| 1429 | #endif
|
|---|
| 1430 | )
|
|---|
| 1431 | {
|
|---|
| 1432 | ECM_REQUEST *ecm;
|
|---|
| 1433 | if (cs_malloc(&ecm, sizeof(ECM_REQUEST)))
|
|---|
| 1434 | {
|
|---|
| 1435 | cs_ftime(&ecm->tps);
|
|---|
| 1436 |
|
|---|
| 1437 | ecm->cwc_cycletime = er->cwc_cycletime;
|
|---|
| 1438 | ecm->cwc_next_cw_cycle = er->cwc_next_cw_cycle;
|
|---|
| 1439 | memcpy(ecm->ecm, er->ecm, sizeof(ecm->ecm)); // ecm[0] is pushed to cacheexclients so we need a copy from it
|
|---|
| 1440 | ecm->caid = caid;
|
|---|
| 1441 | ecm->prid = prid;
|
|---|
| 1442 | ecm->srvid = srvid;
|
|---|
| 1443 | memcpy(ecm->ecmd5, ecmd5, CS_ECMSTORESIZE);
|
|---|
| 1444 | ecm->csp_hash = csp_hash;
|
|---|
| 1445 | ecm->rc = E_FOUND;
|
|---|
| 1446 | memcpy(ecm->cw, cw, sizeof(ecm->cw));
|
|---|
| 1447 | ecm->grp = rdr->grp;
|
|---|
| 1448 | ecm->selected_reader = rdr;
|
|---|
| 1449 | #ifdef CS_CACHEEX_AIO
|
|---|
| 1450 | ecm->ecm_time = ecm_time;
|
|---|
| 1451 | ecm->localgenerated = er->localgenerated;
|
|---|
| 1452 | #endif
|
|---|
| 1453 | #ifdef CS_CACHEEX
|
|---|
| 1454 | if(rdr && cacheex_reader(rdr))
|
|---|
| 1455 | { ecm->cacheex_src = rdr->client; } //so adds hits to reader
|
|---|
| 1456 | #endif
|
|---|
| 1457 |
|
|---|
| 1458 | add_cache(ecm); //add cw to cache
|
|---|
| 1459 |
|
|---|
| 1460 | #ifdef CS_CACHEEX
|
|---|
| 1461 | cs_writelock(__func__, &ecm_pushed_deleted_lock);
|
|---|
| 1462 | ecm->next = ecm_pushed_deleted;
|
|---|
| 1463 | ecm_pushed_deleted = ecm;
|
|---|
| 1464 | cs_writeunlock(__func__, &ecm_pushed_deleted_lock);
|
|---|
| 1465 | #else
|
|---|
| 1466 | NULLFREE(ecm);
|
|---|
| 1467 | #endif
|
|---|
| 1468 | }
|
|---|
| 1469 | }
|
|---|
| 1470 |
|
|---|
| 1471 | void chk_dcw(struct s_ecm_answer *ea)
|
|---|
| 1472 | {
|
|---|
| 1473 | if(!ea || !ea->er)
|
|---|
| 1474 | { return; }
|
|---|
| 1475 |
|
|---|
| 1476 | ECM_REQUEST *ert = ea->er;
|
|---|
| 1477 | struct s_ecm_answer *ea_list;
|
|---|
| 1478 | struct s_reader *eardr = ea->reader;
|
|---|
| 1479 | if(!ert || !eardr)
|
|---|
| 1480 | { return; }
|
|---|
| 1481 |
|
|---|
| 1482 | // ecm request already answered!
|
|---|
| 1483 | if(ert->rc < E_99)
|
|---|
| 1484 | {
|
|---|
| 1485 | #ifdef CS_CACHEEX
|
|---|
| 1486 | if(ea && ert->rc < E_NOTFOUND && ea->rc < E_NOTFOUND && memcmp(ea->cw, ert->cw, sizeof(ert->cw)) != 0)
|
|---|
| 1487 | {
|
|---|
| 1488 | char cw1[16 * 3 + 2], cw2[16 * 3 + 2];
|
|---|
| 1489 | #ifdef WITH_DEBUG
|
|---|
| 1490 | if(cs_dblevel & D_TRACE)
|
|---|
| 1491 | {
|
|---|
| 1492 | cs_hexdump(0, ea->cw, 16, cw1, sizeof(cw1));
|
|---|
| 1493 | cs_hexdump(0, ert->cw, 16, cw2, sizeof(cw2));
|
|---|
| 1494 | }
|
|---|
| 1495 | #endif
|
|---|
| 1496 | char ip1[20] = "", ip2[20] = "";
|
|---|
| 1497 | if(ea->reader && check_client(ea->reader->client)) { cs_strncpy(ip1, cs_inet_ntoa(ea->reader->client->ip), sizeof(ip1)); }
|
|---|
| 1498 | if(ert->cacheex_src) { cs_strncpy(ip2, cs_inet_ntoa(ert->cacheex_src->ip), sizeof(ip2)); }
|
|---|
| 1499 | else if(ert->selected_reader && check_client(ert->selected_reader->client)) { cs_strncpy(ip2, cs_inet_ntoa(ert->selected_reader->client->ip), sizeof(ip2)); }
|
|---|
| 1500 |
|
|---|
| 1501 | ECM_REQUEST *er = ert;
|
|---|
| 1502 | debug_ecm(D_TRACE, "WARNING2: Different CWs %s from %s(%s)<>%s(%s): %s<>%s", buf,
|
|---|
| 1503 | username(ea->reader ? ea->reader->client : ert->client), ip1,
|
|---|
| 1504 | er->cacheex_src ? username(er->cacheex_src) : (ert->selected_reader ? ert->selected_reader->label : "unknown/csp"), ip2,
|
|---|
| 1505 | cw1, cw2);
|
|---|
| 1506 | }
|
|---|
| 1507 | #endif
|
|---|
| 1508 |
|
|---|
| 1509 | return;
|
|---|
| 1510 | }
|
|---|
| 1511 |
|
|---|
| 1512 | #ifdef CS_CACHEEX
|
|---|
| 1513 | /* if answer from cacheex-1 reader, not send answer to client!
|
|---|
| 1514 | * thread check_cache will check counter and send answer to client!
|
|---|
| 1515 | * Anyway, we should check if we have to go to oher stage (>1)
|
|---|
| 1516 | */
|
|---|
| 1517 |
|
|---|
| 1518 | if(eardr && cacheex_reader(eardr))
|
|---|
| 1519 | {
|
|---|
| 1520 | // if wait_time, and not wait_time expired and wait_time due to hitcache(or awtime>0),
|
|---|
| 1521 | // we have to wait cacheex timeout before call other readers (stage>1)
|
|---|
| 1522 | if(cacheex_reader(eardr) && !ert->cacheex_wait_time_expired && ert->cacheex_hitcache)
|
|---|
| 1523 | { return; }
|
|---|
| 1524 |
|
|---|
| 1525 | int8_t cacheex_left = 0;
|
|---|
| 1526 | uint8_t has_cacheex = 0;
|
|---|
| 1527 | if(ert->stage == 1)
|
|---|
| 1528 | {
|
|---|
| 1529 | for(ea_list = ert->matching_rdr; ea_list; ea_list = ea_list->next)
|
|---|
| 1530 | {
|
|---|
| 1531 | cs_readlock(__func__, &ea_list->ecmanswer_lock);
|
|---|
| 1532 | if(((ea_list->status & (READER_CACHEEX | READER_FALLBACK | READER_ACTIVE))) == (READER_CACHEEX | READER_ACTIVE))
|
|---|
| 1533 | { has_cacheex = 1; }
|
|---|
| 1534 | if((!(ea_list->status & READER_FALLBACK) && ((ea_list->status & (REQUEST_SENT | REQUEST_ANSWERED | READER_CACHEEX | READER_ACTIVE)) == (REQUEST_SENT | READER_CACHEEX | READER_ACTIVE))) || ea_list->rc < E_NOTFOUND)
|
|---|
| 1535 | { cacheex_left++; }
|
|---|
| 1536 | cs_readunlock(__func__, &ea_list->ecmanswer_lock);
|
|---|
| 1537 | }
|
|---|
| 1538 |
|
|---|
| 1539 | if(has_cacheex && !cacheex_left) { request_cw_from_readers(ert, 0); }
|
|---|
| 1540 | }
|
|---|
| 1541 |
|
|---|
| 1542 | return;
|
|---|
| 1543 | }
|
|---|
| 1544 | #endif
|
|---|
| 1545 |
|
|---|
| 1546 | int32_t reader_left = 0, local_left = 0, reader_not_flb_left = 0, has_not_fallback = 0, has_local = 0;
|
|---|
| 1547 | ert->selected_reader = eardr;
|
|---|
| 1548 |
|
|---|
| 1549 | switch(ea->rc)
|
|---|
| 1550 | {
|
|---|
| 1551 | case E_FOUND:
|
|---|
| 1552 | memcpy(ert->cw, ea->cw, 16);
|
|---|
| 1553 | ert->cw_ex = ea->cw_ex;
|
|---|
| 1554 | ert->rcEx = 0;
|
|---|
| 1555 | ert->rc = ea->rc;
|
|---|
| 1556 | ert->grp |= eardr->grp;
|
|---|
| 1557 | #ifdef HAVE_DVBAPI
|
|---|
| 1558 | ert->adapter_index = ea->er->adapter_index;
|
|---|
| 1559 | #endif
|
|---|
| 1560 | break;
|
|---|
| 1561 |
|
|---|
| 1562 | case E_INVALID:
|
|---|
| 1563 | case E_NOTFOUND:
|
|---|
| 1564 | {
|
|---|
| 1565 | // check if there are other readers to ask, and if not send NOT_FOUND to client
|
|---|
| 1566 | ert->rcEx = ea->rcEx;
|
|---|
| 1567 | cs_strncpy(ert->msglog, ea->msglog, sizeof(ert->msglog));
|
|---|
| 1568 |
|
|---|
| 1569 | for(ea_list = ert->matching_rdr; ea_list; ea_list = ea_list->next)
|
|---|
| 1570 | {
|
|---|
| 1571 | cs_readlock(__func__, &ea_list->ecmanswer_lock);
|
|---|
| 1572 |
|
|---|
| 1573 | if((!(ea_list->status & READER_FALLBACK) && ((ea_list->status & (REQUEST_SENT | REQUEST_ANSWERED | READER_LOCAL | READER_ACTIVE)) == (REQUEST_SENT | READER_LOCAL | READER_ACTIVE))) || ea_list->rc < E_NOTFOUND)
|
|---|
| 1574 | { local_left++; }
|
|---|
| 1575 |
|
|---|
| 1576 | if((!(ea_list->status & READER_FALLBACK) && ((ea_list->status & (REQUEST_SENT | REQUEST_ANSWERED | READER_ACTIVE)) == (REQUEST_SENT | READER_ACTIVE))) || ea_list->rc < E_NOTFOUND)
|
|---|
| 1577 | { reader_not_flb_left++; }
|
|---|
| 1578 |
|
|---|
| 1579 | if(((ea_list->status & (REQUEST_ANSWERED | READER_ACTIVE)) == (READER_ACTIVE)) || ea_list->rc < E_NOTFOUND)
|
|---|
| 1580 | { reader_left++; }
|
|---|
| 1581 |
|
|---|
| 1582 | if(((ea_list->status & (READER_FALLBACK | READER_ACTIVE))) == (READER_ACTIVE))
|
|---|
| 1583 | { has_not_fallback = 1; }
|
|---|
| 1584 | if(((ea_list->status & (READER_LOCAL | READER_FALLBACK | READER_ACTIVE))) == (READER_LOCAL | READER_ACTIVE))
|
|---|
| 1585 | { has_local = 1; }
|
|---|
| 1586 |
|
|---|
| 1587 | cs_readunlock(__func__, &ea_list->ecmanswer_lock);
|
|---|
| 1588 | }
|
|---|
| 1589 |
|
|---|
| 1590 | switch(ert->stage)
|
|---|
| 1591 | {
|
|---|
| 1592 | case 2: // only local reader (used only if preferlocalcards=1)
|
|---|
| 1593 | {
|
|---|
| 1594 | if(has_local && !local_left) { request_cw_from_readers(ert, 0); }
|
|---|
| 1595 | break;
|
|---|
| 1596 | }
|
|---|
| 1597 | case 3:
|
|---|
| 1598 | {
|
|---|
| 1599 | // any fallback reader not asked yet
|
|---|
| 1600 | if(has_not_fallback && !reader_not_flb_left) { request_cw_from_readers(ert, 0); }
|
|---|
| 1601 | break;
|
|---|
| 1602 | }
|
|---|
| 1603 | }
|
|---|
| 1604 |
|
|---|
| 1605 | if(!reader_left // no more matching reader
|
|---|
| 1606 | #ifdef CS_CACHEEX
|
|---|
| 1607 | && !cfg.wait_until_ctimeout
|
|---|
| 1608 | #endif
|
|---|
| 1609 | )
|
|---|
| 1610 | { ert->rc = E_NOTFOUND; } // so we set the return code
|
|---|
| 1611 |
|
|---|
| 1612 | break;
|
|---|
| 1613 | }
|
|---|
| 1614 |
|
|---|
| 1615 | case E_TIMEOUT: // if timeout, we have to send timeout to client: this is done by ecm_timeout callback
|
|---|
| 1616 | return;
|
|---|
| 1617 | break;
|
|---|
| 1618 |
|
|---|
| 1619 | case E_UNHANDLED:
|
|---|
| 1620 | return;
|
|---|
| 1621 | break;
|
|---|
| 1622 |
|
|---|
| 1623 | default:
|
|---|
| 1624 | cs_log("unexpected ecm answer rc=%d.", ea->rc);
|
|---|
| 1625 | return;
|
|---|
| 1626 | break;
|
|---|
| 1627 | }
|
|---|
| 1628 |
|
|---|
| 1629 | if(ert->rc < E_99)
|
|---|
| 1630 | send_dcw(ert->client, ert);
|
|---|
| 1631 | }
|
|---|
| 1632 |
|
|---|
| 1633 | uint32_t chk_provid(uint8_t *ecm, uint16_t caid)
|
|---|
| 1634 | {
|
|---|
| 1635 | int32_t i, len, descriptor_length = 0;
|
|---|
| 1636 | uint32_t provid = 0;
|
|---|
| 1637 |
|
|---|
| 1638 | switch(caid >> 8)
|
|---|
| 1639 | {
|
|---|
| 1640 | case 0x01: // seca
|
|---|
| 1641 | provid = b2i(2, ecm + 3);
|
|---|
| 1642 | break;
|
|---|
| 1643 |
|
|---|
| 1644 | case 0x05: // viaccess
|
|---|
| 1645 | i = (ecm[4] == 0xD2) ? ecm[5] + 2 : 0; // skip d2 nano
|
|---|
| 1646 | if((ecm[5 + i] == 3) && ((ecm[4 + i] == 0x90) || (ecm[4 + i] == 0x40)))
|
|---|
| 1647 | { provid = (b2i(3, ecm + 6 + i) & 0xFFFFF0); }
|
|---|
| 1648 |
|
|---|
| 1649 | i = (ecm[6] == 0xD2) ? ecm[7] + 2 : 0; // skip d2 nano long ecm
|
|---|
| 1650 | if((ecm[7 + i] == 7) && ((ecm[6 + i] == 0x90) || (ecm[6 + i] == 0x40)))
|
|---|
| 1651 | { provid = (b2i(3, ecm + 8 + i) & 0xFFFFF0); }
|
|---|
| 1652 | break;
|
|---|
| 1653 |
|
|---|
| 1654 | case 0x0D: // cryptoworks
|
|---|
| 1655 | len = (((ecm[1] & 0xf) << 8) | ecm[2]) + 3;
|
|---|
| 1656 | for(i = 8; i < len; i += descriptor_length + 2)
|
|---|
| 1657 | {
|
|---|
| 1658 | descriptor_length = ecm[i + 1];
|
|---|
| 1659 | if(ecm[i] == 0x83)
|
|---|
| 1660 | {
|
|---|
| 1661 | provid = (uint32_t)ecm[i + 2] & 0xFE;
|
|---|
| 1662 | break;
|
|---|
| 1663 | }
|
|---|
| 1664 | }
|
|---|
| 1665 | break;
|
|---|
| 1666 |
|
|---|
| 1667 | case 0x18: // nagra2
|
|---|
| 1668 | if (caid == 0x1801) // more safety
|
|---|
| 1669 | provid = b2i(2, ecm + 5);
|
|---|
| 1670 | break;
|
|---|
| 1671 | }
|
|---|
| 1672 |
|
|---|
| 1673 | return provid;
|
|---|
| 1674 | }
|
|---|
| 1675 |
|
|---|
| 1676 | void update_chid(ECM_REQUEST *er)
|
|---|
| 1677 | {
|
|---|
| 1678 | er->chid = get_subid(er);
|
|---|
| 1679 | }
|
|---|
| 1680 |
|
|---|
| 1681 | /*
|
|---|
| 1682 | * This function writes the current CW from ECM struct to a cwl file.
|
|---|
| 1683 | * The filename is re-calculated and file re-opened every time.
|
|---|
| 1684 | * This will consume a bit cpu time, but nothing has to be stored between
|
|---|
| 1685 | * each call. If not file exists, a header is prepended
|
|---|
| 1686 | */
|
|---|
| 1687 | static void logCWtoFile(ECM_REQUEST *er, uint8_t *cw)
|
|---|
| 1688 | {
|
|---|
| 1689 | FILE *pfCWL;
|
|---|
| 1690 | char srvname[CS_SERVICENAME_SIZE];
|
|---|
| 1691 | /* %s / %s _I %04X _ %s .cwl */
|
|---|
| 1692 | char buf[256 + sizeof(srvname)];
|
|---|
| 1693 | char date[9];
|
|---|
| 1694 | uint8_t i, parity, writeheader = 0;
|
|---|
| 1695 | struct tm timeinfo;
|
|---|
| 1696 |
|
|---|
| 1697 | /*
|
|---|
| 1698 | * search service name for that id and change characters
|
|---|
| 1699 | * causing problems in file name
|
|---|
| 1700 | */
|
|---|
| 1701 |
|
|---|
| 1702 | get_servicename(cur_client(), er->srvid, er->prid, er->caid, srvname, sizeof(srvname));
|
|---|
| 1703 |
|
|---|
| 1704 | for(i = 0; srvname[i]; i++)
|
|---|
| 1705 | if(srvname[i] == ' ') { srvname[i] = '_'; }
|
|---|
| 1706 |
|
|---|
| 1707 | /* calc log file name */
|
|---|
| 1708 | time_t walltime = cs_time();
|
|---|
| 1709 | localtime_r(&walltime, &timeinfo);
|
|---|
| 1710 | strftime(date, sizeof(date), "%Y%m%d", &timeinfo);
|
|---|
| 1711 | snprintf(buf, sizeof(buf), "%s/%s_I%04X_%s.cwl", cfg.cwlogdir, date, er->srvid, srvname);
|
|---|
| 1712 |
|
|---|
| 1713 | /* open failed, assuming file does not exist, yet */
|
|---|
| 1714 | if((pfCWL = fopen(buf, "r")) == NULL)
|
|---|
| 1715 | {
|
|---|
| 1716 | writeheader = 1;
|
|---|
| 1717 | }
|
|---|
| 1718 | else
|
|---|
| 1719 | {
|
|---|
| 1720 | /* we need to close the file if it was opened correctly */
|
|---|
| 1721 | fclose(pfCWL);
|
|---|
| 1722 | }
|
|---|
| 1723 |
|
|---|
| 1724 | if((pfCWL = fopen(buf, "a+")) == NULL)
|
|---|
| 1725 | {
|
|---|
| 1726 | /* maybe this fails because the subdir does not exist. Is there a common function to create it?
|
|---|
| 1727 | for the moment do not print32_t to log on every ecm
|
|---|
| 1728 | cs_log(""error opening cw logfile for writing: %s (errno=%d %s)", buf, errno, strerror(errno)); */
|
|---|
| 1729 | return;
|
|---|
| 1730 | }
|
|---|
| 1731 | if(writeheader)
|
|---|
| 1732 | {
|
|---|
| 1733 | /* no global macro for cardserver name :( */
|
|---|
| 1734 | fprintf(pfCWL, "# OSCam cardserver v%s - https://trac.streamboard.tv/oscam/\n", CS_VERSION);
|
|---|
| 1735 | fprintf(pfCWL, "# control word log file for use with tsdec offline decrypter\n");
|
|---|
| 1736 | strftime(buf, sizeof(buf), "DATE %Y-%m-%d, TIME %H:%M:%S, TZ %Z\n", &timeinfo);
|
|---|
| 1737 | fprintf(pfCWL, "# %s", buf);
|
|---|
| 1738 | fprintf(pfCWL, "# CAID 0x%04X, SID 0x%04X, SERVICE \"%s\"\n", er->caid, er->srvid, srvname);
|
|---|
| 1739 | }
|
|---|
| 1740 |
|
|---|
| 1741 | parity = er->ecm[0] & 1;
|
|---|
| 1742 | fprintf(pfCWL, "%d ", parity);
|
|---|
| 1743 | for(i = parity * 8; i < 8 + parity * 8; i++)
|
|---|
| 1744 | { fprintf(pfCWL, "%02X ", cw[i]); }
|
|---|
| 1745 | /* better use incoming time er->tps rather than current time? */
|
|---|
| 1746 | strftime(buf, sizeof(buf), "%H:%M:%S\n", &timeinfo);
|
|---|
| 1747 | fprintf(pfCWL, "# %s", buf);
|
|---|
| 1748 | fflush(pfCWL);
|
|---|
| 1749 | fclose(pfCWL);
|
|---|
| 1750 | }
|
|---|
| 1751 |
|
|---|
| 1752 | int32_t write_ecm_answer(struct s_reader *reader, ECM_REQUEST *er, int8_t rc, uint8_t rcEx, uint8_t *cw, char *msglog, uint16_t used_cardtier, EXTENDED_CW* cw_ex)
|
|---|
| 1753 | {
|
|---|
| 1754 | if(!reader || !er || !er->tps.time) { return 0; }
|
|---|
| 1755 |
|
|---|
| 1756 | // drop too late answers, to avoid seg fault --> only answer until tps.time+((cfg.ctimeout+500)/1000+1) is accepted
|
|---|
| 1757 | time_t timeout = time(NULL) - ((cfg.ctimeout + 500) / 1000 + 1);
|
|---|
| 1758 | if(er->tps.time < timeout) // < and NOT <=
|
|---|
| 1759 | { return 0; }
|
|---|
| 1760 |
|
|---|
| 1761 | struct timeb now;
|
|---|
| 1762 | cs_ftime(&now);
|
|---|
| 1763 |
|
|---|
| 1764 | #ifdef CS_CACHEEX_AIO
|
|---|
| 1765 | uint8_t dontsetAnswered = 0;
|
|---|
| 1766 | #endif
|
|---|
| 1767 | uint8_t dontwriteStats = 0;
|
|---|
| 1768 |
|
|---|
| 1769 | if(er && er->parent)
|
|---|
| 1770 | {
|
|---|
| 1771 | // parent is only set on reader->client->ecmtask[], but we want original er
|
|---|
| 1772 | ECM_REQUEST *er_reader_cp = er;
|
|---|
| 1773 | er = er->parent; // Now er is "original" ecm, before it was the reader-copy
|
|---|
| 1774 | er_reader_cp->rc = rc;
|
|---|
| 1775 | er_reader_cp->idx = 0;
|
|---|
| 1776 | #ifdef CS_CACHEEX_AIO
|
|---|
| 1777 | er->localgenerated = er_reader_cp->localgenerated;
|
|---|
| 1778 | #endif
|
|---|
| 1779 |
|
|---|
| 1780 | timeout = time(NULL) - ((cfg.ctimeout + 500) / 1000 + 1);
|
|---|
| 1781 | if(er->tps.time < timeout)
|
|---|
| 1782 | { return 0; }
|
|---|
| 1783 | }
|
|---|
| 1784 |
|
|---|
| 1785 | #ifdef CS_CACHEEX_AIO
|
|---|
| 1786 | if(rc < E_NOTFOUND && !er->localgenerated && (reader->cacheex.localgenerated_only_in || chk_lg_only(er, &reader->cacheex.lg_only_in_tab)) && !chk_srvid_localgenerated_only_exception(er))
|
|---|
| 1787 | {
|
|---|
| 1788 | cs_log_dbg(D_CACHEEX, "reader: %s !er->localgenerated - rc: E_NOTFOUND set, no stats written for reader", reader ? reader->label : "-");
|
|---|
| 1789 | rc = E_NOTFOUND;
|
|---|
| 1790 | dontsetAnswered = 1;
|
|---|
| 1791 | dontwriteStats = 1;
|
|---|
| 1792 | }
|
|---|
| 1793 | #endif
|
|---|
| 1794 |
|
|---|
| 1795 | struct s_ecm_answer *ea = get_ecm_answer(reader, er);
|
|---|
| 1796 | if(!ea) { return 0; }
|
|---|
| 1797 |
|
|---|
| 1798 | cs_writelock(__func__, &ea->ecmanswer_lock);
|
|---|
| 1799 |
|
|---|
| 1800 | if((ea->status & REQUEST_ANSWERED))
|
|---|
| 1801 | {
|
|---|
| 1802 | cs_log_dbg(D_READER, "Reader %s already answer, skip this ecm answer!", reader ? reader->label : "-");
|
|---|
| 1803 | cs_writeunlock(__func__, &ea->ecmanswer_lock);
|
|---|
| 1804 | return 0;
|
|---|
| 1805 | }
|
|---|
| 1806 |
|
|---|
| 1807 | // Special checks for rc
|
|---|
| 1808 | // Skip check for BISS1 - cw could be zero but still catch cw=0 by anticascading
|
|---|
| 1809 | // Skip check for BISS2 - we use the extended cw, so the "simple" cw is always zero
|
|---|
| 1810 |
|
|---|
| 1811 | // bad/wrong chksum/ecm
|
|---|
| 1812 | if(rc == E_NOTFOUND && rcEx == E2_WRONG_CHKSUM)
|
|---|
| 1813 | {
|
|---|
| 1814 | cs_log_dbg(D_READER, "ECM for reader %s was bad/has a wrong chksum!", reader ? reader->label : "-");
|
|---|
| 1815 | rc = E_INVALID;
|
|---|
| 1816 | rcEx = E2_WRONG_CHKSUM;
|
|---|
| 1817 | er->stage = 5;
|
|---|
| 1818 |
|
|---|
| 1819 | // dont write stats for bad/wrong chksum/ecm
|
|---|
| 1820 | dontwriteStats = 1;
|
|---|
| 1821 |
|
|---|
| 1822 | // set all other matching_readers => inactive to skip them and dont spread the bad ecm
|
|---|
| 1823 | struct s_ecm_answer *ea_list;
|
|---|
| 1824 | for(ea_list = er->matching_rdr; ea_list; ea_list = ea_list->next)
|
|---|
| 1825 | {
|
|---|
| 1826 | ea_list->status &= ~(READER_ACTIVE | READER_FALLBACK);
|
|---|
| 1827 | }
|
|---|
| 1828 | }
|
|---|
| 1829 |
|
|---|
| 1830 | if(rc < E_NOTFOUND && cw && chk_is_null_CW(cw) && !caid_is_biss(er->caid))
|
|---|
| 1831 | {
|
|---|
| 1832 | rc = E_NOTFOUND;
|
|---|
| 1833 | cs_log_dbg(D_TRACE | D_LB, "WARNING: reader %s send fake cw, set rc=E_NOTFOUND!", reader ? reader->label : "-");
|
|---|
| 1834 | }
|
|---|
| 1835 |
|
|---|
| 1836 | if(rc < E_NOTFOUND && cw && !chk_halfCW(er,cw))
|
|---|
| 1837 | {
|
|---|
| 1838 | rc = E_NOTFOUND;
|
|---|
| 1839 | cs_log_dbg(D_TRACE | D_LB, "WARNING: reader %s send wrong swapped NDS cw, set rc=E_NOTFOUND!", reader ? reader->label : "-");
|
|---|
| 1840 | }
|
|---|
| 1841 |
|
|---|
| 1842 | if(reader && cw && rc < E_NOTFOUND)
|
|---|
| 1843 | {
|
|---|
| 1844 | if(!cfg.disablecrccws && !reader->disablecrccws)
|
|---|
| 1845 | {
|
|---|
| 1846 | if(!chk_if_ignore_checksum(er, &cfg.disablecrccws_only_for) && !chk_if_ignore_checksum(er, &reader->disablecrccws_only_for))
|
|---|
| 1847 | {
|
|---|
| 1848 | uint8_t i, c;
|
|---|
| 1849 | for(i = 0; i < 16; i += 4)
|
|---|
| 1850 | {
|
|---|
| 1851 | c = ((cw[i] + cw[i + 1] + cw[i + 2]) & 0xff);
|
|---|
| 1852 |
|
|---|
| 1853 | if(cw[i + 3] != c)
|
|---|
| 1854 | {
|
|---|
| 1855 | uint8_t nano = 0x00;
|
|---|
| 1856 | if(er->caid == 0x100 && er->ecm[5] > 0x00)
|
|---|
| 1857 | {
|
|---|
| 1858 | nano = er->ecm[5]; // seca nano protection
|
|---|
| 1859 | }
|
|---|
| 1860 |
|
|---|
| 1861 | if(reader->dropbadcws && !nano) // only drop controlword if no cw encryption is applied
|
|---|
| 1862 | {
|
|---|
| 1863 | rc = E_NOTFOUND;
|
|---|
| 1864 | rcEx = E2_WRONG_CHKSUM;
|
|---|
| 1865 | break;
|
|---|
| 1866 | }
|
|---|
| 1867 | else
|
|---|
| 1868 | {
|
|---|
| 1869 | if(!nano) // only fix checksum if no cw encryption is applied (nano = 0)
|
|---|
| 1870 | {
|
|---|
| 1871 | cs_log_dbg(D_TRACE, "notice: changed dcw checksum byte cw[%i] from %02x to %02x", i + 3, cw[i + 3], c);
|
|---|
| 1872 | cw[i + 3] = c;
|
|---|
| 1873 | }
|
|---|
| 1874 | else
|
|---|
| 1875 | {
|
|---|
| 1876 | if(i == 12) // there are servers delivering correct controlwords but with failing last cw checksum (on purpose?!)
|
|---|
| 1877 | {
|
|---|
| 1878 | cs_log_dbg(D_TRACE,"NANO%02d: BAD PEER DETECTED, oscam has fixed the last cw crc that wasn't matching!", nano);
|
|---|
| 1879 | cw[i + 3] = c; // fix the last controlword
|
|---|
| 1880 | }
|
|---|
| 1881 | else
|
|---|
| 1882 | {
|
|---|
| 1883 | cs_log_dbg(D_TRACE,"NANO%02d: not fixing the crc of this cw since its still encrypted!", nano);
|
|---|
| 1884 | break; // crc failed so stop!
|
|---|
| 1885 | }
|
|---|
| 1886 | }
|
|---|
| 1887 | }
|
|---|
| 1888 | }
|
|---|
| 1889 | }
|
|---|
| 1890 | }
|
|---|
| 1891 | else
|
|---|
| 1892 | {
|
|---|
| 1893 | cs_log_dbg(D_TRACE, "notice: CW checksum check disabled for %04X:%06X", er->caid, er->prid);
|
|---|
| 1894 | }
|
|---|
| 1895 | }
|
|---|
| 1896 | else
|
|---|
| 1897 | {
|
|---|
| 1898 | cs_log_dbg(D_TRACE, "notice: CW checksum check disabled");
|
|---|
| 1899 | }
|
|---|
| 1900 |
|
|---|
| 1901 | if(chk_if_ignore_checksum(er, &reader->disablecrccws_only_for) && caid_is_videoguard(er->caid)
|
|---|
| 1902 | #ifdef CS_CACHEEX_AIO
|
|---|
| 1903 | && !chk_srvid_disablecrccws_only_for_exception(er)
|
|---|
| 1904 | #endif
|
|---|
| 1905 | )
|
|---|
| 1906 | {
|
|---|
| 1907 | uint8_t k, csum;
|
|---|
| 1908 | uint8_t hit = 0;
|
|---|
| 1909 | uint8_t oe = checkCWpart(cw, 0) ? 0 : 8;
|
|---|
| 1910 | for(k = 0; k < 8; k += 4)
|
|---|
| 1911 | {
|
|---|
| 1912 | csum = ((cw[k + oe] + cw[k + oe + 1] + cw[k + oe + 2]) & 0xff);
|
|---|
| 1913 | if(cw[k + oe + 3] == csum)
|
|---|
| 1914 | {
|
|---|
| 1915 | hit++;
|
|---|
| 1916 | }
|
|---|
| 1917 | }
|
|---|
| 1918 | if(hit > 1)
|
|---|
| 1919 | {
|
|---|
| 1920 | char ecmd5s[17 * 3];
|
|---|
| 1921 | cs_hexdump(0, er->ecmd5, 16, ecmd5s, sizeof(ecmd5s));
|
|---|
| 1922 | if(reader->dropbadcws)
|
|---|
| 1923 | {
|
|---|
| 1924 | rc = E_NOTFOUND;
|
|---|
| 1925 | rcEx = E2_WRONG_CHKSUM;
|
|---|
| 1926 | cs_log("Probably got bad CW from reader: %s, caid %04X, srvid %04X (%s) - dropping CW, lg: %i", reader->label, er->caid, er->srvid, ecmd5s
|
|---|
| 1927 | #ifdef CS_CACHEEX_AIO
|
|---|
| 1928 | , er->localgenerated);
|
|---|
| 1929 | #else
|
|---|
| 1930 | , 0);
|
|---|
| 1931 | #endif
|
|---|
| 1932 | }
|
|---|
| 1933 | else
|
|---|
| 1934 | {
|
|---|
| 1935 | cs_log("Probably got bad CW from reader: %s, caid %04X, srvid %04X (%s), lg: %i", reader->label, er->caid, er->srvid, ecmd5s
|
|---|
| 1936 | #ifdef CS_CACHEEX_AIO
|
|---|
| 1937 | , er->localgenerated);
|
|---|
| 1938 | #else
|
|---|
| 1939 | , 0);
|
|---|
| 1940 | #endif
|
|---|
| 1941 | }
|
|---|
| 1942 | }
|
|---|
| 1943 | }
|
|---|
| 1944 |
|
|---|
| 1945 | }
|
|---|
| 1946 |
|
|---|
| 1947 | #ifdef CW_CYCLE_CHECK
|
|---|
| 1948 | uint8_t cwc_ct = er->cwc_cycletime > 0 ? er->cwc_cycletime : 0;
|
|---|
| 1949 | uint8_t cwc_ncwc = er->cwc_next_cw_cycle < 2 ? er->cwc_next_cw_cycle : 2;
|
|---|
| 1950 | if(!checkcwcycle(er->client, er, reader, cw, rc, cwc_ct, cwc_ncwc))
|
|---|
| 1951 | {
|
|---|
| 1952 | #ifdef CS_CACHEEX_AIO
|
|---|
| 1953 | if(!er->localgenerated)
|
|---|
| 1954 | {
|
|---|
| 1955 | #endif
|
|---|
| 1956 | rc = E_NOTFOUND;
|
|---|
| 1957 | rcEx = E2_WRONG_CHKSUM;
|
|---|
| 1958 | cs_log_dbg(D_CACHEEX | D_CWC | D_LB, "{client %s, caid %04X, srvid %04X} [write_ecm_answer] cyclecheck failed! Reader: %s set rc: %i", (er->client ? er->client->account->usr : "-"), er->caid, er->srvid, reader ? reader->label : "-", rc);
|
|---|
| 1959 |
|
|---|
| 1960 | #ifdef CS_CACHEEX_AIO
|
|---|
| 1961 | }
|
|---|
| 1962 | else
|
|---|
| 1963 | {
|
|---|
| 1964 | cs_log_dbg(D_CACHEEX | D_CWC | D_LB, "{client %s, caid %04X, srvid %04X} [write_ecm_answer] cyclecheck failed! Reader: %s set rc: %i -> lg-flagged CW -> do nothing", (er->client ? er->client->account->usr : "-"), er->caid, er->srvid, reader ? reader->label : "-", rc);
|
|---|
| 1965 | }
|
|---|
| 1966 | #endif
|
|---|
| 1967 | }
|
|---|
| 1968 | else { cs_log_dbg(D_CACHEEX | D_CWC | D_LB, "{client %s, caid %04X, srvid %04X} [write_ecm_answer] cyclecheck passed! Reader: %s rc: %i", (er->client ? er->client->account->usr : "-"), er->caid, er->srvid, reader ? reader->label : "-", rc); }
|
|---|
| 1969 | #endif
|
|---|
| 1970 | //END -- SPECIAL CHECKs for rc
|
|---|
| 1971 |
|
|---|
| 1972 | #ifdef CS_CACHEEX_AIO
|
|---|
| 1973 | if(!dontsetAnswered)
|
|---|
| 1974 | {
|
|---|
| 1975 | #endif
|
|---|
| 1976 | ea->status |= REQUEST_ANSWERED;
|
|---|
| 1977 | #ifdef CS_CACHEEX_AIO
|
|---|
| 1978 | }
|
|---|
| 1979 | #endif
|
|---|
| 1980 | ea->rc = rc;
|
|---|
| 1981 | ea->ecm_time = comp_timeb(&now, &ea->time_request_sent);
|
|---|
| 1982 | if(ea->ecm_time < 1) { ea->ecm_time = 1; } // set ecm_time 1 if answer immediately
|
|---|
| 1983 | ea->rcEx = rcEx;
|
|---|
| 1984 | if(cw) { memcpy(ea->cw, cw, 16); }
|
|---|
| 1985 | if(msglog) { memcpy(ea->msglog, msglog, MSGLOGSIZE); }
|
|---|
| 1986 | ea->tier = used_cardtier;
|
|---|
| 1987 | if(cw_ex)
|
|---|
| 1988 | {
|
|---|
| 1989 | ea->cw_ex = *cw_ex;
|
|---|
| 1990 | }
|
|---|
| 1991 |
|
|---|
| 1992 | cs_writeunlock(__func__, &ea->ecmanswer_lock);
|
|---|
| 1993 |
|
|---|
| 1994 | struct timeb tpe;
|
|---|
| 1995 | cs_ftime(&tpe);
|
|---|
| 1996 | int32_t ntime = comp_timeb(&tpe, &er->tps);
|
|---|
| 1997 | if(ntime < 1) { ntime = 1; }
|
|---|
| 1998 | cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} [write_ecm_answer] reader %s rc %d, ecm time %d ms (%d ms)", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid, reader ? reader->label : "-", rc, ea->ecm_time, ntime);
|
|---|
| 1999 |
|
|---|
| 2000 | // send ea for ecm request
|
|---|
| 2001 | int32_t res = 0;
|
|---|
| 2002 | struct s_client *cl = er->client;
|
|---|
| 2003 | if(check_client(cl))
|
|---|
| 2004 | {
|
|---|
| 2005 | res = 1;
|
|---|
| 2006 | add_job(er->client, ACTION_ECM_ANSWER_READER, ea, 0); // chk_dcw
|
|---|
| 2007 | }
|
|---|
| 2008 |
|
|---|
| 2009 | // distribute ea for pendings
|
|---|
| 2010 | if(ea->pending) // has pending ea
|
|---|
| 2011 | { distribute_ea(ea); }
|
|---|
| 2012 |
|
|---|
| 2013 |
|
|---|
| 2014 | if(!ea->is_pending) // not for pending ea - only once for ea
|
|---|
| 2015 | {
|
|---|
| 2016 | // cache update
|
|---|
| 2017 | // Skip check for BISS1 - cw could be indeed zero
|
|---|
| 2018 | // Skip check for BISS2 - we use the extended cw, so the "simple" cw is always zero
|
|---|
| 2019 | if(ea && (ea->rc < E_NOTFOUND) && (!chk_is_null_CW(ea->cw) && !caid_is_biss(er->caid)))
|
|---|
| 2020 | {
|
|---|
| 2021 | #ifdef CS_CACHEEX_AIO
|
|---|
| 2022 | int32_t ecmtime = ea->ecm_time;
|
|---|
| 2023 |
|
|---|
| 2024 | if(er->cacheex_wait_time_expired && er->cacheex_wait_time)
|
|---|
| 2025 | ecmtime = ea->ecm_time + er->cacheex_wait_time;
|
|---|
| 2026 | #endif
|
|---|
| 2027 | add_cache_from_reader(er, reader, er->csp_hash, er->ecmd5, ea->cw, er->caid, er->prid, er->srvid
|
|---|
| 2028 | #ifdef CS_CACHEEX_AIO
|
|---|
| 2029 | , ecmtime);
|
|---|
| 2030 | #else
|
|---|
| 2031 | );
|
|---|
| 2032 | #endif
|
|---|
| 2033 | }
|
|---|
| 2034 |
|
|---|
| 2035 | if(!dontwriteStats)
|
|---|
| 2036 | {
|
|---|
| 2037 | // readers stats for LB
|
|---|
| 2038 | send_reader_stat(reader, er, ea, ea->rc);
|
|---|
| 2039 | }
|
|---|
| 2040 |
|
|---|
| 2041 | // reader checks
|
|---|
| 2042 | #ifdef WITH_DEBUG
|
|---|
| 2043 | if(cs_dblevel & D_TRACE)
|
|---|
| 2044 | {
|
|---|
| 2045 | char ecmd5[17 * 3];
|
|---|
| 2046 | cs_hexdump(0, er->ecmd5, 16, ecmd5, sizeof(ecmd5));
|
|---|
| 2047 | rdr_log_dbg(reader, D_TRACE, "ecm answer for ecm hash %s rc=%d", ecmd5, ea->rc);
|
|---|
| 2048 | }
|
|---|
| 2049 | #endif
|
|---|
| 2050 | // Update reader stats:
|
|---|
| 2051 | if(ea->rc == E_FOUND)
|
|---|
| 2052 | {
|
|---|
| 2053 | if(cfg.cwlogdir != NULL)
|
|---|
| 2054 | { logCWtoFile(er, ea->cw); } // CWL logging only if cwlogdir is set in config
|
|---|
| 2055 |
|
|---|
| 2056 | reader->ecmsok++;
|
|---|
| 2057 | #ifdef CS_CACHEEX_AIO
|
|---|
| 2058 | if(er->localgenerated)
|
|---|
| 2059 | reader->ecmsoklg++;
|
|---|
| 2060 | #endif
|
|---|
| 2061 | reader->webif_ecmsok++;
|
|---|
| 2062 | #ifdef CS_CACHEEX
|
|---|
| 2063 | struct s_client *eacl = reader->client;
|
|---|
| 2064 | if(cacheex_reader(reader) && check_client(eacl))
|
|---|
| 2065 | {
|
|---|
| 2066 | eacl->cwcacheexgot++;
|
|---|
| 2067 | cacheex_add_stats(eacl, ea->er->caid, ea->er->srvid, ea->er->prid, 1
|
|---|
| 2068 | #ifdef CS_CACHEEX_AIO
|
|---|
| 2069 | , er->localgenerated);
|
|---|
| 2070 | #else
|
|---|
| 2071 | );
|
|---|
| 2072 | #endif
|
|---|
| 2073 | first_client->cwcacheexgot++;
|
|---|
| 2074 | #ifdef CS_CACHEEX_AIO
|
|---|
| 2075 | if(er->localgenerated)
|
|---|
| 2076 | {
|
|---|
| 2077 | eacl->cwcacheexgotlg++;
|
|---|
| 2078 | first_client->cwcacheexgotlg++;
|
|---|
| 2079 | }
|
|---|
| 2080 | #endif
|
|---|
| 2081 | }
|
|---|
| 2082 | #endif
|
|---|
| 2083 | }
|
|---|
| 2084 | else if(ea->rc == E_NOTFOUND)
|
|---|
| 2085 | {
|
|---|
| 2086 | reader->ecmsnok++;
|
|---|
| 2087 | reader->webif_ecmsnok++;
|
|---|
| 2088 | if(reader->ecmnotfoundlimit && reader->ecmsnok >= reader->ecmnotfoundlimit)
|
|---|
| 2089 | {
|
|---|
| 2090 | rdr_log(reader, "ECM not found limit reached %u. Restarting the reader.",
|
|---|
| 2091 | reader->ecmsnok);
|
|---|
| 2092 | reader->ecmsnok = 0; // Reset the variable
|
|---|
| 2093 | reader->ecmshealthnok = 0; // Reset the variable
|
|---|
| 2094 | add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
|
|---|
| 2095 | }
|
|---|
| 2096 | }
|
|---|
| 2097 |
|
|---|
| 2098 | // this fixes big oscam mistake
|
|---|
| 2099 | // wrong reader status on web info aka not counted timeouts which dispalyed
|
|---|
| 2100 | // reader info 100 percent OK but reader had a ton of unhandled timeouts!
|
|---|
| 2101 | else if(ea->rc == E_TIMEOUT)
|
|---|
| 2102 | {
|
|---|
| 2103 | #ifdef WITH_LB
|
|---|
| 2104 | STAT_QUERY q;
|
|---|
| 2105 | readerinfofix_get_stat_query(er, &q);
|
|---|
| 2106 | READER_STAT *s;
|
|---|
| 2107 | s = readerinfofix_get_add_stat(reader, &q);
|
|---|
| 2108 | if (s)
|
|---|
| 2109 | {
|
|---|
| 2110 | cs_log_dbg(D_LB, "inc fail {client %s, caid %04X, prid %06X, srvid %04X} [write_ecm_answer] reader %s rc %d, ecm time %d ms (%d ms)", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid, reader ? reader->label : "-", rc, ea->ecm_time, ntime);
|
|---|
| 2111 | readerinfofix_inc_fail(s); // now increase fail factor for unhandled timeouts
|
|---|
| 2112 | }
|
|---|
| 2113 | #endif
|
|---|
| 2114 | reader->ecmstout++; // now append timeouts to the readerinfo timeout count
|
|---|
| 2115 | reader->webif_ecmstout++;
|
|---|
| 2116 | }
|
|---|
| 2117 |
|
|---|
| 2118 | // Reader ECMs Health Try (by Pickser)
|
|---|
| 2119 | if(reader->ecmsok != 0 || reader->ecmsnok != 0 || reader->ecmstout != 0)
|
|---|
| 2120 | {
|
|---|
| 2121 | reader->ecmshealthok = ((double) reader->ecmsok / (reader->ecmsok + reader->ecmsnok + reader->ecmstout)) * 100;
|
|---|
| 2122 | #ifdef CS_CACHEEX_AIO
|
|---|
| 2123 | reader->ecmshealthoklg = ((double) reader->ecmsoklg / (reader->ecmsok + reader->ecmsnok + reader->ecmstout)) * 100;
|
|---|
| 2124 | #endif
|
|---|
| 2125 | reader->ecmshealthnok = ((double) reader->ecmsnok / (reader->ecmsok + reader->ecmsnok + reader->ecmstout)) * 100;
|
|---|
| 2126 | reader->ecmshealthtout = ((double) reader->ecmstout / (reader->ecmsok + reader->ecmsnok + reader->ecmstout)) * 100;
|
|---|
| 2127 | }
|
|---|
| 2128 |
|
|---|
| 2129 | if(rc == E_FOUND && reader->resetcycle > 0)
|
|---|
| 2130 | {
|
|---|
| 2131 | reader->resetcounter++;
|
|---|
| 2132 | if(reader->resetcounter > reader->resetcycle)
|
|---|
| 2133 | {
|
|---|
| 2134 | reader->resetcounter = 0;
|
|---|
| 2135 | rdr_log(reader, "Resetting reader, resetcyle of %d ecms reached", reader->resetcycle);
|
|---|
| 2136 | reader->card_status = CARD_NEED_INIT;
|
|---|
| 2137 | cardreader_reset(cl);
|
|---|
| 2138 | }
|
|---|
| 2139 | }
|
|---|
| 2140 | }
|
|---|
| 2141 |
|
|---|
| 2142 | return res;
|
|---|
| 2143 | }
|
|---|
| 2144 |
|
|---|
| 2145 | static void guess_cardsystem(ECM_REQUEST *er)
|
|---|
| 2146 | {
|
|---|
| 2147 | uint16_t last_hope = 0;
|
|---|
| 2148 |
|
|---|
| 2149 | // viaccess - check by provid-search
|
|---|
| 2150 | if((er->prid = chk_provid(er->ecm, 0x500)))
|
|---|
| 2151 | { er->caid = 0x500; }
|
|---|
| 2152 |
|
|---|
| 2153 | // nagra
|
|---|
| 2154 | // is ecm[1] always 0x30 ?
|
|---|
| 2155 | // is ecm[3] always 0x07 ?
|
|---|
| 2156 | if((er->ecm[6] == 1) && (er->ecm[4] == er->ecm[2] - 2))
|
|---|
| 2157 | { er->caid = 0x1801; }
|
|---|
| 2158 |
|
|---|
| 2159 | // seca2 - very poor
|
|---|
| 2160 | if((er->ecm[8] == 0x10) && ((er->ecm[9] & 0xF1) == 1))
|
|---|
| 2161 | { last_hope = 0x100; }
|
|---|
| 2162 |
|
|---|
| 2163 | // is cryptoworks, but which caid ?
|
|---|
| 2164 | if((er->ecm[3] == 0x81) && (er->ecm[4] == 0xFF) &&
|
|---|
| 2165 | (!er->ecm[5]) && (!er->ecm[6]) && (er->ecm[7] == er->ecm[2] - 5))
|
|---|
| 2166 | {
|
|---|
| 2167 | last_hope = 0xd00;
|
|---|
| 2168 | }
|
|---|
| 2169 |
|
|---|
| 2170 | if(!er->caid && er->ecm[2] == 0x31 && er->ecm[0x0b] == 0x28)
|
|---|
| 2171 | { guess_irdeto(er); }
|
|---|
| 2172 |
|
|---|
| 2173 | if(!er->caid) // guess by len...
|
|---|
| 2174 | { er->caid = len4caid[er->ecm[2] + 3]; }
|
|---|
| 2175 |
|
|---|
| 2176 | if(!er->caid)
|
|---|
| 2177 | { er->caid = last_hope; }
|
|---|
| 2178 | }
|
|---|
| 2179 |
|
|---|
| 2180 | // chid calculation from module stat to here
|
|---|
| 2181 | // to improve the quickfix concerning ecm chid info and extend it
|
|---|
| 2182 | // to all client requests wereby the chid is known in module stat
|
|---|
| 2183 |
|
|---|
| 2184 | uint32_t get_subid(ECM_REQUEST *er)
|
|---|
| 2185 | {
|
|---|
| 2186 | if(!er->ecmlen)
|
|---|
| 2187 | { return 0; }
|
|---|
| 2188 |
|
|---|
| 2189 | uint32_t id = 0;
|
|---|
| 2190 | switch(er->caid >> 8)
|
|---|
| 2191 | {
|
|---|
| 2192 | case 0x01: // seca
|
|---|
| 2193 | id = b2i(2, er->ecm + 7);
|
|---|
| 2194 | break;
|
|---|
| 2195 |
|
|---|
| 2196 | case 0x05: // viaccess
|
|---|
| 2197 | id = b2i(2, er->ecm + 8);
|
|---|
| 2198 | break;
|
|---|
| 2199 |
|
|---|
| 2200 | case 0x06: // irdeto
|
|---|
| 2201 | id = b2i(2, er->ecm + 6);
|
|---|
| 2202 | break;
|
|---|
| 2203 |
|
|---|
| 2204 | case 0x09: // videoguard
|
|---|
| 2205 | id = b2i(2, er->ecm + 11);
|
|---|
| 2206 | break;
|
|---|
| 2207 |
|
|---|
| 2208 | case 0x4A: // DRE-Crypt, Bulcrypt, Tongfang and others?
|
|---|
| 2209 | if(!caid_is_bulcrypt(er->caid) && !caid_is_dre(er->caid))
|
|---|
| 2210 | { id = b2i(2, er->ecm + 6); }
|
|---|
| 2211 | break;
|
|---|
| 2212 | }
|
|---|
| 2213 | return id;
|
|---|
| 2214 | }
|
|---|
| 2215 |
|
|---|
| 2216 | static void set_readers_counter(ECM_REQUEST *er)
|
|---|
| 2217 | {
|
|---|
| 2218 | struct s_ecm_answer *ea;
|
|---|
| 2219 |
|
|---|
| 2220 | er->reader_count = 0;
|
|---|
| 2221 | er->fallback_reader_count = 0;
|
|---|
| 2222 | er->localreader_count = 0;
|
|---|
| 2223 | er->cacheex_reader_count = 0;
|
|---|
| 2224 |
|
|---|
| 2225 | for(ea = er->matching_rdr; ea; ea = ea->next)
|
|---|
| 2226 | {
|
|---|
| 2227 | if(ea->status & READER_ACTIVE)
|
|---|
| 2228 | {
|
|---|
| 2229 | if(!(ea->status & READER_FALLBACK))
|
|---|
| 2230 | { er->reader_count++; }
|
|---|
| 2231 | else
|
|---|
| 2232 | { er->fallback_reader_count++; }
|
|---|
| 2233 |
|
|---|
| 2234 | if(cacheex_reader(ea->reader))
|
|---|
| 2235 | { er->cacheex_reader_count++; }
|
|---|
| 2236 | else if(is_localreader(ea->reader, er))
|
|---|
| 2237 | { er->localreader_count++; }
|
|---|
| 2238 | }
|
|---|
| 2239 | }
|
|---|
| 2240 | }
|
|---|
| 2241 |
|
|---|
| 2242 | void write_ecm_answer_fromcache(struct s_write_from_cache *wfc)
|
|---|
| 2243 | {
|
|---|
| 2244 | ECM_REQUEST *er = NULL;
|
|---|
| 2245 | ECM_REQUEST *ecm = NULL;
|
|---|
| 2246 |
|
|---|
| 2247 | er = wfc->er_new;
|
|---|
| 2248 | ecm = wfc->er_cache;
|
|---|
| 2249 |
|
|---|
| 2250 | #ifdef CS_CACHEEX_AIO
|
|---|
| 2251 | if(ecm->localgenerated || (ecm->cw_count > 0x0F000000))
|
|---|
| 2252 | er->localgenerated = 1;
|
|---|
| 2253 | #endif
|
|---|
| 2254 |
|
|---|
| 2255 | int8_t rc_orig = er->rc;
|
|---|
| 2256 |
|
|---|
| 2257 | er->grp |= ecm->grp; // update group
|
|---|
| 2258 | #ifdef CS_CACHEEX
|
|---|
| 2259 | if(ecm->from_csp) { er->csp_answered = 1; } // update er as answered by csp (csp have no group)
|
|---|
| 2260 | #endif
|
|---|
| 2261 |
|
|---|
| 2262 | if(er->rc >= E_NOTFOUND)
|
|---|
| 2263 | {
|
|---|
| 2264 | #ifdef CS_CACHEEX
|
|---|
| 2265 | if(ecm->cacheex_src) // from cacheex or csp
|
|---|
| 2266 | {
|
|---|
| 2267 | er->rc = E_CACHEEX;
|
|---|
| 2268 | }
|
|---|
| 2269 | else
|
|---|
| 2270 | #endif
|
|---|
| 2271 | { er->rc=E_CACHE1; } // from normal readers
|
|---|
| 2272 |
|
|---|
| 2273 | memcpy(er->cw, ecm->cw, 16);
|
|---|
| 2274 | er->selected_reader = ecm->selected_reader;
|
|---|
| 2275 | er->cw_count = ecm->cw_count;
|
|---|
| 2276 |
|
|---|
| 2277 | #ifdef CS_CACHEEX
|
|---|
| 2278 | // here we should be sure cex client has not been freed!
|
|---|
| 2279 | if(ecm->cacheex_src && is_valid_client(ecm->cacheex_src) && !ecm->cacheex_src->kill)
|
|---|
| 2280 | {
|
|---|
| 2281 | er->cacheex_src = ecm->cacheex_src;
|
|---|
| 2282 | er->cwc_cycletime = ecm->cwc_cycletime;
|
|---|
| 2283 | er->cwc_next_cw_cycle = ecm->cwc_next_cw_cycle;
|
|---|
| 2284 | }
|
|---|
| 2285 | else
|
|---|
| 2286 | {
|
|---|
| 2287 | er->cacheex_src = NULL;
|
|---|
| 2288 | }
|
|---|
| 2289 |
|
|---|
| 2290 | int8_t cacheex = check_client(er->client) && er->client->account ? er->client->account->cacheex.mode : 0;
|
|---|
| 2291 | if(cacheex == 1 && check_client(er->client))
|
|---|
| 2292 | {
|
|---|
| 2293 | cacheex_add_stats(er->client, er->caid, er->srvid, er->prid, 0
|
|---|
| 2294 | #ifdef CS_CACHEEX_AIO
|
|---|
| 2295 | , er->localgenerated);
|
|---|
| 2296 | #else
|
|---|
| 2297 | );
|
|---|
| 2298 | #endif
|
|---|
| 2299 | er->client->cwcacheexpush++;
|
|---|
| 2300 | if(er->client->account)
|
|---|
| 2301 | { er->client->account->cwcacheexpush++; }
|
|---|
| 2302 | first_client->cwcacheexpush++;
|
|---|
| 2303 |
|
|---|
| 2304 | #ifdef CS_CACHEEX_AIO
|
|---|
| 2305 | if(er->localgenerated)
|
|---|
| 2306 | {
|
|---|
| 2307 | er->client->cwcacheexpushlg++;
|
|---|
| 2308 | first_client->cwcacheexpushlg++;
|
|---|
| 2309 | }
|
|---|
| 2310 | #endif
|
|---|
| 2311 |
|
|---|
| 2312 | }
|
|---|
| 2313 | #endif
|
|---|
| 2314 |
|
|---|
| 2315 | #ifdef CS_CACHEEX
|
|---|
| 2316 | if(cfg.delay && cacheex!=1) // No delay on cacheexchange mode 1 client!
|
|---|
| 2317 | { cs_sleepms(cfg.delay); }
|
|---|
| 2318 | #else
|
|---|
| 2319 | if(cfg.delay)
|
|---|
| 2320 | { cs_sleepms(cfg.delay); }
|
|---|
| 2321 | #endif
|
|---|
| 2322 |
|
|---|
| 2323 | if(rc_orig == E_UNHANDLED)
|
|---|
| 2324 | {
|
|---|
| 2325 | cs_log_dbg(D_LB,"{client %s, caid %04X, prid %06X, srvid %04X} [write_ecm_answer_fromcache] found cw in CACHE (count %d)!", (check_client(er->client)?er->client->account->usr:"-"),er->caid, er->prid, er->srvid,
|
|---|
| 2326 | #ifdef CS_CACHEEX_AIO
|
|---|
| 2327 | (er->cw_count > 0x0F000000) ? er->cw_count ^= 0x0F000000 : er->cw_count);
|
|---|
| 2328 | #else
|
|---|
| 2329 | er->cw_count);
|
|---|
| 2330 | #endif
|
|---|
| 2331 | send_dcw(er->client, er);
|
|---|
| 2332 | }
|
|---|
| 2333 | }
|
|---|
| 2334 | }
|
|---|
| 2335 |
|
|---|
| 2336 | #ifdef CS_CACHEEX_AIO
|
|---|
| 2337 | static bool ecm_cache_check(ECM_REQUEST *er)
|
|---|
| 2338 | {
|
|---|
| 2339 | if(ecm_cache_init_done && cfg.ecm_cache_droptime > 0)
|
|---|
| 2340 | {
|
|---|
| 2341 | ECM_CACHE *ecm_cache = NULL;
|
|---|
| 2342 | SAFE_RWLOCK_WRLOCK(&ecm_cache_lock);
|
|---|
| 2343 | ecm_cache = find_hash_table(&ht_ecm_cache, &er->csp_hash, sizeof(uint32_t), &compare_csp_hash_ecmcache);
|
|---|
| 2344 | if(!ecm_cache)
|
|---|
| 2345 | {
|
|---|
| 2346 | // ecm_cache-size(count/memory) pre-check
|
|---|
| 2347 | if(
|
|---|
| 2348 | (cfg.ecm_cache_size && (cfg.ecm_cache_size > tommy_hashlin_count(&ht_ecm_cache)))
|
|---|
| 2349 | || (cfg.ecm_cache_memory && (cfg.ecm_cache_memory*1024*1024 > tommy_hashlin_memory_usage(&ht_ecm_cache)))
|
|---|
| 2350 | )
|
|---|
| 2351 | {
|
|---|
| 2352 | if(cs_malloc(&ecm_cache, sizeof(ECM_CACHE)))
|
|---|
| 2353 | {
|
|---|
| 2354 | ecm_cache->csp_hash = er->csp_hash;
|
|---|
| 2355 | cs_ftime(&ecm_cache->first_recv_time);
|
|---|
| 2356 | cs_ftime(&ecm_cache->upd_time);
|
|---|
| 2357 |
|
|---|
| 2358 | tommy_hashlin_insert(&ht_ecm_cache, &ecm_cache->ht_node, ecm_cache, tommy_hash_u32(0, &er->csp_hash, sizeof(er->csp_hash)));
|
|---|
| 2359 | tommy_list_insert_tail(&ll_ecm_cache, &ecm_cache->ll_node, ecm_cache);
|
|---|
| 2360 |
|
|---|
| 2361 | SAFE_RWLOCK_UNLOCK(&ecm_cache_lock);
|
|---|
| 2362 | return true;
|
|---|
| 2363 | }
|
|---|
| 2364 | else{
|
|---|
| 2365 | SAFE_RWLOCK_UNLOCK(&ecm_cache_lock);
|
|---|
| 2366 | cs_log("[ecm_cache] ERROR: NO added HASH to ecm_cache!!");
|
|---|
| 2367 | return false;
|
|---|
| 2368 | }
|
|---|
| 2369 | }
|
|---|
| 2370 | else{
|
|---|
| 2371 | // clean cache call;
|
|---|
| 2372 | SAFE_RWLOCK_UNLOCK(&ecm_cache_lock);
|
|---|
| 2373 | ecm_cache_cleanup(true);
|
|---|
| 2374 | return false;
|
|---|
| 2375 | }
|
|---|
| 2376 | }
|
|---|
| 2377 | // ecm found
|
|---|
| 2378 | else{
|
|---|
| 2379 | int64_t gone_diff = 0;
|
|---|
| 2380 | gone_diff = comp_timeb(&er->tps, &ecm_cache->first_recv_time);
|
|---|
| 2381 | cs_ftime(&ecm_cache->upd_time);
|
|---|
| 2382 |
|
|---|
| 2383 | if(gone_diff >= cfg.ecm_cache_droptime * 1000)
|
|---|
| 2384 | {
|
|---|
| 2385 | cs_log_dbg(D_CW_CACHE, "[ecm_cache] ECM drop, current ecm_cache_size: %i - ecm_cache-mem-size: %i MiB", count_hash_table(&ht_ecm_cache), (int)(tommy_hashlin_memory_usage(&ht_ecm_cache)/1024/1024));
|
|---|
| 2386 | SAFE_RWLOCK_UNLOCK(&ecm_cache_lock);
|
|---|
| 2387 | return false;
|
|---|
| 2388 | }
|
|---|
| 2389 | }
|
|---|
| 2390 |
|
|---|
| 2391 | SAFE_RWLOCK_UNLOCK(&ecm_cache_lock);
|
|---|
| 2392 | return true;
|
|---|
| 2393 | }
|
|---|
| 2394 | else{
|
|---|
| 2395 | cs_log_dbg(D_CW_CACHE,"[ecm_cache] ecm_cache_init_done %i cfg.ecm_cache_size: %"PRIu32" cfg.ecm_cache_memory %"PRIu32" MiB", ecm_cache_init_done, cfg.ecm_cache_size, cfg.ecm_cache_memory);
|
|---|
| 2396 | return true;
|
|---|
| 2397 | }
|
|---|
| 2398 | }
|
|---|
| 2399 | #endif
|
|---|
| 2400 |
|
|---|
| 2401 | void get_cw(struct s_client *client, ECM_REQUEST *er)
|
|---|
| 2402 | {
|
|---|
| 2403 | #ifdef CS_CACHEEX_AIO
|
|---|
| 2404 | cacheex_update_hash(er);
|
|---|
| 2405 | if(!ecm_cache_check(er))
|
|---|
| 2406 | {
|
|---|
| 2407 | er->rc = E_INVALID;
|
|---|
| 2408 | send_dcw(client, er);
|
|---|
| 2409 | free_ecm(er);
|
|---|
| 2410 | return;
|
|---|
| 2411 | }
|
|---|
| 2412 | #endif
|
|---|
| 2413 | cs_log_dump_dbg(D_ATR, er->ecm, er->ecmlen, "get cw for ecm:");
|
|---|
| 2414 | cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} [get_cw] NEW REQUEST!", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid);
|
|---|
| 2415 | increment_n_request(client);
|
|---|
| 2416 |
|
|---|
| 2417 | int32_t i, j, m;
|
|---|
| 2418 | time_t now = time((time_t *)0);
|
|---|
| 2419 | uint32_t line = 0;
|
|---|
| 2420 | uint16_t sct_len;
|
|---|
| 2421 |
|
|---|
| 2422 | er->client = client;
|
|---|
| 2423 | er->rc = E_UNHANDLED; // set default rc status to unhandled
|
|---|
| 2424 | er->cwc_next_cw_cycle = 2; // set it to: we dont know
|
|---|
| 2425 |
|
|---|
| 2426 | // user was on freetv or didn't request for some time
|
|---|
| 2427 | // so we reset lastswitch to get correct stats/webif display
|
|---|
| 2428 | if(now - client->lastecm > cfg.hideclient_to) { client->lastswitch = 0; }
|
|---|
| 2429 | client->lastecm = now;
|
|---|
| 2430 |
|
|---|
| 2431 | if(client == first_client || !client ->account || client->account == first_client->account)
|
|---|
| 2432 | {
|
|---|
| 2433 | // DVBApi+serial is allowed to request anonymous accounts:
|
|---|
| 2434 | int16_t listenertype = get_module(client)->listenertype;
|
|---|
| 2435 | if(listenertype != LIS_DVBAPI && listenertype != LIS_SERIAL)
|
|---|
| 2436 | {
|
|---|
| 2437 | er->rc = E_INVALID;
|
|---|
| 2438 | er->rcEx = E2_GLOBAL;
|
|---|
| 2439 | snprintf(er->msglog, sizeof(er->msglog), "invalid user account %s", username(client));
|
|---|
| 2440 | }
|
|---|
| 2441 | }
|
|---|
| 2442 |
|
|---|
| 2443 | // ecmlen must be 0 (no ecm) or >2 (because SCT_LEN() needs at least 3 bytes)
|
|---|
| 2444 | if(er->ecmlen < 0 || er->ecmlen == 1 || er->ecmlen == 2)
|
|---|
| 2445 | {
|
|---|
| 2446 | er->rc = E_INVALID;
|
|---|
| 2447 | er->rcEx = E2_GLOBAL;
|
|---|
| 2448 | snprintf(er->msglog, sizeof(er->msglog), "ECM size %d invalid, ignored! client %s", er->ecmlen, username(client));
|
|---|
| 2449 | }
|
|---|
| 2450 |
|
|---|
| 2451 | if(er->ecmlen > MAX_ECM_SIZE)
|
|---|
| 2452 | {
|
|---|
| 2453 | er->rc = E_INVALID;
|
|---|
| 2454 | er->rcEx = E2_GLOBAL;
|
|---|
| 2455 | snprintf(er->msglog, sizeof(er->msglog), "ECM size %d > Max ECM size %d, ignored! client %s", er->ecmlen, MAX_ECM_SIZE, username(client));
|
|---|
| 2456 | }
|
|---|
| 2457 |
|
|---|
| 2458 | if(er->ecmlen > 2)
|
|---|
| 2459 | {
|
|---|
| 2460 | sct_len = SCT_LEN(er->ecm);
|
|---|
| 2461 | if(sct_len > er->ecmlen || sct_len < 4)
|
|---|
| 2462 | {
|
|---|
| 2463 | er->rc = E_INVALID;
|
|---|
| 2464 | er->rcEx = E2_GLOBAL;
|
|---|
| 2465 | snprintf(er->msglog, sizeof(er->msglog), "Real ECM size %d > ECM size %d, ignored! client %s", sct_len, er->ecmlen, username(client));
|
|---|
| 2466 | }
|
|---|
| 2467 | er->ecmlen = sct_len;
|
|---|
| 2468 | }
|
|---|
| 2469 |
|
|---|
| 2470 | if(!client->grp)
|
|---|
| 2471 | {
|
|---|
| 2472 | er->rc = E_INVALID;
|
|---|
| 2473 | er->rcEx = E2_GROUP;
|
|---|
| 2474 | snprintf(er->msglog, sizeof(er->msglog), "invalid user group %s", username(client));
|
|---|
| 2475 | }
|
|---|
| 2476 |
|
|---|
| 2477 | if(!er->caid)
|
|---|
| 2478 | { guess_cardsystem(er); }
|
|---|
| 2479 |
|
|---|
| 2480 | /* Quickfix Area */
|
|---|
| 2481 |
|
|---|
| 2482 | // add chid for all client requests as in module stat
|
|---|
| 2483 | update_chid(er);
|
|---|
| 2484 |
|
|---|
| 2485 | // quickfix for 0100:000065
|
|---|
| 2486 | if(er->caid == 0x100 && er->prid == 0x65 && er->srvid == 0)
|
|---|
| 2487 | { er->srvid = 0x0642; }
|
|---|
| 2488 |
|
|---|
| 2489 | // Quickfixes for Opticum/Globo HD9500
|
|---|
| 2490 | // Quickfix for 0500:030300
|
|---|
| 2491 | if(er->caid == 0x500 && er->prid == 0x030300)
|
|---|
| 2492 | { er->prid = 0x030600; }
|
|---|
| 2493 |
|
|---|
| 2494 | // Quickfix for 0500:D20200
|
|---|
| 2495 | if(er->caid == 0x500 && er->prid == 0xD20200)
|
|---|
| 2496 | { er->prid = 0x030600; }
|
|---|
| 2497 |
|
|---|
| 2498 | // betacrypt ecm with nagra header
|
|---|
| 2499 | if(chk_is_betatunnel_caid(er->caid) == 1 && (er->ecmlen == 0x89 || er->ecmlen == 0x4A) && er->ecm[3] == 0x07 && (er->ecm[4] == 0x84 || er->ecm[4] == 0x45))
|
|---|
| 2500 | {
|
|---|
| 2501 | if(er->caid == 0x1702)
|
|---|
| 2502 | {
|
|---|
| 2503 | er->caid = 0x1833;
|
|---|
| 2504 | }
|
|---|
| 2505 | else
|
|---|
| 2506 | {
|
|---|
| 2507 | check_lb_auto_betatunnel_mode(er);
|
|---|
| 2508 | }
|
|---|
| 2509 | cs_log_dbg(D_TRACE, "Quickfix remap beta->nagra: 0x%X, 0x%X, 0x%X, 0x%X", er->caid, er->ecmlen, er->ecm[3], er->ecm[4]);
|
|---|
| 2510 | }
|
|---|
| 2511 |
|
|---|
| 2512 | // nagra ecm with betacrypt header 1801, 1833, 1834, 1835
|
|---|
| 2513 | if(chk_is_betatunnel_caid(er->caid) == 2 && (er->ecmlen == 0x93 || er->ecmlen == 0x54) && er->ecm[13] == 0x07 && (er->ecm[14] == 0x84 || er->ecm[14] == 0x45))
|
|---|
| 2514 | {
|
|---|
| 2515 | if(er->caid == 0x1833)
|
|---|
| 2516 | {
|
|---|
| 2517 | er->caid = 0x1702;
|
|---|
| 2518 | }
|
|---|
| 2519 | else
|
|---|
| 2520 | {
|
|---|
| 2521 | er->caid = 0x1722;
|
|---|
| 2522 | }
|
|---|
| 2523 | cs_log_dbg(D_TRACE, "Quickfix remap nagra->beta: 0x%X, 0x%X, 0x%X, 0x%X", er->caid, er->ecmlen, er->ecm[13], er->ecm[44]);
|
|---|
| 2524 | }
|
|---|
| 2525 |
|
|---|
| 2526 | // Ariva quickfix (invalid nagra provider)
|
|---|
| 2527 | if(((er->caid & 0xFF00) == 0x1800) && er->prid > 0x00FFFF)
|
|---|
| 2528 | { er->prid = 0; }
|
|---|
| 2529 |
|
|---|
| 2530 | // Check for invalid provider, extract provider out of ecm:
|
|---|
| 2531 | uint32_t prid = chk_provid(er->ecm, er->caid);
|
|---|
| 2532 | if(!er->prid)
|
|---|
| 2533 | {
|
|---|
| 2534 | er->prid = prid;
|
|---|
| 2535 | }
|
|---|
| 2536 | else
|
|---|
| 2537 | {
|
|---|
| 2538 | if(prid && prid != er->prid)
|
|---|
| 2539 | {
|
|---|
| 2540 | cs_log_dbg(D_TRACE, "provider fixed: %04X@%06X to %04X@%06X", er->caid, er->prid, er->caid, prid);
|
|---|
| 2541 | er->prid = prid;
|
|---|
| 2542 | }
|
|---|
| 2543 | }
|
|---|
| 2544 |
|
|---|
| 2545 | #ifdef MODULE_NEWCAMD
|
|---|
| 2546 | // Set providerid for newcamd clients if none is given
|
|---|
| 2547 | if(!er->prid && client->ncd_server)
|
|---|
| 2548 | {
|
|---|
| 2549 | int32_t pi = client->port_idx;
|
|---|
| 2550 | if(pi >= 0 && cfg.ncd_ptab.nports && cfg.ncd_ptab.nports >= pi && cfg.ncd_ptab.ports[pi].ncd)
|
|---|
| 2551 | { er->prid = cfg.ncd_ptab.ports[pi].ncd->ncd_ftab.filts[0].prids[0]; }
|
|---|
| 2552 | }
|
|---|
| 2553 | #endif
|
|---|
| 2554 |
|
|---|
| 2555 | // CAID not supported or found
|
|---|
| 2556 | if(!er->caid)
|
|---|
| 2557 | {
|
|---|
| 2558 | er->rc = E_INVALID;
|
|---|
| 2559 | er->rcEx = E2_CAID;
|
|---|
| 2560 | snprintf(er->msglog, MSGLOGSIZE, "CAID not supported or found");
|
|---|
| 2561 | }
|
|---|
| 2562 |
|
|---|
| 2563 | // user expired
|
|---|
| 2564 | if(client->expirationdate && client->expirationdate < client->lastecm)
|
|---|
| 2565 | { er->rc = E_EXPDATE; }
|
|---|
| 2566 |
|
|---|
| 2567 | // out of timeframe
|
|---|
| 2568 | if(client->allowedtimeframe_set)
|
|---|
| 2569 | {
|
|---|
| 2570 | struct tm acttm;
|
|---|
| 2571 | localtime_r(&now, &acttm);
|
|---|
| 2572 | int32_t curday = acttm.tm_wday;
|
|---|
| 2573 | char *dest = strstr(weekdstr,"ALL");
|
|---|
| 2574 | int32_t all_idx = (dest - weekdstr) / 3;
|
|---|
| 2575 | uint8_t allowed = 0;
|
|---|
| 2576 |
|
|---|
| 2577 | // checkout if current time is allowed in the current day
|
|---|
| 2578 | allowed = CHECK_BIT(client->allowedtimeframe[curday][acttm.tm_hour][acttm.tm_min / 30], (acttm.tm_min % 30));
|
|---|
| 2579 |
|
|---|
| 2580 | // or checkout if current time is allowed for all days
|
|---|
| 2581 | allowed |= CHECK_BIT(client->allowedtimeframe[all_idx][acttm.tm_hour][acttm.tm_min / 30], (acttm.tm_min % 30));
|
|---|
| 2582 |
|
|---|
| 2583 | if(!(allowed))
|
|---|
| 2584 | {
|
|---|
| 2585 | er->rc = E_EXPDATE;
|
|---|
| 2586 | }
|
|---|
| 2587 | cs_log_dbg(D_TRACE, "Check Timeframe - result: %d, day:%s time: %02dH%02d, allowed: %s\n", er->rc, shortDay[curday], acttm.tm_hour, acttm.tm_min, allowed ? "true" : "false");
|
|---|
| 2588 | }
|
|---|
| 2589 |
|
|---|
| 2590 | // user disabled
|
|---|
| 2591 | if(client->disabled != 0)
|
|---|
| 2592 | {
|
|---|
| 2593 | if(client->failban & BAN_DISABLED)
|
|---|
| 2594 | {
|
|---|
| 2595 | cs_add_violation(client, client->account->usr);
|
|---|
| 2596 | cs_disconnect_client(client);
|
|---|
| 2597 | }
|
|---|
| 2598 | er->rc = E_DISABLED;
|
|---|
| 2599 | }
|
|---|
| 2600 |
|
|---|
| 2601 | if(!chk_global_whitelist(er, &line))
|
|---|
| 2602 | {
|
|---|
| 2603 | debug_ecm(D_TRACE, "whitelist filtered: %s (%s) line %d", username(client), buf, line);
|
|---|
| 2604 | er->rc = E_INVALID;
|
|---|
| 2605 | }
|
|---|
| 2606 |
|
|---|
| 2607 | #ifdef CS_CACHEEX
|
|---|
| 2608 | if(client->account && client->account->cacheex.mode == 2 && !client->account->cacheex.allow_request)
|
|---|
| 2609 | {
|
|---|
| 2610 | er->rc = E_INVALID;
|
|---|
| 2611 | snprintf(er->msglog, MSGLOGSIZE, "invalid request from cacheex-2 client");
|
|---|
| 2612 | }
|
|---|
| 2613 | #endif
|
|---|
| 2614 |
|
|---|
| 2615 | // rc < 100 -> ecm error
|
|---|
| 2616 | if(er->rc >= E_UNHANDLED)
|
|---|
| 2617 | {
|
|---|
| 2618 | m = er->caid;
|
|---|
| 2619 | i = er->srvid;
|
|---|
| 2620 |
|
|---|
| 2621 | if(i != client->last_srvid || !client->lastswitch)
|
|---|
| 2622 | {
|
|---|
| 2623 | if(cfg.usrfileflag)
|
|---|
| 2624 | { cs_statistics(client); }
|
|---|
| 2625 | client->lastswitch = now;
|
|---|
| 2626 | }
|
|---|
| 2627 |
|
|---|
| 2628 | // user sleeping
|
|---|
| 2629 | if(client->tosleep && (now - client->lastswitch > client->tosleep))
|
|---|
| 2630 | {
|
|---|
| 2631 | if(client->failban & BAN_SLEEPING)
|
|---|
| 2632 | {
|
|---|
| 2633 | cs_add_violation(client, client->account->usr);
|
|---|
| 2634 | cs_disconnect_client(client);
|
|---|
| 2635 | }
|
|---|
| 2636 | if(client->c35_sleepsend != 0)
|
|---|
| 2637 | {
|
|---|
| 2638 | er->rc = E_STOPPED; // send sleep command CMD08 {00 255}
|
|---|
| 2639 | }
|
|---|
| 2640 | else
|
|---|
| 2641 | {
|
|---|
| 2642 | er->rc = E_SLEEPING;
|
|---|
| 2643 | }
|
|---|
| 2644 | }
|
|---|
| 2645 |
|
|---|
| 2646 | client->last_srvid = i;
|
|---|
| 2647 | client->last_caid = m;
|
|---|
| 2648 | client->last_provid = er->prid;
|
|---|
| 2649 |
|
|---|
| 2650 | int32_t ecm_len = (((er->ecm[1] & 0x0F) << 8) | er->ecm[2]) + 3;
|
|---|
| 2651 |
|
|---|
| 2652 | for(j = 0; (j < 6) && (er->rc >= E_UNHANDLED); j++)
|
|---|
| 2653 | {
|
|---|
| 2654 | switch(j)
|
|---|
| 2655 | {
|
|---|
| 2656 | case 0:
|
|---|
| 2657 | // fake (uniq)
|
|---|
| 2658 | if(client->dup)
|
|---|
| 2659 | { er->rc = E_FAKE; }
|
|---|
| 2660 | break;
|
|---|
| 2661 |
|
|---|
| 2662 | case 1:
|
|---|
| 2663 | // invalid (caid)
|
|---|
| 2664 | if(!chk_bcaid(er, &client->ctab))
|
|---|
| 2665 | {
|
|---|
| 2666 | er->rc = E_INVALID;
|
|---|
| 2667 | er->rcEx = E2_CAID;
|
|---|
| 2668 | snprintf(er->msglog, MSGLOGSIZE, "invalid caid 0x%04X", er->caid);
|
|---|
| 2669 | }
|
|---|
| 2670 | break;
|
|---|
| 2671 |
|
|---|
| 2672 | case 2:
|
|---|
| 2673 | // invalid (srvid)
|
|---|
| 2674 | // matching srvids (or 0000) specified in betatunnel will bypass this filter
|
|---|
| 2675 | if(!chk_srvid(client, er))
|
|---|
| 2676 | {
|
|---|
| 2677 | if(!chk_on_btun(SRVID_ZERO, client, er))
|
|---|
| 2678 | {
|
|---|
| 2679 | er->rc = E_INVALID;
|
|---|
| 2680 | snprintf(er->msglog, MSGLOGSIZE, "invalid SID");
|
|---|
| 2681 | }
|
|---|
| 2682 | }
|
|---|
| 2683 | break;
|
|---|
| 2684 |
|
|---|
| 2685 | case 3:
|
|---|
| 2686 | // invalid (ufilters)
|
|---|
| 2687 | if(!chk_ufilters(er))
|
|---|
| 2688 | { er->rc = E_INVALID; }
|
|---|
| 2689 | break;
|
|---|
| 2690 |
|
|---|
| 2691 | case 4:
|
|---|
| 2692 | // invalid (sfilter)
|
|---|
| 2693 | if(!chk_sfilter(er, &get_module(client)->ptab))
|
|---|
| 2694 | { er->rc = E_INVALID; }
|
|---|
| 2695 | break;
|
|---|
| 2696 |
|
|---|
| 2697 | case 5:
|
|---|
| 2698 | // corrupt
|
|---|
| 2699 | if((i = er->ecmlen - ecm_len))
|
|---|
| 2700 | {
|
|---|
| 2701 | if(i > 0)
|
|---|
| 2702 | {
|
|---|
| 2703 | cs_log_dbg(D_TRACE, "warning: ecm size adjusted from %d to %d", er->ecmlen, ecm_len);
|
|---|
| 2704 | er->ecmlen = ecm_len;
|
|---|
| 2705 | }
|
|---|
| 2706 | else
|
|---|
| 2707 | { er->rc = E_CORRUPT; }
|
|---|
| 2708 | }
|
|---|
| 2709 | break;
|
|---|
| 2710 | }
|
|---|
| 2711 | }
|
|---|
| 2712 | }
|
|---|
| 2713 |
|
|---|
| 2714 | // Check for odd/even byte
|
|---|
| 2715 | // Don't check for BISS1 and BISS2 mode 1/E or fake caid (ECM is fake for them)
|
|---|
| 2716 | // Don't check for BISS2 mode CA (ECM table is always 0x80)
|
|---|
| 2717 | if(!caid_is_biss(er->caid) && !caid_is_fake(er->caid) && get_odd_even(er) == 0)
|
|---|
| 2718 | {
|
|---|
| 2719 | cs_log_dbg(D_TRACE, "warning: ecm with null odd/even byte from %s", (check_client(er->client) ? er->client->account->usr : "-"));
|
|---|
| 2720 | er->rc = E_INVALID;
|
|---|
| 2721 | }
|
|---|
| 2722 |
|
|---|
| 2723 | // not continue, send rc to client
|
|---|
| 2724 | if(er->rc < E_UNHANDLED)
|
|---|
| 2725 | {
|
|---|
| 2726 | send_dcw(client, er);
|
|---|
| 2727 | free_ecm(er);
|
|---|
| 2728 | return;
|
|---|
| 2729 | }
|
|---|
| 2730 |
|
|---|
| 2731 |
|
|---|
| 2732 | #ifdef CS_CACHEEX
|
|---|
| 2733 | int8_t cacheex = client->account ? client->account->cacheex.mode : 0;
|
|---|
| 2734 | er->from_cacheex1_client = 0;
|
|---|
| 2735 | if(cacheex == 1) {er->from_cacheex1_client = 1;}
|
|---|
| 2736 | #endif
|
|---|
| 2737 |
|
|---|
| 2738 |
|
|---|
| 2739 | // set preferlocalcards for this ecm request (actually, paramter
|
|---|
| 2740 | // is per user based, maybe in fiture it will be caid based too)
|
|---|
| 2741 | er->preferlocalcards = cfg.preferlocalcards;
|
|---|
| 2742 | if(client->account && client->account->preferlocalcards > -1)
|
|---|
| 2743 | {
|
|---|
| 2744 | er->preferlocalcards = client->account->preferlocalcards;
|
|---|
| 2745 | }
|
|---|
| 2746 | if(er->preferlocalcards <0 || er->preferlocalcards >2) {er->preferlocalcards=0;}
|
|---|
| 2747 |
|
|---|
| 2748 |
|
|---|
| 2749 | if(chk_is_betatunnel_caid(er->caid) && client->ttab.ttnum)
|
|---|
| 2750 | {
|
|---|
| 2751 | cs_log_dump_dbg(D_TRACE, er->ecm, 13, "betatunnel? ecmlen=%d", er->ecmlen);
|
|---|
| 2752 | cs_betatunnel(er);
|
|---|
| 2753 | }
|
|---|
| 2754 |
|
|---|
| 2755 |
|
|---|
| 2756 | // ignore ecm...
|
|---|
| 2757 | int32_t offset = 3;
|
|---|
| 2758 |
|
|---|
| 2759 | // ...and betacrypt header for cache md5 calculation
|
|---|
| 2760 | if(caid_is_betacrypt(er->caid))
|
|---|
| 2761 | { offset = 13; }
|
|---|
| 2762 |
|
|---|
| 2763 | uint8_t md5tmp[MD5_DIGEST_LENGTH];
|
|---|
| 2764 |
|
|---|
| 2765 | // store ECM in cache
|
|---|
| 2766 | memcpy(er->ecmd5, MD5(er->ecm + offset, er->ecmlen - offset, md5tmp), CS_ECMSTORESIZE);
|
|---|
| 2767 | cacheex_update_hash(er);
|
|---|
| 2768 | ac_chk(client, er, 0);
|
|---|
| 2769 |
|
|---|
| 2770 |
|
|---|
| 2771 | //******** CHECK IF FOUND ECM IN CACHE
|
|---|
| 2772 | struct ecm_request_t *ecm = NULL;
|
|---|
| 2773 | ecm = check_cache(er, client);
|
|---|
| 2774 | if(ecm) // found in cache
|
|---|
| 2775 | {
|
|---|
| 2776 | cs_log_dbg(D_LB,"{client %s, caid %04X, prid %06X, srvid %04X} [get_cw] cw found immediately in cache! ", (check_client(er->client)?er->client->account->usr:"-"),er->caid, er->prid, er->srvid);
|
|---|
| 2777 |
|
|---|
| 2778 | struct s_write_from_cache *wfc = NULL;
|
|---|
| 2779 | if(!cs_malloc(&wfc, sizeof(struct s_write_from_cache)))
|
|---|
| 2780 | {
|
|---|
| 2781 | NULLFREE(ecm);
|
|---|
| 2782 | free_ecm(er);
|
|---|
| 2783 | return;
|
|---|
| 2784 | }
|
|---|
| 2785 |
|
|---|
| 2786 | wfc->er_new = er;
|
|---|
| 2787 | wfc->er_cache = ecm;
|
|---|
| 2788 | write_ecm_answer_fromcache(wfc);
|
|---|
| 2789 | NULLFREE(wfc);
|
|---|
| 2790 | NULLFREE(ecm);
|
|---|
| 2791 | free_ecm(er);
|
|---|
| 2792 |
|
|---|
| 2793 | return;
|
|---|
| 2794 | }
|
|---|
| 2795 |
|
|---|
| 2796 | // zaplist ACoSC
|
|---|
| 2797 | #ifdef CS_ANTICASC
|
|---|
| 2798 | if(cfg.acosc_enabled)
|
|---|
| 2799 | {
|
|---|
| 2800 | cs_writelock(__func__, &clientlist_lock);
|
|---|
| 2801 | insert_zaplist(er, client);
|
|---|
| 2802 | cs_writeunlock(__func__, &clientlist_lock);
|
|---|
| 2803 | }
|
|---|
| 2804 | #endif
|
|---|
| 2805 |
|
|---|
| 2806 | er->reader_avail = 0;
|
|---|
| 2807 | er->readers = 0;
|
|---|
| 2808 |
|
|---|
| 2809 | struct s_ecm_answer *ea, *prv = NULL;
|
|---|
| 2810 | struct s_reader *rdr;
|
|---|
| 2811 |
|
|---|
| 2812 | cs_readlock(__func__, &readerlist_lock);
|
|---|
| 2813 | cs_readlock(__func__, &clientlist_lock);
|
|---|
| 2814 |
|
|---|
| 2815 | for(rdr = first_active_reader; rdr; rdr = rdr->next)
|
|---|
| 2816 | {
|
|---|
| 2817 | uint8_t is_fallback = chk_is_fixed_fallback(rdr, er);
|
|---|
| 2818 | int8_t match = matching_reader(er, rdr);
|
|---|
| 2819 |
|
|---|
| 2820 | if(!match) // if this reader does not match, check betatunnel for it
|
|---|
| 2821 | match = lb_check_auto_betatunnel(er, rdr);
|
|---|
| 2822 |
|
|---|
| 2823 | if(match)
|
|---|
| 2824 | {
|
|---|
| 2825 | er->reader_avail++;
|
|---|
| 2826 |
|
|---|
| 2827 | #ifdef CS_CACHEEX
|
|---|
| 2828 | if(cacheex == 1 && !cacheex_reader(rdr)) // ex1-cl only ask ex1-rdr
|
|---|
| 2829 | { continue; }
|
|---|
| 2830 | #endif
|
|---|
| 2831 |
|
|---|
| 2832 | if(!cs_malloc(&ea, sizeof(struct s_ecm_answer)))
|
|---|
| 2833 | { goto OUT; }
|
|---|
| 2834 |
|
|---|
| 2835 | #ifdef WITH_EXTENDED_CW
|
|---|
| 2836 | // Correct CSA mode is CBC - default to that instead
|
|---|
| 2837 | ea->cw_ex.algo_mode = CW_ALGO_MODE_CBC;
|
|---|
| 2838 | #endif
|
|---|
| 2839 |
|
|---|
| 2840 | er->readers++;
|
|---|
| 2841 |
|
|---|
| 2842 | ea->reader = rdr;
|
|---|
| 2843 | ea->er = er;
|
|---|
| 2844 | ea->rc = E_UNHANDLED;
|
|---|
| 2845 | if(prv)
|
|---|
| 2846 | { prv->next = ea; }
|
|---|
| 2847 | else
|
|---|
| 2848 | { er->matching_rdr = ea; }
|
|---|
| 2849 | prv = ea;
|
|---|
| 2850 |
|
|---|
| 2851 | ea->status = READER_ACTIVE;
|
|---|
| 2852 | if(cacheex_reader(rdr))
|
|---|
| 2853 | { ea->status |= READER_CACHEEX; }
|
|---|
| 2854 | else if(is_localreader(rdr, er))
|
|---|
| 2855 | { ea->status |= READER_LOCAL; }
|
|---|
| 2856 |
|
|---|
| 2857 | if(is_fallback && (!is_localreader(rdr, er) || (is_localreader(rdr, er) && !er->preferlocalcards)))
|
|---|
| 2858 | { ea->status |= READER_FALLBACK; }
|
|---|
| 2859 |
|
|---|
| 2860 | ea->pending = NULL;
|
|---|
| 2861 | ea->is_pending = false;
|
|---|
| 2862 | cs_lock_create(__func__, &ea->ecmanswer_lock, "ecmanswer_lock", 5000);
|
|---|
| 2863 | }
|
|---|
| 2864 | }
|
|---|
| 2865 |
|
|---|
| 2866 | OUT:
|
|---|
| 2867 | cs_readunlock(__func__, &clientlist_lock);
|
|---|
| 2868 | cs_readunlock(__func__, &readerlist_lock);
|
|---|
| 2869 |
|
|---|
| 2870 | lb_set_best_reader(er);
|
|---|
| 2871 |
|
|---|
| 2872 | // set reader_count and fallback_reader_count
|
|---|
| 2873 | set_readers_counter(er);
|
|---|
| 2874 |
|
|---|
| 2875 | // if preferlocalcards > 0, check if we have local readers selected:
|
|---|
| 2876 | // if not, switch to preferlocalcards = 0 for this ecm
|
|---|
| 2877 | if(er->preferlocalcards > 0)
|
|---|
| 2878 | {
|
|---|
| 2879 | if(er->localreader_count == 0)
|
|---|
| 2880 | {
|
|---|
| 2881 | er->preferlocalcards = 0;
|
|---|
| 2882 | cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} NO local readers, set preferlocalcards = %d",
|
|---|
| 2883 | (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid, er->preferlocalcards);
|
|---|
| 2884 | }
|
|---|
| 2885 | }
|
|---|
| 2886 |
|
|---|
| 2887 | #ifdef CS_CACHEEX
|
|---|
| 2888 | // WAIT_TIME
|
|---|
| 2889 | uint32_t cacheex_wait_time = 0;
|
|---|
| 2890 | uint32_t wait_time_no_hitcache = 0;
|
|---|
| 2891 | uint32_t wait_time_hitcache = 0;
|
|---|
| 2892 |
|
|---|
| 2893 | if(client->account && !client->account->no_wait_time
|
|---|
| 2894 | #ifdef CS_CACHEEX_AIO
|
|---|
| 2895 | && !chk_srvid_no_wait_time(er)
|
|---|
| 2896 | #endif
|
|---|
| 2897 | && er->preferlocalcards<2)
|
|---|
| 2898 | {
|
|---|
| 2899 | wait_time_no_hitcache = get_cacheex_wait_time(er,NULL); // NO check hitcache. Wait_time is dwtime, or, if 0, awtime.
|
|---|
| 2900 | wait_time_hitcache = get_cacheex_wait_time(er,client); // check hitcache for calculating wait_time! If hitcache wait_time is biggest value between dwtime and awtime, else it's awtime.
|
|---|
| 2901 |
|
|---|
| 2902 | if(
|
|---|
| 2903 | // If "normal" client and ex1-rdr>0, we cannot use hitcache for calculating wait_time because we cannot know if cw is available or not on ex1 server!
|
|---|
| 2904 | (cacheex != 1 && er->cacheex_reader_count)
|
|---|
| 2905 | ||
|
|---|
| 2906 | /* Cw for ex1-cl comes from: INT. cache by "normal" readers (normal clients that ask normal readers), ex1-rdr and ex2-rdr and ex3-rdr.
|
|---|
| 2907 | * If readers, we have to wait cws generating by normal clients asking normal readers and answers by ex1-rdr (cannot use hitcache).
|
|---|
| 2908 | * If no readers, use hitcache for calculating wait_time.
|
|---|
| 2909 | */
|
|---|
| 2910 | (cacheex == 1 && er->reader_avail)
|
|---|
| 2911 | )
|
|---|
| 2912 | { cacheex_wait_time = wait_time_no_hitcache; }
|
|---|
| 2913 | else
|
|---|
| 2914 | { cacheex_wait_time = wait_time_hitcache; }
|
|---|
| 2915 | }
|
|---|
| 2916 |
|
|---|
| 2917 | cs_log_dbg(D_TRACE | D_CACHEEX, "[GET_CW] wait_time %d caid %04X prov %06X srvid %04X rc %d cacheex cl mode %d ex1rdr %d", cacheex_wait_time, er->caid, er->prid, er->srvid, er->rc, cacheex, er->cacheex_reader_count);
|
|---|
| 2918 | cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} [get_cw] wait_time %d - client cacheex mode %d, reader avail for ecm %d, hitcache %d, preferlocalcards %d", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid, cacheex_wait_time, cacheex == 1 ? 1 : 0, er->reader_avail, wait_time_hitcache ? 1 : 0, er->preferlocalcards);
|
|---|
| 2919 | // END WAIT_TIME calculation
|
|---|
| 2920 |
|
|---|
| 2921 | if(!cacheex_wait_time && (er->reader_count + er->fallback_reader_count) == 0)
|
|---|
| 2922 | #else
|
|---|
| 2923 | if((er->reader_count + er->fallback_reader_count) == 0)
|
|---|
| 2924 | #endif
|
|---|
| 2925 | {
|
|---|
| 2926 | er->rc = E_NOTFOUND;
|
|---|
| 2927 | if(!er->rcEx)
|
|---|
| 2928 | { er->rcEx = E2_GROUP; }
|
|---|
| 2929 | snprintf(er->msglog, MSGLOGSIZE, "no matching reader");
|
|---|
| 2930 | cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} [get_cw] NO Readers and NO wait_time... not_found! ", (check_client(er->client) ? er->client->account->usr : "-"), er->caid, er->prid, er->srvid);
|
|---|
| 2931 | send_dcw(client, er);
|
|---|
| 2932 | free_ecm(er);
|
|---|
| 2933 | return;
|
|---|
| 2934 | }
|
|---|
| 2935 |
|
|---|
| 2936 | //insert it in ecmcwcache!
|
|---|
| 2937 | cs_writelock(__func__, &ecmcache_lock);
|
|---|
| 2938 | er->next = ecmcwcache;
|
|---|
| 2939 | ecmcwcache = er;
|
|---|
| 2940 | ecmcwcache_size++;
|
|---|
| 2941 | cs_writeunlock(__func__, &ecmcache_lock);
|
|---|
| 2942 |
|
|---|
| 2943 | er->rcEx = 0;
|
|---|
| 2944 | #ifdef CS_CACHEEX
|
|---|
| 2945 | er->cacheex_wait_time = 0;
|
|---|
| 2946 | er->cacheex_wait_time_expired = 1;
|
|---|
| 2947 | er->cacheex_hitcache = 0;
|
|---|
| 2948 | er->cacheex_mode1_delay = 0;
|
|---|
| 2949 |
|
|---|
| 2950 | if(cacheex_wait_time) // wait time for cacheex
|
|---|
| 2951 | {
|
|---|
| 2952 | er->cacheex_wait_time = cacheex_wait_time;
|
|---|
| 2953 | er->cacheex_wait_time_expired = 0;
|
|---|
| 2954 | er->cacheex_hitcache = wait_time_hitcache ? 1 : 0; // usefull only when cacheex mode 1 readers answers before wait_time and we have to decide if we have to wait until wait_time expires.
|
|---|
| 2955 | er->cacheex_mode1_delay = get_cacheex_mode1_delay(er);
|
|---|
| 2956 |
|
|---|
| 2957 | if(!er->cacheex_mode1_delay && er->cacheex_reader_count > 0)
|
|---|
| 2958 | {
|
|---|
| 2959 | request_cw_from_readers(er, 1); // setting stop_stage=1, we request only cacheex mode 1 readers. Others are requested at cacheex timeout!
|
|---|
| 2960 | }
|
|---|
| 2961 | }
|
|---|
| 2962 | else
|
|---|
| 2963 | #endif
|
|---|
| 2964 | request_cw_from_readers(er, 0);
|
|---|
| 2965 |
|
|---|
| 2966 | #ifdef WITH_DEBUG
|
|---|
| 2967 | if(D_CLIENTECM & cs_dblevel)
|
|---|
| 2968 | {
|
|---|
| 2969 | char buf[ECM_FMT_LEN];
|
|---|
| 2970 | format_ecm(er, buf, ECM_FMT_LEN);
|
|---|
| 2971 | cs_log_dump_dbg(D_CLIENTECM, er->ecm, er->ecmlen, "Client %s ECM dump %s", username(client), buf);
|
|---|
| 2972 | }
|
|---|
| 2973 | #endif
|
|---|
| 2974 |
|
|---|
| 2975 | cw_process_thread_wakeup();
|
|---|
| 2976 | }
|
|---|
| 2977 |
|
|---|
| 2978 | int32_t ecmfmt(char *result, size_t size, uint16_t caid, uint16_t onid, uint32_t prid, uint16_t chid, uint16_t pid,
|
|---|
| 2979 | uint16_t srvid, uint16_t l, char *ecmd5hex, char *csphash, char *cw, uint16_t origin_peer, uint8_t distance, char *payload, char *tier)
|
|---|
| 2980 | {
|
|---|
| 2981 | if(!cfg.ecmfmt)
|
|---|
| 2982 | {
|
|---|
| 2983 | if(tier && payload)
|
|---|
| 2984 | {
|
|---|
| 2985 | return snprintf(result, size, "%04X@%06X/%04X/%04X/%02X:%s:0F06%s:%s", caid, prid, chid, srvid, l, ecmd5hex, payload, tier);
|
|---|
| 2986 | }
|
|---|
| 2987 | else if(tier)
|
|---|
| 2988 | {
|
|---|
| 2989 | return snprintf(result, size, "%04X@%06X/%04X/%04X/%02X:%s:%s", caid, prid, chid, srvid, l, ecmd5hex, tier);
|
|---|
| 2990 | }
|
|---|
| 2991 | else if(payload)
|
|---|
| 2992 | {
|
|---|
| 2993 | return snprintf(result, size, "%04X@%06X/%04X/%04X/%02X:%s:0F06%s", caid, prid, chid, srvid, l, ecmd5hex, payload);
|
|---|
| 2994 | }
|
|---|
| 2995 | else
|
|---|
| 2996 | {
|
|---|
| 2997 | return snprintf(result, size, "%04X@%06X/%04X/%04X/%02X:%s", caid, prid, chid, srvid, l, ecmd5hex);
|
|---|
| 2998 | }
|
|---|
| 2999 | }
|
|---|
| 3000 |
|
|---|
| 3001 | #define ECMFMT_NUMBER 0
|
|---|
| 3002 | #define ECMFMT_STRING 1
|
|---|
| 3003 | #define ECMFMT_CHAR 2
|
|---|
| 3004 |
|
|---|
| 3005 | uint8_t type = 0;
|
|---|
| 3006 | uint32_t ivalue = 0;
|
|---|
| 3007 | char *ifmt = NULL, *sfmt = NULL;
|
|---|
| 3008 | char *svalue = NULL, cvalue = '\0';
|
|---|
| 3009 | uint8_t hide_if_zero = 0;
|
|---|
| 3010 | char *c;
|
|---|
| 3011 | uint32_t s = 0;
|
|---|
| 3012 |
|
|---|
| 3013 | for(c = cfg.ecmfmt; *c; c++)
|
|---|
| 3014 | {
|
|---|
| 3015 | if(*c == '0')
|
|---|
| 3016 | {
|
|---|
| 3017 | hide_if_zero = 1;
|
|---|
| 3018 | continue;
|
|---|
| 3019 | }
|
|---|
| 3020 |
|
|---|
| 3021 | sfmt = NULL;
|
|---|
| 3022 |
|
|---|
| 3023 | switch(*c)
|
|---|
| 3024 | {
|
|---|
| 3025 | case 't':
|
|---|
| 3026 | type = ECMFMT_STRING;
|
|---|
| 3027 | svalue = tier;
|
|---|
| 3028 | if(tier == NULL && !hide_if_zero)
|
|---|
| 3029 | {
|
|---|
| 3030 | type = ECMFMT_NUMBER;
|
|---|
| 3031 | ifmt = "%04X";
|
|---|
| 3032 | ivalue = 0;
|
|---|
| 3033 | }
|
|---|
| 3034 | break;
|
|---|
| 3035 |
|
|---|
| 3036 | case 'c':
|
|---|
| 3037 | type = ECMFMT_NUMBER;
|
|---|
| 3038 | ifmt = "%04X";
|
|---|
| 3039 | ivalue = caid;
|
|---|
| 3040 | break;
|
|---|
| 3041 |
|
|---|
| 3042 | case 'o':
|
|---|
| 3043 | type = ECMFMT_NUMBER;
|
|---|
| 3044 | ifmt = "%04X";
|
|---|
| 3045 | ivalue = onid;
|
|---|
| 3046 | break;
|
|---|
| 3047 |
|
|---|
| 3048 | case 'p':
|
|---|
| 3049 | type = ECMFMT_NUMBER;
|
|---|
| 3050 | ifmt = "%06X";
|
|---|
| 3051 | ivalue = prid;
|
|---|
| 3052 | break;
|
|---|
| 3053 |
|
|---|
| 3054 | case 'i':
|
|---|
| 3055 | type = ECMFMT_NUMBER;
|
|---|
| 3056 | ifmt = "%04X";
|
|---|
| 3057 | ivalue = chid;
|
|---|
| 3058 | break;
|
|---|
| 3059 |
|
|---|
| 3060 | case 'd':
|
|---|
| 3061 | type = ECMFMT_NUMBER;
|
|---|
| 3062 | ifmt = "%04X";
|
|---|
| 3063 | ivalue = pid;
|
|---|
| 3064 | break;
|
|---|
| 3065 |
|
|---|
| 3066 | case 's':
|
|---|
| 3067 | type = ECMFMT_NUMBER;
|
|---|
| 3068 | ifmt = "%04X";
|
|---|
| 3069 | ivalue = srvid;
|
|---|
| 3070 | break;
|
|---|
| 3071 |
|
|---|
| 3072 | case 'l':
|
|---|
| 3073 | type = ECMFMT_NUMBER;
|
|---|
| 3074 | ifmt = "%02X";
|
|---|
| 3075 | ivalue = l;
|
|---|
| 3076 | break;
|
|---|
| 3077 |
|
|---|
| 3078 | case 'h':
|
|---|
| 3079 | type = ECMFMT_STRING;
|
|---|
| 3080 | svalue = ecmd5hex;
|
|---|
| 3081 | break;
|
|---|
| 3082 |
|
|---|
| 3083 | case 'e':
|
|---|
| 3084 | type = ECMFMT_STRING;
|
|---|
| 3085 | svalue = csphash;
|
|---|
| 3086 | break;
|
|---|
| 3087 |
|
|---|
| 3088 | case 'w':
|
|---|
| 3089 | type = ECMFMT_STRING;
|
|---|
| 3090 | svalue = cw;
|
|---|
| 3091 | break;
|
|---|
| 3092 |
|
|---|
| 3093 | case 'j':
|
|---|
| 3094 | type = ECMFMT_NUMBER;
|
|---|
| 3095 | ifmt = "%02X";
|
|---|
| 3096 | ivalue = distance;
|
|---|
| 3097 | break;
|
|---|
| 3098 |
|
|---|
| 3099 | case 'g':
|
|---|
| 3100 | type = ECMFMT_NUMBER;
|
|---|
| 3101 | ifmt = "%04X";
|
|---|
| 3102 | ivalue = origin_peer;
|
|---|
| 3103 | break;
|
|---|
| 3104 |
|
|---|
| 3105 | case '\\':
|
|---|
| 3106 | c++;
|
|---|
| 3107 | type = ECMFMT_CHAR;
|
|---|
| 3108 | cvalue = *c;
|
|---|
| 3109 |
|
|---|
| 3110 | if(cvalue == '\0')
|
|---|
| 3111 | { return s; }
|
|---|
| 3112 | break;
|
|---|
| 3113 |
|
|---|
| 3114 | case 'y':
|
|---|
| 3115 | type = ECMFMT_STRING;
|
|---|
| 3116 | svalue = payload;
|
|---|
| 3117 | sfmt = "0F06%.06s";
|
|---|
| 3118 | if(payload == NULL && !hide_if_zero)
|
|---|
| 3119 | {
|
|---|
| 3120 | type = ECMFMT_NUMBER;
|
|---|
| 3121 | ifmt = "0F06%06X";
|
|---|
| 3122 | ivalue = 0;
|
|---|
| 3123 | }
|
|---|
| 3124 | break;
|
|---|
| 3125 |
|
|---|
| 3126 | case 'Y':
|
|---|
| 3127 | type = ECMFMT_STRING;
|
|---|
| 3128 | svalue = payload;
|
|---|
| 3129 | sfmt = "0F06%s";
|
|---|
| 3130 | if(payload == NULL && !hide_if_zero)
|
|---|
| 3131 | {
|
|---|
| 3132 | type = ECMFMT_NUMBER;
|
|---|
| 3133 | ifmt = "0F06%12X";
|
|---|
| 3134 | ivalue = 0;
|
|---|
| 3135 | }
|
|---|
| 3136 | break;
|
|---|
| 3137 |
|
|---|
| 3138 | default:
|
|---|
| 3139 | type = ECMFMT_CHAR;
|
|---|
| 3140 | cvalue = *c;
|
|---|
| 3141 | break;
|
|---|
| 3142 | }
|
|---|
| 3143 |
|
|---|
| 3144 | if(hide_if_zero)
|
|---|
| 3145 | {
|
|---|
| 3146 | if(type == ECMFMT_NUMBER && ivalue == 0)
|
|---|
| 3147 | {
|
|---|
| 3148 | hide_if_zero = 0;
|
|---|
| 3149 | continue;
|
|---|
| 3150 | }
|
|---|
| 3151 | else if(type == ECMFMT_STRING && svalue == NULL)
|
|---|
| 3152 | {
|
|---|
| 3153 | hide_if_zero = 0;
|
|---|
| 3154 | continue;
|
|---|
| 3155 | }
|
|---|
| 3156 | }
|
|---|
| 3157 |
|
|---|
| 3158 | switch(type)
|
|---|
| 3159 | {
|
|---|
| 3160 | case ECMFMT_NUMBER:
|
|---|
| 3161 | s += snprintf(result + s, size - s, ifmt, ivalue);
|
|---|
| 3162 | break;
|
|---|
| 3163 |
|
|---|
| 3164 | case ECMFMT_STRING:
|
|---|
| 3165 | s += snprintf(result + s, size - s , sfmt != NULL ? sfmt : "%s", svalue);
|
|---|
| 3166 | break;
|
|---|
| 3167 |
|
|---|
| 3168 | case ECMFMT_CHAR:
|
|---|
| 3169 | if(size - s > 1)
|
|---|
| 3170 | {
|
|---|
| 3171 | result[s] = cvalue;
|
|---|
| 3172 | result[s+1] = '\0';
|
|---|
| 3173 | s++;
|
|---|
| 3174 | }
|
|---|
| 3175 | break;
|
|---|
| 3176 |
|
|---|
| 3177 | default:
|
|---|
| 3178 | break;
|
|---|
| 3179 | }
|
|---|
| 3180 | }
|
|---|
| 3181 |
|
|---|
| 3182 | return s;
|
|---|
| 3183 | }
|
|---|
| 3184 |
|
|---|
| 3185 | int32_t format_ecm(ECM_REQUEST *ecm, char *result, size_t size)
|
|---|
| 3186 | {
|
|---|
| 3187 | char ecmd5hex[(16*2)+1];
|
|---|
| 3188 | char csphash[(4*2)+1] = { 0 };
|
|---|
| 3189 | char cwhex[(16*2)+1];
|
|---|
| 3190 | char *payload = NULL;
|
|---|
| 3191 | char *tier = NULL;
|
|---|
| 3192 | #ifdef READER_VIDEOGUARD
|
|---|
| 3193 | char payload_string[(6*2)+1];
|
|---|
| 3194 | char tier_string[83];
|
|---|
| 3195 | struct s_ecm_answer *ea;
|
|---|
| 3196 |
|
|---|
| 3197 | if(ecm->selected_reader && caid_is_videoguard(ecm->selected_reader->caid) && !is_network_reader(ecm->selected_reader))
|
|---|
| 3198 | {
|
|---|
| 3199 | for(ea = ecm->matching_rdr; ea; ea = ea->next)
|
|---|
| 3200 | {
|
|---|
| 3201 | if(ea->tier && (ea->status & REQUEST_ANSWERED) && !is_network_reader(ea->reader))
|
|---|
| 3202 | {
|
|---|
| 3203 | get_tiername_defaultid(ea->tier, ecm->selected_reader->caid, tier_string);
|
|---|
| 3204 | tier = tier_string;
|
|---|
| 3205 | break;
|
|---|
| 3206 | }
|
|---|
| 3207 | }
|
|---|
| 3208 |
|
|---|
| 3209 | cs_hexdump(0, ecm->selected_reader->VgLastPayload, 6, payload_string, sizeof(payload_string));
|
|---|
| 3210 | payload = payload_string;
|
|---|
| 3211 | }
|
|---|
| 3212 | #endif
|
|---|
| 3213 | cs_hexdump(0, ecm->ecmd5, 16, ecmd5hex, sizeof(ecmd5hex));
|
|---|
| 3214 | #ifdef CS_CACHEEX
|
|---|
| 3215 | cs_hexdump(0, (void *)&ecm->csp_hash, 4, csphash, sizeof(csphash));
|
|---|
| 3216 | #endif
|
|---|
| 3217 | cs_hexdump(0, ecm->cw, 16, cwhex, sizeof(cwhex));
|
|---|
| 3218 | #ifdef MODULE_GBOX
|
|---|
| 3219 | if(check_client(ecm->client) && get_module(ecm->client)->num == R_GBOX && ecm->gbox_ecm_dist)
|
|---|
| 3220 | { return ecmfmt(result, size, ecm->caid, ecm->onid, ecm->prid, ecm->chid, ecm->pid, ecm->srvid, ecm->ecmlen, ecmd5hex, csphash, cwhex, ecm->gbox_ecm_src_peer, ecm->gbox_ecm_dist, payload, tier); }
|
|---|
| 3221 | else if (ecm->selected_reader && ecm->selected_reader->typ == R_GBOX && !ecm->gbox_ecm_dist)
|
|---|
| 3222 | { return ecmfmt(result, size, ecm->caid, ecm->onid, ecm->prid, ecm->chid, ecm->pid, ecm->srvid, ecm->ecmlen, ecmd5hex, csphash, cwhex, ecm->selected_reader->gbox_cw_src_peer, ecm->selected_reader->currenthops, payload, tier); }
|
|---|
| 3223 | else
|
|---|
| 3224 | #endif
|
|---|
| 3225 | return ecmfmt(result, size, ecm->caid, ecm->onid, ecm->prid, ecm->chid, ecm->pid, ecm->srvid, ecm->ecmlen, ecmd5hex, csphash, cwhex, 0,
|
|---|
| 3226 | ((ecm->selected_reader && ecm->selected_reader->currenthops) ? ecm->selected_reader->currenthops : 0), payload, tier);
|
|---|
| 3227 | }
|
|---|