Logo Search packages:      
Sourcecode: beid version File versions  Download package

CRLService.cpp

/* ****************************************************************************

 * eID Middleware Project.
 * Copyright (C) 2008-2009 FedICT.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, see
 * http://www.gnu.org/licenses/.

**************************************************************************** */
#include "CRLService.h"
#include "eidErrors.h"
#include "MWException.h"
#include "cryptoFwkBeid.h"
#include "MiscUtil.h"
#include "Log.h"
#include "APLConfig.h"
#include "Config.h"
#include "Util.h"

#include <stdio.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>


namespace eIDMW
{

/*****************************************************************************************
------------------------------------ APL_CrlService ---------------------------------------
*****************************************************************************************/
00043 APL_CrlService::APL_CrlService(APL_CrlDownloadingCache *cache,APL_CryptoFwk *cryptoFwk)
{
      MWLOG(LEV_INFO, MOD_CRL, L"Create CrlService object");
      m_cache=cache;
      m_cryptoFwk=cryptoFwk;

      APL_Config conf_file(CConfig::EIDMW_CONFIG_PARAM_CRL_LOCKFILE);     
      m_flagfilename=CPathUtil::getFullPath(cache->getCacheDirPath(),conf_file.getString());

      m_flagService=NULL;
      m_control=NULL;
}

00056 APL_CrlService::~APL_CrlService()
{
      MWLOG(LEV_INFO, MOD_CRL, L"Delete CrlService object");
}

//we loop until the main process end
00062 void APL_CrlService::Run()
{
      try
      {
            //We try to catch the flag service to define the mode
            startControl();

            if(m_flagService)
            {
                  //DOWNLOAD MODE
                  //First we synchronize
                  if(!m_bStopRequest)
                        m_cache->keepCacheSynchro(m_bStopRequest);

                  //Then we refresh the cache from pending download
                  if(!m_bStopRequest)
                        m_cache->refreshCache(m_bStopRequest,true);
            }

            while(!m_bStopRequest)
            {
                  if(m_flagService)
                  {
                        //DOWNLOAD MODE
                        //This thread runs the controle of the download
                        if(!m_bStopRequest)
                              m_cache->checkForDownload(m_bStopRequest);

                        SleepMillisecs(1000);
                  }
                  else
                  {
                        //QUIET MODE
                        //We wait until the Download mode is release by another process
                        //The service swith between process, so it's important not to do a cleanup and keep the pending download
                        if(startControl())
                              m_cache->refreshCache(m_bStopRequest,false);
                        else
                              SleepMillisecs(1000);
                  }
            }

            stopControl();

      }
      catch (...)
      {
            stopControl();
            m_isRunning = false;
            throw;
      }
}

00115 int APL_CrlService::Start()
{
      return CThread::Start();
}

bool APL_CrlService::startControl()
{
      if(catchFlagFile())
      {
            //Start the control thread
            if(!m_control)
            {
                  m_control = new APL_DownloadControl(m_cache,m_cryptoFwk);
                  m_control->Start();
            }
            return true;
      }

      return false;
}

void APL_CrlService::stopControl()
{
      if(m_control)
      {
            m_control->Stop();

            delete m_control;
            m_control=NULL;
      }

      releaseFlagFile();
}

bool APL_CrlService::pushNewDownload(const char *uri, const char *file, bool bHighPriority,APL_CrlDownloadingCache *cache)
{
      return m_control->pushNewDownload(uri,file,bHighPriority,cache);
}
bool APL_CrlService::catchFlagFile()
{
      if(m_flagService)
            return false;

      int err=0;

#ifndef WIN32
      m_tFlFlag.l_type   = F_WRLCK;  /* F_RDLCK, F_WRLCK, F_UNLCK    */
      m_tFlFlag.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */
      m_tFlFlag.l_start  = 0;        /* Offset from l_whence         */
      m_tFlFlag.l_len    = 0;        /* length, 0 = to EOF           */
      m_tFlFlag.l_pid    = getpid(); /* our PID                      */
#endif

#ifdef WIN32
            //As the file is set with hidden attribute, we try to remove it
            remove(m_flagfilename.c_str());
            err = fopen_s(&m_flagService, m_flagfilename.c_str(), "w");
            SetFileAttributesA(m_flagfilename.c_str(),FILE_ATTRIBUTE_HIDDEN);
#else
            m_flagService = fopen(m_flagfilename.c_str(), "w");
            err = (m_flagService == NULL) ? errno : 0;
#endif
            if (err != 0 && err != EACCES) return false;                                        // Added for unit testing

            if(err==EACCES) 
            {
                  m_flagService=NULL;
                  return false;
            }

      if(m_flagService==NULL)
            return false;
      
      
#ifdef WIN32
      _lock_file(m_flagService);          //Lock the file to avoid other process to access it
#else 
      // on Linux/Mac we set an advisory lock, i.e. it prevents
      // other processes from using the file only if they are collaborative 
      // and check for the lock, otherwise they can do whatever they like ..
      
      if( fcntl(fileno(m_flagService), F_SETLK, &m_tFlFlag) == -1){  /* set the lock */
        fclose(m_flagService);
        m_flagService=NULL;
        return false;
      }
#endif

      return true;
}

bool APL_CrlService::releaseFlagFile()
{
      //If the file is not open, it's an implementation problem
      if(!m_flagService)
            return false;

      
#ifdef WIN32
      _unlock_file(m_flagService);
#else
      m_tFlFlag.l_type   = F_UNLCK;  /* tell it to unlock the region */
            
      if( fcntl(fileno(m_flagService), F_SETLK, &m_tFlFlag) == -1){ /* set the region to unlocked */
             printf("APL_CrlDownloadingCache::releaseFlagFile fcntl: %s\n",strerror(errno));
             exit(1);
      }
#endif
      fclose(m_flagService);

      m_flagService=NULL;

      return true;
}

/*****************************************************************************************
------------------------------------ APL_CrlDownload ---------------------------------------
*****************************************************************************************/
APL_CrlDownloadingCache *APL_CrlDownload::m_cache=NULL;
APL_CryptoFwk *APL_CrlDownload::m_cryptoFwk=NULL;

00236 APL_CrlDownload::APL_CrlDownload(const char *uri, const char *file, bool bHighPriority,unsigned long ulDelay)
{
      MWLOG(LEV_DEBUG, MOD_CRL, L"Create CrlDownload object");
      m_uri=uri;
      m_file=file;
      m_bHighPriority=bHighPriority;
      m_bStarted=false;
      m_Validity="";
      m_ulDownloadingDelay=ulDelay;
}

00247 APL_CrlDownload::~APL_CrlDownload()
{
      //If the download has not starting, we notify the cache
      if(!isStarted())
            if(m_cache)
                  m_cache->notifyDownload(m_uri.c_str(),DOWNLOAD_NOTIFY_END_INTERRUPT,m_Validity.c_str());

      MWLOG(LEV_DEBUG, MOD_CRL, L"Delete CrlDownload object");
}

00257 int APL_CrlDownload::Start()
{
      //If the thread start, the flag m_bWaitingStart is set to false
      int iRet=CThread::Start();

      if(!iRet)
      {
            m_bStarted=true;
      }

      return iRet;
}

00270 void APL_CrlDownload::Run()
{
      try
      {
            if(!m_bStopRequest)
            {
                  setValidity();
                  if(m_cache)
                        m_cache->notifyDownload(m_uri.c_str(),DOWNLOAD_NOTIFY_BEGIN,m_Validity.c_str());

                  if(download())
                  {
                  //When the download is finished, we notify the cache
                        if(m_cache)
                              m_cache->notifyDownload(m_uri.c_str(),DOWNLOAD_NOTIFY_END_OK,m_Validity.c_str());
                  }
                  else
                  {
                        if(m_cache)
                              m_cache->notifyDownload(m_uri.c_str(),DOWNLOAD_NOTIFY_ERR_CONNECT,m_Validity.c_str());
                  }
            }
            resetValidity();

      }
      catch (...)
      {
            if(m_cache)
                  m_cache->notifyDownload(m_uri.c_str(),DOWNLOAD_NOTIFY_END_INTERRUPT,m_Validity.c_str());

            m_isRunning = false;
            throw;
      }

}
00305 void APL_CrlDownload::Stop()
{
      if(m_bHighPriority)           //If it's high priority, we wait until download ends
      {
            CThread::WaitTillStopped();
      }
      else
      {
            CThread::Stop();              //We ask for to stop to exit from the run loop
      }
}

00317 bool APL_CrlDownload::isHighPriority()
{
      return m_bHighPriority;
}

00322 bool APL_CrlDownload::isStarted()
{
      return m_bStarted;
}

00327 bool APL_CrlDownload::isFinished()
{
      if(!isStarted())
            return false;

      if(IsRunning())
            return false;

      return true;
}

00338 bool APL_CrlDownload::download()
{
      bool bRet = false;
      CByteArray baData;
    FILE *pf = NULL;  

    if (m_cryptoFwk->downloadFile(m_uri.c_str(), baData,m_bStopRequest))
    {

            //First get the direcory and check if it exist
            std::string directory=CPathUtil::getDir(m_file.c_str());
            CPathUtil::checkDir(directory.c_str());

        // Then save the file
#ifdef WIN32
        fopen_s(&pf,m_file.c_str(), "wb");
#else
        pf = fopen(m_file.c_str(), "wb");
#endif
        if(NULL != pf)
        {
            size_t ulNumWritten = 0;
            ulNumWritten = fwrite(baData.GetBytes(), sizeof(unsigned char), baData.Size(), pf);
            fclose(pf);
            bRet = true;
        }
      }

    return bRet;

}

//Set Downloading timestamp in format YYYYMMDDThhmmss by default
00371 void APL_CrlDownload::setValidity()
{
      CTimestampUtil::getTimestamp(m_Validity,m_ulDownloadingDelay,CDC_VALIDITY_FORMAT);
}

//reset the validity timestamp
00377 void APL_CrlDownload::resetValidity()
{
      m_Validity="";
}

//Return true is Line Validity > now
00383 bool APL_CrlDownload::checkValidity()
{
      if(m_Validity.empty())
            return true;

      return CTimestampUtil::checkTimestamp(m_Validity,CDC_VALIDITY_FORMAT);
}

/*****************************************************************************************
------------------------------------ APL_DownloadControl ---------------------------------------
*****************************************************************************************/
00394 APL_DownloadControl::APL_DownloadControl(APL_CrlDownloadingCache *cache,APL_CryptoFwk *cryptoFwk)
{
      MWLOG(LEV_INFO, MOD_CRL, L"Create DownloadControl object");

      m_cache=cache;
      m_cryptoFwk=cryptoFwk;

      APL_Config conf_MaxNumber(CConfig::EIDMW_CONFIG_PARAM_CRL_SERVDOWNLOADNR);     
      m_ulMaxNumber = conf_MaxNumber.getLong();

      APL_Config conf_DownloadingDelay(CConfig::EIDMW_CONFIG_PARAM_CRL_TIMEOUT);     
      m_ulDownloadingDelay = conf_DownloadingDelay.getLong();

      m_ulCurrentlyRunning=0;

      APL_CrlDownload::setCache(m_cache);
      APL_CrlDownload::setCryptoFwk(m_cryptoFwk);

      srand((int)time(NULL));
}

00415 APL_DownloadControl::~APL_DownloadControl()
{
      MWLOG(LEV_INFO, MOD_CRL, L"Delete DownloadControl object");
}

00420 void APL_DownloadControl::Run()
{

      try
      {
            while(!m_bStopRequest)
            {
                  if(!m_bStopRequest)
                        deleteOldThreads(false);
                  if(!m_bStopRequest)
                        startNewThreads();

                  if(!m_bStopRequest)
                        SleepMillisecs(100);
            }
      }
      catch (...)
      {
            m_isRunning = false;
            throw;
      }
}

00443 bool APL_DownloadControl::pushNewDownload(const char *uri, const char *file, bool bHighPriority,APL_CrlDownloadingCache *cache)
{
      CAutoMutex autoMutex(&m_Mutex);                 //To prevent multi-access to vector m_threads

      bool bFound=false;

      std::vector<APL_CrlDownload *>::iterator itr;
      APL_CrlDownload *pThread;

      itr = m_threads.begin();
      while(itr!=m_threads.end())
      {
            pThread=*itr;

            if(strcmp(pThread->getUri(),uri)==0)
            {
                  bFound=true;
                  break;
            }

            itr++;
      }

      if(!bFound)
      {
            //Create the thread and add it to the vector
            pThread = new APL_CrlDownload(uri,file,bHighPriority,m_ulDownloadingDelay);
            m_threads.push_back(pThread);
      }

      if(bHighPriority)
      {
            pThread->setHighPriority(true);
      }

      return true;
}

00481 void APL_DownloadControl::deleteOldThreads(bool bForceAll)
{
      CAutoMutex autoMutex(&m_Mutex);                 //To prevent multi-access to vector m_threads

      std::vector<APL_CrlDownload *>::iterator itr;
      APL_CrlDownload *pThread;

      bool bStillValid;
      bool bDelete;

      itr = m_threads.begin();
      while(itr!=m_threads.end())
      {
            pThread=*itr;

            bStillValid=pThread->checkValidity();
            bDelete=false;

            if(bForceAll)                                   //If bForceAll    
            {
                  pThread->Stop();                          //We asked the thread to stop
                  bDelete=true;                                   //Then, we delete it
            }
            else if(pThread->isFinished())            //If the thread finished
            {
                  bDelete=true;                                   //We delete it
            }
            else if(!bStillValid)                     //If it not valid any more
            {                 
                  pThread->Stop();                          //We asked the thread to stop
                  if(!pThread->isHighPriority())            //and, if it's not a high priority, we delete it
                        bDelete=true;                             //Else, download will retry soon
            }

            if(bDelete)
            {
                  delete pThread;
                  itr=m_threads.erase(itr);
                  m_ulCurrentlyRunning--;
            }
            else  //If we delete the threads, me don't need to iterate 
            {                       //because it has already done by the erase
                  itr++;
            }
      } 
}

00528 void APL_DownloadControl::startNewThreads()
{
      CAutoMutex autoMutex(&m_Mutex);                 //To prevent multi-access to vector m_threads

      std::vector<APL_CrlDownload *>::iterator itr;
      APL_CrlDownload *pThread;
      
      //We loop 2 times through the vector.
      //The fisrt time we only run all the HighPriority threads
      itr = m_threads.begin();
      while(itr!=m_threads.end())
      {
            pThread=*itr;
            
            //If the thread is not yet started
            if(!pThread->isStarted())
            {
                  if(pThread->isHighPriority()) 
                  {
                        pThread->Start();             //Start the new thread
                        m_ulCurrentlyRunning++;
                  }
            }

            itr++;
      } 

      //Then if there is place for other threads
      //we made another vector for random selection
      if(m_ulCurrentlyRunning<m_ulMaxNumber)
      {
            std::vector<APL_CrlDownload *> listDownload;

            itr = m_threads.begin();
            while(itr!=m_threads.end())
            {
                  pThread=*itr;
                  
                  //If the thread is not yet started
                  if(!pThread->isStarted())
                  {
                        listDownload.push_back(pThread);
                  }
                  if(m_ulCurrentlyRunning>=m_ulMaxNumber)
                        break;

                  itr++;
            } 
            
            while(listDownload.size()>0 && m_ulCurrentlyRunning<m_ulMaxNumber) 
            {
                  int idx=(int)((double)listDownload.size()*(double)rand()/(double)RAND_MAX);

                  itr = listDownload.begin();
                  for(int i=0;i<idx;i++)
                  {
                        itr++;
                  }
                  pThread=*itr;

                  pThread->Start();             //Start the new thread
                  m_ulCurrentlyRunning++;

                  listDownload.erase(itr);
            }

      }
}

00597 void APL_DownloadControl::Stop()
{
      CThread::Stop();              //We ask for to stop to exit from the run loop
      deleteOldThreads(true);       //Then we delete all threads
}

/*****************************************************************************************
------------------------------------ APL_CrlDownloadingCache ---------------------------------------
*****************************************************************************************/
00606 APL_CrlDownloadingCache::APL_CrlDownloadingCache(APL_CryptoFwk *cryptoFwk)
{
      MWLOG(LEV_INFO, MOD_CRL, L"Create CrlDownloadingCache object");

      m_cryptoFwk=cryptoFwk;

      APL_Config conf_dir(CConfig::EIDMW_CONFIG_PARAM_CRL_CACHEDIR);     
      m_cachedirpath = conf_dir.getString();

      APL_Config conf_file(CConfig::EIDMW_CONFIG_PARAM_CRL_CACHEFILE);     

      m_crlextension = "crl";
      m_cachefilename = CPathUtil::getFullPath(m_cachedirpath.c_str(),conf_file.getString());

#ifdef WIN32
      m_cachefilelock=m_cachefilename;
      m_cachefilelock.append(".lck");
      m_flock=NULL;
#endif

      m_crlService=NULL;

      m_f=NULL;

      //Test if the directory exist
      CPathUtil::checkDir(m_cachedirpath.c_str());

      APL_CdcLine::setCache(this);
      APL_CdcLine::setCryptoFwk(m_cryptoFwk);

      //Start the threads
      startAllThreads();
}

00640 APL_CrlDownloadingCache::~APL_CrlDownloadingCache()
{
      if(m_f)                       //Should not happen
            closeCacheFile();

      stopAllThreads();

      resetLines();

      MWLOG(LEV_INFO, MOD_CRL, L"Delete CrlDownloadingCache object");
}

void APL_CrlDownloadingCache::startAllThreads()
{
      if(!m_crlService)
      {
            m_crlService=new APL_CrlService(this,m_cryptoFwk);
            m_crlService->Start();
      }

}

void APL_CrlDownloadingCache::stopAllThreads()
{

      if(m_crlService)
      {
            m_crlService->Stop();

            delete m_crlService;
            m_crlService=NULL;
      }
}

00674 void APL_CrlDownloadingCache::resetLines()
{
      std::map<std::string,APL_CdcLine *>::const_iterator itr;
      
      itr = m_lines.begin();
      while(itr!=m_lines.end())
      {
            delete itr->second;
            m_lines.erase(itr->first);
            itr = m_lines.begin();
      } 
}

00687 void APL_CrlDownloadingCache::refreshCache(bool &bStopRequest, bool bCleanUp)
{
      CAutoMutex autoMutex(&m_Mutex);                       //To prevent multi-access to cache file and vector m_lines
      
      //We load the cache
      if(!loadCacheFile())
      {
            closeCacheFile();
            return;
      }

      std::map<std::string,APL_CdcLine *>::iterator itr;
      APL_CdcLine *pLine;
      
      //Refresh all the lines
      itr = m_lines.begin();
      while(itr!=m_lines.end())
      {
            pLine=itr->second;

            //If the download has been started by the process that crash, it become High priority
            if(!bCleanUp && (pLine->isDownloadStarted() || pLine->isHighPriority() || pLine->isDownloadRequest()))
                  pLine->setDownloadRequest(true);
            else
                  pLine->setDownloadRequest(false);

            //No download currently exist
            pLine->setWaitingDownload(false);
            pLine->setHighPriority(false);
            pLine->setDownloadEndBefore("");
            pLine->setErrorCode(DOWNLOAD_STATUS_OK);  

            if(pLine->isValidityEmpty() && pLine->getFileExist())
                  pLine->updateValidity(getCacheDirPath());
            
            itr++;

            if(bStopRequest)
                  break;
      } 

      //Write the lines to the cache the unused lined are not saved
      writeCacheFile();

}

00733 void APL_CrlDownloadingCache::keepCacheSynchro(bool &bStopRequest)
{
//The cache file and the directories have to stay synchro
//So before checking we loop through directories to see if there is new file
      CAutoMutex autoMutex(&m_Mutex);                       //To prevent multi-access to cache file and vector m_lines

      //We load the cache
      if(!loadCacheFile())
      {
            closeCacheFile();
            return;
      }

      //Scan all the file in the cache and create the line if missing
      CPathUtil::scanDir(m_cachedirpath.c_str(),"",m_crlextension.c_str(),bStopRequest,this,&APL_CrlDownloadingCache::setFileExist);
 
      //Write the lines to the cache the unused lined are not saved
      writeCacheFile(true);
}

00753 void APL_CrlDownloadingCache::checkForDownload(bool &bStopRequest)
{

      CAutoMutex autoMutex(&m_Mutex);                             //To prevent multi-access to cache file and vector m_lines

      //Load the cache
      if(!loadCacheFile())
      {
            closeCacheFile();
            return;
      }

      std::map<std::string,APL_CdcLine *>::iterator itr;
      APL_CdcLine *pLine;
      bool bPush;
      bool bHighPriority;
      
      //Loop into the map and ask for download if validity expired
      itr = m_lines.begin();
      while(itr!=m_lines.end())
      {
            pLine=itr->second;

            bPush=false;
            bHighPriority=false;

            //If the flag download requested is set,
            //that means that someone is waiting for this crl
            //so we push the download with high priority
            if(pLine->isDownloadRequest())
            {
                  bPush=true;
                  bHighPriority=true;
            }
            else if(!pLine->isWaitingDownload())      //if download is already pushed => just wait
            {
                  if(!pLine->checkValidity())               //if validity is out of date => push
                  {
                        bPush=true;
                  }
            }

            if(bPush)
            {
                  //Ask for download
                  std::string relativePath=pLine->getRelativePath();
                  std::string fullPath=CPathUtil::getFullPath(m_cachedirpath.c_str(),relativePath.c_str());
                  std::string uri=CPathUtil::getUri(relativePath.c_str());

                  if(m_crlService->pushNewDownload(uri.c_str(),fullPath.c_str(),bHighPriority,this))
                  {
                        pLine->setWaitingDownload(true);
                        pLine->setHighPriority(bHighPriority);
                        pLine->setDownloadRequest(false);
                        pLine->setErrorCode(DOWNLOAD_STATUS_OK);        
                  }
            }

            itr++;

            if(bStopRequest)
                  break;
      } 

      writeCacheFile();
}
void APL_CrlDownloadingCache::notifyDownload(const char *uri,tDownloadNotify notify,const char *downloadValidity)
{
      CAutoMutex autoMutex(&m_Mutex);                                   //To prevent multi-access to cache file and vector m_lines

      if(!loadCacheFile())
      {
            closeCacheFile();
            return;
      }

      APL_CdcLine *pLine=findLineInCache(uri);

      switch(notify)
      {
      case DOWNLOAD_NOTIFY_BEGIN:
            pLine->setWaitingDownload(false);                           //Remove the downloading flag
            pLine->setDownloadEndBefore(downloadValidity);        //Download begins => put the flag for the download
            pLine->setErrorCode(DOWNLOAD_STATUS_OK);        
            break;

      case DOWNLOAD_NOTIFY_END_INTERRUPT:
            pLine->setWaitingDownload(false);                           //Remove the downloading flag
            pLine->setDownloadEndBefore("");          
            pLine->setErrorCode(DOWNLOAD_STATUS_OK);        
            break;

      case DOWNLOAD_NOTIFY_END_OK:
            pLine->setWaitingDownload(false);                           //Remove the downloading flag
            pLine->setHighPriority(false);                                    //Remove the HighPriority flag
            pLine->setDownloadEndBefore("");          
            pLine->setErrorCode(DOWNLOAD_STATUS_OK);        
            pLine->updateValidity(getCacheDirPath());             //Download ok => get the validity of the crl file
            break;

      case DOWNLOAD_NOTIFY_ERR_CONNECT:
            pLine->setWaitingDownload(false);                           //Remove the downloading flag
            pLine->setDownloadEndBefore("");          
            pLine->setErrorCode(DOWNLOAD_STATUS_ERR_CONNECT);     //Set ErrorCode to 1
            break;
      }
      writeCacheFile();
}

00862 APL_CdcLine *APL_CrlDownloadingCache::findLineInCache(const char *uri)
{
      if(!m_f)    //The cache file MUST be open
            throw CMWEXCEPTION(EIDMW_ERR_CHECK);

      std::map<std::string,APL_CdcLine *>::iterator itr;
      APL_CdcLine *pLine=NULL;
      std::string relativePath=CPathUtil::getRelativePath(uri);

      itr = m_lines.find(relativePath);
      if(itr==m_lines.end())
      {
            //If not yet in the cache, we create the line
        pLine=new APL_CdcLine(relativePath);
        m_lines[relativePath]=pLine;
      }
      else
      {
            pLine=itr->second;
      }

      return pLine;
}

//The validation of the crl goes wrong (date or signature problem)
//so the download is request
00888 void APL_CrlDownloadingCache::forceCacheUpdate(const char *uri,bool bHighPriority)
{
      CAutoMutex autoMutex(&m_Mutex);                                   //To prevent multi-access to cache file and vector m_lines

      if(!loadCacheFile())
      {
            closeCacheFile();
            return;
      }

      APL_CdcLine *pLine=findLineInCache(uri);

      //if download already start => Do nothing
      //Else =>   Set the download request flag
      if(!pLine->isDownloadStarted())
      {
            pLine->setDownloadRequest(true);
      }

      writeCacheFile();
}

00910 tDownloadStatus APL_CrlDownloadingCache::getCrlDataFromUri(const char *uri, CByteArray &data)
{
      tDownloadStatus eDownloadStatus=DOWNLOAD_STATUS_ERR_UNKNOWN;
      bool bWait=true;
      bool bWrite;
      bool bRequested=false;

      MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromUri: CRL asked URI=%ls",utilStringWiden(uri).c_str());

      std::string file=CPathUtil::getFullPathFromUri(m_cachedirpath.c_str(),uri);

      while(bWait)
      {
            {     //MUTEX SECTION
                  CAutoMutex autoMutex(&m_Mutex);

                  bWrite=false;

                  if(loadCacheFile())
                  {
                        MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromUri: Load cache file status ok");

                        APL_CdcLine *pLine=findLineInCache(uri);

                        if(bRequested && pLine->getErrorCode()!=DOWNLOAD_STATUS_OK) //If request but error =>return the error
                        {
                              MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromUri: Already requested but error occured");
                              eDownloadStatus=pLine->getErrorCode();
                              bWait=false;
                        }
                        else if(pLine->isDownloadNeedToWait())          //If the download is request or already started => we just need to wait
                        {
                              MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromUri: Wait while downloading");
                        }
                        else if(pLine->isWaitingDownload())       //If the download is waiting => we force the request (High priority)    
                        {
                              if(!pLine->isHighPriority())
                              {
                                    MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromUri: High priority => Force download request");
                                    pLine->setDownloadRequest(true);
                                    pLine->setErrorCode(DOWNLOAD_STATUS_OK);  
                                    bWrite=true;
                              }
                        }
                        else                                                  //Else the file in the directory is up to date
                        {
                              MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromUri: Get file from cache directory");
                              if(!getCrlDataFromFile(file.c_str(),data))
                              {
                                    MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromUri: File out of date => Force download request");
                                    pLine->setDownloadRequest(true);
                                    pLine->setErrorCode(DOWNLOAD_STATUS_OK);  
                                    bWrite=true;
                              }
                              else
                              {
                                    eDownloadStatus=DOWNLOAD_STATUS_OK;
                                    bWait=false;
                              }
                        }

                        if(bWrite)
                        {
                              writeCacheFile();
                              MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromUri: Write cache file status");
                        }
                        else
                        {
                              closeCacheFile();
                              MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromUri: Close cache file status");
                        }
                  }
                  else
                  {
                        closeCacheFile();
                  }

            }

            if(bWait)
                  CThread::SleepMillisecs(100);

            bRequested=true;
      }

      MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromUri: Return status=%ld",eDownloadStatus);
      return eDownloadStatus;
}

bool APL_CrlDownloadingCache::getCrlDataFromFile(const char *file, CByteArray &crl)
01000 {
      FILE *f=NULL;

      MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromFile: File asked=%ls",utilStringWiden(file).c_str());

#ifdef WIN32
      errno_t errcode=fopen_s(&f,file, "rb");
      if (errcode != 0) return false;                                         // Added for unit testing
#else
      f = fopen(file, "rb");
      if (f == NULL) return false;                    
#endif

      if(NULL != f)
      {
            MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromFile: File open");
            size_t size = 0;
#ifdef WIN32
            struct _stat buf = {0};
            if(0 == _fstat(_fileno(f), &buf))
#else
            struct stat buf = {0};
                  if(0 == fstat(fileno(f), &buf))
#endif
            {
                  unsigned char *pBuffer = (unsigned char *)malloc(buf.st_size);
                  MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromFile: Memory allocated to buffer (%ld bytes)",buf.st_size);

                  size = fread(pBuffer, sizeof(unsigned char), buf.st_size, f);
                  MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromFile: Read data from file (asked for %ld => received %ld)",buf.st_size,size);

                        if(size == (size_t)buf.st_size)
                        {     
                        crl.Append(pBuffer,(long)size);
                        MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromFile: Append data to buffer");
                  }
            }
                  fclose(f);
            MWLOG(LEV_DEBUG, MOD_CRL, L"APL_CrlDownloadingCache::getCrlDataFromFile: Close file");
      }

      return true;
}

void APL_CrlDownloadingCache::setFileExist(const char *SubDir, const char *File, void *param)
01045 {
  std::map<std::string,APL_CdcLine *>::const_iterator itr;
  APL_CrlDownloadingCache *pCache = static_cast < APL_CrlDownloadingCache * > ( param );
  APL_CdcLine *pLine;
  
  std::string path=SubDir;
  
#ifdef WIN32
  path+=(strlen(SubDir)!=0?"\\":"");
#else
  path+=(strlen(SubDir)!=0 ? "/" : "");
#endif
  path+=File;
  
  if(pCache != NULL){
    itr = pCache->m_lines.find(path);
  
    if(itr==pCache->m_lines.end())
      {
        pLine=new APL_CdcLine(path);
        pCache->m_lines[path]=pLine;
            pLine->updateValidity(pCache->getCacheDirPath());
      }
    else
      {
        pLine=itr->second;
      }
    
    pLine->setFileExist(true);
   } 
}

bool APL_CrlDownloadingCache::loadCacheFile()
01078 {
      //If the file is already open, it's an implementation problem
      if(m_f)
      {
            MWLOG(LEV_ERROR, MOD_CRL, L"APL_CrlDownloadingCache::loadCacheFile: File already loaded");
            throw CMWEXCEPTION(EIDMW_ERR_CHECK);
      }

#ifdef WIN32
      //On Windows, we can't reopen an hidden file. We have to remove it then open it again.
      //That make a concurency hole in the write cache file if we put the lock on the cache file it self
      // so we use an other file explicitely for that
      if(m_flock)
      {
            MWLOG(LEV_ERROR, MOD_CRL, L"APL_CrlDownloadingCache::loadCacheFile: File already locked");
            throw CMWEXCEPTION(EIDMW_ERR_CHECK);
      }
#endif

      resetLines();

      char line[CDC_MAX_LINE_LENGHT];
      APL_CdcLine *pLine;
      int err=0;

      int iLoop;

#ifdef WIN32
      iLoop=0;
      do
      {
            remove(m_cachefilelock.c_str());
            err = fopen_s(&m_flock, m_cachefilelock.c_str(), "w");

            if(err==EACCES) 
                  CThread::SleepMillisecs(10);

            iLoop++;
      } while(err==EACCES && iLoop<500);

      if(err==EACCES)
      {
            MWLOG(LEV_ERROR, MOD_CRL, L"Could not open the lock file '%s'",utilStringWiden(m_cachefilelock).c_str());
            return false;
      }

      _lock_file(m_flock);
      SetFileAttributesA(m_cachefilelock.c_str(),FILE_ATTRIBUTE_HIDDEN);
#else
      m_tFlCache.l_type   = F_RDLCK;  /* F_RDLCK, F_WRLCK, F_UNLCK    */
      m_tFlCache.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */
      m_tFlCache.l_start  = 0;        /* Offset from l_whence         */
      m_tFlCache.l_len    = 0;        /* length, 0 = to EOF           */
      m_tFlCache.l_pid    = getpid(); /* our PID                      */
#endif

      iLoop=0;
      do
      {
#ifdef WIN32
            err = fopen_s(&m_f, m_cachefilename.c_str(), "r");
#else
            m_f = fopen(m_cachefilename.c_str(), "r");
            err = m_f == NULL ? errno : 0;
#endif
            if (err != 0 && err != EACCES && err != ENOENT )
            {
                  MWLOG(LEV_ERROR, MOD_CRL, L"Could not open CRL downloading cache file for reading '%s'",utilStringWiden(m_cachefilename).c_str());
                  return false;
            }

            if(err==EACCES) 
                  CThread::SleepMillisecs(10);

            iLoop++;
      } while(err==EACCES && iLoop<500);

      if(err==EACCES)
      {
            MWLOG(LEV_ERROR, MOD_CRL, L"Could not access CRL downloading cache file for reading '%s'",utilStringWiden(m_cachefilename).c_str());
            return false;
      }

      //If the file doesn't exist, we create it
      if(m_f==NULL)
      {
#ifdef WIN32
            err = fopen_s(&m_f, m_cachefilename.c_str(), "w");
            SetFileAttributesA(m_cachefilename.c_str(),FILE_ATTRIBUTE_HIDDEN);
#else
            m_f = fopen(m_cachefilename.c_str(), "w");
            err = m_f == NULL ? errno : 0;
#endif
            if (err != 0)
            {
                  MWLOG(LEV_ERROR, MOD_CRL, L"Could not create CRL downloading cache file '%s'",utilStringWiden(m_cachefilename).c_str());
                  return false;
            }
            
#ifndef WIN32
            m_tFlCache.l_type   = F_WRLCK; // has to be the same type as the mode used to open the file
#endif
      }

      if(m_f==NULL)
      {
            MWLOG(LEV_ERROR, MOD_CRL, L"Could not open CRL downloading cache file for reading '%s'",utilStringWiden(m_cachefilename).c_str());
            return false;
      }
      
      
#ifdef WIN32
#else 
      // on Linux/Mac we set an advisory lock, i.e. it prevents
      // other processes from using the file only if they are collaborative 
      // and check for the lock, otherwise they can do whatever they like ..
      
      if( fcntl(fileno(m_f), F_SETLKW, &m_tFlCache) == -1){  /* set the lock, waiting if necessary */
        printf("APL_CrlDownloadingCache::loadCacheFile file 0x%0x fcntl: %s\n",(unsigned int)m_f,strerror(errno));
        exit(1);
      }
#endif

    while( fgets (line, CDC_MAX_LINE_LENGHT, m_f) != NULL ) 
      {
            pLine=new APL_CdcLine(line);
            m_lines[pLine->getRelativePath()]=pLine;
      }

      return true;
}

bool APL_CrlDownloadingCache::writeCacheFile(bool bCleanUp)
01211 {
#ifdef WIN32
      if(!m_flock)
      {
            MWLOG(LEV_ERROR, MOD_CRL, L"APL_CrlDownloadingCache::writeCacheFile: File not locked");
            throw CMWEXCEPTION(EIDMW_ERR_CHECK);
      }
#endif

#ifdef WIN32
      fclose(m_f);      //As the file is set with hidden attribute, we need to remove it before open it in write mode
      remove(m_cachefilename.c_str());
      int res = fopen_s(&m_f, m_cachefilename.c_str(), "w");
      if (res == 0)
      {
            SetFileAttributesA(m_cachefilename.c_str(),FILE_ATTRIBUTE_HIDDEN);
      }
      else
#else
      m_f = freopen(m_cachefilename.c_str(), "w",m_f);
      if (m_f == NULL)        
#endif
      {
            MWLOG(LEV_ERROR, MOD_CRL, L"Could not open CRL downloading cache file for writing '%s'",utilStringWiden(m_cachefilename).c_str());
            m_f=NULL;
            return false;
      }

      std::map<std::string,APL_CdcLine *>::const_iterator itr;
      
      itr = m_lines.begin();
      while(itr!=m_lines.end())
      {
            if(!bCleanUp || itr->second->getFileExist())
            {
                  itr->second->writeLine(m_f);
            }
            itr++;
      } 

      return closeCacheFile();
}

bool APL_CrlDownloadingCache::closeCacheFile()
01255 {
      if(m_f)
      {
#ifndef WIN32
            m_tFlCache.l_type   = F_UNLCK;  /* tell it to unlock the region */
            
            if( fcntl(fileno(m_f), F_SETLK, &m_tFlCache) == -1){ /* set the region to unlocked */
              printf("APL_CrlDownloadingCache::closeCacheFile fcntl: %s\n",strerror(errno));
              exit(1);
            }
#endif
            fclose(m_f);
      }

      m_f=NULL;

#ifdef WIN32
      if(m_flock)
      {
            _unlock_file(m_flock);
            fclose(m_flock);
            m_flock=NULL;
      }
#endif

      return true;
}

const char *APL_CrlDownloadingCache::getCacheDirPath()
01284 {
      return m_cachedirpath.c_str();
}

/*****************************************************************************************
------------------------------------ APL_CdcLine ---------------------------------------
*****************************************************************************************/
APL_CrlDownloadingCache *APL_CdcLine::m_cache=NULL;
APL_CryptoFwk *APL_CdcLine::m_cryptoFwk=NULL;

//Take a line from the file cache and split it into field
APL_CdcLine::APL_CdcLine(const char *lineIn)
01296 {
      const int NbrField=7;

      char line[CDC_MAX_LINE_LENGHT];

      int i;
      int sep=0;
      char *field[NbrField];

      field[sep++]=&line[0];

      for(i=0;i<CDC_MAX_LINE_LENGHT-1;i++)
      {
            if(lineIn[i]=='\n' || lineIn[i]=='\0')
            {
                  break;
            }
            else if(lineIn[i]=='|')
            {
                  if(sep>=NbrField)
                        break;
                  line[i]='\0';
                  field[sep++]=&line[i+1];
            }
            else
            {
                  line[i]=lineIn[i];
            }
      }
      line[i]='\0';

      if(sep==NbrField)
      {
            m_RelativePath.assign(field[0]);
            m_Validity.assign(field[1]); 
            m_WaitingDownload=(strcmp(field[2],"1")==0?true:false); 
            m_HighPriority=(strcmp(field[3],"1")==0?true:false); 
            m_DownloadEndBefore.assign(field[4]); 
            m_DownloadRequest=(strcmp(field[5],"1")==0?true:false); 
            m_ErrorCode=(tDownloadStatus)atoi(field[6]);
      }
      else
      {     
            m_RelativePath="";
            m_Validity=""; 
            m_WaitingDownload=false;
            m_HighPriority=false;
            m_DownloadEndBefore="";
            m_DownloadRequest=false;
            m_ErrorCode=DOWNLOAD_STATUS_OK;
      }

      m_fileExist=false;
}

APL_CdcLine::APL_CdcLine(const std::string &relativePath)
01352 {
      m_RelativePath=relativePath;
      m_Validity=""; 
      m_WaitingDownload=false;
      m_HighPriority=false;
      m_DownloadEndBefore="";
      m_DownloadRequest=false;
      m_ErrorCode=DOWNLOAD_STATUS_OK;

      m_fileExist=false;
}

APL_CdcLine::~APL_CdcLine()
01365 {
}

//Two lines are equal if the Path are equal
bool APL_CdcLine::operator== (const APL_CdcLine& cvcline)
01370 {
      return isEqual(cvcline.m_RelativePath);
}

bool APL_CdcLine::isEqual (const std::string &relativePath)
01375 {
      if(m_RelativePath.compare(relativePath))
            return true;
      else 
            return false;
}

void APL_CdcLine::updateValidity(const std::string &cachedirpath)
01383 {
#ifdef WIN32
      std::string fullpath=cachedirpath + "\\" + m_RelativePath;
#else
      std::string fullpath= cachedirpath + "/" + m_RelativePath;
#endif
      std::string validityLastUpdate;
      std::string validityNextUpdate;

      CByteArray crl;

      if(m_cache->getCrlDataFromFile(fullpath.c_str(),crl))
      {
            tCrlInfo info;
            m_cryptoFwk->getCrlInfo(crl,info,CDC_VALIDITY_FORMAT);

            m_Validity=info.validityNextUpdate;
      }
}

//PRIVATE: return true is Line Validity > now
bool APL_CdcLine::checkValidity()
01405 {
      return CTimestampUtil::checkTimestamp(m_Validity,CDC_VALIDITY_FORMAT);
}

//Set DownloadEndBefore timestamp in format YYYYMMDDThhmmss by default
void APL_CdcLine::setDownloadEndBefore(const char *downloadValidity)
01411 {
      m_DownloadEndBefore=downloadValidity;
}

//PRIVATE: return true is DownloadEndBefore > now
bool APL_CdcLine::checkDownloadEndBefore()
01417 {
      return CTimestampUtil::checkTimestamp(m_DownloadEndBefore,CDC_VALIDITY_FORMAT);
}

void APL_CdcLine::writeLine(FILE *f)
01422 {
#ifdef WIN32
      fprintf_s(f,"%s|%s|%d|%d|%s|%d|%lu\n",m_RelativePath.c_str(),m_Validity.c_str(),(m_WaitingDownload?1:0),(m_HighPriority?1:0),m_DownloadEndBefore.c_str(),(m_DownloadRequest?1:0),m_ErrorCode);
#else
      fprintf(f,"%s|%s|%d|%d|%s|%d|%u\n",m_RelativePath.c_str(),m_Validity.c_str(),(m_WaitingDownload?1:0),(m_HighPriority?1:0),m_DownloadEndBefore.c_str(),(m_DownloadRequest?1:0),m_ErrorCode);
#endif
}

}

Generated by  Doxygen 1.6.0   Back to index