|
SASC
DVBSoftCAM
|
00001 /* 00002 * Softcam plugin to VDR (C++) 00003 * 00004 * This code is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This code is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 00018 */ 00019 00020 #include <stdlib.h> 00021 #include <string.h> 00022 00023 #include <vdr/thread.h> 00024 #include <vdr/tools.h> 00025 00026 #include "system.h" 00027 #include "cc.h" 00028 #include "misc.h" 00029 #include "opts.h" 00030 #include "log-core.h" 00031 #include "version.h" 00032 00033 SCAPIVERSTAG(); 00034 00035 #define SYSTEM_NAME "Cardclient" 00036 #define SYSTEM_PRI -15 00037 00038 #define CONF_FILE "cardclient.conf" 00039 00040 static const struct LogModule lm_cc = { 00041 (LMOD_ENABLE|L_CC_ALL)&LOPT_MASK, 00042 (LMOD_ENABLE|L_CC_CORE|L_CC_LOGIN|L_CC_ECM|L_CC_EMM|L_CC_CAMD|L_CC_CAMD35| 00043 L_CC_RDGD|L_CC_NEWCAMD|L_CC_GBOX|L_CC_CCCAM|L_CC_CCCAM2|L_CC_CCCAM2SH|L_CC_CCCAM2EX)&LOPT_MASK, 00044 "cardclient", 00045 { "core","login","ecm","emm","camd","camd35","camd35extra","radegast", 00046 "newcamd","gbox","cccam","cccam2","cccam2data","cccam2shares","cccam2extra"} 00047 }; 00048 ADD_MODULE(L_CC,lm_cc) 00049 00050 static int immediate=true; 00051 00052 // -- cCardClient -------------------------------------------------------------- 00053 00054 cCardClient::cCardClient(const char *Name) 00055 :msECM(32,16) 00056 ,msEMM(32,0) 00057 { 00058 name=Name; 00059 emmAllowed=0; emmCaid[0]=0x1700; emmMask[0]=0xFF00; numCaid=1; 00060 } 00061 00062 bool cCardClient::Immediate(void) 00063 { 00064 return immediate; 00065 } 00066 00067 void cCardClient::CaidsChanged(void) 00068 { 00069 cSystem::CaidsChanged(); 00070 } 00071 00072 bool cCardClient::ParseStdConfig(const char *config, int *num) 00073 { 00074 int n, emm=0; 00075 if(!num) num=&n; 00076 if(sscanf(config,"%63[^:]:%d:%d%n",hostname,&port,&emm,num)<3) return false; 00077 if(emm>0) emmAllowed=1; 00078 if(emm==2) emmAllowed=2; // EMM caching disabled 00079 if(config[*num]=='/') { 00080 numCaid=0; 00081 do { 00082 emmMask[numCaid]=0xFFFF; 00083 int start=(*num)+1; 00084 if(sscanf(&config[start],"%x%n/%x%n",&emmCaid[numCaid],num,&emmMask[numCaid],num)<1) 00085 return false; 00086 *num+=start; 00087 if(emmMask[numCaid]==0x0000 && emmCaid[numCaid]!=0x0000) 00088 PRINTF(L_GEN_WARN,"CAID %04x MASK %04x in cardclient config doesn't match anything!",emmCaid[numCaid],emmMask[numCaid]); 00089 numCaid++; 00090 } while(numCaid<MAX_CC_CAID && config[*num]==','); 00091 } 00092 LBSTART(L_CC_CORE); 00093 LBPUT("hostname=%s port=%d emm=%d emmCaids",hostname,port,emmAllowed); 00094 for(int i=0; i<numCaid; i++) LBPUT(" %04x/%04x",emmCaid[i],emmMask[i]); 00095 LBEND(); 00096 return true; 00097 } 00098 00099 bool cCardClient::CanHandle(unsigned short SysId) 00100 { 00101 for(int i=0; i<numCaid; i++) 00102 if((SysId&emmMask[i])==emmCaid[i]) return true; 00103 return false; 00104 } 00105 00106 void cCardClient::Logout(void) 00107 { 00108 so.Disconnect(); 00109 } 00110 00111 bool cCardClient::SendMsg(const unsigned char *data, int len) 00112 { 00113 if(!so.Connected() && !Login()) return false; 00114 if(so.Write(data,len)<0) { 00115 PRINTF(L_CC_CORE,"send error. reconnecting..."); 00116 Logout(); 00117 return false; 00118 } 00119 return true; 00120 } 00121 00122 int cCardClient::RecvMsg(unsigned char *data, int len, int to) 00123 { 00124 if(!so.Connected() && !Login()) return -1; 00125 int n=so.Read(data,len,to); 00126 if(n<0) { 00127 if(errno==ETIMEDOUT && (len<0 || to==0)) return 0; 00128 PRINTF(L_CC_CORE,"recv error. reconnecting...");; 00129 Logout(); 00130 } 00131 return n; 00132 } 00133 00134 // -- cCardClients ------------------------------------------------------------- 00135 00136 class cCardClients { 00137 friend class cCardClientLink; 00138 private: 00139 static cCardClientLink *first; 00140 // 00141 static void Register(cCardClientLink *ccl); 00142 public: 00143 cCardClientLink *FindByName(const char *name); 00144 }; 00145 00146 cCardClientLink *cCardClients::first=0; 00147 00148 static cCardClients cardclients; 00149 00150 void cCardClients::Register(cCardClientLink *ccl) 00151 { 00152 PRINTF(L_CORE_DYN,"cardclients: registering cardclient %s",ccl->name); 00153 ccl->next=first; 00154 first=ccl; 00155 } 00156 00157 cCardClientLink *cCardClients::FindByName(const char *name) 00158 { 00159 cCardClientLink *ccl=first; 00160 while(ccl) { 00161 if(!strcasecmp(ccl->name,name)) break; 00162 ccl=ccl->next; 00163 } 00164 return ccl; 00165 } 00166 00167 // -- cCardClientLink ---------------------------------------------------------- 00168 00169 cCardClientLink::cCardClientLink(const char *Name) 00170 { 00171 name=Name; 00172 cCardClients::Register(this); 00173 } 00174 00175 // -- cSystemLinkCardClient ----------------------------------------------------------- 00176 00177 class cSystemLinkCardClient : public cSystemLink, public cStructListPlain<cCardClient> { 00178 protected: 00179 virtual bool ParseLinePlain(const char *line); 00180 public: 00181 cSystemLinkCardClient(void); 00182 virtual bool CanHandle(unsigned short SysId); 00183 virtual cSystem *Create(void); 00184 virtual void Clean(void); 00185 cCardClient *FindBySysId(unsigned short id, cCardClient *cc); 00186 }; 00187 00188 static cSystemLinkCardClient staticCcl; 00189 00190 // -- cSystemCardClient --------------------------------------------------------------- 00191 00192 class cSystemCardClient : public cSystem { 00193 private: 00194 cCardClient *cc; 00195 public: 00196 cSystemCardClient(void); 00197 virtual bool ProcessECM(const cEcmInfo *ecm, unsigned char *data); 00198 virtual void ProcessEMM(int pid, int caid, const unsigned char *buffer); 00199 }; 00200 00201 cSystemCardClient::cSystemCardClient(void) 00202 :cSystem(SYSTEM_NAME,SYSTEM_PRI) 00203 { 00204 cc=0; 00205 local=false; hasLogger=true; 00206 } 00207 00208 bool cSystemCardClient::ProcessECM(const cEcmInfo *ecm, unsigned char *data) 00209 { 00210 cCardClient *startCc=cc, *oldcc; 00211 do { 00212 if(cc) { 00213 cTimeMs start; 00214 int id=cc->msECM.Get(data,SCT_LEN(data),cw); 00215 if(id==0 || (id>0 && cc->ProcessECM(ecm,data,cw))) { 00216 int dur=start.Elapsed(); 00217 if(dur>2000) { 00218 char bb[32]; 00219 time_t now=time(0); 00220 ctime_r(&now,bb); stripspace(bb); 00221 PRINTF(L_CC_CORE,"%s: lagged cw %d ms (%s)",bb,dur,cc->Name()); 00222 } 00223 char buff[32]; 00224 snprintf(buff,sizeof(buff),"CC %s",cc->Name()); 00225 KeyOK(buff); 00226 if(id>0) cc->msECM.Cache(id,true,cw); 00227 return true; 00228 } 00229 if(id>0) { 00230 PRINTF(L_CC_CORE,"client %s (%s:%d) ECM failed (%d ms)",cc->Name(),cc->hostname,cc->port,(int)start.Elapsed()); 00231 cc->msECM.Cache(id,false,cw); 00232 } 00233 } 00234 if(!cc) PRINTF(L_CC_CORE,"cc-loop"); 00235 oldcc=cc; 00236 cc=staticCcl.FindBySysId(ecm->caId,cc); 00237 if(cc && cc!=startCc) PRINTF(L_CC_CORE,"now trying client %s (%s:%d)",cc->Name(),cc->hostname,cc->port); 00238 } while(cc!=startCc && cc!=oldcc); 00239 return false; 00240 } 00241 00242 void cSystemCardClient::ProcessEMM(int pid, int caid, const unsigned char *buffer) 00243 { 00244 cCardClient *cc=0; 00245 while((cc=staticCcl.FindBySysId(caid,cc))) 00246 cc->ProcessEMM(caid,buffer); 00247 } 00248 00249 // -- cSystemLinkCardClient ----------------------------------------------------------- 00250 00251 cSystemLinkCardClient::cSystemLinkCardClient(void) 00252 :cSystemLink(SYSTEM_NAME,SYSTEM_PRI) 00253 ,cStructListPlain<cCardClient>("cardclient config",CONF_FILE,SL_MISSINGOK|SL_VERBOSE|SL_NOPURGE) 00254 { 00255 opts=new cOpts(SYSTEM_NAME,1); 00256 opts->Add(new cOptBool("Immediate",trNOOP("Cardclient: connect immediately"),&immediate)); 00257 } 00258 00259 cCardClient *cSystemLinkCardClient::FindBySysId(unsigned short id, cCardClient *cc) 00260 { 00261 ListLock(false); 00262 for(cc=cc ? Next(cc):First(); cc; cc=Next(cc)) 00263 if(cc->CanHandle(id)) break; 00264 ListUnlock(); 00265 return cc; 00266 } 00267 00268 bool cSystemLinkCardClient::CanHandle(unsigned short SysId) 00269 { 00270 return FindBySysId(SysId,0)!=0; 00271 } 00272 00273 cSystem *cSystemLinkCardClient::Create(void) 00274 { 00275 return new cSystemCardClient(); 00276 } 00277 00278 bool cSystemLinkCardClient::ParseLinePlain(const char *line) 00279 { 00280 char name[32]; 00281 int num; 00282 if(sscanf(line,"%31[^:]:%n",name,&num)==1) { 00283 cCardClientLink *ccl=cardclients.FindByName(name); 00284 if(ccl) { 00285 cCardClient *cc=ccl->Create(); 00286 if(cc) { 00287 if(cc->Init(&line[num])) { 00288 Add(cc); 00289 PRINTF(L_CC_CORE,"client '%s' ready",cc->Name()); 00290 if(cc->Immediate()) cc->Login(); 00291 return true; 00292 } 00293 else { 00294 delete cc; 00295 PRINTF(L_GEN_ERROR,"init of cardclient '%s' failed",name); 00296 } 00297 } 00298 else PRINTF(L_GEN_ERROR,"failed to create cardclient '%s'",name); 00299 } 00300 else PRINTF(L_GEN_ERROR,"no client found for card server type '%s'",name); 00301 } 00302 return false; 00303 } 00304 00305 void cSystemLinkCardClient::Clean(void) 00306 { 00307 SafeClear(); 00308 }