SASC-NG
DVBSoftCAM

cc.c

Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines