void cacheex_timeout(ECM_REQUEST *er) { if(er->cacheex_wait_time_expired) return; er->cacheex_wait_time_expired = 1; if(er->rc >= E_UNHANDLED) { cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} cacheex timeout! ", (check_client(er->client) ? er->client->account->usr : "******"), er->caid, er->prid, er->srvid); // if check_cw mode=0, first try to get cw from cache without check counter! CWCHECK check_cw = get_cwcheck(er); if(!check_cw.mode) { struct ecm_request_t *ecm = NULL; ecm = check_cache(er, er->client); if(ecm) // found in cache { struct s_write_from_cache *wfc = NULL; if(!cs_malloc(&wfc, sizeof(struct s_write_from_cache))) { NULLFREE(ecm); return; } wfc->er_new = er; wfc->er_cache = ecm; if(!add_job(er->client, ACTION_ECM_ANSWER_CACHE, wfc, sizeof(struct s_write_from_cache))) // write_ecm_answer_fromcache { NULLFREE(ecm); } return; } } // check if "normal" readers selected, if not send NOT FOUND! // cacheex1-client (having always no "normal" reader), // or not-cacheex-1 client with no normal readers available (or filtered by LB) if((er->reader_count + er->fallback_reader_count - er->cacheex_reader_count) <= 0) { if(!cfg.wait_until_ctimeout) { er->rc = E_NOTFOUND; er->selected_reader = NULL; er->rcEx = 0; cs_log_dbg(D_LB, "{client %s, caid %04X, prid %06X, srvid %04X} cacheex timeout: NO \"normal\" readers... not_found! ", (check_client(er->client) ? er->client->account->usr : "******"), er->caid, er->prid, er->srvid); send_dcw(er->client, er); return; } } else { if(er->stage < 2) { debug_ecm(D_TRACE, "request for %s %s", username(er->client), buf); request_cw_from_readers(er, 0); } } } }
/* * This function returns cw (mostly received) in cache for er, or NULL if not found. * IMPORTANT: * - If found, DON'T forget to free returned ecm, because it is a copy useful to get data * - If found, and cacheex_src client of returned ecm is not NULL, and we want to access it, * remember to check for its validity (client structure is still existent) * E.g.: if(ecm->cacheex_src && is_valid_client(ecm->cacheex_src) && !ecm->cacheex_src->kill) * We don't want make this stuff here to avoid useless cpu time if outside function we would not access to it. */ struct ecm_request_t *check_cache(ECM_REQUEST *er, struct s_client *cl) { if(!er->csp_hash) return NULL; ECM_REQUEST *ecm = NULL; ECMHASH *result; CW *cw; uint64_t grp = cl?cl->grp:0; pthread_rwlock_rdlock(&cache_lock); result = find_hash_table(&ht_cache, &er->csp_hash, sizeof(int32_t),&compare_csp_hash); cw = get_first_cw(result, er); if( cw && ( cw->csp //csp have no grp! || !grp //csp client(no grp) searching for cache || ( grp && cw->grp //ecm group --> only when readers/ex-clients answer (e_found) it && (grp & cw->grp) ) ) ){ #ifdef CS_CACHEEX //if preferlocalcards=2 for this ecm request, we can server ONLY cw from localcards readers until stage<3 if(er->preferlocalcards==2 && !cw->localcards && er->stage<3){ pthread_rwlock_unlock(&cache_lock); return NULL; } CWCHECK check_cw = get_cwcheck(er); if((!cw->proxy && !cw->localcards) //cw received from ONLY cacheex/csp peers && check_cw.counter>1 && cw->count < check_cw.counter && (check_cw.mode || !er->cacheex_wait_time_expired) ){ pthread_rwlock_unlock(&cache_lock); return NULL; } #endif #ifdef CW_CYCLE_CHECK uint8_t cwc_ct = cw->cwc_cycletime > 0 ? cw->cwc_cycletime : 0; uint8_t cwc_ncwc = cw->cwc_next_cw_cycle < 2 ? cw->cwc_next_cw_cycle : 2; if(cw->got_bad_cwc) { pthread_rwlock_unlock(&cache_lock); return NULL; } if(checkcwcycle(cl, er, NULL, cw->cw, 0, cwc_ct, cwc_ncwc) != 0){ cs_debug_mask(D_CWC | D_LB, "{client %s, caid %04X, srvid %04X} [check_cache] cyclecheck passed ecm in INT. cache, ecm->rc %d", (cl ? cl->account->usr : "******"), er->caid, er->srvid, ecm ? ecm->rc : -1); }else{ cs_debug_mask(D_CWC, "cyclecheck [BAD CW Cycle] from Int. Cache detected.. {client %s, caid %04X, srvid %04X} [check_cache] -> skip cache answer", (cl ? cl->account->usr : "******"), er->caid, er->srvid); cw->got_bad_cwc = 1; // no need to check it again pthread_rwlock_unlock(&cache_lock); return NULL; } #endif if (cs_malloc(&ecm, sizeof(ECM_REQUEST))){ ecm->rc = E_FOUND; ecm->rcEx = 0; memcpy(ecm->cw, cw->cw, 16); ecm->grp = cw->grp; ecm->selected_reader = cw->selected_reader; ecm->cwc_cycletime = cw->cwc_cycletime; ecm->cwc_next_cw_cycle = cw->cwc_next_cw_cycle; #ifdef CS_CACHEEX ecm->cacheex_src = cw->cacheex_src; #endif ecm->cw_count = cw->count; } } pthread_rwlock_unlock(&cache_lock); return ecm; }