diff -Nru oscam-1.20-10855~r10626/debian/changelog oscam-1.20-10882~r10652/debian/changelog --- oscam-1.20-10855~r10626/debian/changelog 2015-03-13 09:44:28.000000000 +0000 +++ oscam-1.20-10882~r10652/debian/changelog 2015-04-25 10:46:51.000000000 +0000 @@ -1,433 +1,195 @@ -oscam (1.20-10855~r10626-utopic) utopic; urgency=medium +oscam (1.20-10882~r10652-utopic) utopic; urgency=medium - * [r10626] - - [gbx] Another better return for r10624 - - - - - * [r10625] - - [gbx] Proper return for r10624 - - - - - * [r10624] - - [gbx] Add one more LOCKITER in cards module - - - - - * [r10623] - - [gbx] use LOCKITER instead of ITER for pending cards + * [r10652] + dvbapi: add support for ECMINFO in network mode (bump proto to v2) - * [r10622] + * [r10651] - better to use static inline instead of #ifdef + irdeto basedate update + http://www.streamboard.tv/wbb2/thread.php?postid=541615#post541615 - thnx jsompis + * [r10650] - * [r10621] + - Fix abs() compile warnings reported by BigGyros - fix build without HAVE_DVBAPI - - - * [r10620] - - dvbapi: - - - More rework on handling streampids - - - - * [r10619] - - [gbx] Small correction for writing expired.info + * [r10649] + Fix for chk_port_tab, 'prids' index should be set to 0 for every 'filts' index change - * [r10618] + Tnx to Azurit3 for catching this bug and testing! - Tnx goes to Pr2 for this patch! + http://www.streamboard.tv/oscam/ticket/4165 - - Add Maturity level for Seca card - - Small rework on Viaccess maturity - - Display n/a for not Viaccess or Seca readers + * [r10648] + [gbx] Improve rebroadcast thread - * [r10617] - [gbx] Rework some cards functionalities - - Unify delete cards function. - - Move checkcode to cards module. - - Print expired cards which are currently not send. + * [r10647] + - Fix for broken stapi timeshift introduced r10640 - * [r10616] - Viaccess: (patch by Pr2) + * [r10646] - - Get and display the cards maturity level + - dvbapi: revert flushread before setting new sectionfilter + * [r10645] - * [r10615] + [gbx] Make compilers happy (fix warnings of r10644) - - Cosmetic rework streampid count - - Removed workaround for Vu boxes and gigablue boxes -> it doesnt work! - * [r10614] + * [r10644] - - More rework streampid + [gbx] Move hello send to other send functions - * [r10613] - dvbapi: - - - Only disable streampids not used on another ecmpid on same demuxer or any other demuxer with same index - - Some rework on index assign function - - - - * [r10612] + * [r10643] dvbapi: - More streampid rework - - - - * [r10611] - - - Added workaround for boxes with buggy dvb driver implementations (all vu models and gigablue) - - - - * [r10610] - - dvbapi: - - - Next tryfix blackscreen while recording and zapping around on same transponder. - - - - - * [r10609] - - dvbapi: - - - Another tryfix for blackscreen while recording and zapping around on same transponder - - - - * [r10608] - - [gbx] remove unused variables from structs & fix double local cards - - - - - * [r10607] - - All cas systems: - - - cs_add_entitlement: extended with find only modus and some protection: only add if not found jet! - - Viaccess specific: (Special thanks go again to Bit and Pr2 for their testing and logging!) - - - Separate reassembly buffers for every provid, this should fix reassembly issues if you have viaccess cards with different providers on them. - - Extract provid from 8c/8d nano instead of provid from emmpid so they never can be mixed up with emm 8e for other provid - - Combine with the correct provider 8c/8d emm based on the SA info in the 8e emm - - Smarter and same filters for network and local cards - - Smarter prio of the filters: shared on top, global at the end and skip not useful providers - - Nano A9 provider class check to avoid 90 40 (very big thanks goes to Bit for his analysis!) - - - - - * [r10606] - - - Tryfix flushing a BADF filter will result in infitive loop since select() returns -1 forever - - Compiler warning cosmetics but no log flooding since we are not interested in any result - - - - * [r10605] - - dvbapi - - Now rid of compile warning with flush read + - Some rework on irdeto handling + - Requestmode 1: added check on valid oldecmpid + - Flush ecm filterdata from previous sectionfilter before setting a new ecm sectionfilter - * [r10604] - - Avoid logspam: its slowing down and not funny to see repeating lines + * [r10642] + Dvbapi guet rid off compile warning. + This warning was just cause error msg from function read was not used. + Error handling is well done. So it's just an ennoying warning in this case. + With this nothing changes except that we are rid of the compile warning. - * [r10603] - - Dont flush dvb netapi devices: they (mis)use 1 filter for all! - - Protection against zero-ed emm in case of receiver internal bufferoverflow + * [r10641] + [gbx] reshuffle code to make extra declarations superflous - * [r10602] - Fix for broken dvbapi pmtmode 0 introduced in r10600 (Tnx Q33ny for reporting!) - - - * [r10601] - - - Small logcosmetic fix - - - - * [r10600] + * [r10640] DVBAPI: - - Fix for requestmode 1 changing ecmpid while already descrambling (reused streampid could be disabled by stopping old ecm filter and pmt was send again by receiver) - - Flush stale filterdata at the moment a filter is stopped to empty receiver internal filter databuffer - - - - - * [r10599] - - - Free reassembly buffer - - - - * [r10598] - - - Rework on emm filter rotation - - - - * [r10597] - - - Nicer fix for r10596 - - - - * [r10596] - - - Fix for handling of emmfilters if maxfilters is reached. - - - - * [r10595] - - Introduce caid checking function for Viaccess. - - - * [r10594] - - Introduce caid checking function for Cryptoworks. - - - * [r10593] - - Introduce caid checking function for Nagra. - - - * [r10592] + - More CA device streampid rework - Introduce caid checking function for Seca. - * [r10591] + * [r10639] - Introduce caid checking function for Videoguard. + [gbx] various patches + - revert r10223 to restore good night functionality + - split cards write functions to avoid unnecessary local cards writing - * [r10590] - Introduce caid checking function for Bulcrypt. + * [r10638] - * [r10589] + fritzbox toolchain buildfix - Introduce caid checking functions for Irdeto and Betacrypt. + * [r10637] - * [r10588] + - Small cs378x and cs357x emm fix - Introduce caid checking functions for BISS. - * [r10587] + * [r10636] - cosmetic fixes + updated hashtable code + from http://tommyds.sourceforge.net/index.html - * [r10586] + * [r10635] - removed "via_emm_global" setting, since it is no longer used + gbox build fix - * [r10585] + * [r10634] - - Small cosmetic fix! + Revert r10633 - the people have spoken... + * [r10633] - * [r10584] + cccam: Allow to ignore good/bad sids. - Viaccess: - Special tnx goes to Bit and Pr2 for extensive testing, pointers and feedback! + * [r10632] - - Filtering of global emms (needed e.g. for wiping stale entitlement by provider) - - Local attached cards only: filtering of shared emms that match with the providers on your cards - - Several bugfixes emm filtering/parsing in generic - - Added new parameter for reader emmcache - - Enabled temporarily the viaccess emm debug logs to track down any reported issues + - dvbapi: while disabling certain streampid take camask into consideration! - old emmcache = x,y,z - new: emmcache = x,y,z,d - if you set d to 1 then for that reader device specific emms are enabled. default is off - since this parameter is only handy for certain users and certainly not for users using cards in readers. + * [r10631] + - Stapi dvbapi fix for not stopping old descrambler pid associations after zapping to another channel (introduced r10612) + - * [r10583] - globals: Remove unused defines. + * [r10630] - These defines are not used anywhere. + Newcamd: + - Fix for non-matching emm caid (introduced r10582) - * [r10582] + However the real reason is that before it was broken too: emmcaid was always 0000 but it was eventually checked against 0000 so it passed + The improvements gf introduced made the emmchecks more strict and so the bad code of newcamd started to fail. - csystem: Build ops as static structures. + Tnx Dukynukem for not whining and complaining like others did but eventually providing 2 simple logs and testing the patch! - We don't really need to call a function to initialize our ops structure. - We can directly initialize it and use the structures. Also now we don't - have to size the caids array statically. - * [r10581] + * [r10629] - csystem: Make csystem pointer in struct s_reader const. + - Fix for viaccess provid extraction from emm - This signals that nothing should be changed via this pointer. + Tnx goes to Pr2 for research and patch! - * [r10580] - csystem: Turn reader->csystem into pointer to struct s_cardsystem. + * [r10628] - Stop copying `struct s_cardsystem` into every reader. We can work with - pointer to the structure without problems. + [gbx] Fix cards list cleaned on client logout - This reduces `struct s_reader` size by ~120 bytes. - * [r10579] - csystem: Rename all variables that point to struct s_cardsystem to csystem. + * [r10627] - This makes it easier to grep for places that call back into card systems. + - ECM dump fix for ecms that can not be processed by readers - * [r10578] - - Fix memory leak during RSA operation - - - * [r10577] - - csctapi: Constify pointers to struct s_cardreader. - - This communicates clearly that the ops structure can not be changed - at run time. - - - * [r10576] - - csctapi: Build ops as static structures and return pointer to them. - - Now we keep only one copy of card reader ops into memory and next - step is to constify the structures. - - - * [r10575] - - csctapi: Convert s_reader->crdr structure to pointer to struct s_cardreader. - - This allows us to keep only one copy of cardreader ops, instead of - copying them into every reader context. - - - * [r10574] - - csctapi: Move s_cardreader.flush flag to struct s_reader. - - `flush` flag can be changed on per reader bases (sci reader changes - it for exmaple). If we are going to convert reader->crdr from structure - to pointer we need to move `flush` into reader context. - - - * [r10573] - - csctapi: Preparatons for turning reader->crdr into pointer. - - This commit is just preparation for converting `struct s_reader->crdr` - into pointer to `struct s_cardreader` instead of copy of the structure. - - - * [r10572] - - Do not print # before numbers. - - `#number` is being parsed by trac as reference to ticket number. - So posting logs into trac that contain `#number` messes up the logs. - - It really is just a cosmetic issue but it annoys me. - - - * [r10571] - - newcamd: Try to fix ticket #4125. - - - * [r10570] - - [gbx] Fix doubled local cards - + * [r10626] + [gbx] Another better return for r10624 - * [r10569] - copy emm to send in emm.html - optimized loop - -- Andrey Pavlenko Fri, 13 Mar 2015 12:44:26 +0300 + -- Andrey Pavlenko Sat, 25 Apr 2015 13:46:50 +0300 diff -Nru oscam-1.20-10855~r10626/debian/rules oscam-1.20-10882~r10652/debian/rules --- oscam-1.20-10855~r10626/debian/rules 2015-03-13 09:44:26.000000000 +0000 +++ oscam-1.20-10882~r10652/debian/rules 2015-04-25 10:46:50.000000000 +0000 @@ -2,19 +2,18 @@ DIR := $(CURDIR) DESTDIR := $(DIR)/debian/tmp -NPROC := $(shell getconf _NPROCESSORS_ONLN) MAKE_ARGS := CONF_DIR=/etc/oscam OSCAM_BIN=$(DESTDIR)/oscam DISTRIB_VERSION := $(shell lsb_release -sr) %: - dh $@ + dh $@ --parallel override_dh_auto_build: override_dh_auto_install: # Build oscam mkdir -p "$(DESTDIR)/default" - dh_auto_build -- -j$(NPROJ) $(MAKE_ARGS) USE_PCSC=1 USE_LIBUSB=1 + dh_auto_build -- $(MAKE_ARGS) USE_PCSC=1 USE_LIBUSB=1 mv "$(DESTDIR)/oscam" "$(DESTDIR)/default" # Build oscam-newcamd diff -Nru oscam-1.20-10855~r10626/module-camd35.c oscam-1.20-10882~r10652/module-camd35.c --- oscam-1.20-10855~r10626/module-camd35.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/module-camd35.c 2015-04-25 10:46:41.000000000 +0000 @@ -347,7 +347,7 @@ time(&now); if(!memcmp(cl->lastserial, aureader->hexserial, 8)) - if(abs(now - cl->last) < 180) { return; } + if(llabs(now - cl->last) < 180) { return; } memcpy(cl->lastserial, aureader->hexserial, 8); cl->last = now; @@ -651,7 +651,7 @@ time_t now; int32_t time_diff; time(&now); - time_diff = abs(now - cl->reader->last_s); + time_diff = llabs(now - cl->reader->last_s); if(time_diff>cl->reader->tcp_ito) { if(check_client(cl) && cl->reader->tcp_connected && cl->reader->ph.type==MOD_CONN_TCP) diff -Nru oscam-1.20-10855~r10626/module-cccam.c oscam-1.20-10882~r10652/module-cccam.c --- oscam-1.20-10855~r10626/module-cccam.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/module-cccam.c 2015-04-25 10:46:41.000000000 +0000 @@ -2042,7 +2042,7 @@ { //cs_log("last_s - now = %d, last_g - now = %d, tcp_ito=%d", abs(rdr->last_s - now), abs(rdr->last_g - now), rdr->tcp_ito); //check inactivity timeout: - if((abs(rdr->last_s - now) > rdr->tcp_ito) && (abs(rdr->last_g - now) > rdr->tcp_ito)) // inactivity timeout is entered in seconds in webif! + if((llabs(rdr->last_s - now) > rdr->tcp_ito) && (llabs(rdr->last_g - now) > rdr->tcp_ito)) // inactivity timeout is entered in seconds in webif! { rdr_log_dbg(rdr, D_READER, "inactive_timeout, close connection (fd=%d)", rdr->client->pfd); network_tcp_connection_close(rdr, "inactivity"); @@ -2050,7 +2050,7 @@ } //check read timeout: - int32_t rto = abs(rdr->last_g - now); + int32_t rto = llabs(rdr->last_g - now); //cs_log("last_g - now = %d, rto=%d", rto, rdr->tcp_rto); if(rto > (rdr->tcp_rto)) // this is also entered in seconds, actually its an receive timeout! { diff -Nru oscam-1.20-10855~r10626/module-dvbapi.c oscam-1.20-10882~r10652/module-dvbapi.c --- oscam-1.20-10855~r10626/module-dvbapi.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/module-dvbapi.c 2015-04-25 10:46:41.000000000 +0000 @@ -82,7 +82,7 @@ FD_SET(fd,&rd); while(select(fd+1,&rd,NULL,NULL,&t) > 0) { - (void) read(fd,buff,100); + if (read(fd,buff,100)){;} } } } @@ -365,9 +365,18 @@ { return; } } -int32_t dvbapi_net_send(uint32_t request, int32_t socket_fd, int32_t demux_index, uint32_t filter_number, unsigned char *data) +void dvbapi_net_add_str(unsigned char *packet, int *size, const char *str) { - unsigned char packet[262]; //maximum possible packet size + unsigned char *str_len = &packet[*size]; //string length + *size += 1; + + *str_len = snprintf((char *) &packet[*size], DVBAPI_MAX_PACKET_SIZE - *size, "%s", str); + *size += *str_len; +} + +int32_t dvbapi_net_send(uint32_t request, int32_t socket_fd, int32_t demux_index, uint32_t filter_number, unsigned char *data, struct s_client *client, ECM_REQUEST *er) +{ + unsigned char packet[DVBAPI_MAX_PACKET_SIZE]; //maximum possible packet size int32_t size = 0; // not connected? @@ -407,6 +416,71 @@ size += *info_len; break; } + case DVBAPI_ECM_INFO: + { + if (er->rc >= E_NOTFOUND) + return 0; + + int8_t hops = 0; + + uint16_t sid = htons(er->srvid); //service ID (program number) + memcpy(&packet[size], &sid, 2); + size += 2; + + uint16_t caid = htons(er->caid); //CAID + memcpy(&packet[size], &caid, 2); + size += 2; + + uint16_t pid = htons(er->pid); //PID + memcpy(&packet[size], &pid, 2); + size += 2; + + uint32_t prid = htonl(er->prid); //Provider ID + memcpy(&packet[size], &prid, 4); + size += 4; + + uint32_t ecmtime = htonl(client->cwlastresptime); //ECM time + memcpy(&packet[size], &ecmtime, 4); + size += 4; + + switch (er->rc) + { + case E_FOUND: + if (er->selected_reader) + { + dvbapi_net_add_str(packet, &size, er->selected_reader->label); //reader + if (is_network_reader(er->selected_reader)) + dvbapi_net_add_str(packet, &size, er->selected_reader->device); //from + else + dvbapi_net_add_str(packet, &size, "local"); //from + dvbapi_net_add_str(packet, &size, reader_get_type_desc(er->selected_reader, 1)); //protocol + hops = er->selected_reader->currenthops; + } + break; + + case E_CACHE1: + dvbapi_net_add_str(packet, &size, "Cache"); //reader + dvbapi_net_add_str(packet, &size, "cache1"); //from + dvbapi_net_add_str(packet, &size, "none"); //protocol + break; + + case E_CACHE2: + dvbapi_net_add_str(packet, &size, "Cache"); //reader + dvbapi_net_add_str(packet, &size, "cache2"); //from + dvbapi_net_add_str(packet, &size, "none"); //protocol + break; + + case E_CACHEEX: + dvbapi_net_add_str(packet, &size, "Cache"); //reader + dvbapi_net_add_str(packet, &size, "cache3"); //from + dvbapi_net_add_str(packet, &size, "none"); //protocol + break; + } + + packet[size++] = hops; //hops + + break; + } case DVBAPI_CA_SET_PID: { int sct_capid_size = sizeof(ca_pid_t); @@ -576,7 +650,7 @@ memcpy(sFP2.filter.filter, filt, 16); memcpy(sFP2.filter.mask, mask, 16); if (cfg.dvbapi_listenport || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX) - ret = dvbapi_net_send(DVBAPI_DMX_SET_FILTER, demux[demux_id].socket_fd, demux_id, n, (unsigned char *) &sFP2); + ret = dvbapi_net_send(DVBAPI_DMX_SET_FILTER, demux[demux_id].socket_fd, demux_id, n, (unsigned char *) &sFP2, NULL, NULL); else ret = dvbapi_ioctl(demux[demux_id].demux_fd[n].fd, DMX_SET_FILTER, &sFP2); } @@ -859,7 +933,7 @@ { case DVBAPI_3: if (cfg.dvbapi_listenport || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX) - retfilter = dvbapi_net_send(DVBAPI_DMX_STOP, demux[demux_index].socket_fd, demux_index, num, NULL); + retfilter = dvbapi_net_send(DVBAPI_DMX_STOP, demux[demux_index].socket_fd, demux_index, num, NULL, NULL, NULL); else retfilter = dvbapi_ioctl(fd, DMX_STOP, NULL); break; @@ -935,14 +1009,15 @@ for(j = 0; j < MAX_DEMUX; j++) // check other demuxers for same streampid with same index { - if(demux[j].program_number == 0) { continue; } // skip empty demuxers - if(demux_index == j) { continue; } // skip same demuxer + if(demux[j].program_number == 0) { continue; } // skip empty demuxers + if(demux_index == j) { continue; } // skip same demuxer + if(demux[j].ca_mask != demux[demux_index].ca_mask) { continue;} // skip streampid running on other ca device otherdemuxpid = demux[j].pidindex; - if(otherdemuxpid == -1) { continue; } // Other demuxer not descrambling yet + if(otherdemuxpid == -1) { continue; } // Other demuxer not descrambling yet otherdemuxidx = demux[j].ECMpids[otherdemuxpid].index; - if(!otherdemuxidx || otherdemuxidx != idx) { continue; } // Other demuxer has no index yet, or index is different + if(!otherdemuxidx || otherdemuxidx != idx) { continue; } // Other demuxer has no index yet, or index is different for(k = 0; k < demux[j].STREAMpidcount; k++) { @@ -1166,7 +1241,6 @@ demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].tries = 0xFE; demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].streams = 0; // reset streams! demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].irdeto_curindex = 0xFE; // reset - demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].irdeto_curindex = 0xFE; // reset demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].irdeto_maxindex = 0; // reset demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].irdeto_cycle = 0xFE; // reset demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].table = 0; @@ -1376,20 +1450,21 @@ ca_pid2.pid = demux[demux_id].STREAMpids[num]; // removed last of this streampid on ca? -> disable this pid with -1 on this ca - if(action == REMOVED_STREAMPID_LASTINDEX && is_ca_used(i, ca_pid2.pid) == CA_IS_CLEAR) idx = -1; + if((action == REMOVED_STREAMPID_LASTINDEX) && (is_ca_used(i, ca_pid2.pid) == CA_IS_CLEAR)) idx = -1; // removed index of streampid that is used to decode on ca -> get a fresh one if(action == REMOVED_DECODING_STREAMPID_INDEX) { - ca_pid2.index |= is_ca_used(i, demux[demux_id].STREAMpids[num]); // get an active index for this pid and enable it on ca device + idx = is_ca_used(i, demux[demux_id].STREAMpids[num]); // get an active index for this pid and enable it on ca device + enable = 1; } - ca_pid2.index = idx; + ca_pid2.index = idx; cs_log_dbg(D_DVBAPI, "Demuxer %d %s stream %d pid=0x%04x index=%d on ca%d", demux_id, (enable ? "enable" : "disable"), num + 1, ca_pid2.pid, ca_pid2.index, i); if(cfg.dvbapi_boxtype == BOXTYPE_PC || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX) - dvbapi_net_send(DVBAPI_CA_SET_PID, demux[demux_id].socket_fd, demux_id, -1 /*unused*/, (unsigned char *) &ca_pid2); + dvbapi_net_send(DVBAPI_CA_SET_PID, demux[demux_id].socket_fd, demux_id, -1 /*unused*/, (unsigned char *) &ca_pid2, NULL, NULL); else { currentfd = ca_fd[i]; @@ -2528,16 +2603,21 @@ cs_log_dump_dbg(D_DVBAPI, buffer, length, "capmt:"); cs_log_dbg(D_DVBAPI, "Receiver sends PMT command %d for channel %04X", ca_pmt_list_management, program_number); - if((ca_pmt_list_management == LIST_FIRST || ca_pmt_list_management == LIST_ONLY) && (pmt_stopmarking == 0 && cfg.dvbapi_pmtmode == 6)) + if((ca_pmt_list_management == LIST_FIRST || ca_pmt_list_management == LIST_ONLY)) { for(i = 0; i < MAX_DEMUX; i++) { + if(cfg.dvbapi_pmtmode == 6 && pmt_stopmarking == 1) { continue; } // already marked -> skip! if(demux[i].program_number == 0) { continue; } // skip empty demuxers + if(demux[i].ECMpidcount != 0 && demux[i].pidindex != -1 ) { demux[i].running = 1; } // running channel changes from scrambled to fta if(demux[i].socket_fd != connfd) { continue; } // skip demuxers belonging to other ca pmt connection - demux[i].stopdescramble = 1; // Mark for deletion if not used again by following pmt objects. - cs_log_dbg(D_DVBAPI, "Marked demuxer %d/%d to stop decoding", i, MAX_DEMUX); - pmt_stopmarking = 1; + if(cfg.dvbapi_pmtmode == 6) + { + demux[i].stopdescramble = 1; // Mark for deletion if not used again by following pmt objects. + cs_log_dbg(D_DVBAPI, "Marked demuxer %d/%d (srvid = %04X fd = %d) to stop decoding", i, MAX_DEMUX, demux[i].program_number, connfd); + } } + pmt_stopmarking = 1; } getDemuxOptions(i, buffer, &ca_mask, &demux_index, &adapter_index, &pmtpid); cs_log_dbg(D_DVBAPI,"Receiver wants to demux srvid %04X on adapter %04X camask %04X index %04X pmtpid %04X", @@ -2574,8 +2654,7 @@ openxcas_set_sid(program_number); - demux[i].stopdescramble = 0; // dont stop current demuxer! - if(demux[demux_id].ECMpidcount != 0 && demux[demux_id].pidindex != -1 ) { demux[demux_id].running = 1; } // running channel changes from scrambled to fta + demux[i].stopdescramble = 0; // dont stop current demuxer! break; // no need to explore other demuxers since we have a found! } } @@ -3232,7 +3311,6 @@ { curpid = &demux[demux_id].ECMpids[pid]; } - uint32_t chid = 0x10000; uint32_t ecmlen = (b2i(2, buffer + 1)&0xFFF)+3; ECM_REQUEST *er; @@ -3329,7 +3407,7 @@ { if(curpid->irdeto_curindex != buffer[4]) // old style wrong irdeto index - { + { if(curpid->irdeto_curindex == 0xFE) // check if this ecmfilter just started up { curpid->irdeto_curindex = buffer[4]; // on startup set the current index to the irdeto index of the ecm @@ -3362,8 +3440,8 @@ { if(caid_is_irdeto(curpid->CAID)) { - - if((curpid->irdeto_cycle < 0xFE) && curpid->irdeto_cycle == buffer[4]) // if same: we cycled all indexes but no luck! + + if((curpid->irdeto_cycle < 0xFE) && (curpid->irdeto_cycle == curpid->irdeto_curindex)) // if same: we cycled all indexes but no luck! { struct s_dvbapi_priority *forceentry = dvbapi_check_prio_match(demux_id, pid, 'p'); if(!forceentry || !forceentry->force) // forced pid? keep trying the forced ecmpid, no force kill ecm filter @@ -3379,9 +3457,9 @@ return; } } - if(curpid->irdeto_cycle == 0xFE) { curpid->irdeto_cycle = buffer[4]; } // register irdeto index of current ecm - + curpid->irdeto_curindex++; // set check on next index + if(curpid->irdeto_cycle == 0xFE) curpid->irdeto_cycle = buffer[4]; // on startup set to current irdeto index if(curpid->irdeto_curindex > curpid->irdeto_maxindex) { curpid->irdeto_curindex = 0; } // check if we reached max irdeto index, if so reset to 0 curpid->table = 0; @@ -3459,12 +3537,13 @@ if(p->type == 'i' && (p->chid < 0x10000 && p->chid == chid)) // found a ignore chid match with current ecm -> ignoring this irdeto index { curpid->irdeto_curindex++; + if(curpid->irdeto_cycle == 0xFE) curpid->irdeto_cycle = buffer[4]; // on startup set to current irdeto index if(curpid->irdeto_curindex > curpid->irdeto_maxindex) // check if curindex is over the max { curpid->irdeto_curindex = 0; } curpid->table = 0; - if(caid_is_irdeto(curpid->CAID)) // irdeto: wait for the correct index + if(caid_is_irdeto(curpid->CAID) && (curpid->irdeto_cycle != curpid->irdeto_curindex)) // irdeto: wait for the correct index + check if we cycled all { dvbapi_set_section_filter(demux_id, er, filter_num); // set ecm filter to odd + even since this chid has to be ignored! } @@ -3482,9 +3561,12 @@ return; } } - if (er){ + + if(er) + { curpid->table = er->ecm[0]; } + request_cw(dvbapi_client, er, demux_id, 1); // register this ecm for delayed ecm response check return; // end of ecm filterhandling! } @@ -4048,7 +4130,7 @@ client_proto_version = client_proto; //setting the global var according to the client // as a response we are sending our info to the client: - dvbapi_net_send(DVBAPI_SERVER_INFO, connfd, -1, -1, NULL); + dvbapi_net_send(DVBAPI_SERVER_INFO, connfd, -1, -1, NULL, NULL, NULL); break; } } @@ -4162,39 +4244,60 @@ { int32_t idx = dvbapi_ca_setpid(demux_id, pid); // prepare ca if (idx == -1) return; // return on no index! + +#ifdef WITH_COOLAPI ca_descr.index = idx; ca_descr.parity = n; - cs_log_dbg(D_DVBAPI, "Demuxer %d writing %s part (%s) of controlword, replacing expired (%s)", demux_id, (n == 1 ? "even" : "odd"), - newcw, lastcw); memcpy(demux[demux_id].lastcw[n], cw + (n * 8), 8); memcpy(ca_descr.cw, cw + (n * 8), 8); - -#ifdef WITH_COOLAPI cs_log_dbg(D_DVBAPI, "Demuxer %d write cw%d index: %d (ca_mask %d)", demux_id, n, ca_descr.index, demux[demux_id].ca_mask); coolapi_write_cw(demux[demux_id].ca_mask, demux[demux_id].STREAMpids, demux[demux_id].STREAMpidcount, &ca_descr); #else - int32_t i; + int32_t i,j, write_cw = 0; for(i = 0; i < MAX_DEMUX; i++) { - if(demux[demux_id].ca_mask & (1 << i)) + if(!(demux[demux_id].ca_mask & (1 << i))) continue; // ca not in use by this demuxer! + + for(j = 0; j < demux[demux_id].STREAMpidcount; j++) { - cs_log_dbg(D_DVBAPI, "Demuxer %d write cw%d index: %d (ca%d)", demux_id, n, ca_descr.index, i); - - if(cfg.dvbapi_boxtype == BOXTYPE_PC || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX) - dvbapi_net_send(DVBAPI_CA_SET_DESCR, demux[demux_id].socket_fd, demux_id, -1 /*unused*/, (unsigned char *) &ca_descr); - else + if(!demux[demux_id].ECMpids[pid].streams || ((demux[demux_id].ECMpids[pid].streams & (1 << j)) == (uint) (1 << j))) { - if(ca_fd[i] <= 0) + int32_t usedidx = is_ca_used(i, demux[demux_id].STREAMpids[j]); + if(idx != usedidx) { - ca_fd[i] = dvbapi_open_device(1, i, demux[demux_id].adapter_index); - if(ca_fd[i] <= 0) - { continue; } // proceed next stream + cs_log_dbg(D_DVBAPI,"Demuxer %d ca%d is using index %d for streampid %04X -> skip!", demux_id, i, usedidx, demux[demux_id].STREAMpids[j]); + continue; // if not used for descrambling -> skip! } - if (dvbapi_ioctl(ca_fd[i], CA_SET_DESCR, &ca_descr) < 0) { - cs_log("ERROR: ioctl(CA_SET_DESCR): %s", strerror(errno)); + else + { + cs_log_dbg(D_DVBAPI,"Demuxer %d ca%d is using index %d for streampid %04X -> write!", demux_id, i, usedidx, demux[demux_id].STREAMpids[j]); + write_cw = 1; } } } + if(!write_cw) { continue; } // no need to write the cw since this ca isnt using it! + + ca_descr.index = idx; + ca_descr.parity = n; + memcpy(demux[demux_id].lastcw[n], cw + (n * 8), 8); + memcpy(ca_descr.cw, cw + (n * 8), 8); + cs_log_dbg(D_DVBAPI, "Demuxer %d writing %s part (%s) of controlword, replacing expired (%s)", demux_id, (n == 1 ? "even" : "odd"), newcw, lastcw); + cs_log_dbg(D_DVBAPI, "Demuxer %d write cw%d index: %d (ca%d)", demux_id, n, ca_descr.index, i); + + if(cfg.dvbapi_boxtype == BOXTYPE_PC || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX) + dvbapi_net_send(DVBAPI_CA_SET_DESCR, demux[demux_id].socket_fd, demux_id, -1 /*unused*/, (unsigned char *) &ca_descr, NULL, NULL); + else + { + if(ca_fd[i] <= 0) + { + ca_fd[i] = dvbapi_open_device(1, i, demux[demux_id].adapter_index); + if(ca_fd[i] <= 0) { continue; } + } + if (dvbapi_ioctl(ca_fd[i], CA_SET_DESCR, &ca_descr) < 0) + { + cs_log("ERROR: ioctl(CA_SET_DESCR): %s", strerror(errno)); + } + } } #endif } @@ -4308,7 +4411,7 @@ int32_t t, o, ecmcounter = 0; int32_t oldpidindex = demux[i].pidindex; demux[i].pidindex = j; // set current ecmpid as the new pid to descramble - demux[i].ECMpids[j].index = demux[i].ECMpids[oldpidindex].index; // swap index with lower status pid that was descrambling + if(oldpidindex != -1) demux[i].ECMpids[j].index = demux[i].ECMpids[oldpidindex].index; // swap index with lower status pid that was descrambling for(t = 0; t < demux[i].ECMpidcount; t++) //check this pid with controlword FOUND for higher status: { if(t != j && demux[i].ECMpids[j].status >= demux[i].ECMpids[t].status) @@ -4491,7 +4594,9 @@ client->last = time((time_t *)0); // ********* TO BE FIXED LATER ON ****** FILE *ecmtxt = NULL; - if (!cfg.dvbapi_listenport && cfg.dvbapi_boxtype != BOXTYPE_PC_NODMX) + if (cfg.dvbapi_listenport && client_proto_version >= 2) + dvbapi_net_send(DVBAPI_ECM_INFO, demux[i].socket_fd, i, 0, NULL, client, er); + else if (!cfg.dvbapi_listenport && cfg.dvbapi_boxtype != BOXTYPE_PC_NODMX) ecmtxt = fopen(ECMINFO_FILE, "w"); if(ecmtxt != NULL && er->rc < E_NOTFOUND) { @@ -4704,6 +4809,7 @@ { int32_t ret = -1; + switch(selected_api) { case DVBAPI_3: @@ -4740,7 +4846,7 @@ memcpy(sFP2.filter.filter, filter, 16); memcpy(sFP2.filter.mask, mask, 16); if (cfg.dvbapi_listenport || cfg.dvbapi_boxtype == BOXTYPE_PC_NODMX) - ret = dvbapi_net_send(DVBAPI_DMX_SET_FILTER, demux[demux_index].socket_fd, demux_index, num, (unsigned char *) &sFP2); + ret = dvbapi_net_send(DVBAPI_DMX_SET_FILTER, demux[demux_index].socket_fd, demux_index, num, (unsigned char *) &sFP2, NULL, NULL); else ret = dvbapi_ioctl(fd, DMX_SET_FILTER, &sFP2); } @@ -4998,8 +5104,13 @@ { if(listitem->cadevice != cadevice) continue; if(pid && listitem->streampid != pid) continue; - uint32_t i = 0, newindex = 0; - while(!newindex) + uint32_t i = 0; + int32_t newindex = -1; + if(listitem->caindex != 0xFFFF) + { + newindex = listitem->caindex; + } + while(newindex == -1) { if((listitem->activeindexers&(1 << i)) == (uint)(1 << i)) { diff -Nru oscam-1.20-10855~r10626/module-dvbapi.h oscam-1.20-10882~r10652/module-dvbapi.h --- oscam-1.20-10855~r10626/module-dvbapi.h 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/module-dvbapi.h 2015-04-25 10:46:41.000000000 +0000 @@ -49,7 +49,7 @@ #define DUMMY_FD 0xFFFF //constants used int socket communication: -#define DVBAPI_PROTOCOL_VERSION 1 +#define DVBAPI_PROTOCOL_VERSION 2 #define DVBAPI_CA_SET_PID 0x40086f87 #define DVBAPI_CA_SET_DESCR 0x40106f86 @@ -62,6 +62,9 @@ #define DVBAPI_FILTER_DATA 0xFFFF0000 #define DVBAPI_CLIENT_INFO 0xFFFF0001 #define DVBAPI_SERVER_INFO 0xFFFF0002 +#define DVBAPI_ECM_INFO 0xFFFF0003 + +#define DVBAPI_MAX_PACKET_SIZE 262 //maximum possible packet size struct box_devices { diff -Nru oscam-1.20-10855~r10626/module-dvbapi-stapi.c oscam-1.20-10882~r10652/module-dvbapi-stapi.c --- oscam-1.20-10855~r10626/module-dvbapi-stapi.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/module-dvbapi-stapi.c 2015-04-25 10:46:41.000000000 +0000 @@ -573,7 +573,7 @@ if(demux[demux_id].DescramblerHandle[n] == 0) { return; } if(mode == ASSOCIATE) - { + { int32_t k; for(k = 0; k < SLOTNUM; k++) { @@ -700,6 +700,18 @@ } if(demux[demux_id].DescramblerHandle[n] == 0) { continue; } + + int32_t pidnum = demux[demux_id].pidindex; // get current pidindex used for descrambling + int32_t idx = demux[demux_id].ECMpids[pidnum].index; + + if(!idx) // if no indexer for this pid get one! + { + idx = dvbapi_get_descindex(demux_id); + demux[demux_id].ECMpids[pidnum].index = idx; + cs_log_dbg(D_DVBAPI, "Demuxer %d PID: %d CAID: %04X ECMPID: %04X is using index %d", demux_id, pidnum, + demux[demux_id].ECMpids[pidnum].CAID, demux[demux_id].ECMpids[pidnum].ECM_PID, idx - 1); + } + for(k = 0; k < STREAMpidcount; k++) { stapi_DescramblerAssociate(demux_id, STREAMpids[k], ASSOCIATE, n); diff -Nru oscam-1.20-10855~r10626/module-gbox.c oscam-1.20-10882~r10652/module-gbox.c --- oscam-1.20-10855~r10626/module-gbox.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/module-gbox.c 2015-04-25 10:46:41.000000000 +0000 @@ -33,13 +33,7 @@ static uint8_t local_gbox_initialized = 0; static time_t last_stats_written; -static void gbox_send_checkcode(struct s_client *cli); -static void gbox_local_cards(struct s_reader *reader, TUNTAB *ttab); -static int8_t gbox_incoming_ecm(struct s_client *cli, uchar *data, int32_t n); -static int8_t gbox_cw_received(struct s_client *cli, uchar *data, int32_t n); -static int32_t gbox_recv_chk(struct s_client *cli, uchar *dcw, int32_t *rc, uchar *data, int32_t n); -static int32_t gbox_checkcode_recv(struct s_client *cli, uchar *checkcode); -static int32_t gbox_send_ecm(struct s_client *cli, ECM_REQUEST *er, uchar *UNUSED(buf)); +static int32_t gbox_send_ecm(struct s_client *cli, ECM_REQUEST *er, uchar *UNUSED(buf)); char *get_gbox_tmp_fname(char *fext) { @@ -165,7 +159,9 @@ void gbox_write_version(void) { - FILE *fhandle = fopen(get_gbox_tmp_fname(FILE_GBOX_VERSION), "w"); + char *fext= FILE_GBOX_VERSION; + char *fname = get_gbox_tmp_fname(fext); + FILE *fhandle = fopen(fname, "w"); if(!fhandle) { cs_log("Couldn't open %s: %s", get_gbox_tmp_fname(FILE_GBOX_VERSION), strerror(errno)); @@ -230,15 +226,23 @@ return found; } +static int8_t gbox_peer_online(struct gbox_peer *peer, uint8_t online) +{ + if (!peer) { return -1; } + + peer->online = online; + gbox_write_peer_onl(); + return 0; +} + static int8_t gbox_reinit_peer(struct gbox_peer *peer) { if (!peer) { return -1; } - NULLFREE(peer->hostname); - peer->online = 0; + peer->ecm_idx = 0; peer->next_hello = 0; gbox_delete_cards(GBOX_DELETE_FROM_PEER, peer->gbox.id); -// peer->my_user = NULL; + gbox_peer_online(peer, GBOX_PEER_OFFLINE); return 0; } @@ -257,6 +261,127 @@ return 0; } +void gbox_send(struct s_client *cli, uchar *buf, int32_t l) +{ + struct gbox_peer *peer = cli->gbox; + + cs_log_dump_dbg(D_READER, buf, l, "<- decrypted data (%d bytes):", l); + + hostname2ip(cli->reader->device, &SIN_GET_ADDR(cli->udp_sa)); + SIN_GET_FAMILY(cli->udp_sa) = AF_INET; + SIN_GET_PORT(cli->udp_sa) = htons((uint16_t)cli->reader->r_port); + + gbox_encrypt(buf, l, peer->gbox.password); + sendto(cli->udp_fd, buf, l, 0, (struct sockaddr *)&cli->udp_sa, cli->udp_sa_len); + cs_log_dump_dbg(D_READER, buf, l, "<- encrypted data (%d bytes):", l); +} + +void gbox_send_hello_packet(struct s_client *cli, int8_t number, uchar *outbuf, uchar *ptr, int32_t nbcards, uint8_t hello_stat) +{ + struct gbox_peer *peer = cli->gbox; + int32_t hostname_len = strlen(cfg.gbox_hostname); + int32_t len; + gbox_message_header(outbuf, MSG_HELLO, peer->gbox.password, local_gbox.password); + // initial HELLO = 0, subsequent = 1 + if(hello_stat > GBOX_STAT_HELLOS) + { outbuf[10] = 1; } + else + { outbuf[10] = 0; } + outbuf[11] = number; // 0x80 (if last packet) else 0x00 | packet number + + if((number & 0x0F) == 0) + { + if(hello_stat != GBOX_STAT_HELLOL) + { memcpy(++ptr, gbox_get_checkcode(), 7); } + else + { memset(++ptr, 0, 7); } + ptr += 7; + *ptr = local_gbox.minor_version; + *(++ptr) = local_gbox.cpu_api; + memcpy(++ptr, cfg.gbox_hostname, hostname_len); + ptr += hostname_len; + *ptr = hostname_len; + } + len = ptr - outbuf + 1; + switch(hello_stat) + { + case GBOX_STAT_HELLOL: + cs_log("<- HelloL to %s", cli->reader->label); + break; + case GBOX_STAT_HELLOS: + cs_log("<- HelloS total cards %d to %s", nbcards, cli->reader->label); + break; + case GBOX_STAT_HELLOR: + cs_log("<- HelloR total cards %d to %s", nbcards, cli->reader->label); + break; + default: + cs_log("<- hello total cards %d to %s", nbcards, cli->reader->label); + break; + } + cs_log_dump_dbg(D_READER, outbuf, len, "<- hello, (len=%d):", len); + + gbox_compress(outbuf, len, &len); + + gbox_send(cli, outbuf, len); +} + +void gbox_send_hello(struct s_client *proxy, uint8_t hello_stat) +{ + if (!proxy) + { + cs_log("Invalid call to gbox_send_hello with proxy"); + return; + } + uint16_t nbcards = 0; + uint8_t packet; + uchar buf[2048]; + packet = 0; + uchar *ptr = buf + 11; + if(gbox_count_cards() != 0 && hello_stat > GBOX_STAT_HELLOL) + { + struct gbox_peer *peer = proxy->gbox; + if (!peer || !peer->my_user || !peer->my_user->account) + { + cs_log("Invalid call to gbox_send_hello with peer"); + return; + } + memset(buf, 0, sizeof(buf)); + struct gbox_card *card; + GBOX_CARDS_ITER *gci = gbox_cards_iter_create(); + while((card = gbox_cards_iter_next(gci))) + { + //send to user only cards which matching CAID from account and lvl > 0 + //do not send peer cards back + if(chk_ctab(gbox_get_caid(card->caprovid), &peer->my_user->account->ctab) && (card->lvl > 0) && + (!card->origin_peer || (card->origin_peer && card->origin_peer->gbox.id != peer->gbox.id))) + { + *(++ptr) = card->caprovid >> 24; + *(++ptr) = card->caprovid >> 16; + *(++ptr) = card->caprovid >> 8; + *(++ptr) = card->caprovid & 0xff; + *(++ptr) = 1; //note: original gbx is more efficient and sends all cards of one caid as package + *(++ptr) = card->id.slot; + *(++ptr) = ((card->lvl - 1) << 4) + card->dist + 1; + *(++ptr) = card->id.peer >> 8; + *(++ptr) = card->id.peer & 0xff; + nbcards++; + if(nbcards == 100) //check if 100 is good or we need more sophisticated algorithm + { + gbox_send_hello_packet(proxy, packet, buf, ptr, nbcards, hello_stat); + packet++; + nbcards = 0; + ptr = buf + 11; + memset(buf, 0, sizeof(buf)); + } + } + } + gbox_cards_iter_destroy(gci); + } // end if local card exists + //last packet has bit 0x80 set + gbox_send_hello_packet(proxy, 0x80 | packet, buf, ptr, nbcards, hello_stat); + return; +} + void gbox_reconnect_client(uint16_t gbox_id) { struct s_client *cl; @@ -303,6 +428,8 @@ { if (cl->typ == 'c' && cl->gbox_peer_id == cli->gbox_peer_id && cl != cli) { + cl->reader = NULL; + cl->gbox = NULL; cs_log_dbg(D_READER, "disconnected double client %s",username(cl)); cs_disconnect_client(cl); } @@ -402,6 +529,32 @@ return ncards_in_msg; } +//returns 1 if checkcode changed / 0 if not +static int32_t gbox_checkcode_recv(struct s_client *cli, uchar *checkcode) +{ + struct gbox_peer *peer = cli->gbox; + char tmp[14]; + + if(memcmp(peer->checkcode, checkcode, 7)) + { + memcpy(peer->checkcode, checkcode, 7); + cs_log_dbg(D_READER, "-> new checkcode=%s", cs_hexdump(0, peer->checkcode, 14, tmp, sizeof(tmp))); + return 1; + } + return 0; +} + +static void gbox_send_checkcode(struct s_client *cli) +{ + struct gbox_peer *peer = cli->gbox; + uchar outbuf[20]; + + gbox_message_header(outbuf, MSG_CHECKCODE, peer->gbox.password, local_gbox.password); + memcpy(outbuf + 10, gbox_get_checkcode(), 7); + + gbox_send(cli, outbuf, 17); +} + int32_t gbox_cmd_hello(struct s_client *cli, uchar *data, int32_t n) { if (!cli || !cli->gbox || !cli->reader || !data) { return -1; } @@ -475,9 +628,16 @@ else //last packet of Hello { peer->filtered_cards = gbox_count_peer_cards(peer->gbox.id); - if(!data[0xA]) + if(!data[10]) { - cs_log("-> HelloS in %d packets from %s (%s:%d) V2.%02X with %d cards filtered to %d cards", (data[0x0B] & 0x0f)+1, cli->reader->label, cs_inet_ntoa(cli->ip), cli->reader->r_port, peer->gbox.minor_version, peer->total_cards, peer->filtered_cards); + memset(&tmpbuf[0], 0, 7); + if (data[11] == 0x80 && !memcmp(data+12,tmpbuf,7)) + { + cs_log("-> HelloL in %d packets from %s (%s:%d) V2.%02X with %d cards filtered to %d cards", (data[0x0B] & 0x0f)+1, cli->reader->label, cs_inet_ntoa(cli->ip), cli->reader->r_port, peer->gbox.minor_version, peer->total_cards, peer->filtered_cards); + gbox_peer_online(peer, GBOX_PEER_ONLINE); + } + else + { cs_log("-> HelloS in %d packets from %s (%s:%d) V2.%02X with %d cards filtered to %d cards", (data[0x0B] & 0x0f)+1, cli->reader->label, cs_inet_ntoa(cli->ip), cli->reader->r_port, peer->gbox.minor_version, peer->total_cards, peer->filtered_cards); } gbox_send_hello(cli, GBOX_STAT_HELLOR); } else @@ -486,19 +646,19 @@ gbox_send_checkcode(cli); } if(!peer->online) - { gbox_send_hello(cli, GBOX_STAT_HELLOS); } - peer->online = 1; + { + gbox_send_hello(cli, GBOX_STAT_HELLOS); + gbox_peer_online(peer, GBOX_PEER_ONLINE); + } cli->reader->tcp_connected = 2; //we have card if(!peer->filtered_cards) { cli->reader->card_status = NO_CARD; } else - { cli->reader->card_status = CARD_INSERTED; } - - peer->next_hello = 0; - gbox_write_cards_info(); - gbox_write_peer_onl(); - cli->last = time((time_t *)0); //hello is activity on proxy + { cli->reader->card_status = CARD_INSERTED; } } + peer->next_hello = 0; + gbox_write_share_cards_info(); + cli->last = time((time_t *)0); //hello is activity on proxy } else { peer->next_hello++; } return 0; @@ -605,6 +765,97 @@ return 0; } +static uint32_t gbox_get_pending_time(ECM_REQUEST *er, uint16_t peer_id, uint8_t slot) +{ + if (!er) { return 0; } + + uint32_t ret_time = 0; + struct gbox_card_pending *pending = NULL; + LL_LOCKITER *li = ll_li_create(er->gbox_cards_pending, 0); + while ((pending = ll_li_next(li))) + { + if ((pending->id.peer == peer_id) && (pending->id.slot == slot)) + { + ret_time = pending->pending_time; + break; + } + } + ll_li_destroy(li); + return ret_time; +} + +static int32_t gbox_recv_chk(struct s_client *cli, uchar *dcw, int32_t *rc, uchar *data, int32_t n) +{ + if(!cli || gbox_decode_cmd(data) != MSG_CW || n < 44) + { return -1; } + + int i; + uint16_t id_card = 0; + struct s_client *proxy; + if(cli->typ != 'p') + { proxy = get_gbox_proxy(cli->gbox_peer_id); } + else + { proxy = cli; } + if (!proxy || !proxy->reader) + { + cs_log("error, gbox_recv_chk, proxy not found"); + return -1; + } + proxy->last = time((time_t *)0); + *rc = 1; + memcpy(dcw, data + 14, 16); + uint32_t crc = b2i(4, data + 30); + char tmp[32]; + cs_log_dbg(D_READER, "-> cws=%s, peer=%04X, ecm_pid=%04X, sid=%04X, crc=%08X, type=%02X, dist=%01X, unkn1=%01X, unkn2=%02X, chid/0x0000/0xffff=%04X", + cs_hexdump(0, dcw, 32, tmp, sizeof(tmp)), + data[10] << 8 | data[11], data[6] << 8 | data[7], data[8] << 8 | data[9], crc, data[41], data[42] & 0x0f, data[42] >> 4, data[43], data[37] << 8 | data[38]); + struct timeb t_now; + cs_ftime(&t_now); + int64_t cw_time = GBOX_DEFAULT_CW_TIME; + for(i = 0; i < cfg.max_pending; i++) + { + if(proxy->ecmtask[i].gbox_crc == crc) + { + id_card = b2i(2, data + 10); + cw_time = comp_timeb(&t_now, &proxy->ecmtask[i].tps) - gbox_get_pending_time(&proxy->ecmtask[i], id_card, data[36]); + gbox_add_good_sid(id_card, proxy->ecmtask[i].caid, data[36], proxy->ecmtask[i].srvid, cw_time); + proxy->reader->currenthops = data[42] & 0x0f; + gbox_remove_all_bad_sids(&proxy->ecmtask[i], proxy->ecmtask[i].srvid); + if(proxy->ecmtask[i].gbox_ecm_status == GBOX_ECM_NOT_ASKED || proxy->ecmtask[i].gbox_ecm_status == GBOX_ECM_ANSWERED) + { return -1; } + proxy->ecmtask[i].gbox_ecm_status = GBOX_ECM_ANSWERED; + proxy->ecmtask[i].gbox_ecm_id = id_card; + *rc = 1; + return proxy->ecmtask[i].idx; + } + } + //late answers from other peers,timing not possible + gbox_add_good_sid(id_card, data[34] << 8 | data[35], data[36], data[8] << 8 | data[9], GBOX_DEFAULT_CW_TIME); + cs_log_dbg(D_READER, "no task found for crc=%08x", crc); + return -1; +} + +static int8_t gbox_cw_received(struct s_client *cli, uchar *data, int32_t n) +{ + int32_t rc = 0, i = 0, idx = 0; + uchar dcw[16]; + + idx = gbox_recv_chk(cli, dcw, &rc, data, n); + if(idx < 0) { return -1; } // no dcw received + if(!idx) { idx = cli->last_idx; } + cli->reader->last_g = time((time_t *)0); // for reconnect timeout + for(i = 0; i < cfg.max_pending; i++) + { + if(cli->ecmtask[i].idx == idx) + { + cli->pending--; + casc_check_dcw(cli->reader, i, rc, dcw); + return 0; + } + } + return -1; +} + int32_t gbox_cmd_switch(struct s_client *proxy, uchar *data, int32_t n) { if (!data || !proxy) { return -1; } @@ -612,6 +863,7 @@ switch(cmd) { case MSG_BOXINFO: + cs_log("-> BOXINFO from %s",username(proxy)); gbox_send_hello(proxy, GBOX_STAT_HELLOR); break; case MSG_GOODBYE: @@ -694,10 +946,107 @@ return 0; } -static uint32_t gbox_get_pw(uchar *buf) +static void gbox_local_cards(struct s_reader *reader, TUNTAB *ttab) { - return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; -} + int32_t i; + uint32_t prid = 0; + int8_t slot = 0; +#ifdef MODULE_CCCAM + LL_ITER it, it2; + struct cc_card *card = NULL; + struct cc_data *cc; + uint32_t checksum = 0; + uint16_t cc_peer_id = 0; + struct cc_provider *provider; + uint8_t *node1 = NULL; + uint8_t min_reshare = 0; + gbox_delete_cards(GBOX_DELETE_WITH_TYPE, GBOX_CARD_TYPE_CCCAM); +#endif + gbox_delete_cards(GBOX_DELETE_WITH_ID, local_gbox.id); + struct s_client *cl; + cs_readlock(&clientlist_lock); + for(cl = first_client; cl; cl = cl->next) + { + if(cl->typ == 'r' && cl->reader && cl->reader->card_status == 2) + { + slot = gbox_next_free_slot(local_gbox.id); + //SECA, Viaccess and Cryptoworks have multiple providers + if(caid_is_seca(cl->reader->caid) || caid_is_viaccess(cl->reader->caid) || caid_is_cryptoworks(cl->reader->caid)) + { + for(i = 0; i < cl->reader->nprov; i++) + { + prid = cl->reader->prid[i][1] << 16 | + cl->reader->prid[i][2] << 8 | cl->reader->prid[i][3]; + gbox_add_card(local_gbox.id, gbox_get_caprovid(cl->reader->caid, prid), slot, reader->gbox_reshare, 0, GBOX_CARD_TYPE_LOCAL, NULL); + } + } + else + { + gbox_add_card(local_gbox.id, gbox_get_caprovid(cl->reader->caid, 0), slot, reader->gbox_reshare, 0, GBOX_CARD_TYPE_LOCAL, NULL); + + //Check for Betatunnel on gbox account in oscam.user + if (chk_is_betatunnel_caid(cl->reader->caid) == 1 && ttab->ttdata && cl->reader->caid == ttab->ttdata[0].bt_caidto) + { + //For now only first entry in tunnel tab. No sense in iteration? + //Add betatunnel card to transmitted list + gbox_add_card(local_gbox.id, gbox_get_caprovid(ttab->ttdata[0].bt_caidfrom, 0), slot, reader->gbox_reshare, 0, GBOX_CARD_TYPE_BETUN, NULL); + cs_log_dbg(D_READER, "gbox created betatunnel card for caid: %04X->%04X", ttab->ttdata[0].bt_caidfrom, cl->reader->caid); + } + } + } //end local readers +#ifdef MODULE_CCCAM + if((cfg.cc_reshare > -1) && (reader->gbox_cccam_reshare) && cl->typ == 'p' && cl->reader && cl->reader->typ == R_CCCAM && cl->cc) + { + cc = cl->cc; + it = ll_iter_create(cc->cards); + while((card = ll_iter_next(&it))) + { + //calculate gbox id from cc node + node1 = ll_has_elements(card->remote_nodes); + checksum = ((node1[0] ^ node1[7]) << 8) | + ((node1[1] ^ node1[6]) << 24) | + (node1[2] ^ node1[5]) | + ((node1[3] ^ node1[4]) << 16); + cc_peer_id = ((((checksum >> 24) & 0xFF) ^((checksum >> 8) & 0xFF)) << 8 | + (((checksum >> 16) & 0xFF) ^(checksum & 0xFF))); + slot = gbox_next_free_slot(cc_peer_id); + min_reshare = cfg.cc_reshare; + if (card->reshare < min_reshare) + { min_reshare = card->reshare; } + min_reshare++; //strange CCCam logic. 0 means direct peers + if (reader->gbox_cccam_reshare < min_reshare) + { min_reshare = reader->gbox_cccam_reshare; } + if(caid_is_seca(card->caid) || caid_is_viaccess(card->caid) || caid_is_cryptoworks(card->caid)) + { + it2 = ll_iter_create(card->providers); + while((provider = ll_iter_next(&it2))) + { gbox_add_card(cc_peer_id, gbox_get_caprovid(card->caid, provider->prov), slot, min_reshare, card->hop, GBOX_CARD_TYPE_CCCAM, NULL); } + } + else + { gbox_add_card(cc_peer_id, gbox_get_caprovid(card->caid, 0), slot, min_reshare, card->hop, GBOX_CARD_TYPE_CCCAM, NULL); } + } + } //end cccam +#endif + } //end for clients + cs_readunlock(&clientlist_lock); + + if (cfg.gbox_proxy_cards_num > 0) + { + for (i = 0; i < cfg.gbox_proxy_cards_num; i++) + { + slot = gbox_next_free_slot(local_gbox.id); + gbox_add_card(local_gbox.id, cfg.gbox_proxy_card[i], slot, reader->gbox_reshare, 0, GBOX_CARD_TYPE_PROXY, NULL); + if ((cfg.gbox_proxy_card[i] >> 24) == 0x05) + { + cs_log_dbg(D_READER,"add proxy card: slot %d %04lX:%06lX",slot, (cfg.gbox_proxy_card[i] >> 16) & 0xFFF0, cfg.gbox_proxy_card[i] & 0xFFFFF); + } else + { + cs_log_dbg(D_READER,"add proxy card: slot %d %04lX:%06lX",slot, cfg.gbox_proxy_card[i] >> 16, cfg.gbox_proxy_card[i] & 0xFFFF); + } + } + } // end add proxy reader cards + gbox_write_local_cards_info(); +} //end add local gbox cards //returns -1 in case of error, 1 if authentication was performed, 0 else static int8_t gbox_check_header(struct s_client *cli, struct s_client *proxy, uchar *data, int32_t l) @@ -719,7 +1068,7 @@ cs_log_dump_dbg(D_READER, data, n, "-> decrypted data (%d bytes):", n); //verify my pass received - my_received_pw = gbox_get_pw(&data[2]); + my_received_pw = b2i(4, data + 2); if (my_received_pw == local_gbox.password) { cs_log_dbg(D_READER, "-> data, peer : %04x data: %s", cli->gbox_peer_id, cs_hexdump(0, data, l, tmp, sizeof(tmp))); @@ -728,7 +1077,7 @@ { if (cli->gbox_peer_id == NO_GBOX_ID) { - if (gbox_auth_client(cli, gbox_get_pw(&data[6])) < 0) + if (gbox_auth_client(cli, b2i(4, data + 6)) < 0) { cs_log_dbg(D_READER, "Authentication failed. Please check user in oscam.server and oscam.user"); return -1; @@ -739,7 +1088,7 @@ peer = proxy->gbox; } if (!peer) { return -1; } - peer_received_pw = gbox_get_pw(&data[6]); + peer_received_pw = b2i(4, data + 6); if (peer_received_pw != peer->gbox.password) { cs_log("gbox peer: %04X sends wrong password", peer->gbox.id); @@ -771,119 +1120,16 @@ if (!proxy) { return -1; } if (!IP_EQUAL(cli->ip, proxy->ip)) - { - cs_log("Received IP %s did not match previous IP %s. Try to reconnect.", cs_inet_ntoa(cli->ip), cs_inet_ntoa(proxy->ip)); - gbox_reconnect_client(cli->gbox_peer_id); - return -1; - } - if(!peer) { return -1; } - - return authentication_done; -} - -//returns 1 if checkcode changed / 0 if not -static int32_t gbox_checkcode_recv(struct s_client *cli, uchar *checkcode) -{ - struct gbox_peer *peer = cli->gbox; - char tmp[14]; - - if(memcmp(peer->checkcode, checkcode, 7)) - { - memcpy(peer->checkcode, checkcode, 7); - cs_log_dbg(D_READER, "-> new checkcode=%s", cs_hexdump(0, peer->checkcode, 14, tmp, sizeof(tmp))); - return 1; - } - return 0; -} - -void gbox_send(struct s_client *cli, uchar *buf, int32_t l) -{ - struct gbox_peer *peer = cli->gbox; - - cs_log_dump_dbg(D_READER, buf, l, "<- decrypted data (%d bytes):", l); - - hostname2ip(cli->reader->device, &SIN_GET_ADDR(cli->udp_sa)); - SIN_GET_FAMILY(cli->udp_sa) = AF_INET; - SIN_GET_PORT(cli->udp_sa) = htons((uint16_t)cli->reader->r_port); - - gbox_encrypt(buf, l, peer->gbox.password); - sendto(cli->udp_fd, buf, l, 0, (struct sockaddr *)&cli->udp_sa, cli->udp_sa_len); - cs_log_dump_dbg(D_READER, buf, l, "<- encrypted data (%d bytes):", l); -} - -void gbox_send_hello_packet(struct s_client *cli, int8_t number, uchar *outbuf, uchar *ptr, int32_t nbcards, uint8_t hello_stat) -{ - struct gbox_peer *peer = cli->gbox; - int32_t hostname_len = strlen(cfg.gbox_hostname); - int32_t len; - gbox_message_header(outbuf, MSG_HELLO, peer->gbox.password, local_gbox.password); - // initial HELLO = 0, subsequent = 1 - if(hello_stat > GBOX_STAT_HELLOS) - { outbuf[10] = 1; } - else - { outbuf[10] = 0; } - outbuf[11] = number; // 0x80 (if last packet) else 0x00 | packet number - - if((number & 0x0F) == 0) - { - if(hello_stat != GBOX_STAT_HELLOL) - { memcpy(++ptr, gbox_get_checkcode(), 7); } - else - { memset(++ptr, 0, 7); } - ptr += 7; - *ptr = local_gbox.minor_version; - *(++ptr) = local_gbox.cpu_api; - memcpy(++ptr, cfg.gbox_hostname, hostname_len); - ptr += hostname_len; - *ptr = hostname_len; - } - len = ptr - outbuf + 1; - switch(hello_stat) - { - case GBOX_STAT_HELLOL: - cs_log("<- HelloL to %s", cli->reader->label); - break; - case GBOX_STAT_HELLOS: - cs_log("<- HelloS total cards %d to %s", nbcards, cli->reader->label); - break; - case GBOX_STAT_HELLOR: - cs_log("<- HelloR total cards %d to %s", nbcards, cli->reader->label); - break; - default: - cs_log("<- hello total cards %d to %s", nbcards, cli->reader->label); - break; - } - cs_log_dump_dbg(D_READER, outbuf, len, "<- hello, (len=%d):", len); - - gbox_compress(outbuf, len, &len); - - gbox_send(cli, outbuf, len); -} - -static void gbox_send_checkcode(struct s_client *cli) -{ - struct gbox_peer *peer = cli->gbox; - uchar outbuf[20]; - - gbox_message_header(outbuf, MSG_CHECKCODE, peer->gbox.password, local_gbox.password); - memcpy(outbuf + 10, gbox_get_checkcode(), 7); + { + cs_log("Received IP %s did not match previous IP %s. Try to reconnect.", cs_inet_ntoa(cli->ip), cs_inet_ntoa(proxy->ip)); + gbox_reconnect_client(cli->gbox_peer_id); + return -1; + } + if(!peer) { return -1; } - gbox_send(cli, outbuf, 17); + return authentication_done; } -/* -static void gbox_send_boxinfo(struct s_client *cli) -{ - struct gbox_peer *peer = cli->gbox; - uchar outbuf[256]; - int32_t hostname_len = strlen(cfg.gbox_hostname); - gbox_message_header(outbuf, MSG_BOXINFO, peer); - outbuf[0xA] = local_gbox.minor_version; - outbuf[0xB] = local_gbox.type; - memcpy(&outbuf[0xC], cfg.gbox_hostname, hostname_len); - gbox_send(cli, outbuf, hostname_len + 0xC); -} -*/ static int32_t gbox_recv(struct s_client *cli, uchar *buf, int32_t l) { uchar data[RECEIVE_BUFFER_SIZE]; @@ -991,198 +1237,6 @@ cs_log_dbg(D_READER, "<- CW (distance: %d) to %04X via %s/%d", ere->gbox_hops, ere->gbox_peer, cli->reader->label, cli->port); } -static void gbox_local_cards(struct s_reader *reader, TUNTAB *ttab) -{ - int32_t i; - uint32_t prid = 0; - int8_t slot = 0; -#ifdef MODULE_CCCAM - LL_ITER it, it2; - struct cc_card *card = NULL; - struct cc_data *cc; - uint32_t checksum = 0; - uint16_t cc_peer_id = 0; - struct cc_provider *provider; - uint8_t *node1 = NULL; - uint8_t min_reshare = 0; - gbox_delete_cards(GBOX_DELETE_WITH_TYPE, GBOX_CARD_TYPE_CCCAM); -#endif - gbox_delete_cards(GBOX_DELETE_WITH_ID, local_gbox.id); - struct s_client *cl; - cs_readlock(&clientlist_lock); - for(cl = first_client; cl; cl = cl->next) - { - if(cl->typ == 'r' && cl->reader && cl->reader->card_status == 2) - { - slot = gbox_next_free_slot(local_gbox.id); - //SECA, Viaccess and Cryptoworks have multiple providers - if(caid_is_seca(cl->reader->caid) || caid_is_viaccess(cl->reader->caid) || caid_is_cryptoworks(cl->reader->caid)) - { - for(i = 0; i < cl->reader->nprov; i++) - { - prid = cl->reader->prid[i][1] << 16 | - cl->reader->prid[i][2] << 8 | cl->reader->prid[i][3]; - gbox_add_card(local_gbox.id, gbox_get_caprovid(cl->reader->caid, prid), slot, reader->gbox_reshare, 0, GBOX_CARD_TYPE_LOCAL, NULL); - } - } - else - { - gbox_add_card(local_gbox.id, gbox_get_caprovid(cl->reader->caid, 0), slot, reader->gbox_reshare, 0, GBOX_CARD_TYPE_LOCAL, NULL); - - //Check for Betatunnel on gbox account in oscam.user - if (chk_is_betatunnel_caid(cl->reader->caid) == 1 && ttab->ttdata && cl->reader->caid == ttab->ttdata[0].bt_caidto) - { - //For now only first entry in tunnel tab. No sense in iteration? - //Add betatunnel card to transmitted list - gbox_add_card(local_gbox.id, gbox_get_caprovid(ttab->ttdata[0].bt_caidfrom, 0), slot, reader->gbox_reshare, 0, GBOX_CARD_TYPE_BETUN, NULL); - cs_log_dbg(D_READER, "gbox created betatunnel card for caid: %04X->%04X", ttab->ttdata[0].bt_caidfrom, cl->reader->caid); - } - } - } //end local readers -#ifdef MODULE_CCCAM - if((cfg.cc_reshare > -1) && (reader->gbox_cccam_reshare) && cl->typ == 'p' && cl->reader && cl->reader->typ == R_CCCAM && cl->cc) - { - cc = cl->cc; - it = ll_iter_create(cc->cards); - while((card = ll_iter_next(&it))) - { - //calculate gbox id from cc node - node1 = ll_has_elements(card->remote_nodes); - checksum = ((node1[0] ^ node1[7]) << 8) | - ((node1[1] ^ node1[6]) << 24) | - (node1[2] ^ node1[5]) | - ((node1[3] ^ node1[4]) << 16); - cc_peer_id = ((((checksum >> 24) & 0xFF) ^((checksum >> 8) & 0xFF)) << 8 | - (((checksum >> 16) & 0xFF) ^(checksum & 0xFF))); - slot = gbox_next_free_slot(cc_peer_id); - min_reshare = cfg.cc_reshare; - if (card->reshare < min_reshare) - { min_reshare = card->reshare; } - min_reshare++; //strange CCCam logic. 0 means direct peers - if (reader->gbox_cccam_reshare < min_reshare) - { min_reshare = reader->gbox_cccam_reshare; } - if(caid_is_seca(card->caid) || caid_is_viaccess(card->caid) || caid_is_cryptoworks(card->caid)) - { - it2 = ll_iter_create(card->providers); - while((provider = ll_iter_next(&it2))) - { gbox_add_card(cc_peer_id, gbox_get_caprovid(card->caid, provider->prov), slot, min_reshare, card->hop, GBOX_CARD_TYPE_CCCAM, NULL); } - } - else - { gbox_add_card(cc_peer_id, gbox_get_caprovid(card->caid, 0), slot, min_reshare, card->hop, GBOX_CARD_TYPE_CCCAM, NULL); } - } - } //end cccam -#endif - } //end for clients - cs_readunlock(&clientlist_lock); - - if (cfg.gbox_proxy_cards_num > 0) - { - for (i = 0; i < cfg.gbox_proxy_cards_num; i++) - { - slot = gbox_next_free_slot(local_gbox.id); - gbox_add_card(local_gbox.id, cfg.gbox_proxy_card[i], slot, reader->gbox_reshare, 0, GBOX_CARD_TYPE_PROXY, NULL); - if ((cfg.gbox_proxy_card[i] >> 24) == 0x05) - { - cs_log_dbg(D_READER,"add proxy card: slot %d %04lX:%06lX",slot, (cfg.gbox_proxy_card[i] >> 16) & 0xFFF0, cfg.gbox_proxy_card[i] & 0xFFFFF); - } else - { - cs_log_dbg(D_READER,"add proxy card: slot %d %04lX:%06lX",slot, cfg.gbox_proxy_card[i] >> 16, cfg.gbox_proxy_card[i] & 0xFFFF); - } - } - } // end add proxy reader cards -} //end add local gbox cards - -static uint32_t gbox_get_pending_time(ECM_REQUEST *er, uint16_t peer_id, uint8_t slot) -{ - if (!er) { return 0; } - - uint32_t ret_time = 0; - struct gbox_card_pending *pending = NULL; - LL_LOCKITER *li = ll_li_create(er->gbox_cards_pending, 0); - while ((pending = ll_li_next(li))) - { - if ((pending->id.peer == peer_id) && (pending->id.slot == slot)) - { - ret_time = pending->pending_time; - break; - } - } - ll_li_destroy(li); - return ret_time; -} - -static int32_t gbox_recv_chk(struct s_client *cli, uchar *dcw, int32_t *rc, uchar *data, int32_t n) -{ - if(!cli || gbox_decode_cmd(data) != MSG_CW || n < 44) - { return -1; } - - int i; - uint16_t id_card = 0; - struct s_client *proxy; - if(cli->typ != 'p') - { proxy = get_gbox_proxy(cli->gbox_peer_id); } - else - { proxy = cli; } - if (!proxy || !proxy->reader) - { - cs_log("error, gbox_recv_chk, proxy not found"); - return -1; - } - proxy->last = time((time_t *)0); - *rc = 1; - memcpy(dcw, data + 14, 16); - uint32_t crc = data[30] << 24 | data[31] << 16 | data[32] << 8 | data[33]; - char tmp[32]; - cs_log_dbg(D_READER, "-> cws=%s, peer=%04X, ecm_pid=%04X, sid=%04X, crc=%08X, type=%02X, dist=%01X, unkn1=%01X, unkn2=%02X, chid/0x0000/0xffff=%04X", - cs_hexdump(0, dcw, 32, tmp, sizeof(tmp)), - data[10] << 8 | data[11], data[6] << 8 | data[7], data[8] << 8 | data[9], crc, data[41], data[42] & 0x0f, data[42] >> 4, data[43], data[37] << 8 | data[38]); - struct timeb t_now; - cs_ftime(&t_now); - int64_t cw_time = GBOX_DEFAULT_CW_TIME; - for(i = 0; i < cfg.max_pending; i++) - { - if(proxy->ecmtask[i].gbox_crc == crc) - { - id_card = data[10] << 8 | data[11]; - cw_time = comp_timeb(&t_now, &proxy->ecmtask[i].tps) - gbox_get_pending_time(&proxy->ecmtask[i], id_card, data[36]); - gbox_add_good_sid(id_card, proxy->ecmtask[i].caid, data[36], proxy->ecmtask[i].srvid, cw_time); - proxy->reader->currenthops = data[42] & 0x0f; - gbox_remove_all_bad_sids(&proxy->ecmtask[i], proxy->ecmtask[i].srvid); - if(proxy->ecmtask[i].gbox_ecm_status == GBOX_ECM_NOT_ASKED || proxy->ecmtask[i].gbox_ecm_status == GBOX_ECM_ANSWERED) - { return -1; } - proxy->ecmtask[i].gbox_ecm_status = GBOX_ECM_ANSWERED; - proxy->ecmtask[i].gbox_ecm_id = id_card; - *rc = 1; - return proxy->ecmtask[i].idx; - } - } - //late answers from other peers,timing not possible - gbox_add_good_sid(id_card, data[34] << 8 | data[35], data[36], data[8] << 8 | data[9], GBOX_DEFAULT_CW_TIME); - cs_log_dbg(D_READER, "no task found for crc=%08x", crc); - return -1; -} - -static int8_t gbox_cw_received(struct s_client *cli, uchar *data, int32_t n) -{ - int32_t rc = 0, i = 0, idx = 0; - uchar dcw[16]; - - idx = gbox_recv_chk(cli, dcw, &rc, data, n); - if(idx < 0) { return -1; } // no dcw received - if(!idx) { idx = cli->last_idx; } - cli->reader->last_g = time((time_t *)0); // for reconnect timeout - for(i = 0; i < cfg.max_pending; i++) - { - if(cli->ecmtask[i].idx == idx) - { - cli->pending--; - casc_check_dcw(cli->reader, i, rc, dcw); - return 0; - } - } - return -1; -} - void *gbox_rebroadcast_thread(struct gbox_rbc_thread_args *args) { if (!args) { return NULL; } @@ -1191,12 +1245,20 @@ ECM_REQUEST *er = args->er; uint32_t waittime = args->waittime; - if (!cli) { return NULL; } + //NEEDFIX currently the next line avoids a second rebroadcast + if (!is_valid_client(cli)) { return NULL; } + + pthread_mutex_lock(&cli->thread_lock); + cli->thread_active = 1; pthread_setspecific(getclient, cli); set_thread_name(__func__); - + cli->thread_active = 0; + pthread_mutex_unlock(&cli->thread_lock); + cs_sleepms(waittime); - if (!cli || !cli->gbox || !er) { return NULL; } + if (!cli || cli->kill || !cli->gbox || !er) { return NULL; } + pthread_mutex_lock(&cli->thread_lock); + cli->thread_active = 1; struct gbox_peer *peer = cli->gbox; @@ -1214,6 +1276,8 @@ gbox_send_ecm(cli, er, NULL); cs_writeunlock(&peer->lock); } + cli->thread_active = 0; + pthread_mutex_unlock(&cli->thread_lock); return NULL; } @@ -1364,22 +1428,31 @@ { //Create thread to rebroacast ecm after time pthread_t rbc_thread; + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, PTHREAD_STACK_SIZE); struct gbox_rbc_thread_args args; args.cli = cli; args.er = er; if ((current_avg_card_time > 0) && (cont_card_1 == 1)) - { args.waittime = current_avg_card_time + (current_avg_card_time / 2); } + { + args.waittime = current_avg_card_time + (current_avg_card_time / 2); + if (args.waittime < GBOX_MIN_REBROADCAST_TIME) + { args.waittime = GBOX_MIN_REBROADCAST_TIME; } + } else { args.waittime = GBOX_REBROADCAST_TIMEOUT; } cs_log_dbg(D_READER, "Creating rebroadcast thread with waittime: %d", args.waittime); - int32_t ret = pthread_create(&rbc_thread, NULL, (void *)gbox_rebroadcast_thread, &args); + int32_t ret = pthread_create(&rbc_thread, &attr, (void *)gbox_rebroadcast_thread, &args); if(ret) { cs_log("Can't create gbox rebroadcast thread (errno=%d %s)", ret, strerror(ret)); + pthread_attr_destroy(&attr); return -1; } else { pthread_detach(rbc_thread); } + pthread_attr_destroy(&attr); } else { er->gbox_ecm_status--; } @@ -1453,11 +1526,8 @@ if(!cs_malloc(&cli->gbox, sizeof(struct gbox_peer))) { return -1; } - struct gbox_peer *peer = cli->gbox; struct s_reader *rdr = cli->reader; - - rdr->card_status = CARD_NEED_INIT; - rdr->tcp_connected = 0; + struct gbox_peer *peer = cli->gbox; memset(peer, 0, sizeof(struct gbox_peer)); @@ -1470,11 +1540,18 @@ cs_log("error, double/invalid gbox id: %04X", peer->gbox.id); return -1; } + cs_lock_create(&peer->lock, "gbox_lock", 5000); + + gbox_reinit_peer(peer); + cli->gbox_peer_id = peer->gbox.id; cli->pfd = 0; cli->crypted = 1; + rdr->card_status = CARD_NEED_INIT; + rdr->tcp_connected = 0; + set_null_ip(&cli->ip); if((cli->udp_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) @@ -1505,11 +1582,6 @@ cli->pfd = cli->udp_fd; - cs_lock_create(&peer->lock, "gbox_lock", 5000); - - gbox_reinit_peer(peer); - - cli->reader->card_status = CARD_NEED_INIT; gbox_send_hello(cli, GBOX_STAT_HELLOL); if(!cli->reader->gbox_maxecmsend) @@ -1536,9 +1608,9 @@ if (proxy && proxy->gbox) { - if (abs(proxy->last - time(NULL)) > abs(cl->lastecm - time(NULL))) - { time_since_last = abs(cl->lastecm - time(NULL)); } - else { time_since_last = abs(proxy->last - time(NULL)); } + if (llabs(proxy->last - time(NULL)) > llabs(cl->lastecm - time(NULL))) + { time_since_last = llabs(cl->lastecm - time(NULL)); } + else { time_since_last = llabs(proxy->last - time(NULL)); } if (time_since_last > (HELLO_KEEPALIVE_TIME*3) && cl->gbox_peer_id != NO_GBOX_ID) { //gbox peer apparently died without saying goodbye @@ -1549,7 +1621,7 @@ cs_writeunlock(&peer->lock); } - time_since_last = abs(cl->lastecm - time(NULL)); + time_since_last = llabs(cl->lastecm - time(NULL)); if (time_since_last > HELLO_KEEPALIVE_TIME && cl->gbox_peer_id != NO_GBOX_ID) { peer = proxy->gbox; @@ -1594,16 +1666,21 @@ gbox_reinit_proxy(proxy); } } - return 0; + return 0; } -void gbox_cleanup(struct s_client *cl) +void gbox_send_good_night(void) { gbox_free_cardlist(); - if(cl && cl->gbox && cl->typ == 'p') - { gbox_send_peer_good_night(cl); } -} - + struct s_client *cli; + cs_readlock(&clientlist_lock); + for(cli = first_client; cli; cli = cli->next) + { + if(cli->gbox && cli->typ == 'p') + { gbox_send_peer_good_night(cli); } + } + cs_readunlock(&clientlist_lock); +} /* void gbox_send_goodbye(uint16_t boxid) //to implement later { @@ -1625,8 +1702,7 @@ } cs_readunlock(&clientlist_lock); } -*/ -/* + void gbox_send_HERE_query (uint16_t boxid) //gbox.net send this cmd { uchar outbuf[30]; @@ -1651,6 +1727,19 @@ } cs_readunlock(&clientlist_lock); } +//This is most likely the same as MSG_HERE. Don't know what would be the difference +static void gbox_send_boxinfo(struct s_client *cli) +{ + struct gbox_peer *peer = cli->gbox; + uchar outbuf[256]; + int32_t hostname_len = strlen(cfg.gbox_hostname); + + gbox_message_header(outbuf, MSG_BOXINFO, peer); + outbuf[0xA] = local_gbox.minor_version; + outbuf[0xB] = local_gbox.type; + memcpy(&outbuf[0xC], cfg.gbox_hostname, hostname_len); + gbox_send(cli, outbuf, hostname_len + 0xC); +} */ void module_gbox(struct s_module *ph) { @@ -1673,7 +1762,6 @@ ph->send_dcw = gbox_send_dcw; ph->recv = gbox_recv; - ph->cleanup = gbox_cleanup; ph->c_init = gbox_client_init; ph->c_recv_chk = gbox_recv_chk; ph->c_send_ecm = gbox_send_ecm; diff -Nru oscam-1.20-10855~r10626/module-gbox-cards.c oscam-1.20-10882~r10652/module-gbox-cards.c --- oscam-1.20-10855~r10626/module-gbox-cards.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/module-gbox-cards.c 2015-04-25 10:46:41.000000000 +0000 @@ -4,6 +4,7 @@ #ifdef MODULE_GBOX #include "module-gbox.h" +#include "module-gbox-cards.h" #include "module-gbox-helper.h" #include "oscam-lock.h" #include "oscam-garbage.h" @@ -17,22 +18,34 @@ CS_MUTEX_LOCK gbox_cards_lock; uchar checkcode[7]; -void gbox_write_cards_info(void) +GBOX_CARDS_ITER *gbox_cards_iter_create(void) +{ + GBOX_CARDS_ITER *gci; + if(!cs_malloc(&gci, sizeof(GBOX_CARDS_ITER))) + { return NULL; } + cs_readlock(&gbox_cards_lock); + gci->it = ll_iter_create(gbox_cards); + return gci; +} + +void gbox_cards_iter_destroy(GBOX_CARDS_ITER *gci) +{ + cs_readunlock(&gbox_cards_lock); + if (gci) { add_garbage(gci); } +} + +struct gbox_card *gbox_cards_iter_next(GBOX_CARDS_ITER *gci) +{ + if (gci) { return ll_iter_next(&gci->it); } + else { return NULL; } +} + +void gbox_write_share_cards_info(void) { - uint16_t card_count_local = 0; uint16_t card_count_shared = 0; uint16_t card_count_expired = 0; - char *fext = FILE_LOCAL_CARDS_INFO; - char *fname = get_gbox_tmp_fname(fext); - FILE *fhandle_local; - fhandle_local = fopen(fname, "w"); - if(!fhandle_local) - { - cs_log("Couldn't open %s: %s", fname, strerror(errno)); - return; - } - fext = FILE_SHARED_CARDS_INFO; - fname = get_gbox_tmp_fname(fext); + char *fext = FILE_SHARED_CARDS_INFO; + char *fname = get_gbox_tmp_fname(fext); FILE *fhandle_shared; fhandle_shared = fopen(fname, "w"); if(!fhandle_shared) @@ -42,46 +55,19 @@ } struct gbox_card *card; - cs_readlock(&gbox_cards_lock); LL_ITER it = ll_iter_create(gbox_cards); while((card = ll_iter_next(&it))) { - switch (card->type) + if (card->type == GBOX_CARD_TYPE_GBOX) { - case GBOX_CARD_TYPE_GBOX: fprintf(fhandle_shared, "CardID %2d at %s Card %08X Sl:%2d Lev:%1d dist:%1d id:%04X\n", card_count_shared, card->origin_peer->hostname, card->caprovid, card->id.slot, card->lvl, card->dist, card->id.peer); card_count_shared++; - break; - case GBOX_CARD_TYPE_LOCAL: - fprintf(fhandle_local, "CardID:%2d %s %08X Sl:%2d id:%04X\n", - card_count_local, "Local_Card", card->caprovid, card->id.slot, card->id.peer); - card_count_local++; - break; - case GBOX_CARD_TYPE_BETUN: - fprintf(fhandle_local, "CardID:%2d %s %08X Sl:%2d id:%04X\n", - card_count_local, "Betun_Card", card->caprovid, card->id.slot, card->id.peer); - card_count_local++; - break; - case GBOX_CARD_TYPE_CCCAM: - fprintf(fhandle_local, "CardID:%2d %s %08X Sl:%2d id:%04X\n", - card_count_local, "CCcam_Card", card->caprovid, card->id.slot, card->id.peer); - card_count_local++; - break; - case GBOX_CARD_TYPE_PROXY: - fprintf(fhandle_local, "CardID:%2d %s %08X Sl:%2d id:%04X\n", - card_count_local, "Proxy_Card", card->caprovid, card->id.slot, card->id.peer); - card_count_local++; - break; - default: - cs_log("Invalid card type: %d in gbox_write_cards_info", card->type); - break; } } cs_readunlock(&gbox_cards_lock); - fclose(fhandle_local); fclose(fhandle_shared); fext = FILE_BACKUP_CARDS_INFO; @@ -110,21 +96,73 @@ return; } +void gbox_write_local_cards_info(void) +{ + uint16_t card_count_local = 0; + char *fext = FILE_LOCAL_CARDS_INFO; + char *fname = get_gbox_tmp_fname(fext); + FILE *fhandle_local; + fhandle_local = fopen(fname, "w"); + if(!fhandle_local) + { + cs_log("Couldn't open %s: %s", fname, strerror(errno)); + return; + } + + struct gbox_card *card; + cs_readlock(&gbox_cards_lock); + LL_ITER it = ll_iter_create(gbox_cards); + while((card = ll_iter_next(&it))) + { + switch (card->type) + { + case GBOX_CARD_TYPE_GBOX: + break; + case GBOX_CARD_TYPE_LOCAL: + fprintf(fhandle_local, "CardID:%2d %s %08X Sl:%2d id:%04X\n", + card_count_local, "Local_Card", card->caprovid, card->id.slot, card->id.peer); + card_count_local++; + break; + case GBOX_CARD_TYPE_BETUN: + fprintf(fhandle_local, "CardID:%2d %s %08X Sl:%2d id:%04X\n", + card_count_local, "Betun_Card", card->caprovid, card->id.slot, card->id.peer); + card_count_local++; + break; + case GBOX_CARD_TYPE_CCCAM: + fprintf(fhandle_local, "CardID:%2d %s %08X Sl:%2d id:%04X\n", + card_count_local, "CCcam_Card", card->caprovid, card->id.slot, card->id.peer); + card_count_local++; + break; + case GBOX_CARD_TYPE_PROXY: + fprintf(fhandle_local, "CardID:%2d %s %08X Sl:%2d id:%04X\n", + card_count_local, "Proxy_Card", card->caprovid, card->id.slot, card->id.peer); + card_count_local++; + break; + default: + cs_log("Invalid card type: %d in gbox_write_cards_info", card->type); + break; + } + } + cs_readunlock(&gbox_cards_lock); + fclose(fhandle_local); +} + void gbox_write_stats(void) { int32_t card_count = 0; struct gbox_good_srvid *srvid_good = NULL; struct gbox_bad_srvid *srvid_bad = NULL; + char *fext = FILE_STATS; + char *fname = get_gbox_tmp_fname(fext); FILE *fhandle; - fhandle = fopen(get_gbox_tmp_fname(FILE_STATS), "w"); + fhandle = fopen(fname, "w"); if(!fhandle) { - cs_log("Couldn't open %s: %s", get_gbox_tmp_fname(FILE_STATS), strerror(errno)); + cs_log("Couldn't open %s: %s", fname, strerror(errno)); return; } struct gbox_card *card; - cs_readlock(&gbox_cards_lock); LL_ITER it = ll_iter_create(gbox_cards); while((card = ll_iter_next(&it))) @@ -185,29 +223,30 @@ return; } -static int8_t closer_path_known(uint32_t caprovid, uint16_t id_peer, uint8_t slot, uint8_t distance) +static uint8_t closer_path_known(uint32_t caprovid, uint16_t id_peer, uint8_t slot, uint8_t distance) { + uint8_t ret = 0; + struct gbox_card *card; cs_readlock(&gbox_cards_lock); LL_ITER it = ll_iter_create(gbox_cards); - struct gbox_card *card; while((card = ll_iter_next(&it))) { if (card->caprovid == caprovid && card->id.peer == id_peer && card->id.slot == slot && card->dist <= distance) { - cs_readunlock(&gbox_cards_lock); - return 1; + ret = 1; + break; } } cs_readunlock(&gbox_cards_lock); - return 0; + return ret; } -static int8_t got_from_backup(uint32_t caprovid, uint16_t id_peer, uint8_t slot, struct gbox_peer *origin_peer) +static uint8_t got_from_backup(uint32_t caprovid, uint16_t id_peer, uint8_t slot, struct gbox_peer *origin_peer) { uint8_t ret = 0; + struct gbox_card *card; cs_writelock(&gbox_cards_lock); LL_ITER it = ll_iter_create(gbox_backup_cards); - struct gbox_card *card; while((card = ll_iter_next(&it))) { if (card->caprovid == caprovid && card->id.peer == id_peer && card->id.slot == slot) @@ -221,8 +260,7 @@ break; } } - cs_writeunlock(&gbox_cards_lock); - + cs_writeunlock(&gbox_cards_lock); return ret; } @@ -272,6 +310,11 @@ return &checkcode[0]; } +uint16_t gbox_count_cards(void) +{ + return ll_count(gbox_cards); +} + uint16_t gbox_count_peer_cards(uint16_t peer_id) { uint16_t counter = 0; @@ -352,70 +395,6 @@ return; } -void gbox_send_hello(struct s_client *proxy, uint8_t hello_stat) -{ - if (!proxy) - { - cs_log("Invalid call to gbox_send_hello with proxy"); - return; - } - - uint16_t nbcards = 0; - uint8_t packet; - uchar buf[2048]; - - packet = 0; - uchar *ptr = buf + 11; - if(ll_count(gbox_cards) != 0 && hello_stat > GBOX_STAT_HELLOL) - { - struct gbox_peer *peer = proxy->gbox; - if (!peer || !peer->my_user || !peer->my_user->account) - { - cs_log("Invalid call to gbox_send_hello with peer"); - return; - } - memset(buf, 0, sizeof(buf)); - - cs_readlock(&gbox_cards_lock); - LL_ITER it = ll_iter_create(gbox_cards); - struct gbox_card *card; - while((card = ll_iter_next(&it))) - { - //send to user only cards which matching CAID from account and lvl > 0 - //do not send peer cards back - if(chk_ctab(gbox_get_caid(card->caprovid), &peer->my_user->account->ctab) && (card->lvl > 0) && (!card->origin_peer || card->origin_peer->gbox.id != peer->gbox.id)) - { - *(++ptr) = card->caprovid >> 24; - *(++ptr) = card->caprovid >> 16; - *(++ptr) = card->caprovid >> 8; - *(++ptr) = card->caprovid & 0xff; - *(++ptr) = 1; //note: original gbx is more efficient and sends all cards of one caid as package - *(++ptr) = card->id.slot; - //If you modify the next line you are going to destroy the community - //It will be recognized by original gbx and you will get banned - *(++ptr) = ((card->lvl - 1) << 4) + card->dist + 1; - *(++ptr) = card->id.peer >> 8; - *(++ptr) = card->id.peer & 0xff; - nbcards++; - if(nbcards == 100) //check if 100 is good or we need more sophisticated algorithm - { - //NEEDFIX: Try to get rid of send hello in cards function - gbox_send_hello_packet(proxy, packet, buf, ptr, nbcards, hello_stat); - packet++; - nbcards = 0; - ptr = buf + 11; - memset(buf, 0, sizeof(buf)); - } - } - } - cs_readunlock(&gbox_cards_lock); - } // end if local card exists - //last packet has bit 0x80 set - gbox_send_hello_packet(proxy, 0x80 | packet, buf, ptr, nbcards, hello_stat); - - return; -} - void gbox_add_good_sid(uint16_t id_card, uint16_t caid, uint8_t slot, uint16_t sid_ok, uint32_t cw_time) { struct gbox_card *card = NULL; @@ -560,7 +539,7 @@ { if (!enough || *current_avg_card_time > card->average_cw_time) { - time_since_lastcw = abs(srvid_good->last_cw_received - time(NULL)); + time_since_lastcw = llabs(srvid_good->last_cw_received - time(NULL)); *current_avg_card_time = card->average_cw_time; if (enough) { cont_1 = cont_1 - 3; } diff -Nru oscam-1.20-10855~r10626/module-gbox-cards.h oscam-1.20-10882~r10652/module-gbox-cards.h --- oscam-1.20-10855~r10626/module-gbox-cards.h 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/module-gbox-cards.h 2015-04-25 10:46:41.000000000 +0000 @@ -2,15 +2,25 @@ #define MODULE_GBOX_CARDS_H_ #ifdef MODULE_GBOX -void gbox_write_cards_info(void); +typedef struct gboxcardsiter GBOX_CARDS_ITER; +struct gboxcardsiter +{ + LL_ITER it; +}; + +GBOX_CARDS_ITER *gbox_cards_iter_create(void); +void gbox_cards_iter_destroy(GBOX_CARDS_ITER *gci); +struct gbox_card *gbox_cards_iter_next(GBOX_CARDS_ITER *gci); +void gbox_write_share_cards_info(void); +void gbox_write_local_cards_info(void); void gbox_write_stats(void); void init_gbox_cards(void); void gbox_add_card(uint16_t id_peer, uint32_t caprovid, uint8_t slot, uint8_t level, uint8_t distance, uint8_t type, struct gbox_peer *origin_peer); uchar *gbox_get_checkcode(void); uint16_t gbox_count_peer_cards(uint16_t peer_id); +uint16_t gbox_count_cards(void); void gbox_delete_cards(uint8_t delete_type, uint16_t criteria); void gbox_free_cardlist(void); -void gbox_send_hello(struct s_client *proxy, uint8_t hello_stat); void gbox_add_good_sid(uint16_t id_card, uint16_t caid, uint8_t slot, uint16_t sid_ok, uint32_t cw_time); void gbox_remove_bad_sid(uint16_t id_peer, uint8_t id_slot, uint16_t sid); uint8_t gbox_next_free_slot(uint16_t id); diff -Nru oscam-1.20-10855~r10626/module-gbox.h oscam-1.20-10882~r10652/module-gbox.h --- oscam-1.20-10855~r10626/module-gbox.h 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/module-gbox.h 2015-04-25 10:46:41.000000000 +0000 @@ -19,6 +19,7 @@ #define DEFAULT_GBOX_RECONNECT 300 #define CS_GBOX_MAX_LOCAL_CARDS 16 #define GBOX_REBROADCAST_TIMEOUT 1250 +#define GBOX_MIN_REBROADCAST_TIME 100 #define GBOX_SID_CONFIRM_TIME 3600 #define GBOX_DEFAULT_CW_TIME 500 @@ -66,6 +67,9 @@ #define GBOX_DELETE_WITH_ID 1 #define GBOX_DELETE_WITH_TYPE 2 +#define GBOX_PEER_OFFLINE 0 +#define GBOX_PEER_ONLINE 1 + struct gbox_rbc_thread_args { struct s_client *cli; @@ -116,7 +120,7 @@ uint32_t average_cw_time; struct gbox_peer *origin_peer; }; - + struct gbox_data { uint16_t id; @@ -160,9 +164,10 @@ void gbox_send(struct s_client *cli, uchar *buf, int32_t l); int8_t gbox_message_header(uchar *buf, uint16_t cmd, uint32_t peer_password, uint32_t local_password); void gbox_free_cards_pending(ECM_REQUEST *er); -void gbox_send_hello_packet(struct s_client *proxy, int8_t number, uchar *outbuf, uchar *ptr, int32_t nbcards, uint8_t hello_stat); +void gbox_send_good_night(void); #else static inline void gbox_free_cards_pending(ECM_REQUEST *UNUSED(er)) { } +static inline void gbox_send_good_night(void) { } #endif #endif diff -Nru oscam-1.20-10855~r10626/module-gbox-helper.c oscam-1.20-10882~r10652/module-gbox-helper.c --- oscam-1.20-10855~r10626/module-gbox-helper.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/module-gbox-helper.c 2015-04-25 10:46:41.000000000 +0000 @@ -54,6 +54,7 @@ // N@gr@ case 0x18: caprovid = (caid >> 8) << 24 | (caid & 0xFF) << 16; + break; default: caprovid = (caid >> 8) << 24 | (caid & 0xFF) << 16 | (prid & 0xFFFF); diff -Nru oscam-1.20-10855~r10626/module-newcamd.c oscam-1.20-10882~r10652/module-newcamd.c --- oscam-1.20-10855~r10626/module-newcamd.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/module-newcamd.c 2015-04-25 10:46:41.000000000 +0000 @@ -1114,8 +1114,7 @@ memset(&epg, 0, sizeof(epg)); epg.emmlen = buf[2] + 3; - if (cl->ftab.filts) - caid = cl->ftab.filts[0].caid; + caid = cfg.ncd_ptab.ports[cl->port_idx].ncd->ncd_ftab.filts[0].caid; epg.caid[0] = (uchar)(caid >> 8); epg.caid[1] = (uchar)(caid); @@ -1345,7 +1344,7 @@ time_t now; int32_t time_diff; time(&now); - time_diff = abs(now - rdr->last_s); + time_diff = llabs(now - rdr->last_s); if(time_diff > (rdr->tcp_ito)) { if(client->ncd_keepalive) diff -Nru oscam-1.20-10855~r10626/module-radegast.c oscam-1.20-10882~r10652/module-radegast.c --- oscam-1.20-10855~r10626/module-radegast.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/module-radegast.c 2015-04-25 10:46:41.000000000 +0000 @@ -333,7 +333,7 @@ if(rdr->tcp_ito > 0) { int32_t time_diff; - time_diff = abs(now - rdr->last_s); + time_diff = llabs(now - rdr->last_s); if(time_diff > (rdr->tcp_ito)) { network_tcp_connection_close(rdr, "inactivity"); diff -Nru oscam-1.20-10855~r10626/module-scam.c oscam-1.20-10882~r10652/module-scam.c --- oscam-1.20-10855~r10626/module-scam.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/module-scam.c 2015-04-25 10:46:41.000000000 +0000 @@ -395,7 +395,7 @@ if(rdr->tcp_ito > 0) { int32_t time_diff; - time_diff = abs(now - rdr->last_s); + time_diff = llabs(now - rdr->last_s); if(time_diff > (rdr->tcp_ito)) { network_tcp_connection_close(rdr, "inactivity"); diff -Nru oscam-1.20-10855~r10626/module-stat.c oscam-1.20-10882~r10652/module-stat.c --- oscam-1.20-10855~r10626/module-stat.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/module-stat.c 2015-04-25 10:46:41.000000000 +0000 @@ -1442,10 +1442,10 @@ } - cs_log_dbg(D_LB, "loadbalancer: reader %s lbvalue = %d (time-avg %d)", rdr->label, abs(current), s->time_avg); + cs_log_dbg(D_LB, "loadbalancer: reader %s lbvalue = %d (time-avg %d)", rdr->label, (int) llabs(current), s->time_avg); #if defined(WEBIF) || defined(LCDSUPPORT) - rdr->lbvalue = abs(current); + rdr->lbvalue = llabs(current); #endif ea->value = current; diff -Nru oscam-1.20-10855~r10626/module-webif-lib.c oscam-1.20-10882~r10652/module-webif-lib.c --- oscam-1.20-10855~r10626/module-webif-lib.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/module-webif-lib.c 2015-04-25 10:46:41.000000000 +0000 @@ -759,12 +759,12 @@ cur_usage->check_available &= ~(1 << 10); cur_usage->check_available &= ~(1 << 11); - cur_usage->cpu_usage_user = 100.0 * abs(cur_ticks - last_ticks) / total_time_diff; + cur_usage->cpu_usage_user = 100.0 * llabs(cur_ticks - last_ticks) / total_time_diff; cur_ticks = cur_usage->stime_ticks + cur_usage->cstime_ticks; last_ticks = last_usage->stime_ticks + last_usage->cstime_ticks; - cur_usage->cpu_usage_sys = 100.0 * abs(cur_ticks - last_ticks) / total_time_diff; + cur_usage->cpu_usage_sys = 100.0 * llabs(cur_ticks - last_ticks) / total_time_diff; } } #endif diff -Nru oscam-1.20-10855~r10626/oscam.c oscam-1.20-10882~r10652/oscam.c --- oscam-1.20-10855~r10626/oscam.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/oscam.c 2015-04-25 10:46:41.000000000 +0000 @@ -1688,6 +1688,7 @@ save_emmstat_to_file(); cccam_done_share(); + gbox_send_good_night(); kill_all_clients(); kill_all_readers(); diff -Nru oscam-1.20-10855~r10626/oscam-client.c oscam-1.20-10882~r10652/oscam-client.c --- oscam-1.20-10855~r10626/oscam-client.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/oscam-client.c 2015-04-25 10:46:41.000000000 +0000 @@ -615,7 +615,7 @@ if((rdr->tcp_ito && is_cascading_reader(rdr)) || (rdr->typ == R_CCCAM) || (rdr->typ == R_CAMD35) || (rdr->typ == R_CS378X) || (rdr->typ == R_SCAM) || (rdr->tcp_ito != 0 && rdr->typ == R_RADEGAST)) { time_t now = time(NULL); - int32_t time_diff = abs(now - rdr->last_check); + int32_t time_diff = llabs(now - rdr->last_check); if(time_diff > 60 || (time_diff > 30 && (rdr->typ == R_CCCAM || rdr->typ == R_CAMD35 || rdr->typ == R_CS378X)) || ((time_diff > (rdr->tcp_rto?rdr->tcp_rto:60)) && rdr->typ == R_RADEGAST)) //check 1x per minute or every 30s for cccam/camd35 or reconnecttimeout radegast if 0 defaut 60s { add_job(rdr->client, ACTION_READER_IDLE, NULL, 0); diff -Nru oscam-1.20-10855~r10626/oscam-conf-chk.c oscam-1.20-10882~r10652/oscam-conf-chk.c --- oscam-1.20-10855~r10626/oscam-conf-chk.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/oscam-conf-chk.c 2015-04-25 10:46:41.000000000 +0000 @@ -421,8 +421,8 @@ if((ptr2 = strchr(trim(ptr3), ':'))) { *ptr2++ = '\0'; - newptab->ports[iport].ncd->ncd_ftab.nfilts++; - ifilt = newptab->ports[iport].ncd->ncd_ftab.nfilts - 1; + ifilt = newptab->ports[iport].ncd->ncd_ftab.nfilts++; + j = 0; newptab->ports[iport].ncd->ncd_ftab.filts[ifilt].caid = (uint16_t)a2i(ptr3, 4); newptab->ports[iport].ncd->ncd_ftab.filts[ifilt].prids[j] = a2i(ptr2, 6); } diff -Nru oscam-1.20-10855~r10626/oscam-ecm.c oscam-1.20-10882~r10652/oscam-ecm.c --- oscam-1.20-10855~r10626/oscam-ecm.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/oscam-ecm.c 2015-04-25 10:46:41.000000000 +0000 @@ -1898,6 +1898,7 @@ void get_cw(struct s_client *client, ECM_REQUEST *er) { + cs_log_dump_dbg(D_ATR, er->ecm, er->ecmlen, "get cw for ecm:"); 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); increment_n_request(client); diff -Nru oscam-1.20-10855~r10626/oscam-emm.c oscam-1.20-10882~r10652/oscam-emm.c --- oscam-1.20-10855~r10626/oscam-emm.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/oscam-emm.c 2015-04-25 10:46:41.000000000 +0000 @@ -226,7 +226,7 @@ return 1; } - if(!reader->auprovid && ((reader->typ == R_CAMD35 || reader->typ == R_CS378X) && (prid & 0xFFFF) == (provid & 0xFFFF))) + if((reader->typ == R_CAMD35 || reader->typ == R_CS378X) && (prid & 0xFFFF) == (provid & 0xFFFF)) { rdr_log_dbg(reader, D_EMM, "CS378: Match after fixing reader provid %06X to ??%04X and emm provid %06X to ??%04X -> SEND!", prid, prid&0xFFFF, provid, provid&0xFFFF); return 1; diff -Nru oscam-1.20-10855~r10626/oscam-reader.c oscam-1.20-10882~r10652/oscam-reader.c --- oscam-1.20-10855~r10626/oscam-reader.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/oscam-reader.c 2015-04-25 10:46:41.000000000 +0000 @@ -1117,7 +1117,7 @@ time_t now; int32_t time_diff; time(&now); - time_diff = abs(now - reader->last_s); + time_diff = llabs(now - reader->last_s); if(time_diff > reader->tcp_ito) { struct s_client *cl = reader->client; diff -Nru oscam-1.20-10855~r10626/reader-irdeto.c oscam-1.20-10882~r10652/reader-irdeto.c --- oscam-1.20-10855~r10626/reader-irdeto.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/reader-irdeto.c 2015-04-25 10:46:41.000000000 +0000 @@ -175,6 +175,7 @@ {0x0624, 0x0006, "CZE", 946598400L}, // 30.12.1999, 16:00 //skyklink irdeto {0x0624, 0x0006, "SVK", 946598400L}, // 30.12.1999, 16:00 //skyklink irdeto {0x0666, 0x0006, "SVK", 946598400L}, // 30.12.1999, 16:00 //cslink irdeto + {0x0668, 0x0006, "SVK", 946598400L}, // 30.12.1999, 00:00 //Towercom Irdeto {0x0666, 0x0006, "CZE", 946598400L}, // 30.12.1999, 16:00 //cslink irdeto {0x0648, 0x0608, "AUT", 946598400L}, // 31.12.1999, 00:00 //orf ice irdeto {0x0648, 0x0005, "AUT", 946598400L}, // 31.12.1999, 00:00 //orf ice irdeto diff -Nru oscam-1.20-10855~r10626/reader-viaccess.c oscam-1.20-10882~r10652/reader-viaccess.c --- oscam-1.20-10855~r10626/reader-viaccess.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/reader-viaccess.c 2015-04-25 10:46:41.000000000 +0000 @@ -1369,7 +1369,7 @@ if(ep->emm[3] == 0x90 && ep->emm[4] == 0x03) { - provid = b2i(4, ep->emm+5); + provid = b2i(3, ep->emm+5); provid &=0xFFFFF0; i2b_buf(4, provid, ep->provid); } diff -Nru oscam-1.20-10855~r10626/README.dvbapi_protocol oscam-1.20-10882~r10652/README.dvbapi_protocol --- oscam-1.20-10855~r10626/README.dvbapi_protocol 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/README.dvbapi_protocol 2015-04-25 10:46:41.000000000 +0000 @@ -182,3 +182,25 @@ '3f' packed to OSCam. To stop decoding specified demux the following CA_PMT data should be sent to OSCam: 9F 80 3f 04 83 02 00 If is 0xff, then it is parsed as a wildcard and all demuxers associated with the connection are stopped. + + +In protocol version 2 the new packet with ECM info data was introduced: + +-= DVBAPI_ECM_INFO =- +----------------------------------------------------------------------- +type/size description +----------------------------------------------------------------------- +uint32_t operation code -> DVBAPI_ECM_INFO +uint8_t adapter index +uint16_t Service ID +uint16_t CAID +uint16_t PID +uint32_t Provider ID +uint32_t ECM time (ms) +uint8_t size of followed string (255 bytes max) +string reader name (string length should be max 255 bytes) +uint8_t size of followed string (255 bytes max) +string from - source name (string length should be max 255 bytes) +uint8_t size of followed string (255 bytes max) +string protocol name (string length should be max 255 bytes) +uint8_t hops (cccam & gbox; set to 0 otherwise) diff -Nru oscam-1.20-10855~r10626/tommyDS_hashlin/tommychain.h oscam-1.20-10882~r10652/tommyDS_hashlin/tommychain.h --- oscam-1.20-10855~r10626/tommyDS_hashlin/tommychain.h 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/tommyDS_hashlin/tommychain.h 2015-04-25 10:46:41.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2010 Andrea Mazzoleni. All rights reserved. + * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,10 +12,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY ANDREA MAZZOLENI AND CONTRIBUTORS ``AS IS'' + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL ANDREA MAZZOLENI OR CONTRIBUTORS BE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS @@ -167,11 +167,11 @@ * Value stored inside the bit bucket. * It's used to know which bucket is empty of full. */ - unsigned counter; + tommy_count_t counter; tommy_node* node = chain->head; tommy_node* tail = chain->tail; - unsigned mask; - unsigned i; + tommy_count_t mask; + tommy_count_t i; counter = 0; while (1) { @@ -210,11 +210,10 @@ mask = counter >> i; while (mask != 1) { mask >>= 1; - if (mask & 1) { - tommy_chain_merge_degenerated(&bit[i+1], &bit[i], cmp); - } else { - bit[i+1] = bit[i]; - } + if (mask & 1) + tommy_chain_merge_degenerated(&bit[i + 1], &bit[i], cmp); + else + bit[i + 1] = bit[i]; ++i; } diff -Nru oscam-1.20-10855~r10626/tommyDS_hashlin/tommyhash.c oscam-1.20-10882~r10652/tommyDS_hashlin/tommyhash.c --- oscam-1.20-10855~r10626/tommyDS_hashlin/tommyhash.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/tommyDS_hashlin/tommyhash.c 2015-04-25 10:46:41.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2010 Andrea Mazzoleni. All rights reserved. + * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,10 +12,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY ANDREA MAZZOLENI AND CONTRIBUTORS ``AS IS'' + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL ANDREA MAZZOLENI OR CONTRIBUTORS BE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS @@ -35,40 +35,40 @@ /* allow unaligned read on Intel x86 and x86_64 platforms */ #if defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__x86_64__) || defined(_M_X64) /* defines from http://predef.sourceforge.net/ */ - return *(tommy_uint32_t*)ptr; + return *(const tommy_uint32_t*)ptr; #else const unsigned char* ptr8 = tommy_cast(const unsigned char*, ptr); return ptr8[0] + ((tommy_uint32_t)ptr8[1] << 8) + ((tommy_uint32_t)ptr8[2] << 16) + ((tommy_uint32_t)ptr8[3] << 24); #endif } -#define tommy_rot(x,k) \ - (((x)<<(k)) | ((x)>>(32-(k)))) +#define tommy_rot(x, k) \ + (((x) << (k)) | ((x) >> (32 - (k)))) -#define tommy_mix(a,b,c) \ +#define tommy_mix(a, b, c) \ do { \ a -= c; a ^= tommy_rot(c, 4); c += b; \ b -= a; b ^= tommy_rot(a, 6); a += c; \ c -= b; c ^= tommy_rot(b, 8); b += a; \ - a -= c; a ^= tommy_rot(c,16); c += b; \ - b -= a; b ^= tommy_rot(a,19); a += c; \ + a -= c; a ^= tommy_rot(c, 16); c += b; \ + b -= a; b ^= tommy_rot(a, 19); a += c; \ c -= b; c ^= tommy_rot(b, 4); b += a; \ } while (0) -#define tommy_final(a,b,c) \ +#define tommy_final(a, b, c) \ do { \ - c ^= b; c -= tommy_rot(b,14); \ - a ^= c; a -= tommy_rot(c,11); \ - b ^= a; b -= tommy_rot(a,25); \ - c ^= b; c -= tommy_rot(b,16); \ - a ^= c; a -= tommy_rot(c,4); \ - b ^= a; b -= tommy_rot(a,14); \ - c ^= b; c -= tommy_rot(b,24); \ + c ^= b; c -= tommy_rot(b, 14); \ + a ^= c; a -= tommy_rot(c, 11); \ + b ^= a; b -= tommy_rot(a, 25); \ + c ^= b; c -= tommy_rot(b, 16); \ + a ^= c; a -= tommy_rot(c, 4); \ + b ^= a; b -= tommy_rot(a, 14); \ + c ^= b; c -= tommy_rot(b, 24); \ } while (0) tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tommy_size_t key_len) { - const unsigned char* key = tommy_cast(const unsigned char*,void_key); + const unsigned char* key = tommy_cast(const unsigned char*, void_key); tommy_uint32_t a, b, c; a = b = c = 0xdeadbeef + ((tommy_uint32_t)key_len) + init_val; @@ -78,7 +78,7 @@ b += tommy_le_uint32_read(key + 4); c += tommy_le_uint32_read(key + 8); - tommy_mix(a,b,c); + tommy_mix(a, b, c); key_len -= 12; key += 12; @@ -110,14 +110,14 @@ case 1 : a += key[0]; } - tommy_final(a,b,c); + tommy_final(a, b, c); return c; } tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void* void_key, tommy_size_t key_len) { - const unsigned char* key = tommy_cast(const unsigned char*,void_key); + const unsigned char* key = tommy_cast(const unsigned char*, void_key); tommy_uint32_t a, b, c; a = b = c = 0xdeadbeef + ((tommy_uint32_t)key_len) + (init_val & 0xffffffff); @@ -128,7 +128,7 @@ b += tommy_le_uint32_read(key + 4); c += tommy_le_uint32_read(key + 8); - tommy_mix(a,b,c); + tommy_mix(a, b, c); key_len -= 12; key += 12; @@ -160,7 +160,7 @@ case 1 : a += key[0]; } - tommy_final(a,b,c); + tommy_final(a, b, c); return c + ((tommy_uint64_t)b << 32); } diff -Nru oscam-1.20-10855~r10626/tommyDS_hashlin/tommyhash.h oscam-1.20-10882~r10652/tommyDS_hashlin/tommyhash.h --- oscam-1.20-10855~r10626/tommyDS_hashlin/tommyhash.h 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/tommyDS_hashlin/tommyhash.h 2015-04-25 10:46:41.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2010 Andrea Mazzoleni. All rights reserved. + * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,10 +12,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY ANDREA MAZZOLENI AND CONTRIBUTORS ``AS IS'' + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL ANDREA MAZZOLENI OR CONTRIBUTORS BE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS @@ -24,7 +24,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ - + /** \file * Hash functions for the use with ::tommy_hashtable, ::tommy_hashdyn and ::tommy_hashlin. */ @@ -48,7 +48,7 @@ * from http://www.burtleburtle.net/bob/hash/doobs.html, function hashlittle(). * \param init_val Initialization value. * Using a different initialization value, you can generate a completely different set of hash values. - * Use 0 if not relevalt. + * Use 0 if not relevant. * \param void_key Pointer at the data to hash. * \param key_len Size of the data to hash. * \note @@ -63,9 +63,9 @@ * from http://www.burtleburtle.net/bob/hash/doobs.html, function hashlittle2(). * \param init_val Initialization value. * Using a different initialization value, you can generate a completely different set of hash values. - * Use 0 if not relevalt. + * Use 0 if not relevant. * \param void_key Pointer at the data to hash. - * \param key_len Size of the data to hash. + * \param key_len Size of the data to hash. * \note * This function is endianess independent. * \return The hash value of 64 bits. diff -Nru oscam-1.20-10855~r10626/tommyDS_hashlin/tommyhashlin.c oscam-1.20-10882~r10652/tommyDS_hashlin/tommyhashlin.c --- oscam-1.20-10855~r10626/tommyDS_hashlin/tommyhashlin.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/tommyDS_hashlin/tommyhashlin.c 2015-04-25 10:46:41.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2010 Andrea Mazzoleni. All rights reserved. + * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,10 +12,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY ANDREA MAZZOLENI AND CONTRIBUTORS ``AS IS'' + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL ANDREA MAZZOLENI OR CONTRIBUTORS BE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS @@ -28,7 +28,6 @@ #include "tommyhashlin.h" #include "tommylist.h" -#include /* for memset */ #include /* for assert */ /******************************************************************************/ @@ -41,75 +40,47 @@ #define TOMMY_HASHLIN_STATE_GROW 1 #define TOMMY_HASHLIN_STATE_SHRINK 2 +/** + * Set the hashtable in stable state. + */ +tommy_inline void tommy_hashlin_stable(tommy_hashlin* hashlin) +{ + hashlin->state = TOMMY_HASHLIN_STATE_STABLE; + + /* setup low_mask/max/split to allow tommy_hashlin_bucket_ref() */ + /* and tommy_hashlin_foreach() to work regardless we are in stable state */ + hashlin->low_max = hashlin->bucket_max; + hashlin->low_mask = hashlin->bucket_mask; + hashlin->split = 0; +} + void tommy_hashlin_init(tommy_hashlin* hashlin) { + tommy_uint_t i; + /* fixed initial size */ hashlin->bucket_bit = TOMMY_HASHLIN_BIT; hashlin->bucket_max = 1 << hashlin->bucket_bit; hashlin->bucket_mask = hashlin->bucket_max - 1; - hashlin->bucket[0] = tommy_cast(tommy_hashlin_node**, tommy_malloc(hashlin->bucket_max * sizeof(tommy_hashlin_node*))); - memset(hashlin->bucket[0], 0, hashlin->bucket_max * sizeof(tommy_hashlin_node*)); - hashlin->bucket_mac = 1; + hashlin->bucket[0] = tommy_cast(tommy_hashlin_node**, tommy_calloc(hashlin->bucket_max, sizeof(tommy_hashlin_node*))); + for (i = 1; i < TOMMY_HASHLIN_BIT; ++i) + hashlin->bucket[i] = hashlin->bucket[0]; /* stable state */ - hashlin->state = TOMMY_HASHLIN_STATE_STABLE; + tommy_hashlin_stable(hashlin); hashlin->count = 0; } void tommy_hashlin_done(tommy_hashlin* hashlin) { - /* we assume to be empty, so we free only the first bucket */ - assert(hashlin->bucket_mac == 1); + tommy_uint_t i; tommy_free(hashlin->bucket[0]); -} - -/** - * Return the bucket at the specified pos. - */ -tommy_inline tommy_hashlin_node** tommy_hashlin_pos(tommy_hashlin* hashlin, tommy_hash_t pos) -{ - unsigned bsr; - - /* special case for the first bucket */ - if (pos < (1 << TOMMY_HASHLIN_BIT)) { - return &hashlin->bucket[0][pos]; + for (i = TOMMY_HASHLIN_BIT; i < hashlin->bucket_bit; ++i) { + tommy_hashlin_node** segment = hashlin->bucket[i]; + tommy_free(&segment[((tommy_ptrdiff_t)1) << i]); } - - /* get the highest bit set */ - bsr = tommy_ilog2_u32(pos); - - /* clear the highest bit */ - pos -= 1 << bsr; - - return &hashlin->bucket[bsr - TOMMY_HASHLIN_BIT + 1][pos]; -} - -/** - * Return the bucket to use. - */ -tommy_inline tommy_hashlin_node** tommy_hashlin_bucket_ptr(tommy_hashlin* hashlin, tommy_hash_t hash) -{ - unsigned pos; - - /* if we are reallocating */ - if (hashlin->state != TOMMY_HASHLIN_STATE_STABLE) { - /* compute the old position */ - pos = hash & hashlin->low_mask; - - /* if we have not reallocated this position yet */ - if (pos >= hashlin->split) { - - /* use it as it was before */ - return tommy_hashlin_pos(hashlin, pos); - } - } - - /* otherwise operates normally */ - pos = hash & hashlin->bucket_mask; - - return tommy_hashlin_pos(hashlin, pos); } /** @@ -125,16 +96,24 @@ /* otherwise continue with the already setup shrink one */ /* but in backward direction */ if (hashlin->state == TOMMY_HASHLIN_STATE_STABLE) { + tommy_hashlin_node** segment; + /* set the lower size */ hashlin->low_max = hashlin->bucket_max; hashlin->low_mask = hashlin->bucket_mask; - /* grow the hash size and allocate */ + /* allocate the new vector using malloc() and not calloc() */ + /* because data is fully initialized in the split process */ + segment = tommy_cast(tommy_hashlin_node**, tommy_malloc(hashlin->low_max * sizeof(tommy_hashlin_node*))); + + /* store it adjusting the offset */ + /* cast to ptrdiff_t to ensure to get a negative value */ + hashlin->bucket[hashlin->bucket_bit] = &segment[-(tommy_ptrdiff_t)hashlin->low_max]; + + /* grow the hash size */ ++hashlin->bucket_bit; hashlin->bucket_max = 1 << hashlin->bucket_bit; hashlin->bucket_mask = hashlin->bucket_max - 1; - hashlin->bucket[hashlin->bucket_mac] = tommy_cast(tommy_hashlin_node**, tommy_malloc(hashlin->low_max * sizeof(tommy_hashlin_node*))); - ++hashlin->bucket_mac; /* start from the beginning going forward */ hashlin->split = 0; @@ -147,21 +126,19 @@ /* if we are growing */ if (hashlin->state == TOMMY_HASHLIN_STATE_GROW) { /* compute the split target required to finish the reallocation before the next resize */ - unsigned split_target = 2 * hashlin->count; + tommy_count_t split_target = 2 * hashlin->count; /* reallocate buckets until the split target */ while (hashlin->split + hashlin->low_max < split_target) { tommy_hashlin_node** split[2]; tommy_hashlin_node* j; - unsigned mask; + tommy_count_t mask; /* get the low bucket */ split[0] = tommy_hashlin_pos(hashlin, hashlin->split); /* get the high bucket */ - /* it's always in the second half, so we can index it directly */ - /* without calling tommy_hashlin_pos() */ - split[1] = &hashlin->bucket[hashlin->bucket_mac-1][hashlin->split]; + split[1] = tommy_hashlin_pos(hashlin, hashlin->split + hashlin->low_max); /* save the low bucket */ j = *split[0]; @@ -170,17 +147,17 @@ *split[0] = 0; *split[1] = 0; - /* compute the bit to identify the bucket */ - mask = hashlin->bucket_mask & ~hashlin->low_mask; + /* the bit used to identify the bucket */ + mask = hashlin->low_max; /* flush the bucket */ while (j) { tommy_hashlin_node* j_next = j->next; - unsigned index_ = (j->key & mask) != 0; - if (*split[index_]) - tommy_list_insert_tail_not_empty(*split[index_], j); + tommy_count_t pos = (j->key & mask) != 0; + if (*split[pos]) + tommy_list_insert_tail_not_empty(*split[pos], j); else - tommy_list_insert_first(split[index_], j); + tommy_list_insert_first(split[pos], j); j = j_next; } @@ -189,7 +166,8 @@ /* if we have finished, change the state */ if (hashlin->split == hashlin->low_max) { - hashlin->state = TOMMY_HASHLIN_STATE_STABLE; + /* go in stable mode */ + tommy_hashlin_stable(hashlin); break; } } @@ -227,7 +205,7 @@ /* if we are shrinking */ if (hashlin->state == TOMMY_HASHLIN_STATE_SHRINK) { /* compute the split target required to finish the reallocation before the next resize */ - unsigned split_target = 8 * hashlin->count; + tommy_count_t split_target = 8 * hashlin->count; /* reallocate buckets until the split target */ while (hashlin->split + hashlin->low_max > split_target) { @@ -235,21 +213,19 @@ /* go backward position */ --hashlin->split; - + /* get the low bucket */ split[0] = tommy_hashlin_pos(hashlin, hashlin->split); /* get the high bucket */ - /* it's always in the second half, so we can index it directly */ - /* without calling tommy_hashlin_pos() */ - split[1] = &hashlin->bucket[hashlin->bucket_mac-1][hashlin->split]; + split[1] = tommy_hashlin_pos(hashlin, hashlin->split + hashlin->low_max); /* concat the high bucket into the low one */ tommy_list_concat(split[0], split[1]); /* if we have finished, clean up and change the state */ if (hashlin->split == 0) { - hashlin->state = TOMMY_HASHLIN_STATE_STABLE; + tommy_hashlin_node** segment; /* shrink the hash size */ --hashlin->bucket_bit; @@ -257,8 +233,11 @@ hashlin->bucket_mask = hashlin->bucket_max - 1; /* free the last segment */ - --hashlin->bucket_mac; - tommy_free(hashlin->bucket[hashlin->bucket_mac]); + segment = hashlin->bucket[hashlin->bucket_bit]; + tommy_free(&segment[((tommy_ptrdiff_t)1) << hashlin->bucket_bit]); + + /* go in stable mode */ + tommy_hashlin_stable(hashlin); break; } } @@ -267,7 +246,7 @@ void tommy_hashlin_insert(tommy_hashlin* hashlin, tommy_hashlin_node* node, void* data, tommy_hash_t hash) { - tommy_list_insert_tail(tommy_hashlin_bucket_ptr(hashlin, hash), node, data); + tommy_list_insert_tail(tommy_hashlin_bucket_ref(hashlin, hash), node, data); node->key = hash; @@ -278,7 +257,7 @@ void* tommy_hashlin_remove_existing(tommy_hashlin* hashlin, tommy_hashlin_node* node) { - tommy_list_remove_existing(tommy_hashlin_bucket_ptr(hashlin, node->key), node); + tommy_list_remove_existing(tommy_hashlin_bucket_ref(hashlin, node->key), node); --hashlin->count; @@ -287,36 +266,69 @@ return node->data; } -tommy_hashlin_node* tommy_hashlin_bucket(tommy_hashlin* hashlin, tommy_hash_t hash) -{ - return *tommy_hashlin_bucket_ptr(hashlin, hash); -} - void* tommy_hashlin_remove(tommy_hashlin* hashlin, tommy_search_func* cmp, const void* cmp_arg, tommy_hash_t hash) { - tommy_hashlin_node** let_ptr = tommy_hashlin_bucket_ptr(hashlin, hash); - tommy_hashlin_node* i = *let_ptr; + tommy_hashlin_node** let_ptr = tommy_hashlin_bucket_ref(hashlin, hash); + tommy_hashlin_node* node = *let_ptr; - while (i) { + while (node) { /* we first check if the hash matches, as in the same bucket we may have multiples hash values */ - if (i->key == hash && cmp(cmp_arg, i->data) == 0) { - tommy_list_remove_existing(let_ptr, i); + if (node->key == hash && cmp(cmp_arg, node->data) == 0) { + tommy_list_remove_existing(let_ptr, node); --hashlin->count; hashlin_shrink_step(hashlin); - return i->data; + return node->data; } - i = i->next; + node = node->next; } return 0; } +void tommy_hashlin_foreach(tommy_hashlin* hashlin, tommy_foreach_func* func) +{ + tommy_count_t bucket_max; + tommy_count_t pos; + + /* number of valid buckets */ + bucket_max = hashlin->low_max + hashlin->split; + + for (pos = 0; pos < bucket_max; ++pos) { + tommy_hashlin_node* node = *tommy_hashlin_pos(hashlin, pos); + + while (node) { + void* data = node->data; + node = node->next; + func(data); + } + } +} + +void tommy_hashlin_foreach_arg(tommy_hashlin* hashlin, tommy_foreach_arg_func* func, void* arg) +{ + tommy_count_t bucket_max; + tommy_count_t pos; + + /* number of valid buckets */ + bucket_max = hashlin->low_max + hashlin->split; + + for (pos = 0; pos < bucket_max; ++pos) { + tommy_hashlin_node* node = *tommy_hashlin_pos(hashlin, pos); + + while (node) { + void* data = node->data; + node = node->next; + func(arg, data); + } + } +} + tommy_size_t tommy_hashlin_memory_usage(tommy_hashlin* hashlin) { return hashlin->bucket_max * (tommy_size_t)sizeof(hashlin->bucket[0][0]) - + hashlin->count * (tommy_size_t)sizeof(tommy_hashlin_node); + + hashlin->count * (tommy_size_t)sizeof(tommy_hashlin_node); } diff -Nru oscam-1.20-10855~r10626/tommyDS_hashlin/tommyhashlin.h oscam-1.20-10882~r10652/tommyDS_hashlin/tommyhashlin.h --- oscam-1.20-10855~r10626/tommyDS_hashlin/tommyhashlin.h 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/tommyDS_hashlin/tommyhashlin.h 2015-04-25 10:46:41.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2010 Andrea Mazzoleni. All rights reserved. + * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,10 +12,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY ANDREA MAZZOLENI AND CONTRIBUTORS ``AS IS'' + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL ANDREA MAZZOLENI OR CONTRIBUTORS BE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS @@ -84,7 +84,7 @@ * return *(const int*)arg != ((const struct object*)obj)->value; * } * - * int value_to_find = 1; + * int value_to_find = 1; * struct object* obj = tommy_hashlin_search(&hashlin, compare, &value_to_find, tommy_inthash_u32(value_to_find)); * if (!obj) { * // not found @@ -99,7 +99,7 @@ * different keys. * * \code - * int value_to_find = 1; + * int value_to_find = 1; * tommy_node* i = tommy_hashlin_bucket(&hashlin, tommy_inthash_u32(value_to_find)); * while (i) { * struct object* obj = i->data; // gets the object pointer @@ -117,7 +117,7 @@ * and remove. * * \code - * struct object* obj = tommy_trie_remove(&hashtable, compare, &value_to_remove, tommy_inthash_u32(value_to_remove)); + * struct object* obj = tommy_hashlin_remove(&hashlin, compare, &value_to_remove, tommy_inthash_u32(value_to_remove)); * if (obj) { * free(obj); // frees the object allocated memory * } @@ -130,9 +130,11 @@ * tommy_hashlin_done(&hashlin); * \endcode * - * Note that you cannot iterates over all the elements in the hashtable using the - * hashtable itself. You have to insert all the elements also in a ::tommy_list, - * and use the list to iterate. See the \ref multiindex example for more detail. + * If you need to iterate over all the elements in the hashtable, you can use + * tommy_hashlin_foreach() or tommy_hashlin_foreach_arg(). + * If you need a more precise control with a real iteration, you have to insert + * all the elements also in a ::tommy_list, and use the list to iterate. + * See the \ref multiindex example for more detail. */ #ifndef __TOMMYHASHLIN_H @@ -150,7 +152,7 @@ #define TOMMY_HASHLIN_BIT 6 /** - * Linear hashtable node. + * Hashtable node. * This is the node that you have to include inside your objects. */ typedef tommy_node tommy_hashlin_node; @@ -161,19 +163,19 @@ #define TOMMY_HASHLIN_BIT_MAX 32 /** - * Linear chained hashtable. + * Hashtable container type. + * \note Don't use internal fields directly, but access the container only using functions. */ typedef struct tommy_hashlin_struct { tommy_hashlin_node** bucket[TOMMY_HASHLIN_BIT_MAX]; /**< Dynamic array of hash buckets. One list for each hash modulus. */ - unsigned bucket_bit; /**< Bits used in the bit mask. */ - unsigned bucket_max; /**< Number of buckets. */ - unsigned bucket_mask; /**< Bit mask to access the buckets. */ - unsigned bucket_mac; /**< Number of vectors allocated. */ - unsigned low_max; /**< Low order max value. */ - unsigned low_mask; /**< Low order mask value. */ - unsigned split; /**< Split position. */ - unsigned state; /**< Reallocation state. */ - unsigned count; /**< Number of elements. */ + tommy_uint_t bucket_bit; /**< Bits used in the bit mask. */ + tommy_count_t bucket_max; /**< Number of buckets. */ + tommy_count_t bucket_mask; /**< Bit mask to access the buckets. */ + tommy_count_t low_max; /**< Low order max value. */ + tommy_count_t low_mask; /**< Low order mask value. */ + tommy_count_t split; /**< Split position. */ + tommy_count_t count; /**< Number of elements. */ + tommy_uint_t state; /**< Reallocation state. */ } tommy_hashlin; /** @@ -183,11 +185,14 @@ /** * Deinitializes the hashtable. + * + * You can call this function with elements still contained, + * but such elements are not going to be freed by this call. */ void tommy_hashlin_done(tommy_hashlin* hashlin); /** - * Inserts an element in the the hashtable. + * Inserts an element in the hashtable. */ void tommy_hashlin_insert(tommy_hashlin* hashlin, tommy_hashlin_node* node, void* data, tommy_hash_t hash); @@ -196,7 +201,6 @@ * You have to provide a compare function and the hash of the element you want to remove. * If the element is not found, 0 is returned. * If more equal elements are present, the first one is removed. - * This operation is faster than calling tommy_hashlin_bucket() and tommy_hashlin_remove_existing() separately. * \param cmp Compare function called with cmp_arg as first argument and with the element to compare as a second one. * The function should return 0 for equal elements, anything other for different elements. * \param cmp_arg Compare argument passed as first argument of the compare function. @@ -205,6 +209,48 @@ */ void* tommy_hashlin_remove(tommy_hashlin* hashlin, tommy_search_func* cmp, const void* cmp_arg, tommy_hash_t hash); +/** \internal + * Returns the bucket at the specified position. + */ +tommy_inline tommy_hashlin_node** tommy_hashlin_pos(tommy_hashlin* hashlin, tommy_hash_t pos) +{ + tommy_uint_t bsr; + + /* get the highest bit set, in case of all 0, return 0 */ + bsr = tommy_ilog2_u32(pos | 1); + + return &hashlin->bucket[bsr][pos]; +} + +/** \internal + * Returns a pointer to the bucket of the specified hash. + */ +tommy_inline tommy_hashlin_node** tommy_hashlin_bucket_ref(tommy_hashlin* hashlin, tommy_hash_t hash) +{ + tommy_count_t pos; + tommy_count_t high_pos; + + pos = hash & hashlin->low_mask; + high_pos = hash & hashlin->bucket_mask; + + /* if this position is already allocated in the high half */ + if (pos < hashlin->split) { + /* The following assigment is expected to be implemented */ + /* with a conditional move instruction */ + /* that results in a little better and constant performance */ + /* regardless of the split position. */ + /* This affects mostly the worst case, when the split value */ + /* is near at its half, resulting in a totally unpredictable */ + /* condition by the CPU. */ + /* In such case the use of the conditional move is generally faster. */ + + /* use also the high bit */ + pos = high_pos; + } + + return tommy_hashlin_pos(hashlin, pos); +} + /** * Gets the bucket of the specified hash. * The bucket is guaranteed to contain ALL the elements with the specified hash, @@ -213,7 +259,10 @@ * \param hash Hash of the element to find. * \return The head of the bucket, or 0 if empty. */ -tommy_hashlin_node* tommy_hashlin_bucket(tommy_hashlin* hashlin, tommy_hash_t hash); +tommy_inline tommy_hashlin_node* tommy_hashlin_bucket(tommy_hashlin* hashlin, tommy_hash_t hash) +{ + return *tommy_hashlin_bucket_ref(hashlin, hash); +} /** * Searches an element in the hashtable. @@ -228,6 +277,7 @@ tommy_inline void* tommy_hashlin_search(tommy_hashlin* hashlin, tommy_search_func* cmp, const void* cmp_arg, tommy_hash_t hash) { tommy_hashlin_node* i = tommy_hashlin_bucket(hashlin, hash); + while (i) { /* we first check if the hash matches, as in the same bucket we may have multiples hash values */ if (i->key == hash && cmp(cmp_arg, i->data) == 0) @@ -245,9 +295,46 @@ void* tommy_hashlin_remove_existing(tommy_hashlin* hashlin, tommy_hashlin_node* node); /** + * Calls the specified function for each element in the hashtable. + * + * You can use this function to deallocate all the elements inserted. + * + * \code + * tommy_hashlin hashlin; + * + * // initializes the hashtable + * tommy_hashlin_init(&hashlin); + * + * ... + * + * // creates an object + * struct object* obj = malloc(sizeof(struct object)); + * + * ... + * + * // insert it in the hashtable + * tommy_hashlin_insert(&hashlin, &obj->node, obj, tommy_inthash_u32(obj->value)); + * + * ... + * + * // deallocates all the objects iterating the hashtable + * tommy_hashlin_foreach(&hashlin, free); + * + * // deallocates the hashtable + * tommy_hashlin_done(&hashlin); + * \endcode + */ +void tommy_hashlin_foreach(tommy_hashlin* hashlin, tommy_foreach_func* func); + +/** + * Calls the specified function with an argument for each element in the hashtable. + */ +void tommy_hashlin_foreach_arg(tommy_hashlin* hashlin, tommy_foreach_arg_func* func, void* arg); + +/** * Gets the number of elements. */ -tommy_inline unsigned tommy_hashlin_count(tommy_hashlin* hashlin) +tommy_inline tommy_count_t tommy_hashlin_count(tommy_hashlin* hashlin) { return hashlin->count; } diff -Nru oscam-1.20-10855~r10626/tommyDS_hashlin/tommylist.c oscam-1.20-10882~r10652/tommyDS_hashlin/tommylist.c --- oscam-1.20-10855~r10626/tommyDS_hashlin/tommylist.c 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/tommyDS_hashlin/tommylist.c 2015-04-25 10:46:41.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2010 Andrea Mazzoleni. All rights reserved. + * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,10 +12,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY ANDREA MAZZOLENI AND CONTRIBUTORS ``AS IS'' + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL ANDREA MAZZOLENI OR CONTRIBUTORS BE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS @@ -34,9 +34,8 @@ tommy_node* first_tail; tommy_node* second_head; - if (tommy_list_empty(second)) { + if (tommy_list_empty(second)) return; - } if (tommy_list_empty(first)) { *first = *second; diff -Nru oscam-1.20-10855~r10626/tommyDS_hashlin/tommylist.h oscam-1.20-10882~r10652/tommyDS_hashlin/tommylist.h --- oscam-1.20-10855~r10626/tommyDS_hashlin/tommylist.h 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/tommyDS_hashlin/tommylist.h 2015-04-25 10:46:41.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2010 Andrea Mazzoleni. All rights reserved. + * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,10 +12,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY ANDREA MAZZOLENI AND CONTRIBUTORS ``AS IS'' + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL ANDREA MAZZOLENI OR CONTRIBUTORS BE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS @@ -28,18 +28,18 @@ /** \file * Double linked list for collisions into hashtables. * - * This list is a double linked list mainly targetted for collisions into an hashtables, - * but useable also as a generic list. + * This list is a double linked list mainly targetted for handling collisions + * into an hashtables, but useable also as a generic list. * * The main feature of this list is to require only one pointer to represent the - * list, compared to a classic implementation requiring an head an a tail pointers. + * list, compared to a classic implementation requiring a head an a tail pointers. * This reduces the memory usage in hashtables. * * Another feature is to support the insertion at the end of the list. This allow to store * collisions in a stable order. Where for stable order we mean that equal elements keep * their insertion order. * - * To initialize the list, you have to call tommy_list_init(), or simply assign + * To initialize the list, you have to call tommy_list_init(), or to simply assign * to it NULL, as an empty list is represented by the NULL value. * * \code @@ -69,7 +69,7 @@ * tommy_list_insert_tail(&list, &obj->node, obj); // inserts the object * \endcode * - * To iterates over all the elements in the list you have to call + * To iterate over all the elements in the list you have to call * tommy_list_head() to get the head of the list and follow the * tommy_node::next pointer until NULL. * @@ -84,19 +84,14 @@ * } * \endcode * - * To destroy the list you have only to remove all the elements, as the list is - * completely inplace and it doesn't allocate memory. + * To destroy the list you have to remove all the elements, + * as the list is completely inplace and it doesn't allocate memory. + * This can be done with the tommy_list_foreach() function. * * \code - * tommy_node* i = tommy_list_head(&list); - * while (i) { - * tommy_node* i_next = i->next; // saves the next element before freeing - * - * free(i->data); // frees the object allocated memory - * - * i = i_next; // goes to the next element - * } - * \endcode + * // deallocates all the objects iterating the list + * tommy_list_foreach(&list, free); + * \endcode */ #ifndef __TOMMYLIST_H @@ -108,7 +103,7 @@ /* list */ /** - * Double linked list for collisions into hashtables. + * Double linked list type. */ typedef tommy_node* tommy_list; @@ -151,7 +146,7 @@ */ tommy_inline void tommy_list_insert_first(tommy_list* list, tommy_node* node) { - /* one element "circular" prev list */ + /* one element "circular" prev list */ node->prev = node; /* one element "0 terminated" next list */ @@ -206,11 +201,10 @@ { tommy_node* head = tommy_list_head(list); - if (head) { + if (head) tommy_list_insert_head_not_empty(list, node); - } else { + else tommy_list_insert_first(list, node); - } node->data = data; } @@ -224,11 +218,10 @@ { tommy_node* head = tommy_list_head(list); - if (head) { + if (head) tommy_list_insert_tail_not_empty(head, node); - } else { + else tommy_list_insert_first(list, node); - } node->data = data; } @@ -264,18 +257,16 @@ tommy_node* head = tommy_list_head(list); /* remove from the "circular" prev list */ - if (node->next) { + if (node->next) node->next->prev = node->prev; - } else { + else head->prev = node->prev; /* the last */ - } /* remove from the "0 terminated" next list */ - if (head == node) { + if (head == node) *list = node->next; /* the new head, in case 0 */ - } else { + else node->prev->next = node->next; - } return node->data; } @@ -294,7 +285,7 @@ * It's a stable merge sort with O(N*log(N)) worst complexity. * It's faster on degenerated cases like partially ordered lists. * \param cmp Compare function called with two elements. - * The function should return <0 if the first element is less than the second, == 0 if equal, and > 0 if greather. + * The function should return <0 if the first element is less than the second, ==0 if equal, and >0 if greather. */ void tommy_list_sort(tommy_list* list, tommy_compare_func* cmp); @@ -309,10 +300,36 @@ /** * Calls the specified function for each element in the list. + * + * You can use this function to deallocate all the elements + * inserted in a list. + * + * \code + * tommy_list list; + * + * // initializes the list + * tommy_list_init(&list); + * + * ... + * + * // creates an object + * struct object* obj = malloc(sizeof(struct object)); + * + * ... + * + * // insert it in the list + * tommy_list_insert_tail(&list, &obj->node, obj); + * + * ... + * + * // deallocates all the objects iterating the list + * tommy_list_foreach(&list, free); + * \endcode */ tommy_inline void tommy_list_foreach(tommy_list* list, tommy_foreach_func* func) { tommy_node* node = tommy_list_head(list); + while (node) { void* data = node->data; node = node->next; @@ -321,11 +338,12 @@ } /** - * Calls the specified function with argument for each element in the list. + * Calls the specified function with an argument for each element in the list. */ tommy_inline void tommy_list_foreach_arg(tommy_list* list, tommy_foreach_arg_func* func, void* arg) { tommy_node* node = tommy_list_head(list); + while (node) { void* data = node->data; node = node->next; diff -Nru oscam-1.20-10855~r10626/tommyDS_hashlin/tommytypes.h oscam-1.20-10882~r10652/tommyDS_hashlin/tommytypes.h --- oscam-1.20-10855~r10626/tommyDS_hashlin/tommytypes.h 2015-03-13 09:44:16.000000000 +0000 +++ oscam-1.20-10882~r10652/tommyDS_hashlin/tommytypes.h 2015-04-25 10:46:41.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright 2010 Andrea Mazzoleni. All rights reserved. + * Copyright (c) 2010, Andrea Mazzoleni. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,10 +12,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY ANDREA MAZZOLENI AND CONTRIBUTORS ``AS IS'' + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL ANDREA MAZZOLENI OR CONTRIBUTORS BE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS @@ -35,21 +35,37 @@ /******************************************************************************/ /* types */ -#if defined(_MSC_VER) #include + +#if defined(_MSC_VER) typedef unsigned tommy_uint32_t; /**< Generic uint32_t type. */ typedef unsigned _int64 tommy_uint64_t; /**< Generic uint64_t type. */ -typedef size_t tommy_size_t; /**< Generic size_t type. */ typedef size_t tommy_uintptr_t; /**< Generic uintptr_t type. */ #else #include typedef uint32_t tommy_uint32_t; /**< Generic uint32_t type. */ typedef uint64_t tommy_uint64_t; /**< Generic uint64_t type. */ -typedef uintptr_t tommy_size_t; /**< Generic size_t type. */ typedef uintptr_t tommy_uintptr_t; /**< Generic uintptr_t type. */ #endif +typedef size_t tommy_size_t; /**< Generic size_t type. */ +typedef ptrdiff_t tommy_ptrdiff_t; /**< Generic ptrdiff_t type. */ typedef int tommy_bool_t; /**< Generic boolean type. */ +/** + * Generic unsigned integer type. + * + * It has no specific size, as is used to store only small values. + * To make the code more efficient, a full 32 bit integer is used. + */ +typedef tommy_uint32_t tommy_uint_t; + +/** + * Generic unsigned integer for counting objects. + * + * TommyDS doesn't support more than 2^32-1 objects. + */ +typedef tommy_uint32_t tommy_count_t; + /** \internal * Type cast required for the C++ compilation. * When compiling in C++ we cannot convert a void* pointer to another pointer. @@ -64,16 +80,25 @@ /******************************************************************************/ /* heap */ -/* by default uses malloc/realloc/free */ +/* by default uses malloc/calloc/realloc/free */ /** - * Generic malloc(), realloc() and free() functions. - * Redefine them to what you need. By default they map to the C malloc(), realloc() and free(). + * Generic malloc(), calloc(), realloc() and free() functions. + * Redefine them to what you need. By default they map to the C malloc(), calloc(), realloc() and free(). */ -#if !defined(tommy_malloc) && !defined(tommy_realloc) && !defined(tommy_free) +#if !defined(tommy_malloc) || !defined(tommy_calloc) || !defined(tommy_realloc) || !defined(tommy_free) #include +#endif +#if !defined(tommy_malloc) #define tommy_malloc malloc +#endif +#if !defined(tommy_calloc) +#define tommy_calloc calloc +#endif +#if !defined(tommy_realloc) #define tommy_realloc realloc +#endif +#if !defined(tommy_free) #define tommy_free free #endif @@ -109,7 +134,7 @@ */ #if !defined(tommy_likely) #if defined(__GNUC__) -#define tommy_likely(x) __builtin_expect(!!(x),1) +#define tommy_likely(x) __builtin_expect(!!(x), 1) #else #define tommy_likely(x) (x) #endif @@ -120,7 +145,7 @@ */ #if !defined(tommy_unlikely) #if defined(__GNUC__) -#define tommy_unlikely(x) __builtin_expect(!!(x),0) +#define tommy_unlikely(x) __builtin_expect(!!(x), 0) #else #define tommy_unlikely(x) (x) #endif @@ -218,7 +243,7 @@ * Search function for elements. * \param arg Pointer at the value to search. * \param obj Pointer at the object to compare to. - * \return ==0 if the value matches the element. != 0 if different. + * \return ==0 if the value matches the element. !=0 if different. * * Note that the first argument is a pointer to the value to search and * the second one is a pointer to the object to compare. @@ -235,14 +260,14 @@ * return *(const int*)arg != ((const struct object*)obj)->value; * } * - * int value_to_find = 1; + * int value_to_find = 1; * struct object* obj = tommy_hashtable_search(&hashtable, compare, &value_to_find, tommy_inthash_u32(value_to_find)); * if (!obj) { * // not found * } else { * // found * } - * \endcode + * \endcode * */ typedef int tommy_search_func(const void* arg, const void* obj); @@ -271,37 +296,54 @@ #if defined(_MSC_VER) && !defined(__cplusplus) #include #pragma intrinsic(_BitScanReverse) +#pragma intrinsic(_BitScanForward) #endif /** \internal * Integer log2 for constants. * You can use it only for exact power of 2 up to 256. */ -#define TOMMY_ILOG2(value) ((value) == 256 ? 8 : (value) == 128 ? 7 :(value) == 64 ? 6 : (value) == 32 ? 5 : (value) == 16 ? 4 : (value) == 8 ? 3 : (value) == 4 ? 2 : (value) == 2 ? 1 : 0) +#define TOMMY_ILOG2(value) ((value) == 256 ? 8 : (value) == 128 ? 7 : (value) == 64 ? 6 : (value) == 32 ? 5 : (value) == 16 ? 4 : (value) == 8 ? 3 : (value) == 4 ? 2 : (value) == 2 ? 1 : 0) /** * Bit scan reverse or integer log2. * Return the bit index of the most significant 1 bit. * * If no bit is set, the result is undefined. - * To force a return 0 in this case, you can use tommy_ilog2(value | 1). + * To force a return 0 in this case, you can use tommy_ilog2_u32(value | 1). + * + * Other interesting ways for bitscan are at: * - * Other interesting ways for bitscan can be found at: - * - * Bit Twiddling Hacks - * http://graphics.stanford.edu/~seander/bithacks.html + * Bit Twiddling Hacks + * http://graphics.stanford.edu/~seander/bithacks.html * * Chess Programming BitScan * http://chessprogramming.wikispaces.com/BitScan * * \param value Value to scan. 0 is not allowed. - * \return The index of the most significan bit set. + * \return The index of the most significant bit set. */ -tommy_inline unsigned tommy_ilog2_u32(tommy_uint32_t value) +tommy_inline tommy_uint_t tommy_ilog2_u32(tommy_uint32_t value) { +#if defined(_MSC_VER) + unsigned long count; + _BitScanReverse(&count, value); + return count; + /* +#elif defined(__GNUC__) + * GCC implements __builtin_clz(x) as "__builtin_clz(x) = bsr(x) ^ 31" + * + * Where "x ^ 31 = 31 - x", but gcc does not optimize "31 - __builtin_clz(x)" to bsr(x), + * but generates 31 - (bsr(x) xor 31). + * + * So we write "__builtin_clz(x) ^ 31" instead of "31 - __builtin_clz(x)", + * to allow the double xor to be optimized out. + return __builtin_clz(value) ^ 31; + */ +#else /* Find the log base 2 of an N-bit integer in O(lg(N)) operations with multiply and lookup */ /* from http://graphics.stanford.edu/~seander/bithacks.html */ - static const int TOMMY_DE_BRUIJN_INDEX_ILOG2[32] = { + static unsigned char TOMMY_DE_BRUIJN_INDEX_ILOG2[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; @@ -313,6 +355,7 @@ value |= value >> 16; return TOMMY_DE_BRUIJN_INDEX_ILOG2[(tommy_uint32_t)(value * 0x07C4ACDDU) >> 27]; +#endif } /** @@ -321,18 +364,26 @@ * * If no bit is set, the result is undefined. * \param value Value to scan. 0 is not allowed. - * \return The index of the least significan bit set. + * \return The index of the least significant bit set. */ -tommy_inline unsigned tommy_ctz_u32(tommy_uint32_t value) +tommy_inline tommy_uint_t tommy_ctz_u32(tommy_uint32_t value) { +#if defined(_MSC_VER) + unsigned long count; + _BitScanForward(&count, value); + return count; +#elif defined(__GNUC__) + return __builtin_ctz(value); +#else /* Count the consecutive zero bits (trailing) on the right with multiply and lookup */ /* from http://graphics.stanford.edu/~seander/bithacks.html */ - static const tommy_uint32_t TOMMY_DE_BRUIJN_INDEX_CTZ[32] = { + static const unsigned char TOMMY_DE_BRUIJN_INDEX_CTZ[32] = { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 }; - return TOMMY_DE_BRUIJN_INDEX_CTZ[(tommy_uint32_t)(((value & -value) * 0x077CB531U)) >> 27]; + return TOMMY_DE_BRUIJN_INDEX_CTZ[(tommy_uint32_t)(((value & - value) * 0x077CB531U)) >> 27]; +#endif } /**