void config_list_set_defaults(const struct config_list *clist, void *config_data) { const struct config_list *c; for (c = clist; c->opt_type != OPT_UNKNOWN; c++) { void *var = config_data + c->var_offset; switch (c->opt_type) { case OPT_INT8: { *(int8_t *)var = c->def.d_int8; break; } case OPT_UINT8: { *(uint8_t *)var = c->def.d_uint8; break; } case OPT_INT32: { *(int32_t *)var = c->def.d_int32; break; } case OPT_UINT32: { *(uint32_t *)var = c->def.d_uint32; break; } case OPT_STRING: { char **scfg = var; NULLFREE(*scfg); if (c->def.d_char) *scfg = cs_strdup(c->def.d_char); break; } case OPT_SSTRING: { char *scfg = var; scfg[0] = '\0'; if (c->def.d_char && strlen(c->def.d_char)) cs_strncpy(scfg, c->def.d_char, c->str_size - 1); break; } case OPT_FUNC: { c->ops.process_fn((const char *)c->config_name, "", var, NULL); break; } case OPT_FUNC_EXTRA: { c->ops.process_fn_extra((const char *)c->config_name, "", var, c->def.d_extra, NULL); break; } case OPT_SAVE_FUNC: case OPT_FIXUP_FUNC: case OPT_UNKNOWN: continue; } } return; }
static void logfile_fn(const char *token, char *value, void *UNUSED(setting), FILE *f) { if(value) { char *saveptr1 = NULL; cfg.logtostdout = 0; cfg.logtosyslog = 0; NULLFREE(cfg.logfile); if(strlen(value) > 0) { char *pch; for(pch = strtok_r(value, ";", &saveptr1); pch != NULL; pch = strtok_r(NULL, ";", &saveptr1)) { pch = trim(pch); if(!strcmp(pch, "stdout")) { cfg.logtostdout = 1; } else if(!strcmp(pch, "syslog")) { cfg.logtosyslog = 1; } else { NULLFREE(cfg.logfile); if(!(cfg.logfile = cs_strdup(pch))) { continue; } } } } else { if(!(cfg.logfile = cs_strdup(CS_LOGFILE))) { cfg.logtostdout = 1; } } return; } if(cfg.logfile || cfg.logtostdout == 1 || cfg.logtosyslog == 1 || cfg.http_full_cfg) { value = mk_t_logfile(); fprintf_conf(f, token, "%s\n", value); free_mk_t(value); } }
/* * Destroy the window specified and recycle the window slot. */ void nds_destroy_nhwindow(winid win) { nds_nhwindow_t *window = windows[win]; nds_clear_nhwindow(win); if (window->img) { free_ppm(window->img); } NULLFREE(window); windows[win] = NULL; }
void config_list_free_values(const struct config_list *clist, void *config_data) { const struct config_list *c; for (c = clist; c->opt_type != OPT_UNKNOWN; c++) { void *var = config_data + c->var_offset; if (c->opt_type == OPT_STRING) { char **scfg = var; NULLFREE(*scfg); } if (c->free_value && (c->opt_type == OPT_FUNC || c->opt_type == OPT_FUNC_EXTRA)) { c->free_value(var); } } return; }
void kill_all_clients(void) { struct s_client *cl; for(cl = first_client->next; cl; cl = cl->next) { if(cl->typ == 'c' || cl->typ == 'm') { if(cl->account && cl->account->usr) { cs_log("killing client %s", cl->account->usr); } kill_thread(cl); } } NULLFREE(processUsername); }
void cacheex_load_config_file(void) { struct s_cacheex_matcher *entry, *old_list; old_list = cfg.cacheex_matcher; cfg.cacheex_matcher = cacheex_matcher_read_int(); while(old_list) { entry = old_list->next; NULLFREE(old_list); old_list = entry; } }
int32_t ICC_Async_Device_Init (struct s_reader *reader) { reader->fdmc=-1; rdr_debug_mask(reader, D_IFD, "Opening device %s", reader->device); reader->written = 0; int32_t ret = reader->crdr.reader_init(reader); if (ret == OK) rdr_debug_mask(reader, D_IFD, "Device %s succesfully opened", reader->device); else { if(reader->typ != R_SC8in1) NULLFREE(reader->crdr_data); rdr_debug_mask(reader, D_IFD, "ERROR: Can't open %s device", reader->device); } return ret; }
/* Clears the s_ptab struct provided by setting nfilts and nprids to zero. */ void clear_ptab(struct s_ptab *ptab) { int32_t i; ptab->nports = 0; for(i = 0; i < CS_MAXPORTS; i++) { if(ptab->ports[i].ncd) { ptab->ports[i].ncd->ncd_ftab.nfilts = 0; ptab->ports[i].ncd->ncd_ftab.filts[0].nprids = 0; NULLFREE(ptab->ports[i].ncd); ptab->ports[i].ncd = NULL; } } }
nds_cmd_t nds_get_pan_direction() { winid win; menu_item *sel; ANY_P ids[4]; nds_cmd_t cmd; int res; win = create_nhwindow(NHW_MENU); start_menu(win); ids[0].a_int = CMD_PAN_UP; ids[1].a_int = CMD_PAN_DOWN; ids[2].a_int = CMD_PAN_LEFT; ids[3].a_int = CMD_PAN_RIGHT; add_menu(win, NO_GLYPH, &(ids[0]), 0, 0, 0, "Pan Up", 0); add_menu(win, NO_GLYPH, &(ids[1]), 0, 0, 0, "Pan Down", 0); add_menu(win, NO_GLYPH, &(ids[2]), 0, 0, 0, "Pan Left", 0); add_menu(win, NO_GLYPH, &(ids[3]), 0, 0, 0, "Pan Right", 0); end_menu(win, "What Direction?"); res = select_menu(win, PICK_ONE, &sel); destroy_nhwindow(win); if (res <= 0) { cmd.f_char = -1; cmd.name = NULL; } else { cmd.f_char = sel->item.a_int; if (cmd.f_char == CMD_PAN_UP) { cmd.name = "Pan Up"; } else if (cmd.f_char == CMD_PAN_DOWN) { cmd.name = "Pan Down"; } else if (cmd.f_char == CMD_PAN_LEFT) { cmd.name = "Pan Left"; } else if (cmd.f_char == CMD_PAN_RIGHT) { cmd.name = "Pan Right"; } } NULLFREE(sel); return cmd; }
static struct CRYPTO_dynlock_value *SSL_dyn_create_function(const char *file, int32_t line) { struct CRYPTO_dynlock_value *l; if(!cs_malloc(&l, sizeof(struct CRYPTO_dynlock_value))) { return NULL; } if(pthread_mutex_init(&l->mutex, NULL)) { // Initialization of mutex failed. NULLFREE(l); return (NULL); } pthread_mutex_init(&l->mutex, NULL); // just to remove compiler warnings... if(file || line) { return l; } return l; }
static int32_t radegast_send_ecm(struct s_client *client, ECM_REQUEST *er, uchar *UNUSED(buf)) { int32_t n; uchar provid_buf[8]; uchar header[22] = "\x02\x01\x00\x06\x08\x30\x30\x30\x30\x30\x30\x30\x30\x07\x04\x30\x30\x30\x38\x08\x01\x02"; uchar *ecmbuf; if(!radegast_connect()) { return (-1); } if(!cs_malloc(&ecmbuf, er->ecmlen + 30)) { return -1; } ecmbuf[0] = 1; ecmbuf[1] = (er->ecmlen + 30 - 2) & 0xff; memcpy(ecmbuf + 2, header, sizeof(header)); for(n = 0; n < 4; n++) { snprintf((char *)provid_buf + (n * 2), sizeof(provid_buf) - (n * 2), "%02X", ((uchar *)(&er->prid))[4 - 1 - n]); } ecmbuf[7] = provid_buf[0]; ecmbuf[8] = provid_buf[1]; ecmbuf[9] = provid_buf[2]; ecmbuf[10] = provid_buf[3]; ecmbuf[11] = provid_buf[4]; ecmbuf[12] = provid_buf[5]; ecmbuf[13] = provid_buf[6]; ecmbuf[14] = provid_buf[7]; ecmbuf[2 + sizeof(header)] = 0xa; ecmbuf[3 + sizeof(header)] = 2; ecmbuf[4 + sizeof(header)] = er->caid >> 8; ecmbuf[5 + sizeof(header)] = er->caid & 0xff; ecmbuf[6 + sizeof(header)] = 3; ecmbuf[7 + sizeof(header)] = er->ecmlen & 0xff; memcpy(ecmbuf + 8 + sizeof(header), er->ecm, er->ecmlen); ecmbuf[4] = er->caid >> 8; client->reader->msg_idx = er->idx; n = send(client->pfd, ecmbuf, er->ecmlen + 30, 0); cs_debug_mask(D_TRACE, "radegast: sending ecm"); cs_ddump_mask(D_CLIENT, ecmbuf, er->ecmlen + 30, "ecm:"); NULLFREE(ecmbuf); return ((n < 1) ? (-1) : 0); }
static void scam_generate_deskey(char *keyString, uint8_t *desKey) { uint8_t iv[8], *tmpKey; int32_t i, passLen, alignedPassLen; uint32_t key_schedule[32]; memset(iv, 0, 8); memset(desKey, 0, 8); passLen = keyString == NULL ? 0 : strlen(keyString); if(passLen > 1024) { passLen = 1024; } alignedPassLen = (passLen + 7) & -8; if(alignedPassLen == 0) alignedPassLen = 8; if(!cs_malloc(&tmpKey, alignedPassLen)) { return; } if(passLen == 0) { memset(tmpKey, 0xAA, 8); passLen = 8; } else { memcpy(tmpKey, keyString, passLen); } for(i=0; i<alignedPassLen-passLen; i++) { tmpKey[passLen+i] = (uint8_t)i; } xxor(desKey,8,tmpKey,iv); for(i=0; i<alignedPassLen; i+=8) { des_set_key(&tmpKey[i], key_schedule); des(&tmpKey[i], key_schedule, 1); xxor(desKey,8,desKey,&tmpKey[i]); } NULLFREE(tmpKey); }
void cacheex_cleanup_hitcache(bool force) { CACHE_HIT *cachehit; node *i,*i_next; struct timeb now; int64_t gone, gone_max_hitcache_time; int32_t timeout = (cfg.max_hitcache_time + (cfg.max_hitcache_time / 2)) * 1000; // 1,5 int32_t clean_grp = (cfg.max_hitcache_time * 1000); SAFE_RWLOCK_WRLOCK(&hitcache_lock); i = get_first_node_list(&ll_hitcache); while (i) { i_next = i->next; cachehit = get_data_from_node(i); if(!cachehit) { i = i_next; continue; } cs_ftime(&now); gone = comp_timeb(&now, &cachehit->time); gone_max_hitcache_time = comp_timeb(&now, &cachehit->max_hitcache_time); if(force || gone>timeout) { remove_elem_list(&ll_hitcache, &cachehit->ll_node); remove_elem_hash_table(&ht_hitcache, &cachehit->ht_node); NULLFREE(cachehit); } else if(gone_max_hitcache_time >= clean_grp){ cachehit->grp = cachehit->grp_last_max_hitcache_time; cachehit->grp_last_max_hitcache_time = 0; cs_ftime(&cachehit->max_hitcache_time); } i = i_next; } SAFE_RWLOCK_UNLOCK(&hitcache_lock); }
void chk_cltab(char *classasc, CLASSTAB *clstab) { int32_t max_an = 0, max_bn = 0; char *ptr1, *saveptr1 = NULL, *classasc_org; CLASSTAB newclstab, oldclstab; memset(&newclstab, 0, sizeof(newclstab)); newclstab.an = newclstab.bn = 0; if(!cs_malloc(&classasc_org, sizeof(char)*strlen(classasc)+1)) { return; } cs_strncpy(classasc_org, classasc, sizeof(char)*strlen(classasc)+1); for(ptr1 = strtok_r(classasc, ",", &saveptr1); ptr1; ptr1 = strtok_r(NULL, ",", &saveptr1)) { ptr1 = trim(ptr1); if(ptr1[0] == '!') { max_bn++; } else { max_an++; } } if(max_an && !cs_malloc(&newclstab.aclass, sizeof(uchar)*max_an)) { NULLFREE(classasc_org); return; } if(max_bn && !cs_malloc(&newclstab.bclass, sizeof(uchar)*max_bn)) { NULLFREE(newclstab.aclass); NULLFREE(classasc_org); return; } classasc = classasc_org; for(ptr1 = strtok_r(classasc, ",", &saveptr1); ptr1; ptr1 = strtok_r(NULL, ",", &saveptr1)) { ptr1 = trim(ptr1); if(ptr1[0] == '!') { newclstab.bclass[newclstab.bn++] = (uchar)a2i(ptr1 + 1, 2); } else { newclstab.aclass[newclstab.an++] = (uchar)a2i(ptr1, 2); } } NULLFREE(classasc_org); memcpy(&oldclstab, clstab, sizeof(CLASSTAB)); memcpy(clstab, &newclstab, sizeof(CLASSTAB)); NULLFREE(oldclstab.aclass); NULLFREE(oldclstab.bclass); }
/**** INCOMING FILTER CHECK ***/ uint8_t check_cacheex_filter(struct s_client *cl, ECM_REQUEST *er) { if(check_client(cl) && cl->typ == 'p' && cl->reader && cl->reader->cacheex.mode==2 && (!cl->reader->cacheex.drop_csp || checkECMD5(er)) //cacheex_drop_csp-check && chk_ctab(er->caid, &cl->reader->ctab) //Caid-check && (!checkECMD5(er) || chk_ident_filter(er->caid, er->prid, &cl->reader->ftab)) //Ident-check (not for csp: prid=0 always!) && chk_srvid(cl, er) //Service-check ) { return 1; } if(check_client(cl) && cl->typ == 'c' && cl->account && cl->account->cacheex.mode==3 && (!cl->account->cacheex.drop_csp || checkECMD5(er)) //cacheex_drop_csp-check && chk_ctab(er->caid, &cl->ctab) //Caid-check && (!checkECMD5(er) || chk_ident_filter(er->caid, er->prid, &cl->ftab)) //Ident-check (not for csp: prid=0 always!) && chk_srvid(cl, er) //Service-check ) { return 1; } NULLFREE(er); return 0; }
static void cs_write_log_int(char *txt) { if(exit_oscam == 1) { cs_write_log(txt, 1); } else { char *newtxt = cs_strdup(txt); if(!newtxt) { return; } struct s_log *log; if(!cs_malloc(&log, sizeof(struct s_log))) { NULLFREE(newtxt); return; } log->txt = newtxt; log->header_len = 0; log->direct_log = 1; log_list_add(log); } }
int32_t cardreader_do_checkhealth(struct s_reader *reader) { struct s_client *cl = reader->client; if(reader_card_inserted(reader)) { if(reader->card_status == NO_CARD || reader->card_status == UNKNOWN) { rdr_log(reader, "card detected"); led_status_card_detected(); reader->card_status = CARD_NEED_INIT; add_job(cl, ACTION_READER_RESET, NULL, 0); } } else { rdr_log_dbg(reader, D_READER, "%s: !reader_card_inserted", __func__); if(reader->card_status == CARD_INSERTED || reader->card_status == CARD_NEED_INIT) { rdr_log(reader, "card ejected"); reader_nullcard(reader); if(reader->csystem && reader->csystem->card_done) reader->csystem->card_done(reader); NULLFREE(reader->csystem_data); if(cl) { cl->lastemm = 0; cl->lastecm = 0; } led_status_card_ejected(); } reader->card_status = NO_CARD; } rdr_log_dbg(reader, D_READER, "%s: reader->card_status = %d, ret = %d", __func__, reader->card_status, reader->card_status == CARD_INSERTED); return reader->card_status == CARD_INSERTED; }
void cacheex_cwcheck_tab_fn(const char *token, char *value, void *setting, FILE *f) { CWCHECKTAB *cacheex_value_table = setting; if(value) { if(strlen(value) == 0) { cacheex_value_table->cwchecknum = 0; NULLFREE(cacheex_value_table->cwcheckdata); } else { chk_cacheex_cwcheck_valuetab(value, cacheex_value_table); } return; } if(cacheex_value_table->cwchecknum || cfg.http_full_cfg) { value = mk_t_cacheex_cwcheck_valuetab(cacheex_value_table); fprintf_conf(f, token, "%s\n", value); free_mk_t(value); } }
int config_list_parse(const struct config_list *clist, const char *token, char *value, void *config_data) { const struct config_list *c; for(c = clist; c->opt_type != OPT_UNKNOWN; c++) { if(c->opt_type == OPT_SAVE_FUNC || c->opt_type == OPT_FIXUP_FUNC) { continue; } if(strcasecmp(token, c->config_name) != 0) { continue; } void *var = config_data + c->var_offset; switch(c->opt_type) { case OPT_INT8: { *(int8_t *)var = (int8_t)strToIntVal(value, c->def.d_int8); return 1; } case OPT_UINT8: { uint32_t tmp = strToUIntVal(value, c->def.d_uint8); *(uint8_t *)var = (uint8_t)(tmp <= 0xff ? tmp : 0xff); return 1; } case OPT_INT32: { int32_t tmp = strToIntVal(value, c->def.d_int32); memcpy(var, &tmp, sizeof(int32_t)); return 1; } case OPT_UINT32: { uint32_t tmp = strToUIntVal(value, c->def.d_uint32); memcpy(var, &tmp, sizeof(uint32_t)); return 1; } case OPT_STRING: { char **scfg = var; if(c->def.d_char && strlen(value) == 0) // Set default { value = c->def.d_char; } NULLFREE(*scfg); if(strlen(value)) { *scfg = cs_strdup(value); } return 1; } case OPT_SSTRING: { char *scfg = var; if(c->def.d_char && strlen(value) == 0) // Set default { value = c->def.d_char; } scfg[0] = '\0'; unsigned int len = strlen(value); if(len) { strncpy(scfg, value, c->str_size - 1); if(len > c->str_size) { fprintf(stderr, "WARNING: Config value for '%s' (%s, len=%u) exceeds max length: %d (%s)\n", token, value, len, c->str_size - 1, scfg); } } return 1; } case OPT_HEX_ARRAY: { uint8_t *hex_array = var; if(!strlen(value)) { memset(hex_array, 0, c->def.array_size); } else if(key_atob_l(value, hex_array, c->def.array_size * 2)) { memset(hex_array, 0, c->def.array_size); fprintf(stderr, "WARNING: Config value for '%s' (%s, len=%zu) requires %d chars.\n", token, value, strlen(value), c->def.array_size * 2); } return 1; } case OPT_FUNC: { c->ops.process_fn(token, value, var, NULL); return 1; } case OPT_FUNC_EXTRA: { c->ops.process_fn_extra(token, value, var, c->def.d_extra, NULL); return 1; } case OPT_FIXUP_FUNC: case OPT_SAVE_FUNC: return 1; case OPT_UNKNOWN: { fprintf(stderr, "Unknown config type (%s = %s).", token, value); break; } } } return 0; }
static void *chkcache_process(void) { set_thread_name(__func__); time_t timeout; struct ecm_request_t *er, *ecm; #ifdef CS_CACHEEX uint8_t add_hitcache_er; struct s_reader *cl_rdr; struct s_reader *rdr; struct s_ecm_answer *ea; struct s_client *cex_src=NULL; #endif struct s_write_from_cache *wfc=NULL; while(1) { cs_readlock(&ecmcache_lock); for(er = ecmcwcache; er; er = er->next) { timeout = time(NULL)-((cfg.ctimeout+500)/1000+1); if(er->tps.time < timeout) { break; } if(er->rc<E_UNHANDLED || er->readers_timeout_check) //already answered { continue; } //******** CHECK IF FOUND ECM IN CACHE ecm = check_cache(er, er->client); if(ecm) //found in cache { #ifdef CS_CACHEEX //check for add_hitcache if(ecm->cacheex_src) //cw from cacheex { if((er->cacheex_wait_time && !er->cacheex_wait_time_expired) || !er->cacheex_wait_time) //only when no wait_time expires (or not wait_time) { //add_hitcache already called, but we check if we have to call it for these (er) caid|prid|srvid if(ecm->prid!=er->prid || ecm->srvid!=er->srvid) { cex_src = ecm->cacheex_src && is_valid_client(ecm->cacheex_src) && !ecm->cacheex_src->kill ? ecm->cacheex_src : NULL; //here we should be sure cex client has not been freed! if(cex_src) { //add_hitcache only if client is really active add_hitcache_er=1; cl_rdr = cex_src->reader; if(cl_rdr && cl_rdr->cacheex.mode == 2) { for(ea = er->matching_rdr; ea; ea = ea->next) { rdr = ea->reader; if(cl_rdr == rdr && ((ea->status & REQUEST_ANSWERED) == REQUEST_ANSWERED)) { cs_debug_mask(D_CACHEEX|D_CSP|D_LB,"{client %s, caid %04X, prid %06X, srvid %04X} [CACHEEX] skip ADD self request!", (check_client(er->client)?er->client->account->usr:"******"),er->caid, er->prid, er->srvid); add_hitcache_er=0; //don't add hit cache, reader requested self } } } if(add_hitcache_er) { add_hitcache(cex_src, er); //USE cacheex client (to get correct group) and ecm from requesting client (to get correct caid|prid|srvid)!!! } } } } else { //add_hitcache already called, but we have to remove it because cacheex not coming before wait_time if(ecm->prid==er->prid && ecm->srvid==er->srvid) { del_hitcache(ecm); } } } //END check for add_hitcache #endif if(check_client(er->client)) { wfc=NULL; if(!cs_malloc(&wfc, sizeof(struct s_write_from_cache))) { NULLFREE(ecm); continue; } 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); continue; } } else { NULLFREE(ecm); } } } cs_readunlock(&ecmcache_lock); cs_sleepms(10); } return NULL; }
void dvbapi_load_channel_cache(void) { if (USE_OPENXCAS) // Why? return; char fname[256]; char line[1024]; FILE *file; struct s_channel_cache *c; get_config_filename(fname, sizeof(fname), "oscam.ccache"); file = fopen(fname, "r"); if(!file) { cs_log("dvbapi channelcache can't read from file %s", fname); return; } int32_t i = 1; int32_t valid = 0; char *ptr, *saveptr1 = NULL; char *split[6]; memset(line, 0, sizeof(line)); while(fgets(line, sizeof(line), file)) { if(!line[0] || line[0] == '#' || line[0] == ';') { continue; } for(i = 0, ptr = strtok_r(line, ",", &saveptr1); ptr && i < 6 ; ptr = strtok_r(NULL, ",", &saveptr1), i++) { split[i] = ptr; } valid = (i == 5); if(valid) { if(!cs_malloc(&c, sizeof(struct s_channel_cache))) { continue; } c->caid = a2i(split[0], 4); c->prid = a2i(split[1], 6); c->srvid = a2i(split[2], 4); c->pid = a2i(split[3], 4); c->chid = a2i(split[4], 6); if(valid && c->caid != 0) { if(!channel_cache) { channel_cache = ll_create("channel cache"); } ll_append(channel_cache, c); } else { NULLFREE(c); } } } fclose(file); cs_log("dvbapi channelcache loaded from %s", fname); }
/* * mk_t-functions give back a constant empty string when allocation fails or when the result is an empty string. * This function thus checks the stringlength and only frees if necessary. */ void free_mk_t(char *value) { if(strlen(value) > 0) { NULLFREE(value); } }
void cc_cacheex_push_in(struct s_client *cl, uchar *buf) { struct cc_data *cc = cl->cc; ECM_REQUEST *er; if(!cc) { return; } if(cl->reader) { cl->reader->last_s = cl->reader->last_g = time((time_t *)0); } if(cl) { cl->last = time(NULL); } int8_t rc = buf[14]; if(rc != E_FOUND && rc != E_UNHANDLED) //Maybe later we could support other rcs { return; } uint16_t size = buf[12] | (buf[13] << 8); if(size != sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw)) { cs_log_dbg(D_CACHEEX, "cacheex: %s received old cash-push format! data ignored!", username(cl)); return; } if(!(er = get_ecmtask())) { return; } er->caid = b2i(2, buf + 0); er->prid = b2i(4, buf + 2); er->srvid = b2i(2, buf + 10); er->ecm[0] = buf[19]!=0x80 && buf[19]!=0x81 ? 0 : buf[19]; //odd/even byte, usefull to send it over CSP and to check cw for swapping er->rc = rc; er->ecmlen = 0; if(buf[18]) { if(buf[18] & (0x01 << 7)) { er->cwc_cycletime = (buf[18] & 0x7F); // remove bit 8 to get cycletime er->cwc_next_cw_cycle = 1; } else { er->cwc_cycletime = buf[18]; er->cwc_next_cw_cycle = 0; } } if (er->cwc_cycletime && er->cwc_next_cw_cycle < 2) { if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode) { cl->account->cwc_info++; } else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode)) { cl->cwc_info++; } cs_log_dbg(D_CWC, "CWC (CE) received from %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid); } uint8_t *ofs = buf + 20; //Read ecmd5 memcpy(er->ecmd5, ofs, sizeof(er->ecmd5)); //16 ofs += sizeof(er->ecmd5); if(!check_cacheex_filter(cl, er)) { return; } //Read csp_hash: er->csp_hash = ntohl(b2i(4, ofs)); ofs += 4; //Read cw: memcpy(er->cw, ofs, sizeof(er->cw)); //16 ofs += sizeof(er->cw); //Read lastnode count: uint8_t count = *ofs; ofs++; //check max nodes: if(count > cacheex_maxhop(cl)) { cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes (max=%d), ignored! %s", (int32_t)count, cacheex_maxhop(cl), username(cl)); NULLFREE(er); return; } cs_log_dbg(D_CACHEEX, "cacheex: received %d nodes %s", (int32_t)count, username(cl)); //Read lastnodes: uint8_t *data; if (er){ er->csp_lastnodes = ll_create("csp_lastnodes"); } while(count) { if(!cs_malloc(&data, 8)) { break; } memcpy(data, ofs, 8); ofs += 8; ll_append(er->csp_lastnodes, data); count--; cs_log_dbg(D_CACHEEX, "cacheex: received node %" PRIu64 "X %s", cacheex_node_id(data), username(cl)); } //for compatibility: add peer node if no node received: if(!ll_count(er->csp_lastnodes)) { if(!cs_malloc(&data, 8)) { return; } memcpy(data, cc->peer_node_id, 8); ll_append(er->csp_lastnodes, data); cs_log_dbg(D_CACHEEX, "cacheex: added missing remote node id %" PRIu64 "X", cacheex_node_id(data)); } cacheex_add_to_cache(cl, er); }
static int32_t cc_cacheex_push_out(struct s_client *cl, struct ecm_request_t *er) { int8_t rc = (er->rc < E_NOTFOUND) ? E_FOUND : er->rc; if(rc != E_FOUND && rc != E_UNHANDLED) { return -1; } //Maybe later we could support other rcs if(cl->reader) { if(!cl->reader->tcp_connected) { cc_cli_connect(cl); } } struct cc_data *cc = cl->cc; if(!cc || !cl->udp_fd) { cs_log_dbg(D_CACHEEX, "cacheex: not connected %s -> no push", username(cl)); return (-1); } uint32_t size = sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw) + sizeof(uint8_t) + (ll_count(er->csp_lastnodes) + 1) * 8; unsigned char *buf; if(!cs_malloc(&buf, size + 20)) //camd35_send() adds +20 { return -1; } // build ecm message //buf[0] = er->caid >> 8; //buf[1] = er->caid & 0xff; //buf[2] = er->prid >> 24; //buf[3] = er->prid >> 16; //buf[4] = er->prid >> 8; //buf[5] = er->prid & 0xff; //buf[10] = er->srvid >> 8; //buf[11] = er->srvid & 0xff; buf[12] = (sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw)) & 0xff; buf[13] = (sizeof(er->ecmd5) + sizeof(er->csp_hash) + sizeof(er->cw)) >> 8; //buf[12] = 0; //buf[13] = 0; buf[14] = rc; i2b_buf(2, er->caid, buf + 0); i2b_buf(4, er->prid, buf + 2); i2b_buf(2, er->srvid, buf + 10); if(er->cwc_cycletime && er->cwc_next_cw_cycle < 2) { buf[18] = er->cwc_cycletime; // contains cwc stage3 cycletime if(er->cwc_next_cw_cycle == 1) { buf[18] = (buf[18] | 0x80); } // set bit 8 to high if(cl->typ == 'c' && cl->account && cl->account->cacheex.mode) { cl->account->cwc_info++; } else if((cl->typ == 'p' || cl->typ == 'r') && (cl->reader && cl->reader->cacheex.mode)) { cl->cwc_info++; } cs_log_dbg(D_CWC, "CWC (CE) push to %s cycletime: %isek - nextcwcycle: CW%i for %04X@%06X:%04X", username(cl), er->cwc_cycletime, er->cwc_next_cw_cycle, er->caid, er->prid, er->srvid); } buf[19] = er->ecm[0] != 0x80 && er->ecm[0] != 0x81 ? 0 : er->ecm[0]; uint8_t *ofs = buf + 20; //write oscam ecmd5: memcpy(ofs, er->ecmd5, sizeof(er->ecmd5)); //16 ofs += sizeof(er->ecmd5); //write csp hashcode: i2b_buf(4, htonl(er->csp_hash), ofs); ofs += 4; //write cw: memcpy(ofs, er->cw, sizeof(er->cw)); //16 ofs += sizeof(er->cw); //write node count: *ofs = ll_count(er->csp_lastnodes) + 1; ofs++; //write own node: memcpy(ofs, cc->node_id, 8); ofs += 8; //write other nodes: LL_LOCKITER *li = ll_li_create(er->csp_lastnodes, 0); uint8_t *node; while((node = ll_li_next(li))) { memcpy(ofs, node, 8); ofs += 8; } ll_li_destroy(li); int32_t res = cc_cmd_send(cl, buf, size + 20, MSG_CACHE_PUSH); if(res > 0) // cache-ex is pushing out, so no receive but last_g should be updated otherwise disconnect! { if(cl->reader) { cl->reader->last_s = cl->reader->last_g = time((time_t *)0); } // correct if(cl) { cl->last = time(NULL); } } NULLFREE(buf); return res; }
static int32_t ecm_ratelimit_findspace(struct s_reader *reader, ECM_REQUEST *er, struct ecmrl rl, int32_t reader_mode) { int32_t h, foundspace = -1; int32_t maxecms = MAXECMRATELIMIT; // init maxecms int32_t totalecms = 0; // init totalecms struct timeb actualtime; cs_ftime(&actualtime); for(h = 0; h < MAXECMRATELIMIT; h++) // release slots with srvid that are overtime, even if not called from reader module to maximize available slots! { if(reader->rlecmh[h].last.time == -1) { continue; } int32_t gone = comp_timeb(&actualtime, &reader->rlecmh[h].last); if( gone >= (reader->rlecmh[h].ratelimittime + reader->rlecmh[h].srvidholdtime) || gone < 0) // gone <0 fixup for bad systemtime on dvb receivers while changing transponders { cs_debug_mask(D_CLIENT, "ratelimiter srvid %04X released from slot #%d/%d of reader %s (%d>=%d ratelimit ms + %d ms srvidhold!)", reader->rlecmh[h].srvid, h + 1, MAXECMRATELIMIT, reader->label, gone, reader->rlecmh[h].ratelimittime, reader->rlecmh[h].srvidholdtime); reader->rlecmh[h].last.time = -1; reader->rlecmh[h].srvid = -1; reader->rlecmh[h].kindecm = 0; } if(reader->rlecmh[h].last.time == -1) { continue; } if(reader->rlecmh[h].ratelimitecm < maxecms) { maxecms = reader->rlecmh[h].ratelimitecm; } // we found a more critical ratelimit srvid totalecms++; } cs_debug_mask(D_CLIENT, "ratelimiter found total of %d srvid for reader %s most critical is limited to %d requests", totalecms, reader->label, maxecms); if(reader->cooldown[0] && reader->cooldownstate != 1) { maxecms = MAXECMRATELIMIT; } // dont apply ratelimits if cooldown isnt in use or not in effect for(h = 0; h < MAXECMRATELIMIT; h++) // check if srvid is already in a slot { if(reader->rlecmh[h].last.time == -1) { continue; } if(reader->rlecmh[h].srvid == er->srvid && reader->rlecmh[h].caid == rl.caid && reader->rlecmh[h].provid == rl.provid && (!reader->rlecmh[h].chid || (reader->rlecmh[h].chid == rl.chid))) { int32_t gone = comp_timeb(&actualtime, &reader->rlecmh[h].last); cs_debug_mask(D_CLIENT, "ratelimiter found srvid %04X for %d ms in slot #%d/%d of reader %s", er->srvid, gone, h + 1, MAXECMRATELIMIT, reader->label); // check ecmunique if enabled and ecmunique time is done if(reader_mode && reader->ecmunique) { gone = comp_timeb(&actualtime, &reader->rlecmh[h].last); if(gone < reader->ratelimittime) { if(memcmp(reader->rlecmh[h].ecmd5, er->ecmd5, CS_ECMSTORESIZE)) { if(er->ecm[0] == reader->rlecmh[h].kindecm) { char ecmd5[17 * 3]; cs_hexdump(0, reader->rlecmh[h].ecmd5, 16, ecmd5, sizeof(ecmd5)); cs_debug_mask(D_CLIENT, "ratelimiter ecm %s in this slot for next %d ms!", ecmd5, (int)(reader->rlecmh[h].ratelimittime - gone)); struct ecm_request_t *erold = NULL; if(!cs_malloc(&erold, sizeof(struct ecm_request_t))) { return -2; } memcpy(erold, er, sizeof(struct ecm_request_t)); // copy ecm all memcpy(erold->ecmd5, reader->rlecmh[h].ecmd5, CS_ECMSTORESIZE); // replace md5 hash struct ecm_request_t *ecm = NULL; ecm = check_cache(erold, erold->client); //CHECK IF FOUND ECM IN CACHE NULLFREE(erold); if(ecm) //found in cache { write_ecm_answer(reader, er, ecm->rc, ecm->rcEx, ecm->cw, NULL); } else { write_ecm_answer(reader, er, E_NOTFOUND, E2_RATELIMIT, NULL, "Ratelimiter: no slots free!"); } NULLFREE(ecm); return -2; } continue; } } if((er->ecm[0] == reader->rlecmh[h].kindecm) && (gone <= (reader->ratelimittime + reader->srvidholdtime))) { cs_debug_mask(D_CLIENT, "ratelimiter srvid %04X ecm type %s, only allowing %s for next %d ms in slot #%d/%d of reader %s -> skipping this slot!", reader->rlecmh[h].srvid, (reader->rlecmh[h].kindecm == 0x80 ? "even" : "odd"), (reader->rlecmh[h].kindecm == 0x80 ? "odd" : "even"), (int)(reader->rlecmh[h].ratelimittime + reader->rlecmh[h].srvidholdtime - gone), h + 1, maxecms, reader->label); continue; } } if(h > 0) { for(foundspace = 0; foundspace < h; foundspace++) // check for free lower slot { if(reader->rlecmh[foundspace].last.time == -1) { reader->rlecmh[foundspace] = reader->rlecmh[h]; // replace ecm request info reader->rlecmh[h].srvid = -1; reader->rlecmh[h].last.time = -1; if(foundspace < maxecms) { cs_debug_mask(D_CLIENT, "ratelimiter moved srvid %04X to slot #%d/%d of reader %s", er->srvid, foundspace + 1, maxecms, reader->label); return foundspace; // moving to lower free slot! } else { cs_debug_mask(D_CLIENT, "ratelimiter removed srvid %04X from slot #%d/%d of reader %s", er->srvid, foundspace + 1, maxecms, reader->label); reader->rlecmh[foundspace].last.time = -1; // free this slot since we are over ratelimit! return -1; // sorry, ratelimit! } } } } if(h < maxecms) // found but cant move to lower position! { return h; // return position if within ratelimits! } else { reader->rlecmh[h].last.time = -1; // free this slot since we are over ratelimit! cs_debug_mask(D_CLIENT, "ratelimiter removed srvid %04X from slot #%d/%d of reader %s", er->srvid, h + 1, maxecms, reader->label); return -1; // sorry, ratelimit! } } } // srvid not found in slots! if((reader->cooldown[0] && reader->cooldownstate == 1) || !reader->cooldown[0]) { ; // do we use cooldown at all, are we in cooldown fase? // we are in cooldown or no cooldown configured! if(totalecms + 1 > maxecms || totalecms + 1 > rl.ratelimitecm) // check if this channel fits in! { cs_debug_mask(D_CLIENT, "ratelimiter for reader %s has no free slots!", reader->label); return -1; } } else { maxecms = MAXECMRATELIMIT; // no limits right now! } for(h = 0; h < maxecms; h++) // check for free slot { if(reader->rlecmh[h].last.time == -1) { if(reader_mode) { cs_debug_mask(D_CLIENT, "ratelimiter added srvid %04X to slot #%d/%d of reader %s", er->srvid, h + 1, maxecms, reader->label); } return h; // free slot found -> assign it! } else { int32_t gone = comp_timeb(&actualtime, &reader->rlecmh[h].last); cs_debug_mask(D_CLIENT, "ratelimiter srvid %04X for %d ms present in slot #%d/%d of reader %s", reader->rlecmh[h].srvid, gone , h + 1, maxecms, reader->label); } //occupied slots } #ifdef HAVE_DVBAPI /* Overide ratelimit priority for dvbapi request */ foundspace = -1; int32_t gone = 0; if((cfg.dvbapi_enabled == 1) && streq(er->client->account->usr, cfg.dvbapi_usr)) { if(reader->lastdvbapirateoverride.time == 0) { // fixup for first run! gone = comp_timeb(&actualtime, &reader->lastdvbapirateoverride); } if(gone > reader->ratelimittime) { struct timeb minecmtime = actualtime; for(h = 0; h < MAXECMRATELIMIT; h++) { gone = comp_timeb(&minecmtime, &reader->rlecmh[h].last); if(gone > 0) { minecmtime = reader->rlecmh[h].last; foundspace = h; } } reader->lastdvbapirateoverride = actualtime; cs_debug_mask(D_CLIENT, "prioritizing DVBAPI user %s over other watching client", er->client->account->usr); cs_debug_mask(D_CLIENT, "ratelimiter forcing srvid %04X into slot #%d/%d of reader %s", er->srvid, foundspace + 1, maxecms, reader->label); return foundspace; } else cs_debug_mask(D_CLIENT, "DVBAPI User %s is switching too fast for ratelimit and can't be prioritized!", er->client->account->usr); } #endif return (-1); // no slot found }
static int32_t ghttp_recv_chk(struct s_client *client, uchar *dcw, int32_t *rc, uchar *buf, int32_t UNUSED(n)) { char* data; char* lenstr; int rcode, len = 0; s_ghttp* context = (s_ghttp*)client->ghttp; ECM_REQUEST *er = &context->last_ecm; data = strstr((char*)buf, "HTTP/1.1"); if(!data) { cs_debug_mask(D_CLIENT, "%s: non http or otherwise corrupt response/disconnect: %s", client->reader->label, buf); network_tcp_connection_close(client->reader, "receive error or idle timeout"); return -1; } data = data + strlen("HTTP/1.1 "); rcode = atoi(data); if(rcode < 200 || rcode > 204) { cs_debug_mask(D_CLIENT, "%s: http error code %d", client->reader->label, rcode); data = strstr(data, "Content-Type: application/octet-stream"); // if not octet-stream, google error. need reconnect? if(data) // we have error info string in data { lenstr = strstr((char*)buf, "Content-Length: "); if(lenstr) { lenstr = lenstr + strlen("Content-Length: "); len = atoi(lenstr); } data = strstr(data, "\r\n\r\n") + 4; if(data) { data[len] = '\0'; cs_debug_mask(D_CLIENT, "%s: http error message: %s", client->reader->label, data); } } if(rcode == 503) { context->prev_sid = 0; if(context->do_post_next) { cs_debug_mask(D_CLIENT, "%s: recv_chk got 503 despite post, trying reconnect", client->reader->label); network_tcp_connection_close(client->reader, "timeout"); return -1; } else { // on 503 timeout, switch to POST context->do_post_next = 1; cs_debug_mask(D_CLIENT, "%s: recv_chk got 503, trying direct post", client->reader->label); _ghttp_post_ecmdata(client, er); *rc = 0; memset(dcw, 0, 16); return -1; } } else if(rcode == 401) { cs_debug_mask(D_CLIENT, "%s: session expired, trying direct post", client->reader->label); context->do_post_next = 1; NULLFREE(context->session_id); _ghttp_post_ecmdata(client, er); *rc = 0; memset(dcw, 0, 16); return -1; } return -1; } // switch back to cache get after rapid ecm response (arbitrary atm), only effect is a slight bw save for client if(context->do_post_next && context->last_ecm.srvid == context->prev_sid) { if(client->cwlastresptime > 0 && client->cwlastresptime < 800) { cs_debug_mask(D_CLIENT, "%s: prev resp time for same sid was %d ms, switching back to cache get for next req", client->reader->label, client->cwlastresptime); context->do_post_next = 0; } } data = strstr((char*)buf, "Set-Cookie: GSSID="); if(data) { data += strlen("Set-Cookie: GSSID="); NULLFREE(context->session_id); if(cs_malloc(&context->session_id, 7)) { // todo dont assume session id of length 6 strncpy((char*)context->session_id, data, 6); context->session_id[6] = '\0'; cs_debug_mask(D_CLIENT, "%s: set session_id to: %s", client->reader->label, context->session_id); } } data = strstr((char*)buf, "Content-Length: 16"); if(data) { data = strstr((char*)buf, "\r\n\r\n"); data += 4; memcpy(dcw, data, 16); *rc = 1; char tmp_dbg[33]; cs_debug_mask(D_CLIENT, "%s: recv chk - %s", client->reader->label, cs_hexdump(0, dcw, 16, tmp_dbg, sizeof (tmp_dbg))); return client->reader->msg_idx; } else { cs_debug_mask(D_CLIENT, "%s: recv_chk fail!", client->reader->label); } return -1; }
void *work_thread(void *ptr) { struct job_data *data = (struct job_data *)ptr; struct s_client *cl = data->cl; struct s_reader *reader = cl->reader; struct timeb start, end; // start time poll, end time poll struct job_data tmp_data; struct pollfd pfd[1]; pthread_setspecific(getclient, cl); cl->thread = pthread_self(); cl->thread_active = 1; set_work_thread_name(data); struct s_module *module = get_module(cl); uint16_t bufsize = module->bufsize; //CCCam needs more than 1024bytes! if(!bufsize) { bufsize = 1024; } uint8_t *mbuf; if(!cs_malloc(&mbuf, bufsize)) { return NULL; } cl->work_mbuf = mbuf; // Track locally allocated data, because some callback may call cs_exit/cs_disconect_client/pthread_exit and then mbuf would be leaked int32_t n = 0, rc = 0, i, idx, s; uint8_t dcw[16]; int8_t restart_reader = 0; while(cl->thread_active) { cs_ftime(&start); // register start time while(cl->thread_active) { if(!cl || cl->kill || !is_valid_client(cl)) { pthread_mutex_lock(&cl->thread_lock); cl->thread_active = 0; pthread_mutex_unlock(&cl->thread_lock); cs_debug_mask(D_TRACE, "ending thread (kill)"); __free_job_data(cl, data); cl->work_mbuf = NULL; // Prevent free_client from freeing mbuf (->work_mbuf) free_client(cl); if(restart_reader) { restart_cardreader(reader, 0); } NULLFREE(mbuf); pthread_exit(NULL); return NULL; } if(data && data->action != ACTION_READER_CHECK_HEALTH) { cs_debug_mask(D_TRACE, "data from add_job action=%d client %c %s", data->action, cl->typ, username(cl)); } if(!data) { if(!cl->kill && cl->typ != 'r') { client_check_status(cl); } // do not call for physical readers as this might cause an endless job loop pthread_mutex_lock(&cl->thread_lock); if(cl->joblist && ll_count(cl->joblist) > 0) { LL_ITER itr = ll_iter_create(cl->joblist); data = ll_iter_next_remove(&itr); if(data) { set_work_thread_name(data); } //cs_debug_mask(D_TRACE, "start next job from list action=%d", data->action); } pthread_mutex_unlock(&cl->thread_lock); } if(!data) { /* for serial client cl->pfd is file descriptor for serial port not socket for example: pfd=open("/dev/ttyUSB0"); */ if(!cl->pfd || module->listenertype == LIS_SERIAL) { break; } pfd[0].fd = cl->pfd; pfd[0].events = POLLIN | POLLPRI; pthread_mutex_lock(&cl->thread_lock); cl->thread_active = 2; pthread_mutex_unlock(&cl->thread_lock); rc = poll(pfd, 1, 3000); pthread_mutex_lock(&cl->thread_lock); cl->thread_active = 1; pthread_mutex_unlock(&cl->thread_lock); if(rc > 0) { cs_ftime(&end); // register end time cs_debug_mask(D_TRACE, "[OSCAM-WORK] new event %d occurred on fd %d after %"PRId64" ms inactivity", pfd[0].revents, pfd[0].fd, comp_timeb(&end, &start)); data = &tmp_data; data->ptr = NULL; cs_ftime(&start); // register start time for new poll next run if(reader) { data->action = ACTION_READER_REMOTE; } else { if(cl->is_udp) { data->action = ACTION_CLIENT_UDP; data->ptr = mbuf; data->len = bufsize; } else { data->action = ACTION_CLIENT_TCP; } if(pfd[0].revents & (POLLHUP | POLLNVAL | POLLERR)) { cl->kill = 1; } } } } if(!data) { continue; } if(!reader && data->action < ACTION_CLIENT_FIRST) { __free_job_data(cl, data); break; } if(!data->action) { break; } struct timeb actualtime; cs_ftime(&actualtime); int32_t gone = comp_timeb(&actualtime, &data->time); if(data != &tmp_data && gone > (int) cfg.ctimeout+1000) { cs_debug_mask(D_TRACE, "dropping client data for %s time %dms", username(cl), gone); __free_job_data(cl, data); continue; } if(data != &tmp_data) { cl->work_job_data = data; } // Track the current job_data switch(data->action) { case ACTION_READER_IDLE: reader_do_idle(reader); break; case ACTION_READER_REMOTE: s = check_fd_for_data(cl->pfd); if(s == 0) // no data, another thread already read from fd? { break; } if(s < 0) { if(reader->ph.type == MOD_CONN_TCP) { network_tcp_connection_close(reader, "disconnect"); } break; } rc = reader->ph.recv(cl, mbuf, bufsize); if(rc < 0) { if(reader->ph.type == MOD_CONN_TCP) { network_tcp_connection_close(reader, "disconnect on receive"); } break; } cl->last = time(NULL); // *********************************** TO BE REPLACE BY CS_FTIME() LATER **************** idx = reader->ph.c_recv_chk(cl, dcw, &rc, mbuf, rc); if(idx < 0) { break; } // no dcw received if(!idx) { idx = cl->last_idx; } reader->last_g = time(NULL); // *********************************** TO BE REPLACE BY CS_FTIME() LATER **************** // for reconnect timeout for(i = 0, n = 0; i < cfg.max_pending && n == 0; i++) { if(cl->ecmtask[i].idx == idx) { cl->pending--; casc_check_dcw(reader, i, rc, dcw); n++; } } break; case ACTION_READER_RESET: cardreader_do_reset(reader); break; case ACTION_READER_ECM_REQUEST: reader_get_ecm(reader, data->ptr); break; case ACTION_READER_EMM: reader_do_emm(reader, data->ptr); break; case ACTION_READER_CARDINFO: reader_do_card_info(reader); break; case ACTION_READER_INIT: if(!cl->init_done) { reader_init(reader); } break; case ACTION_READER_RESTART: cl->kill = 1; restart_reader = 1; break; case ACTION_READER_RESET_FAST: reader->card_status = CARD_NEED_INIT; cardreader_do_reset(reader); break; case ACTION_READER_CHECK_HEALTH: cardreader_do_checkhealth(reader); break; case ACTION_READER_CAPMT_NOTIFY: if(reader->ph.c_capmt) { reader->ph.c_capmt(cl, data->ptr); } break; case ACTION_CLIENT_UDP: n = module->recv(cl, data->ptr, data->len); if(n < 0) { break; } module->s_handler(cl, data->ptr, n); break; case ACTION_CLIENT_TCP: s = check_fd_for_data(cl->pfd); if(s == 0) // no data, another thread already read from fd? { break; } if(s < 0) // system error or fd wants to be closed { cl->kill = 1; // kill client on next run continue; } n = module->recv(cl, mbuf, bufsize); if(n < 0) { cl->kill = 1; // kill client on next run continue; } module->s_handler(cl, mbuf, n); break; case ACTION_CACHEEX_TIMEOUT: #ifdef CS_CACHEEX cacheex_timeout(data->ptr); #endif break; case ACTION_FALLBACK_TIMEOUT: fallback_timeout(data->ptr); break; case ACTION_CLIENT_TIMEOUT: ecm_timeout(data->ptr); break; case ACTION_ECM_ANSWER_READER: chk_dcw(data->ptr); break; case ACTION_ECM_ANSWER_CACHE: write_ecm_answer_fromcache(data->ptr); break; case ACTION_CLIENT_INIT: if(module->s_init) { module->s_init(cl); } cl->is_udp = module->type == MOD_CONN_UDP; cl->init_done = 1; break; case ACTION_CLIENT_IDLE: if(module->s_idle) { module->s_idle(cl); } else { cs_log("user %s reached %d sec idle limit.", username(cl), cfg.cmaxidle); cl->kill = 1; } break; case ACTION_CACHE_PUSH_OUT: { #ifdef CS_CACHEEX ECM_REQUEST *er = data->ptr; int32_t res = 0, stats = -1; // cc-nodeid-list-check if(reader) { if(reader->ph.c_cache_push_chk && !reader->ph.c_cache_push_chk(cl, er)) { break; } res = reader->ph.c_cache_push(cl, er); stats = cacheex_add_stats(cl, er->caid, er->srvid, er->prid, 0); } else { if(module->c_cache_push_chk && !module->c_cache_push_chk(cl, er)) { break; } res = module->c_cache_push(cl, er); } debug_ecm(D_CACHEEX, "pushed ECM %s to %s res %d stats %d", buf, username(cl), res, stats); cl->cwcacheexpush++; if(cl->account) { cl->account->cwcacheexpush++; } first_client->cwcacheexpush++; #endif break; } case ACTION_CLIENT_KILL: cl->kill = 1; break; case ACTION_CLIENT_SEND_MSG: { #ifdef MODULE_CCCAM struct s_clientmsg *clientmsg = (struct s_clientmsg *)data->ptr; cc_cmd_send(cl, clientmsg->msg, clientmsg->len, clientmsg->cmd); #endif break; } } // switch __free_job_data(cl, data); } if(thread_pipe[1] && (mbuf[0] != 0x00)) { cs_ddump_mask(D_TRACE, mbuf, 1, "[OSCAM-WORK] Write to pipe:"); if(write(thread_pipe[1], mbuf, 1) == -1) // wakeup client check { cs_debug_mask(D_TRACE, "[OSCAM-WORK] Writing to pipe failed (errno=%d %s)", errno, strerror(errno)); } } // Check for some race condition where while we ended, another thread added a job pthread_mutex_lock(&cl->thread_lock); if(cl->joblist && ll_count(cl->joblist) > 0) { pthread_mutex_unlock(&cl->thread_lock); continue; } else { cl->thread_active = 0; pthread_mutex_unlock(&cl->thread_lock); break; } } cl->thread_active = 0; cl->work_mbuf = NULL; // Prevent free_client from freeing mbuf (->work_mbuf) NULLFREE(mbuf); pthread_exit(NULL); return NULL; }
/** * adds a job to the job queue * if ptr should be free() after use, set len to the size * else set size to 0 **/ int32_t add_job(struct s_client *cl, enum actions action, void *ptr, int32_t len) { if(!cl || cl->kill) { if(!cl) { cs_log("WARNING: add_job failed. Client killed!"); } // Ignore jobs for killed clients if(len && ptr) { NULLFREE(ptr); } return 0; } #ifdef CS_CACHEEX // Avoid full running queues: if(action == ACTION_CACHE_PUSH_OUT && ll_count(cl->joblist) > 2000) { cs_debug_mask(D_TRACE, "WARNING: job queue %s %s has more than 2000 jobs! count=%d, dropped!", cl->typ == 'c' ? "client" : "reader", username(cl), ll_count(cl->joblist)); if(len && ptr) { NULLFREE(ptr); } // Thread down??? pthread_mutex_lock(&cl->thread_lock); if(cl && !cl->kill && cl->thread && cl->thread_active) { // Just test for invalid thread id: if(pthread_detach(cl->thread) == ESRCH) { cl->thread_active = 0; cs_debug_mask(D_TRACE, "WARNING: %s %s thread died!", cl->typ == 'c' ? "client" : "reader", username(cl)); } } pthread_mutex_unlock(&cl->thread_lock); return 0; } #endif struct job_data *data; if(!cs_malloc(&data, sizeof(struct job_data))) { if(len && ptr) { NULLFREE(ptr); } return 0; } data->action = action; data->ptr = ptr; data->cl = cl; data->len = len; cs_ftime(&data->time); pthread_mutex_lock(&cl->thread_lock); if(cl && !cl->kill && cl->thread_active) { if(!cl->joblist) { cl->joblist = ll_create("joblist"); } ll_append(cl->joblist, data); if(cl->thread_active == 2) { pthread_kill(cl->thread, OSCAM_SIGNAL_WAKEUP); } pthread_mutex_unlock(&cl->thread_lock); cs_debug_mask(D_TRACE, "add %s job action %d queue length %d %s", action > ACTION_CLIENT_FIRST ? "client" : "reader", action, ll_count(cl->joblist), username(cl)); return 1; } pthread_attr_t attr; pthread_attr_init(&attr); /* pcsc doesn't like this either; segfaults on x86, x86_64 */ struct s_reader *rdr = cl->reader; if(cl->typ != 'r' || !rdr || rdr->typ != R_PCSC) { pthread_attr_setstacksize(&attr, PTHREAD_STACK_SIZE); } if(action != ACTION_READER_CHECK_HEALTH) { cs_debug_mask(D_TRACE, "start %s thread action %d", action > ACTION_CLIENT_FIRST ? "client" : "reader", action); } int32_t ret = pthread_create(&cl->thread, &attr, work_thread, (void *)data); if(ret) { cs_log("ERROR: can't create thread for %s (errno=%d %s)", action > ACTION_CLIENT_FIRST ? "client" : "reader", ret, strerror(ret)); free_job_data(data); } else { pthread_detach(cl->thread); } pthread_attr_destroy(&attr); cl->thread_active = 1; pthread_mutex_unlock(&cl->thread_lock); return 1; }
int32_t init_srvid(void) { int8_t new_syntax = 1; FILE *fp = open_config_file("oscam.srvid2"); if(!fp) { fp = open_config_file(cs_srid); if(fp) { new_syntax = 0; } } if(!fp) { fp = create_config_file("oscam.srvid2"); if(fp) { flush_config_file(fp, "oscam.srvid2"); } return 0; } int32_t nr = 0, i, j; char *payload, *saveptr1 = NULL, *saveptr2 = NULL, *token; const char *tmp; if(!cs_malloc(&token, MAXLINESIZE)) { return 0; } struct s_srvid *srvid = NULL, *new_cfg_srvid[16], *last_srvid[16]; // A cache for strings within srvids. A checksum is calculated which is the start point in the array (some kind of primitive hash algo). // From this point, a sequential search is done. This greatly reduces the amount of string comparisons. const char **stringcache[1024]; int32_t allocated[1024] = { 0 }; int32_t used[1024] = { 0 }; struct timeb ts, te; cs_ftime(&ts); memset(last_srvid, 0, sizeof(last_srvid)); memset(new_cfg_srvid, 0, sizeof(new_cfg_srvid)); while(fgets(token, MAXLINESIZE, fp)) { int32_t l, len = 0, len2, srvidtmp; uint32_t k; uint32_t pos; char *srvidasc, *prov; tmp = trim(token); if(tmp[0] == '#') { continue; } if((l = strlen(tmp)) < 6) { continue; } if(!(srvidasc = strchr(token, ':'))) { continue; } if(!(payload = strchr(token, '|'))) { continue; } *payload++ = '\0'; if(!cs_malloc(&srvid, sizeof(struct s_srvid))) { NULLFREE(token); fclose(fp); return (1); } char tmptxt[128]; int32_t offset[4] = { -1, -1, -1, -1 }; char *ptr1 = NULL, *ptr2 = NULL; const char *searchptr[4] = { NULL, NULL, NULL, NULL }; const char **ptrs[4] = { &srvid->prov, &srvid->name, &srvid->type, &srvid->desc }; uint32_t max_payload_length = MAXLINESIZE - (payload - token); if(new_syntax) { ptrs[0] = &srvid->name; ptrs[1] = &srvid->type; ptrs[2] = &srvid->desc; ptrs[3] = &srvid->prov; } // allow empty strings as "||" if(payload[0] == '|' && (strlen(payload)+2 < max_payload_length)) { memmove(payload+1, payload, strlen(payload)+1); payload[0] = ' '; } for(k=1; ((k < max_payload_length) && (payload[k] != '\0')); k++) { if(payload[k-1] == '|' && payload[k] == '|') { if(strlen(payload+k)+2 < max_payload_length-k) { memmove(payload+k+1, payload+k, strlen(payload+k)+1); payload[k] = ' '; } else { break; } } } for(i = 0, ptr1 = strtok_r(payload, "|", &saveptr1); ptr1 && (i < 4) ; ptr1 = strtok_r(NULL, "|", &saveptr1), ++i) { // check if string is in cache len2 = strlen(ptr1); pos = 0; for(j = 0; j < len2; ++j) { pos += (uint8_t)ptr1[j]; } pos = pos % 1024; for(j = 0; j < used[pos]; ++j) { if(!strcmp(stringcache[pos][j], ptr1)) { searchptr[i] = stringcache[pos][j]; break; } } if(searchptr[i]) { continue; } offset[i] = len; cs_strncpy(tmptxt + len, trim(ptr1), sizeof(tmptxt) - len); len += strlen(ptr1) + 1; } char *tmpptr = NULL; if(len > 0 && !cs_malloc(&tmpptr, len)) { continue; } srvid->data = tmpptr; if(len > 0) { memcpy(tmpptr, tmptxt, len); } for(i = 0; i < 4; i++) { if(searchptr[i]) { *ptrs[i] = searchptr[i]; continue; } if(offset[i] > -1) { *ptrs[i] = tmpptr + offset[i]; // store string in stringcache tmp = *ptrs[i]; len2 = strlen(tmp); pos = 0; for(j = 0; j < len2; ++j) { pos += (uint8_t)tmp[j]; } pos = pos % 1024; if(used[pos] >= allocated[pos]) { if(allocated[pos] == 0) { if(!cs_malloc(&stringcache[pos], 16 * sizeof(char *))) { break; } } else { if(!cs_realloc(&stringcache[pos], (allocated[pos] + 16) * sizeof(char *))) { break; } } allocated[pos] += 16; } stringcache[pos][used[pos]] = tmp; used[pos] += 1; } } *srvidasc++ = '\0'; if(new_syntax) { srvidtmp = dyn_word_atob(token) & 0xFFFF; } else { srvidtmp = dyn_word_atob(srvidasc) & 0xFFFF; } if(srvidtmp < 0) { NULLFREE(tmpptr); NULLFREE(srvid); continue; } else { srvid->srvid = srvidtmp; } srvid->ncaid = 0; for(i = 0, ptr1 = strtok_r(new_syntax ? srvidasc : token, ",", &saveptr1); (ptr1); ptr1 = strtok_r(NULL, ",", &saveptr1), i++) { srvid->ncaid++; } if(!cs_malloc(&srvid->caid, sizeof(struct s_srvid_caid) * srvid->ncaid)) { NULLFREE(tmpptr); NULLFREE(srvid); return 0; } ptr1 = new_syntax ? srvidasc : token; for(i = 0; i < srvid->ncaid; i++) { prov = strchr(ptr1,'@'); srvid->caid[i].nprovid = 0; if(prov) { if(prov[1] != '\0') { for(j = 0, ptr2 = strtok_r(prov+1, "@", &saveptr2); (ptr2); ptr2 = strtok_r(NULL, "@", &saveptr2), j++) { srvid->caid[i].nprovid++; } if(!cs_malloc(&srvid->caid[i].provid, sizeof(uint32_t) * srvid->caid[i].nprovid)) { for(j = 0; j < i; j++) { NULLFREE(srvid->caid[j].provid); } NULLFREE(srvid->caid); NULLFREE(tmpptr); NULLFREE(srvid); return 0; } ptr2 = prov+1; for(j = 0; j < srvid->caid[i].nprovid; j++) { srvid->caid[i].provid[j] = dyn_word_atob(ptr2) & 0xFFFFFF; ptr2 = ptr2 + strlen(ptr2) + 1; } } else { ptr2 = prov+2; } prov[0] = '\0'; } srvid->caid[i].caid = dyn_word_atob(ptr1) & 0xFFFF; if(prov) { ptr1 = ptr2; } else { ptr1 = ptr1 + strlen(ptr1) + 1; } } nr++; if(new_cfg_srvid[srvid->srvid >> 12]) { last_srvid[srvid->srvid >> 12]->next = srvid; } else { new_cfg_srvid[srvid->srvid >> 12] = srvid; } last_srvid[srvid->srvid >> 12] = srvid; }
int32_t init_provid(void) { FILE *fp = open_config_file(cs_provid); if(!fp) { return 0; } int32_t nr; char *payload, *saveptr1 = NULL, *token; if(!cs_malloc(&token, MAXLINESIZE)) { return 0; } struct s_provid *provid_ptr = NULL; struct s_provid *new_cfg_provid = NULL, *last_provid; nr = 0; while(fgets(token, MAXLINESIZE, fp)) { int32_t i, l; struct s_provid *new_provid = NULL; char *tmp, *ptr1; tmp = trim(token); if(tmp[0] == '#') { continue; } if((l = strlen(tmp)) < 11) { continue; } if(!(payload = strchr(token, '|'))) { continue; } *payload++ = '\0'; if(!cs_malloc(&new_provid, sizeof(struct s_provid))) { NULLFREE(token); fclose(fp); return (1); } new_provid->nprovid = 0; for(i = 0, ptr1 = strtok_r(token, ":@", &saveptr1); ptr1; ptr1 = strtok_r(NULL, ":@", &saveptr1), i++) { if(i==0) { new_provid->caid = a2i(ptr1, 3); continue; } new_provid->nprovid++; } if(!cs_malloc(&new_provid->provid, sizeof(uint32_t) * new_provid->nprovid)) { NULLFREE(new_provid); NULLFREE(token); fclose(fp); return (1); } ptr1 = token + strlen(token) + 1; for(i = 0; i < new_provid->nprovid ; i++) { new_provid->provid[i] = a2i(ptr1, 3); ptr1 = ptr1 + strlen(ptr1) + 1; } for(i = 0, ptr1 = strtok_r(payload, "|", &saveptr1); ptr1; ptr1 = strtok_r(NULL, "|", &saveptr1), i++) { switch(i) { case 0: cs_strncpy(new_provid->prov, trim(ptr1), sizeof(new_provid->prov)); break; case 1: cs_strncpy(new_provid->sat, trim(ptr1), sizeof(new_provid->sat)); break; case 2: cs_strncpy(new_provid->lang, trim(ptr1), sizeof(new_provid->lang)); break; } } if(strlen(new_provid->prov) == 0) { NULLFREE(new_provid->provid); NULLFREE(new_provid); continue; } nr++; if(provid_ptr) { provid_ptr->next = new_provid; } else { new_cfg_provid = new_provid; } provid_ptr = new_provid; } NULLFREE(token); fclose(fp); if(nr > 0) { cs_log("%d provid's loaded", nr); } if(new_cfg_provid == NULL) { if(!cs_malloc(&new_cfg_provid, sizeof(struct s_provid))) { return (1); } } cs_writelock(__func__, &config_lock); //this allows reloading of provids, so cleanup of old data is needed: last_provid = cfg.provid; //old data cfg.provid = new_cfg_provid; //assign after loading, so everything is in memory cs_writeunlock(__func__, &config_lock); struct s_client *cl; for(cl = first_client->next; cl ; cl = cl->next) { cl->last_providptr = NULL; } struct s_provid *ptr, *nptr; if(last_provid) { ptr = last_provid; while(ptr) //cleanup old data: { add_garbage(ptr->provid); nptr = ptr->next; add_garbage(ptr); ptr = nptr; } } return (0); }