• Main Page
  • Related Pages
  • Modules
  • Classes
  • Files
  • Directories

CAAccountingInstance.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2000, The JAP-Team All rights reserved.
00003 Redistribution and use in source and binary forms, with or without
00004 modification, are permitted provided that the following conditions are
00005 met:
00006 
00007 - Redistributions of source code must retain the above copyright
00008 notice, this list of conditions and the following disclaimer.
00009 
00010 - Redistributions in binary form must reproduce the above
00011 copyright notice, this list of conditions and the following
00012 disclaimer in the documentation and/or other materials provided
00013 with the distribution.
00014 
00015 - Neither the name of the University of Technology Dresden,
00016 Germany nor the names of its contributors may be used to endorse
00017 or promote products derived from this software without specific
00018 prior written permission.
00019 
00020 
00021 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00024 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
00025 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00026 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00027 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00028 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00029 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00030 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00031 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
00032 */
00033 #include "StdAfx.h"
00034 #ifdef PAYMENT
00035 
00036 #include "CAAccountingInstance.hpp"
00037 #include "CAAccountingControlChannel.hpp"
00038 #include "CABase64.hpp"
00039 #include "CAMsg.hpp"
00040 #include "CAUtil.hpp"
00041 #include "CASignature.hpp"
00042 #include "CAThreadPool.hpp"
00043 #include "CAXMLErrorMessage.hpp"
00044 #include "Hashtable.hpp"
00045 #include "packetintro.h"
00046 #include "CALibProxytest.hpp"
00047 
00048 //for testing purposes only
00049 #define JAP_DIGEST_LENGTH 28
00050 
00051 XERCES_CPP_NAMESPACE::DOMDocument* CAAccountingInstance::m_preparedCCRequest;
00052 
00053 const SINT32 CAAccountingInstance::HANDLE_PACKET_CONNECTION_OK = 1;
00054 const SINT32 CAAccountingInstance::HANDLE_PACKET_CONNECTION_UNCHECKED = 4;
00055 const SINT32 CAAccountingInstance::HANDLE_PACKET_HOLD_CONNECTION = 0;
00056 const SINT32 CAAccountingInstance::HANDLE_PACKET_PREPARE_FOR_CLOSING_CONNECTION = 2;
00057 const SINT32 CAAccountingInstance::HANDLE_PACKET_CLOSE_CONNECTION = 3;
00058 
00059 SINT32 CAAccountingInstance::m_prepaidBytesMinimum = 0;
00060 
00061 volatile UINT64 CAAccountingInstance::m_iCurrentSettleTransactionNr = 0;
00062 
00066 CAAccountingInstance * CAAccountingInstance::ms_pInstance = NULL;
00067 
00068 const UINT64 CAAccountingInstance::PACKETS_BEFORE_NEXT_CHECK = 100;
00069 
00070 const UINT32 CAAccountingInstance::MAX_TOLERATED_MULTIPLE_LOGINS = 10;
00071 
00072 const UINT32 CAAccountingInstance::MAX_SETTLED_CCS = 10;
00073 
00077 CAAccountingInstance::CAAccountingInstance(CAFirstMix* callingMix)
00078   {
00079     CAMsg::printMsg( LOG_DEBUG, "AccountingInstance initialising\n" );
00080     m_seqBIConnErrors = 0;
00081     m_pMutex = new CAMutex();
00082     //m_pIPBlockList = new CATempIPBlockList(60000);
00083     m_pSettlementMutex = new CAConditionVariable();
00084     //m_loginHashTableChangeInProgress = false; //for synchronizing settlementTransactions of loginThreads and SettlementThread.
00085     m_nextSettleNr = 0; //The next thread's number to alter the login hash table
00086     m_settleWaitNr = 0; //The wait number when it is equal to nextSettle number it's the thread's turn has to to
00087               //alter the login hash table
00088     // initialize Database connection
00089     //m_dbInterface = new CAAccountingDBInterface();
00090     m_pPiInterface = new CAAccountingBIInterface();
00091     m_mix = callingMix;
00092     /*if(m_dbInterface->initDBConnection() != E_SUCCESS)
00093     {
00094       CAMsg::printMsg( LOG_ERR, "**************** AccountingInstance: Could not connect to DB!\n");
00095       exit(1);
00096     }*/
00097 
00098     // initialize JPI signature tester
00099     m_AiName = new UINT8[256];
00100     CALibProxytest::getOptions()->getAiID(m_AiName, 256);
00101     if (CALibProxytest::getOptions()->getBI() != NULL)
00102     {
00103       //m_pJpiVerifyingInstance = CALibProxytest::getOptions()->getBI()->getVerifier();
00104       m_pPiInterface->setPIServerConfiguration(CALibProxytest::getOptions()->getBI());
00105     }
00106     m_iHardLimitBytes = CALibProxytest::getOptions()->getPaymentHardLimit();
00107     m_iSoftLimitBytes = CALibProxytest::getOptions()->getPaymentSoftLimit();
00108 
00109     prepareCCRequest(callingMix, m_AiName);
00110 
00111     m_currentAccountsHashtable =
00112       new Hashtable((UINT32 (*)(void *))Hashtable::hashUINT64, (SINT32 (*)(void *,void *))Hashtable::compareUINT64, 2000);
00113 
00114     m_certHashCC =
00115       new Hashtable((UINT32 (*)(void *))Hashtable::stringHash, (SINT32 (*)(void *,void *))Hashtable::stringCompare);
00116     for (UINT32 i = 0; i < m_allHashesLen; i++)
00117     {
00118       m_certHashCC->put(m_allHashes[i], m_allHashes[i]);
00119     }
00120 
00121     // launch BI settleThread
00122     m_pSettleThread = new CAAccountingSettleThread(m_currentAccountsHashtable,
00123                             m_currentCascade);
00124 
00125     m_aiThreadPool = new CAThreadPool(NUM_LOGIN_WORKER_TRHEADS, MAX_LOGIN_QUEUE, false);
00126   }
00127 
00128 
00132 CAAccountingInstance::~CAAccountingInstance()
00133   {
00134     INIT_STACK;
00135     BEGIN_STACK("~CAAccountingInstance");
00136 
00137     /*
00138      * avoid calling this desctructor concurrently!
00139      */
00140     m_pMutex->lock();
00141 
00142     CAMsg::printMsg( LOG_DEBUG, "AccountingInstance dying\n" );
00143     if (m_pSettleThread)
00144     {
00145       CAMsg::printMsg( LOG_DEBUG, "deleting m_pSettleThread\n" );
00146       //m_pSettleThread->settle();
00147       delete m_pSettleThread;
00148       m_pSettleThread = NULL;
00149     }
00150 
00151     if (m_aiThreadPool)
00152     {
00153       CAMsg::printMsg( LOG_DEBUG, "deleting m_aiThreadPool\n" );
00154       delete m_aiThreadPool;
00155       m_aiThreadPool = NULL;
00156     }
00157 
00158     /*if (m_dbInterface)
00159     {
00160       CAMsg::printMsg( LOG_DEBUG, "termintaing dbConnection\n" );
00161       m_dbInterface->terminateDBConnection();
00162       delete m_dbInterface;
00163     }
00164     m_dbInterface = NULL;*/
00165 
00166 
00167     delete m_pPiInterface;
00168     m_pPiInterface = NULL;
00169 
00170     delete m_pSettlementMutex;
00171     m_pSettlementMutex = NULL;
00172     //delete m_pIPBlockList;
00173     //m_pIPBlockList = NULL;
00174 
00175 
00176     delete[] m_AiName;
00177     m_AiName = NULL;
00178 
00179     if (m_currentAccountsHashtable)
00180     {
00181       m_currentAccountsHashtable->getMutex()->lock();
00182       CAMsg::printMsg( LOG_DEBUG, "CAAccountingInstance: Clearing accounts hashtable...\n");
00183       m_currentAccountsHashtable->clear(HASH_EMPTY_NONE, HASH_EMPTY_DELETE);
00184       CAMsg::printMsg( LOG_DEBUG, "CAAccountingInstance: Deleting accounts hashtable...\n" );
00185       m_currentAccountsHashtable->getMutex()->unlock();
00186       delete m_currentAccountsHashtable;
00187       m_currentAccountsHashtable = NULL;
00188     }
00189     m_currentAccountsHashtable = NULL;
00190     CAMsg::printMsg( LOG_DEBUG, "CAAccountingInstance: Accounts hashtable deleted.\n" );
00191 
00192     delete[] m_currentCascade;
00193     m_currentCascade = NULL;
00194 
00195     if(m_certHashCC != NULL)
00196     {
00197       for (UINT32 i = 0; i < m_allHashesLen; i++)
00198       {
00199         UINT8* certHash = (UINT8*)m_certHashCC->remove(m_allHashes[i]);
00200       }
00201       m_certHashCC->clear(HASH_EMPTY_NONE, HASH_EMPTY_DELETE);
00202       delete m_certHashCC;
00203       m_certHashCC = NULL;
00204     }
00205 
00206     if (m_allHashes)
00207     {
00208       for (UINT32 i = 0; i < m_allHashesLen; i++)
00209       {
00210         delete m_allHashes[i];
00211         m_allHashes[i] = NULL;
00212       }
00213       delete[] m_allHashes;
00214     }
00215     m_allHashes = NULL;
00216 
00217     m_pMutex->unlock();
00218 
00219     delete m_pMutex;
00220     m_pMutex = NULL;
00221     FINISH_STACK("~CAAccountingInstance");
00222 
00223     CAMsg::printMsg( LOG_DEBUG, "AccountingInstance dying finished.\n" );
00224   }
00225 
00226 UINT32 CAAccountingInstance::getAuthFlags(fmHashTableEntry * pHashEntry)
00227 {
00228   if (pHashEntry == NULL)
00229   {
00230     return 0;
00231   }
00232 
00233   tAiAccountingInfo* pAccInfo = pHashEntry->pAccountingInfo;
00234 
00235   if (pAccInfo == NULL)
00236   {
00237     return 0;
00238   }
00239 
00240   return pAccInfo->authFlags;
00241 }
00242 
00243 UINT32 CAAccountingInstance::getNrOfUsers()
00244 {
00245   UINT32 users = 0;
00246 
00247   if (ms_pInstance != NULL)
00248   {
00249     ms_pInstance->m_pMutex->lock();
00250     if(ms_pInstance->m_currentAccountsHashtable != NULL)
00251     {
00252       // getting the size is an atomic operation and does not need synchronization
00253       users = ms_pInstance->m_currentAccountsHashtable->getSize();
00254     }
00255     else
00256     {
00257       CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Trying to access Hashtable after it has been disposed!!.\n");
00258     }
00259     ms_pInstance->m_pMutex->unlock();
00260   }
00261 
00262   return users;
00263 }
00264 
00265 
00266 THREAD_RETURN CAAccountingInstance::processThread(void* a_param)
00267 {
00268   INIT_STACK;
00269   BEGIN_STACK("CAAccountingInstance::processThread");
00270 
00271   aiQueueItem* item = (aiQueueItem*)a_param;
00272   bool bDelete = false;
00273   DOMElement *elem = item->pDomDoc->getDocumentElement();
00274 
00275   // call the handle function
00276   (ms_pInstance->*(item->handleFunc))(item->pAccInfo, elem);
00277 
00278   item->pAccInfo->mutex->lock();
00279   item->pAccInfo->nrInQueue--;
00280   if (item->pAccInfo->authFlags & AUTH_DELETE_ENTRY &&
00281     item->pAccInfo->nrInQueue == 0)
00282   {
00283     /*
00284      * There is no more entry of this connection in the queue,
00285      * and the connection is closed. We have to delete the entry.
00286      */
00287     bDelete = true;
00288     CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Deleting account entry from AI thread.\n");
00289   }
00290 
00291   if (item->pAccInfo->nrInQueue < 0)
00292   {
00293     CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: AI thread found negative handle queue!\n");
00294   }
00295   item->pAccInfo->mutex->unlock();
00296 
00297   if (bDelete)
00298   {
00299     delete item->pAccInfo->mutex;
00300     item->pAccInfo->mutex = NULL;
00301     delete item->pAccInfo;
00302     item->pAccInfo = NULL;
00303   }
00304 
00305   delete item->pDomDoc;
00306   item->pDomDoc = NULL;
00307   delete item;
00308   item = NULL;
00309 
00310   FINISH_STACK("CAAccountingInstance::processThread");
00311 
00312   THREAD_RETURN_SUCCESS;
00313 }
00314 
00315 SINT32 CAAccountingInstance::handleJapPacket(fmHashTableEntry *pHashEntry, bool a_bControlMessage, bool a_bMessageToJAP)
00316 {
00317   SINT32 ret = handleJapPacket_internal(pHashEntry, a_bControlMessage, a_bMessageToJAP);
00318 
00319   INIT_STACK;
00320   FINISH_STACK("CAAccountingInstance::handleJapPacket");
00321 
00322   return ret;
00323 }
00324 
00335 SINT32 CAAccountingInstance::handleJapPacket_internal(fmHashTableEntry *pHashEntry, bool a_bControlMessage, bool a_bMessageToJAP)
00336   {
00337     INIT_STACK;
00338     BEGIN_STACK("CAAccountingInstance::handleJapPacket");
00339 
00340     CAAccountingDBInterface *dbInterface = NULL;
00341 
00342     if (pHashEntry == NULL || pHashEntry->pAccountingInfo == NULL)
00343     {
00344       return HANDLE_PACKET_CLOSE_CONNECTION;
00345     }
00346 
00347     tAiAccountingInfo* pAccInfo = pHashEntry->pAccountingInfo;
00348     AccountLoginHashEntry* loginEntry = NULL;
00349     CAXMLErrorMessage* err = NULL;
00350 
00351     pAccInfo->mutex->lock();
00352 
00353     if (pAccInfo->authFlags & AUTH_DELETE_ENTRY)
00354     {
00355       pAccInfo->mutex->unlock();
00356       return HANDLE_PACKET_CLOSE_CONNECTION;
00357     }
00358 
00359     //Should never happen since control flow assert that this method cannot be invoked
00360     //when a login is not finished.
00361     if ( (pAccInfo->authFlags & AUTH_LOGIN_NOT_FINISHED) && !a_bMessageToJAP )
00362     {
00363       CAMsg::printMsg(LOG_ERR, "CAAccountingInstance:  User violates login protocol");
00364       pAccInfo->mutex->unlock();
00365       return HANDLE_PACKET_CLOSE_CONNECTION;
00366     }
00367 
00368     //still preparing to close connection -> no data is forwarded upstream and only control messages are
00369     //sent downstream if a user connection is in this state.
00370     if ( pAccInfo->authFlags & AUTH_FATAL_ERROR )
00371     {
00372       pAccInfo->mutex->unlock();
00373       return HANDLE_PACKET_PREPARE_FOR_CLOSING_CONNECTION;
00374     }
00375 
00376     if (a_bControlMessage)
00377     {
00378       pAccInfo->mutex->unlock();
00379       return HANDLE_PACKET_CONNECTION_UNCHECKED;
00380     }
00381     else
00382     {
00383        // count the packet and continue checkings
00384       pAccInfo->transferredBytes += MIXPACKET_SIZE;
00385       pAccInfo->sessionPackets++;
00386 #ifdef SDTFA
00387       IncrementShmPacketCount();
00388 #endif
00389     }
00390 
00391     if (pAccInfo->authFlags & AUTH_MULTIPLE_LOGIN)
00392     {
00393       return returnPrepareKickout(pAccInfo, new CAXMLErrorMessage(CAXMLErrorMessage::ERR_MULTIPLE_LOGIN, (UINT8*)"Only one login per account is allowed!"));
00394     }
00395 
00396     // do the following tests after a lot of Mix packets only (gain speed...)
00397     if (!(pAccInfo->authFlags & (AUTH_TIMEOUT_STARTED | AUTH_HARD_LIMIT_REACHED | AUTH_ACCOUNT_EMPTY | AUTH_WAITING_FOR_FIRST_SETTLED_CC)) &&
00398       pAccInfo->sessionPackets % PACKETS_BEFORE_NEXT_CHECK != 0)
00399     {
00400       //CAMsg::printMsg( LOG_DEBUG, "Now we gain some speed after %d session packets..., auth-flags: %x\n", pAccInfo->sessionPackets, pAccInfo->authFlags);
00401       pAccInfo->mutex->unlock();
00402       return HANDLE_PACKET_CONNECTION_UNCHECKED;
00403     }
00404 
00405 
00406     SAVE_STACK("CAAccountingInstance::handleJapPacket", "before accounts hash");
00407 
00408     if (!ms_pInstance->m_currentAccountsHashtable)
00409     {
00410       // accounting instance is dying...
00411       return returnKickout(pAccInfo);
00412     }
00413 
00414     ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
00415     //Suppose, this section checks the flags set after settlement */
00416     loginEntry = (AccountLoginHashEntry*)ms_pInstance->m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
00417     if (loginEntry)
00418     {
00419       pAccInfo->authFlags &= ~loginEntry->authRemoveFlags;
00420       //CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Remove flag: %d\n", loginEntry->authRemoveFlags);
00421 
00422 
00423       /*if (loginEntry->ownerRef != pHashEntry)
00424       {
00425         // this is not the latest connection of this user; kick him out...
00426         pAccInfo->authFlags |= AUTH_MULTIPLE_LOGIN;
00427         ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
00428         return returnPrepareKickout(pAccInfo, new CAXMLErrorMessage(CAXMLErrorMessage::ERR_MULTIPLE_LOGIN, (UINT8*)"Only one login per account is allowed!"));
00429       }
00430       else */
00431       if (loginEntry->authFlags & AUTH_OUTDATED_CC)
00432       {
00433         loginEntry->authFlags &= ~AUTH_OUTDATED_CC;
00434 
00435         UINT8 tmp[32];
00436         print64(tmp,pAccInfo->accountNumber);
00437         CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Fixing bytes from outdated CC for account %s...\n", tmp);
00438         // we had stored an outdated CC; insert confirmed bytes from current CC here and also update client
00439         CAXMLCostConfirmation * pCC = NULL;
00440         bool bSettled;
00441 
00442         dbInterface = CAAccountingDBInterface::getConnection();//new CAAccountingDBInterface();
00443         if(dbInterface != NULL)
00444         {
00445           dbInterface->getCostConfirmation(pAccInfo->accountNumber,
00446                            ms_pInstance->m_currentCascade,
00447                            &pCC,
00448                            bSettled);
00449           CAAccountingDBInterface::releaseConnection(dbInterface);
00450           dbInterface = NULL;
00451         }
00452         /*ms_pInstance->m_dbInterface->getCostConfirmation(pAccInfo->accountNumber,
00453           ms_pInstance->m_currentCascade, &pCC, bSettled);*/
00454 
00455         if (pCC != NULL)
00456         {
00457           if (bSettled)
00458           {
00459             pAccInfo->transferredBytes += loginEntry->confirmedBytes - pAccInfo->confirmedBytes;
00460             pAccInfo->confirmedBytes = loginEntry->confirmedBytes;
00461             loginEntry->confirmedBytes = 0;
00462             pAccInfo->authFlags |= AUTH_SENT_CC_REQUEST;
00463             pAccInfo->pControlChannel->sendXMLMessage(pCC->getXMLDocument());
00464           }
00465           else
00466           {
00467             CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: While trying to fix bytes from outdated CC,"
00468               "another CC was received! Waiting for settlement... \n");
00469           }
00470           delete pCC;
00471           pCC = NULL;
00472         }
00473         else
00474         {
00475           CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Bytes from outdated CC could not be fixed!\n");
00476         }
00477       }
00478       else if (loginEntry->authFlags & AUTH_ACCOUNT_EMPTY)
00479       {
00480         if(!(pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY))
00481         {
00482           // Do not reset the flag, so that the confirmedBytes are always reset.
00483           //loginEntry->authFlags &= ~AUTH_ACCOUNT_EMPTY;
00484           pAccInfo->authFlags |= AUTH_ACCOUNT_EMPTY;
00485           /* confirmedBytes = 0 leads to immediate disconnection.
00486            * If confirmedBytes > 0,  any remaining prepaid bytes may be used.
00487            */
00488           pAccInfo->confirmedBytes = loginEntry->confirmedBytes;
00489           if (pAccInfo->confirmedBytes < pAccInfo->transferredBytes)
00490           {
00491             // this account is really empty; prevent an overflow in the prepaid bytes calculation
00492              pAccInfo->transferredBytes = pAccInfo->confirmedBytes;
00493           }
00494 
00495           //CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Account %llu is empty!\n", pAccInfo->accountNumber);
00496           CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Account %llu empty with %d prepaid bytes, (transferred bytes: %llu, confirmed bytes: %llu)!\n",
00497                       pAccInfo->accountNumber, getPrepaidBytes(pAccInfo), pAccInfo->transferredBytes, pAccInfo->confirmedBytes);
00498         }
00499 
00500       }
00501       else if (loginEntry->authFlags & AUTH_INVALID_ACCOUNT)
00502       {
00503         loginEntry->authFlags &= ~AUTH_INVALID_ACCOUNT;
00504         CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Found invalid account %llu ! Kicking out user...\n", pAccInfo->accountNumber);
00505         err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_KEY_NOT_FOUND);
00506       }
00507       else if (loginEntry->authFlags & AUTH_BLOCKED)
00508       {
00509         loginEntry->authFlags &= ~AUTH_BLOCKED;
00510         CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Kicking out user with blocked account %llu !\n", pAccInfo->accountNumber);
00511         err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_BLOCKED);
00512       }
00513       else if (loginEntry->authFlags & AUTH_DATABASE)
00514       {
00515         loginEntry->authFlags &= ~AUTH_DATABASE;
00516         CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Kicking out user with account %llu due to database error...\n", pAccInfo->accountNumber);
00517         err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_DATABASE_ERROR);
00518       }
00519       else if (loginEntry->authFlags & AUTH_UNKNOWN)
00520       {
00521         loginEntry->authFlags &= ~AUTH_UNKNOWN;
00522         CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Unknown error, account %llu! Kicking out user...\n", pAccInfo->accountNumber);
00523         err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR);
00524       }
00525     }
00526     else
00527     {
00528       CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: handleJapPacket %s,%s did not find user login hash entry for account %llu, owner/accInfo: %p/%p!\n",
00529           (a_bMessageToJAP ? "downstream" : "upstream"),
00530           (a_bControlMessage ? "ctl" : "data"),
00531           pAccInfo->accountNumber, pAccInfo->ownerRef, pHashEntry->pAccountingInfo);
00532       ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
00533       return returnKickout(pAccInfo);
00534     }
00535 
00536     ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
00537 
00538     if (pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY)
00539     {
00540       // There should be no time limit. The connections is simply closed after all prepaid bytes are gone.
00541       pAccInfo->lastHardLimitSeconds = time(NULL);
00542 
00543       //#ifdef DEBUG
00544 
00545       //#endif
00546 
00547       if (getPrepaidBytes(pAccInfo) <= 0)
00548       {
00549         CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Account %llu empty! Kicking out user...\n",
00550             pAccInfo->accountNumber);
00551         err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_ACCOUNT_EMPTY);
00552       }
00553       else
00554       {
00562         pAccInfo->mutex->unlock();
00563         return HANDLE_PACKET_CONNECTION_OK;
00564       }
00565     }
00566 
00568     //pAccInfo->mutex->lock();
00569 
00570     SAVE_STACK("CAAccountingInstance::handleJapPacket", "before err");
00571 
00572     if (err)
00573     {
00574       return returnPrepareKickout(pAccInfo, err);
00575     }
00576 
00577     //----------------------------------------------------------
00578     // ******     Hardlimit cost confirmation check **********
00579     //counting unconfirmed bytes is not necessary anymore, since we deduct from prepaid bytes
00580     //UINT32 unconfirmedBytes=diff64(pAccInfo->transferredBytes,pAccInfo->confirmedBytes);
00581 
00582     //confirmed and transferred bytes are cumulative, so they use UINT64 to store potentially huge values
00583     //prepaid Bytes as the difference will be much smaller, but might be negative, so we cast to signed int
00584     SINT32 prepaidBytes = getPrepaidBytes(pAccInfo);
00585 
00586     if (prepaidBytes < 0 ||  prepaidBytes <= (SINT32) ms_pInstance->m_iHardLimitBytes)
00587     {
00588       UINT32 prepaidInterval = CALibProxytest::getOptions()->getPrepaidInterval();
00589 
00590       if ((pAccInfo->authFlags & AUTH_HARD_LIMIT_REACHED) == 0)
00591       {
00592         pAccInfo->lastHardLimitSeconds = time(NULL);
00593         pAccInfo->authFlags |= AUTH_HARD_LIMIT_REACHED;
00594       }
00595 
00596 #ifdef DEBUG
00597       CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Hard limit of %d bytes triggered in %d seconds \n",
00598               ms_pInstance->m_iHardLimitBytes,
00599               (pAccInfo->lastHardLimitSeconds + HARD_LIMIT_TIMEOUT - time(NULL)));
00600 #endif
00601 
00602       if ( ( (time(NULL) >= pAccInfo->lastHardLimitSeconds + HARD_LIMIT_TIMEOUT) && (prepaidBytes <= 0) )
00603            || (prepaidBytes < 0 && (UINT32)(prepaidBytes * (-1)) >= prepaidInterval) )
00604       {
00605 //#ifdef DEBUG
00606         char* strReason;
00607         if (time(NULL) >= pAccInfo->lastHardLimitSeconds + HARD_LIMIT_TIMEOUT)
00608         {
00609           strReason = "timeout";
00610         }
00611         else
00612         {
00613           strReason = "negative prepaid interval exceeded";
00614         }
00615         CAMsg::printMsg( LOG_INFO, "Accounting instance: User refused "
00616                 "to send cost confirmation (HARDLIMIT EXCEEDED, %s). "
00617                 "PrepaidBytes were: %d\n", strReason, prepaidBytes);
00618 //#endif
00619 
00620         //ms_pInstance->m_pIPBlockList->insertIP( pHashEntry->peerIP );
00621         pAccInfo->lastHardLimitSeconds = 0;
00622         return returnPrepareKickout(pAccInfo, new CAXMLErrorMessage(CAXMLErrorMessage::ERR_NO_CONFIRMATION));
00623       }
00624       else
00625       {
00626         if( !(pAccInfo->authFlags & AUTH_SENT_CC_REQUEST) )
00627         {
00628           sendCCRequest(pAccInfo);
00629         }
00630       }
00631     }
00632     else
00633     {
00634       pAccInfo->authFlags &= ~AUTH_HARD_LIMIT_REACHED;
00635     }
00636 
00637     //-------------------------------------------------------
00638     // *** SOFT LIMIT CHECK *** is it time to request a new cost confirmation?
00639     if ( prepaidBytes < 0 || prepaidBytes <= (SINT32) ms_pInstance->m_iSoftLimitBytes )
00640     {
00641 #ifdef DEBUG
00642       CAMsg::printMsg(LOG_ERR, "soft limit of %d bytes triggered \n",ms_pInstance->m_iSoftLimitBytes);
00643 #endif
00644       if( !(pAccInfo->authFlags & AUTH_SENT_CC_REQUEST) )
00645       {//we have sent a first CC request
00646         // no CC request sent yet --> send a first CC request
00647         sendCCRequest(pAccInfo);
00648       }
00649     }// end of soft limit exceeded
00650 
00651     //everything is fine! let the packet pass thru
00652     pAccInfo->mutex->unlock();
00653     return HANDLE_PACKET_CONNECTION_OK;
00654   }
00655 
00656 /******************************************************************/
00657 //methods to provide a unified point of exit for handleJapPacket
00658 /******************************************************************/
00659 
00660 
00661 SINT32 CAAccountingInstance::getPrepaidBytes(tAiAccountingInfo* pAccInfo)
00662 {
00663   if (pAccInfo == NULL)
00664   {
00665     return 0;
00666   }
00667 
00668   //most unlikely that either transferred bytes or confirmed bytes
00669   //are > 0x8000000000000000
00670 
00671   SINT64 prepaidBytes = pAccInfo->confirmedBytes - pAccInfo->transferredBytes;
00672   //difference must be a value that fits into a signed 32 bit integer.
00673   if ((prepaidBytes > 0) && (prepaidBytes & 0x7FFFFFFF00000000LL))
00674   {
00675     CAMsg::printMsg(LOG_CRIT, "PrepaidBytes overflow: %lld\n", prepaidBytes);
00676     CAMsg::printMsg(LOG_INFO, "TransferredBytes: %llu  ConfirmedBytes: %llu\n", pAccInfo->transferredBytes, pAccInfo->confirmedBytes);
00677   }
00678   return (SINT32) prepaidBytes;
00679 
00680   /*SINT32 prepaidBytes;
00681 #ifdef DEBUG
00682   CAMsg::printMsg(LOG_INFO, "Calculating TransferredBytes: %llu  ConfirmedBytes: %llu\n",
00683       pAccInfo->transferredBytes, pAccInfo->confirmedBytes);
00684 #endif
00685   if (pAccInfo->confirmedBytes > pAccInfo->transferredBytes)
00686   {
00687     prepaidBytes = pAccInfo->confirmedBytes - pAccInfo->transferredBytes;
00688     if (prepaidBytes < 0)
00689     {
00690       // PrepaidBytes should be greater than 0 !!!
00691       UINT8 tmp[32], tmp2[32];
00692       print64(tmp,pAccInfo->transferredBytes);
00693       print64(tmp2,pAccInfo->confirmedBytes);
00694 
00695       CAMsg::printMsg(LOG_CRIT, "PrepaidBytes are way to high! Maybe a hacker attack? Or CC did get lost?\n");
00696       CAMsg::printMsg(LOG_INFO, "TransferredBytes: %s  ConfirmedBytes: %s\n", tmp, tmp2);
00697       UINT32 prepaidInterval = CALibProxytest::getOptions()->getPrepaidInterval();
00698       prepaidBytes = (SINT32)prepaidInterval;
00699       pAccInfo->transferredBytes = pAccInfo->confirmedBytes - prepaidInterval;
00700     }
00701   }
00702   else
00703   {
00704     prepaidBytes = pAccInfo->transferredBytes - pAccInfo->confirmedBytes;
00705     prepaidBytes *= -1;
00706   }
00707 
00708   return prepaidBytes;*/
00709 }
00710 
00714 SINT32 CAAccountingInstance::returnKickout(tAiAccountingInfo* pAccInfo)
00715 {
00716   UINT8 tmp[32];
00717   print64(tmp,pAccInfo->accountNumber);
00718   CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: should kick out user with account %s now...\n", tmp);
00719   setPrepaidBytesToZero_internal(pAccInfo);
00720   pAccInfo->mutex->unlock();
00721   return HANDLE_PACKET_CLOSE_CONNECTION;
00722 }
00723 
00724 void CAAccountingInstance::setPrepaidBytesToZero(tAiAccountingInfo* pAccInfo)
00725 {
00726   pAccInfo->mutex->lock();
00727   setPrepaidBytesToZero_internal(pAccInfo);
00728   pAccInfo->mutex->unlock();
00729 }
00730 
00731 /* prepaid bytes are calculated like that */
00732 inline void CAAccountingInstance::setPrepaidBytesToZero_internal(tAiAccountingInfo* pAccInfo)
00733 {
00734   pAccInfo->transferredBytes = pAccInfo->confirmedBytes;
00735 }
00736 
00737 /*
00738  * hold packet, no timeout started
00739  * (Usage: send an error message before kicking out the user:
00740  * sets AUTH_FATAL_ERROR )
00741  * IMPORTANT: You need to hold a lock for pAccInfo->mutex when invoking this.
00742  * Postcondition is that pAccInfo->mutex is unlocked.
00743  */
00744 SINT32 CAAccountingInstance::returnPrepareKickout(tAiAccountingInfo* pAccInfo, CAXMLErrorMessage* a_error)
00745 {
00746   pAccInfo->authFlags |= AUTH_FATAL_ERROR;
00747 
00748   if (a_error)
00749   {
00750     //CAMsg::printMsg(LOG_CRIT, "AccountingInstance: Sending error message...\n");
00751     XERCES_CPP_NAMESPACE::DOMDocument* doc=NULL;
00752     a_error->toXmlDocument(doc);
00753     delete a_error;
00754     a_error = NULL;
00755     //pAccInfo->sessionPackets = 0; // allow some pakets to pass by to send the control message
00756     CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: before prepare Kickout send...\n");
00757     pAccInfo->pControlChannel->sendXMLMessage(doc);
00758     if (doc != NULL)
00759     {
00760       doc->release();
00761       doc = NULL;
00762     }
00763   }
00764   else
00765   {
00766     CAMsg::printMsg(LOG_CRIT, "AccountingInstance: Should send error message, but none is available!\n");
00767   }
00768 
00769   pAccInfo->mutex->unlock();
00770   return HANDLE_PACKET_PREPARE_FOR_CLOSING_CONNECTION;
00771 }
00772 
00773 SINT32 CAAccountingInstance::sendInitialCCRequest(tAiAccountingInfo* pAccInfo, CAXMLCostConfirmation *pCC, SINT32 prepaidBytes)
00774 {
00775   XERCES_CPP_NAMESPACE::DOMDocument* doc=NULL;
00776 
00777   SINT32 ret = makeInitialCCRequest(pCC, doc, prepaidBytes);
00778   if( (ret != E_SUCCESS) || (doc == NULL))
00779   {
00780     CAMsg::printMsg(LOG_ERR, "cannot send initial CC request, ret: %d\n", ret);
00781     return E_UNKNOWN;
00782   }
00783 #ifdef DEBUG
00784   UINT32 debuglen = 3000;
00785   UINT8 debugout[3000];
00786   DOM_Output::dumpToMem(doc,debugout,&debuglen);
00787   debugout[debuglen] = 0;
00788   CAMsg::printMsg(LOG_DEBUG, "the CC sent looks like this: %s \n",debugout);
00789 #endif
00790   ret = pAccInfo->pControlChannel->sendXMLMessage(doc);
00791   if (doc != NULL)
00792   {
00793     doc->release();
00794     doc = NULL;
00795   }
00796   return ret;
00797 }
00798 
00799 SINT32 CAAccountingInstance::sendCCRequest(tAiAccountingInfo* pAccInfo)
00800 {
00801   INIT_STACK;
00802   BEGIN_STACK("CAAccountingInstance::sendCCRequest");
00803 
00804   XERCES_CPP_NAMESPACE::DOMDocument* doc=NULL;
00805     UINT32 prepaidInterval = CALibProxytest::getOptions()->getPrepaidInterval();
00806 
00807     pAccInfo->authFlags |= AUTH_SENT_CC_REQUEST;
00808 
00809     if (pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY)
00810     {
00811       // do not send further CC requests for this account
00812       return E_SUCCESS;
00813     }
00814 
00815     // prepaid bytes are "confirmed bytes - transfered bytes"
00816     //UINT64 bytesToConfirm = pAccInfo->confirmedBytes + (prepaidInterval) - (pAccInfo->confirmedBytes - pAccInfo->transferredBytes);
00817     pAccInfo->bytesToConfirm = (prepaidInterval) + pAccInfo->transferredBytes;
00818   makeCCRequest(pAccInfo->accountNumber, pAccInfo->bytesToConfirm, doc);
00819   //pAccInfo->authFlags |= AUTH_SENT_CC_REQUEST;
00820 #ifdef DEBUG
00821   CAMsg::printMsg(LOG_DEBUG, "CC request sent for %llu bytes, transferrred bytes: %llu bytes.\n",pAccInfo->bytesToConfirm, pAccInfo->transferredBytes);
00822   CAMsg::printMsg(LOG_DEBUG, "prepaid Interval: %u \n",prepaidInterval);
00823 
00824   UINT32 debuglen = 3000;
00825   UINT8 debugout[3000];
00826   DOM_Output::dumpToMem(doc,debugout,&debuglen);
00827   debugout[debuglen] = 0;
00828   CAMsg::printMsg(LOG_DEBUG, "the CC sent looks like this: %s \n",debugout);
00829 #endif
00830 
00831   //FINISH_STACK("CAAccountingInstance::sendCCRequest");
00832 
00833   SINT32 ret = pAccInfo->pControlChannel->sendXMLMessage(doc);
00834   if (doc != NULL)
00835   {
00836     doc->release();
00837     doc = NULL;
00838   }
00839   return ret;
00840 }
00841 
00842 
00843 bool CAAccountingInstance::cascadeMatchesCC(CAXMLCostConfirmation *pCC)
00844 {
00845 
00846     UINT8* certHash;
00847     if(m_allHashesLen !=  pCC->getNumberOfHashes() )
00848     {
00849       return false;
00850     }
00851 
00852     for (UINT32 i = 0; i < pCC->getNumberOfHashes(); i++)
00853     {
00854       certHash = pCC->getPriceCertHash(i);
00855       if ((certHash = (UINT8*)m_certHashCC->getValue(certHash)) != NULL)
00856       {
00857 #ifdef DEBUG
00858         CAMsg::printMsg( LOG_INFO, "CC1: %s\n", certHash);
00859 #endif
00860       }
00861       else
00862       {
00863 #ifdef DEBUG
00864         CAMsg::printMsg(LOG_DEBUG, "CC do not match current cascade.\n");
00865 #endif
00866         return false;
00867       }
00868     }
00869 #ifdef DEBUG
00870     CAMsg::printMsg(LOG_DEBUG, "CC matches current Cascade.\n");
00871 #endif
00872     return true;
00873 }
00874 
00886 SINT32 CAAccountingInstance::prepareCCRequest(CAMix* callingMix, UINT8* a_AiName)
00887 {
00888   m_preparedCCRequest = createDOMDocument();
00889 
00890   DOMElement* elemRoot = createDOMElement(m_preparedCCRequest,"PayRequest");
00891   setDOMElementAttribute(elemRoot,"version",(UINT8*) "1.0");
00892   m_preparedCCRequest->appendChild(elemRoot);
00893   DOMElement* elemCC = createDOMElement(m_preparedCCRequest,"CC");
00894   setDOMElementAttribute(elemCC,"version",(UINT8*) "1.2");
00895   elemRoot->appendChild(elemCC);
00896   DOMElement* elemAiName = createDOMElement(m_preparedCCRequest,"AiID");
00897   setDOMElementValue(elemAiName, a_AiName);
00898   elemCC->appendChild(elemAiName);
00899 
00900   //extract price certificate elements from cascadeInfo
00901   //get cascadeInfo from CAMix(which makeCCRequest needs to extract the price certs
00902   XERCES_CPP_NAMESPACE::DOMDocument* cascadeInfoDoc=NULL;
00903   callingMix->getMixCascadeInfo(cascadeInfoDoc);
00904 
00905   DOMElement* cascadeInfoElem = cascadeInfoDoc->getDocumentElement();
00906   DOMNodeList* allMixes = getElementsByTagName(cascadeInfoElem,"Mix");
00907   UINT32 nrOfMixes = allMixes->getLength();
00908   DOMNode** mixNodes = new DOMNode*[nrOfMixes]; //so we can use separate loops for extracting, hashing and appending
00909 
00910   DOMNode* curMixNode=NULL;
00911   for (UINT32 i = 0, j = 0, count = nrOfMixes; i < count; i++, j++){
00912     //cant use getDOMChildByName from CAUtil here yet, since it will always return the first child
00913     curMixNode = allMixes->item(i);
00914     if (getDOMChildByName(curMixNode,"PriceCertificate",mixNodes[j],true) != E_SUCCESS)
00915     {
00916       j--;
00917       nrOfMixes--;
00918     }
00919   }
00920 
00921   //hash'em, and get subjectkeyidentifiers
00922     UINT8 digest[SHA_DIGEST_LENGTH];
00923     m_allHashes=new UINT8*[nrOfMixes];
00924     m_allHashesLen = nrOfMixes;
00925     UINT8** allSkis=new UINT8*[nrOfMixes];
00926     DOMNode* skiNode=NULL;
00927     for (UINT32 i = 0; i < nrOfMixes; i++){
00928       UINT8* out=new UINT8[5000];
00929       UINT32 outlen=5000;
00930 
00931       DOM_Output::makeCanonical(mixNodes[i],out,&outlen);
00932       out[outlen] = 0;
00933 #ifdef DEBUG
00934       CAMsg::printMsg(LOG_DEBUG, "price cert to be hashed: %s",out);
00935 #endif
00936       SHA1(out,outlen,digest);
00937       delete[] out;
00938       out = NULL;
00939 
00940       UINT32 len = 1024;
00941       UINT8* tmpBuff = new UINT8[len+1];
00942       memset(tmpBuff, 0, len+1);
00943       if(CABase64::encode(digest,SHA_DIGEST_LENGTH,tmpBuff,&len)!=E_SUCCESS)
00944         return E_UNKNOWN;
00945       //tmpBuff[len]=0;
00946 
00947 
00948       //line breaks might have been added, and would lead to database problems
00949       strtrim(tmpBuff); //return value ohny significant for NULL or all-whitespace string, ignore
00950 
00951       m_allHashes[i] = tmpBuff;
00952       CAMsg::printMsg(LOG_DEBUG,"Price certificate hash of Mix %u is: %s\n", i, m_allHashes[i]);
00953       //do not delete tmpBuff here, since we're using allHashes below
00954 
00955       if (getDOMChildByName(mixNodes[i],"SubjectKeyIdentifier",skiNode,true) != E_SUCCESS)
00956         {
00957           CAMsg::printMsg(LOG_CRIT,"Could not get mix id from price cert");
00958         }
00959 
00960       allSkis[i] =  (UINT8*) XMLString::transcode(skiNode->getFirstChild()->getNodeValue());
00961 
00962   }
00963   //concatenate the hashes, and store for future reference to identify the cascade
00964     m_currentCascade = new UINT8[256];
00965     memset(m_currentCascade, 0, (sizeof(UINT8)*256 ));
00966     for (UINT32 j = 0; j < nrOfMixes; j++)
00967     {
00968         //check for hash value size (should always be OK)
00969         if (strlen((const char*)m_currentCascade) > ( 256 - strlen((const char*)m_allHashes[j]) )   )
00970         {
00971           CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance::prepareCCRequest: "
00972               "Too many/too long hash values, ran out of allocated memory\n");
00973           return E_UNKNOWN;
00974         }
00975         if (j == 0)
00976         {
00977             m_currentCascade = (UINT8*) strcpy( (char*) m_currentCascade,(const char*)m_allHashes[j]);
00978         } else
00979         {
00980             m_currentCascade = (UINT8*) strcat((char*)m_currentCascade,(char*)m_allHashes[j]);
00981         }
00982     }
00983 
00984     //and append to CC
00985   DOMElement* elemPriceCerts = createDOMElement(m_preparedCCRequest,"PriceCertificates");
00986   DOMElement* elemCert=NULL;
00987   for (UINT32 i = 0; i < nrOfMixes; i++)
00988   {
00989     elemCert = createDOMElement(m_preparedCCRequest,"PriceCertHash");
00990     //CAMsg::printMsg(LOG_DEBUG,"hash to be inserted in cc: index %d, value %s\n",i,m_allHashes[i]);
00991     setDOMElementValue(elemCert,m_allHashes[i]);
00992     //delete[] allHashes[i];
00993     setDOMElementAttribute(elemCert,"id",allSkis[i]);
00994     setDOMElementAttribute(elemCert, "position", i);
00995     if (i == 0)
00996     {
00997       setDOMElementAttribute(elemCert,"isAI",(UINT8*)"true");
00998     }
00999     elemPriceCerts->appendChild(elemCert);
01000   }
01001   elemCC->appendChild(elemPriceCerts);
01002 #ifdef DEBUG
01003   CAMsg::printMsg(LOG_DEBUG, "finished method makeCCRequest\n");
01004 #endif
01005 
01006   delete[] mixNodes;
01007   mixNodes = NULL;
01008   //delete[] allHashes;
01009   delete[] allSkis;
01010   allSkis = NULL;
01011   return E_SUCCESS;
01012 
01013 }
01014 
01020 SINT32 CAAccountingInstance::makeInitialCCRequest(CAXMLCostConfirmation *pCC, XERCES_CPP_NAMESPACE::DOMDocument* & doc, SINT32 prepaidBytes)
01021   {
01022     if( (pCC == NULL) || (pCC->getXMLDocument() == NULL) ||
01023       (pCC->getXMLDocument()->getDocumentElement() == NULL) )
01024     {
01025       CAMsg::printMsg(LOG_ERR, "Error creating initial CCrequest (pCC ref: %p)\n", pCC);
01026       return E_UNKNOWN;
01027     }
01028     DOMNode* elemCC=NULL;
01029 
01030     doc = createDOMDocument();
01031     DOMNode *ccRoot = doc->importNode(pCC->getXMLDocument()->getDocumentElement(),true);
01032     doc->appendChild(doc->importNode(m_preparedCCRequest->getDocumentElement(),true));
01033     setDOMElementAttribute(doc->getDocumentElement(), "initialCC", true);
01034     DOMElement *elemPrepaidBytes = createDOMElement(doc, "PrepaidBytes");
01035     setDOMElementValue(elemPrepaidBytes, prepaidBytes);
01036     getDOMChildByName(doc->getDocumentElement(),"CC",elemCC);
01037     if(elemCC == NULL)
01038     {
01039       return E_UNKNOWN;
01040     }
01041     doc->getDocumentElement()->replaceChild(ccRoot, elemCC);
01042     doc->getDocumentElement()->appendChild(elemPrepaidBytes);
01043     return E_SUCCESS;
01044   }
01045 
01046 SINT32 CAAccountingInstance::makeCCRequest(const UINT64 accountNumber, const UINT64 transferredBytes, XERCES_CPP_NAMESPACE::DOMDocument* & doc)
01047   {
01048     INIT_STACK;
01049     BEGIN_STACK("CAAccountingInstance::makeCCRequest");
01050 
01051     DOMNode* elemCC=NULL;
01052 
01053     doc = createDOMDocument();
01054     doc->appendChild(doc->importNode(m_preparedCCRequest->getDocumentElement(),true));
01055 
01056     getDOMChildByName(doc->getDocumentElement(),"CC",elemCC);
01057 
01058     DOMElement* elemAccount = createDOMElement(doc,"AccountNumber");
01059     setDOMElementValue(elemAccount, accountNumber);
01060     elemCC->appendChild(elemAccount);
01061     DOMElement* elemBytes = createDOMElement(doc,"TransferredBytes");
01062     setDOMElementValue(elemBytes, transferredBytes);
01063     elemCC->appendChild(elemBytes);
01064 
01065     FINISH_STACK("CAAccountingInstance::makeCCRequest");
01066 
01067     return E_SUCCESS;
01068   }
01069 
01070 
01071 SINT32 CAAccountingInstance::sendAILoginConfirmation(tAiAccountingInfo* pAccInfo,
01072                            const UINT32 code,
01073                            UINT8 * message)
01074   {
01075     SINT32 sendSuccess = E_SUCCESS;
01076     XERCES_CPP_NAMESPACE::DOMDocument* doc = createDOMDocument();
01077     DOMElement *elemRoot = createDOMElement(doc, "LoginConfirmation");
01078     setDOMElementAttribute(elemRoot, "code", code);
01079     setDOMElementValue(elemRoot, message);
01080     doc->appendChild(elemRoot);
01081 
01082 #ifdef DEBUG
01083     UINT32 debuglen = 3000;
01084     UINT8 debugout[3000];
01085     DOM_Output::dumpToMem(doc,debugout,&debuglen);
01086     debugout[debuglen] = 0;
01087     CAMsg::printMsg(LOG_DEBUG, "the AILogin Confirmation sent looks like this: %s \n",debugout);
01088 #endif
01089     sendSuccess = pAccInfo->pControlChannel->sendXMLMessage(doc);
01090     if (doc != NULL)
01091     {
01092       doc->release();
01093       doc = NULL;
01094     }
01095     return sendSuccess;
01096   }
01097 
01098 
01106 SINT32 CAAccountingInstance::processJapMessage(fmHashTableEntry * pHashEntry,const XERCES_CPP_NAMESPACE::DOMDocument* a_DomDoc)
01107   {
01108     INIT_STACK;
01109     BEGIN_STACK("CAAccountingInstance::processJapMessage");
01110 
01111     if (pHashEntry == NULL)
01112     {
01113       return E_UNKNOWN;
01114     }
01115 
01116     DOMElement* root = a_DomDoc->getDocumentElement();
01117     if(root == NULL)
01118     {
01119       CAMsg::printMsg(LOG_DEBUG, "ProcessJapMessage: getDocument Element is null!!!\n" );
01120       return E_UNKNOWN;
01121     }
01122     char* docElementName = XMLString::transcode(root->getTagName());
01123     SINT32 hf_ret = 0;
01124 
01125 
01126     // what type of message is it?
01127     if ( strcmp( docElementName, "AccountCertificate" ) == 0 )
01128       {
01129         #ifdef DEBUG
01130           CAMsg::printMsg( LOG_DEBUG, "Received an AccountCertificate. Calling handleAccountCertificate()\n" );
01131         #endif
01132         //handleFunc = &CAAccountingInstance::handleAccountCertificate;
01133         hf_ret = ms_pInstance->handleAccountCertificate( pHashEntry->pAccountingInfo, root );
01134         processJapMessageLoginHelper(pHashEntry, hf_ret, false);
01135       }
01136     else if ( strcmp( docElementName, "Response" ) == 0)
01137       {
01138         #ifdef DEBUG
01139           CAMsg::printMsg( LOG_DEBUG, "Received a Response (challenge-response)\n" );
01140         #endif
01141         //handleFunc = &CAAccountingInstance::handleChallengeResponse;
01142         hf_ret = ms_pInstance->handleChallengeResponse( pHashEntry->pAccountingInfo, root );
01143         processJapMessageLoginHelper(pHashEntry, hf_ret, false);
01144         /*if(hf_ret != CAXMLErrorMessage::ERR_OK)
01145         {
01146           unlockLogin(pHashEntry);
01147         }
01148         else*/
01149         if(hf_ret == (SINT32) CAXMLErrorMessage::ERR_OK)
01150         {
01151           //CAMsg::printMsg( LOG_DEBUG, "Prepaid bytes are: %d\n", getPrepaidBytes(pHashEntry->pAccountingInfo));
01152 
01153           if( (getPrepaidBytes(pHashEntry->pAccountingInfo) > 0) &&
01154             !(pHashEntry->pAccountingInfo->authFlags &
01155               (AUTH_ACCOUNT_EMPTY | AUTH_BLOCKED | AUTH_INVALID_ACCOUNT)) )
01156           {
01157             pHashEntry->pAccountingInfo->authFlags |= AUTH_LOGIN_SKIP_SETTLEMENT;
01158           }
01159         }
01160       }
01161     else if ( strcmp( docElementName, "CC" ) == 0 )
01162       {
01163         #ifdef DEBUG
01164           CAMsg::printMsg( LOG_DEBUG, "Received a CC. Calling handleCostConfirmation()\n" );
01165         #endif
01166         //handleFunc = &CAAccountingInstance::handleCostConfirmation;
01167         hf_ret = ms_pInstance->handleCostConfirmation( pHashEntry->pAccountingInfo, root );
01168         processJapMessageLoginHelper(pHashEntry, hf_ret, true);
01169         /*if(hf_ret != CAXMLErrorMessage::ERR_OK)
01170         {
01171           unlockLogin(pHashEntry);
01172         }*/
01173       }
01174     else
01175     {
01176       CAMsg::printMsg( LOG_ERR,
01177           "AI Received XML message with unknown root element \"%s\". This is not accepted!\n",
01178                       docElementName
01179                     );
01180 
01181       SAVE_STACK("CAAccountingInstance::processJapMessage", "error");
01182       XMLString::release(&docElementName);
01183       return E_UNKNOWN;
01184     }
01185 
01186 
01187     XMLString::release(&docElementName);
01188 
01211     // remove these lines if AI thread pool is used (see @todo above)
01212     //(ms_pInstance->*handleFunc)(pHashEntry->pAccountingInfo, root );
01213 
01214     FINISH_STACK("CAAccountingInstance::processJapMessage");
01215     return E_SUCCESS;
01216   }
01217 
01218 void CAAccountingInstance::processJapMessageLoginHelper(fmHashTableEntry *pHashEntry,
01219                               UINT32 handlerReturnValue,
01220                               bool lastLoginMessage)
01221 {
01222   if(pHashEntry->pAccountingInfo != NULL)
01223   {
01224     if(pHashEntry->pAccountingInfo->mutex == NULL)
01225     {
01226       return;
01227     }
01228     pHashEntry->pAccountingInfo->mutex->lock();
01229     if(pHashEntry->pAccountingInfo->authFlags & AUTH_LOGIN_NOT_FINISHED)
01230     {
01231       if(handlerReturnValue != CAXMLErrorMessage::ERR_OK)
01232       {
01233         pHashEntry->pAccountingInfo->authFlags &= ~AUTH_LOGIN_NOT_FINISHED;
01234         pHashEntry->pAccountingInfo->authFlags |= AUTH_LOGIN_FAILED;
01235 
01236         CAXMLErrorMessage *err = NULL;
01237         XERCES_CPP_NAMESPACE::DOMDocument *errDoc = NULL;
01238 
01239         /*if(pHashEntry->pAccountingInfo->authFlags & AUTH_BLOCKED )
01240         {
01241           err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_BLOCKED,
01242                         (UINT8 *) "AI login: access denied because your account is blocked");
01243         }
01244         else if(pHashEntry->pAccountingInfo->authFlags & AUTH_ACCOUNT_EMPTY )
01245         {
01246           err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_ACCOUNT_EMPTY,
01247                         (UINT8 *) "AI login: access denied because your account is empty");
01248         }
01249         else if(pHashEntry->pAccountingInfo->authFlags & AUTH_INVALID_ACCOUNT )
01250         {
01251           err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_NO_BALANCE,
01252                         (UINT8 *) "AI login: access denied because your account is not valid");
01253         }
01254         else */ if(pHashEntry->pAccountingInfo->authFlags & AUTH_FAKE )
01255         {
01256           err = new CAXMLErrorMessage(handlerReturnValue);
01257 
01258         }
01259         else if(pHashEntry->pAccountingInfo->authFlags & AUTH_MULTIPLE_LOGIN )
01260         {
01261           err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_MULTIPLE_LOGIN,
01262                         (UINT8*)"You are already logged in.");
01263 
01264         }
01265         else
01266         {
01267           err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR,
01268                         (UINT8 *) "AI login: error occured while connecting, access denied");
01269         }
01270 
01271 
01272         if(err != NULL)
01273         {
01274           err->toXmlDocument(errDoc);
01275           pHashEntry->pAccountingInfo->pControlChannel->sendXMLMessage(errDoc);
01276           delete err;
01277           err = NULL;
01278         }
01279         if(errDoc != NULL)
01280         {
01281           errDoc->release();
01282           errDoc = NULL;
01283         }
01284         /*sendAILoginConfirmation(pHashEntry->pAccountingInfo,
01285                     CAXMLErrorMessage::ERR_BLOCKED,
01286                     (UINT8*) "AI access denied");*/
01287       }
01288       else if(lastLoginMessage)
01289       {
01290         //CAMsg::printMsg( LOG_ERR, "User successfully logged in\n");
01291         pHashEntry->pAccountingInfo->authFlags &= ~AUTH_LOGIN_NOT_FINISHED;
01292       }
01293 
01294     }
01295     pHashEntry->pAccountingInfo->mutex->unlock();
01296   }
01297 }
01298 
01299 SINT32 CAAccountingInstance::loginProcessStatus(fmHashTableEntry *pHashEntry)
01300 {
01301   SINT32 ret = 0;
01302   if(pHashEntry == NULL)
01303   {
01304     return ret |= AUTH_LOGIN_FAILED;
01305   }
01306   if(pHashEntry->pAccountingInfo == NULL)
01307   {
01308     return ret |= AUTH_LOGIN_FAILED;
01309   }
01310   if(pHashEntry->pAccountingInfo->mutex == NULL)
01311   {
01312     return ret |= AUTH_LOGIN_FAILED;
01313   }
01314   pHashEntry->pAccountingInfo->mutex->lock();
01315   ret = pHashEntry->pAccountingInfo->authFlags &
01316     (AUTH_LOGIN_NOT_FINISHED | AUTH_LOGIN_FAILED | AUTH_LOGIN_SKIP_SETTLEMENT | AUTH_MULTIPLE_LOGIN);
01317   pHashEntry->pAccountingInfo->mutex->unlock();
01318   return ret;
01319 }
01320 
01325 SINT32 CAAccountingInstance::finishLoginProcess(fmHashTableEntry *pHashEntry)
01326 {
01327   SINT32 ret = 0;
01328   UINT64 accountNumber = 0;
01329   AccountLoginHashEntry *loginEntry;
01330   tAiAccountingInfo* pAccInfo = pHashEntry->pAccountingInfo;
01331 
01332   if(ms_pInstance==NULL)
01333   {
01334     return ret |= AUTH_LOGIN_FAILED;
01335   }
01336   if(ms_pInstance->m_currentAccountsHashtable == NULL)
01337   {
01338     return ret |= AUTH_LOGIN_FAILED;
01339   }
01340   if(ms_pInstance->m_currentAccountsHashtable->getMutex() == NULL)
01341   {
01342     return ret |= AUTH_LOGIN_FAILED;
01343   }
01344   if(pHashEntry == NULL)
01345   {
01346     return ret |= AUTH_LOGIN_FAILED;
01347   }
01348   if(pHashEntry->pAccountingInfo == NULL)
01349   {
01350     return ret |= AUTH_LOGIN_FAILED;
01351   }
01352   if(pHashEntry->pAccountingInfo->mutex == NULL)
01353   {
01354     return ret |= AUTH_LOGIN_FAILED;
01355   }
01356   pAccInfo->mutex->lock();
01357   accountNumber = pAccInfo->accountNumber;
01358 
01359   //reset login flags
01360   pAccInfo->authFlags &= (~AUTH_LOGIN_SKIP_SETTLEMENT & ~AUTH_LOGIN_NOT_FINISHED);
01361 
01362   if (!(pAccInfo->authFlags & AUTH_SETTLED_ONCE))
01363   {
01364     UINT32 statusCode = 0;
01365     CAAccountingDBInterface* dbInterface = CAAccountingDBInterface::getConnection();
01366     if (dbInterface != NULL && dbInterface->getAccountStatus(accountNumber, statusCode) == E_SUCCESS)
01367     {
01368       if (statusCode > 0)
01369       {
01370         CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: No CC was settled for account %llu. Using DB status %u.\n",
01371           accountNumber, statusCode);
01372       }
01373       pAccInfo->authFlags |= statusCode;
01374     }
01375     else
01376     {
01377       CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: No CC was settled for account %llu. Could not fetch status from DB!.\n");
01378     }
01379     CAAccountingDBInterface::releaseConnection(dbInterface);
01380     dbInterface = NULL;
01381   }
01382 
01383   ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
01384   loginEntry = (AccountLoginHashEntry*)ms_pInstance->m_currentAccountsHashtable->getValue(&accountNumber);
01385 
01386   if (loginEntry)
01387   {
01388     if(loginEntry->authRemoveFlags)
01389     pAccInfo->authFlags &= ~(loginEntry->authRemoveFlags);
01390     pAccInfo->authFlags |= (loginEntry->authFlags & CRITICAL_SETTLE_FLAGS);
01391   }
01392   else
01393   {
01394     pAccInfo->authFlags |= AUTH_INVALID_ACCOUNT;
01395   }
01396   /*ret = pHashEntry->pAccountingInfo->authFlags &
01397     (AUTH_LOGIN_NOT_FINISHED | AUTH_LOGIN_FAILED);*/
01398 
01399 
01400   CAXMLErrorMessage *err = NULL;
01401   XERCES_CPP_NAMESPACE::DOMDocument *errDoc = NULL;
01402   /* Instead of using special login confirmation messages
01403    * we rather send XMLErrorMessages for backward compatibility reasons
01404    * because old JAPs (version <= 00.09.021) can handle them
01405    */
01406   if(pAccInfo->authFlags & AUTH_BLOCKED )
01407   {
01408     err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_BLOCKED,
01409                   (UINT8 *) "AI login: access denied because your account is blocked");
01410     CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: Account %llu seems blocked.\n", accountNumber);
01411   }
01412   else if(pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY )
01413   {
01414     err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_ACCOUNT_EMPTY,
01415                   (UINT8 *) "AI login: access denied because your account is empty");
01416     if ((pAccInfo->authFlags & AUTH_SETTLED_ONCE))
01417     {
01418       pAccInfo->confirmedBytes = loginEntry->confirmedBytes;
01419       if (pAccInfo->confirmedBytes < pAccInfo->transferredBytes)
01420       {
01421         // this account is really empty; prevent an overflow in the prepaid bytes calculation
01422         pAccInfo->transferredBytes = pAccInfo->confirmedBytes;
01423       }
01424       if (getPrepaidBytes(pAccInfo) > 0)
01425       {
01426         // the user may user his last bytes and is kicked out after that
01427         delete err;
01428         err = NULL;
01429       }
01430     }
01431     else
01432     {
01433       // TODO I am not sure whether this is enough; check this later
01434       loginEntry->confirmedBytes = pAccInfo->confirmedBytes;
01435       pAccInfo->transferredBytes = pAccInfo->confirmedBytes;
01436     }
01437     CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: Account %llu seems empty.\n", accountNumber);
01438   }
01439   else if(pAccInfo->authFlags & AUTH_INVALID_ACCOUNT )
01440   {
01441     err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_NO_BALANCE,
01442                   (UINT8 *) "AI login: access denied because your account is not valid");
01443     CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: Account %llu seems invalid.\n", accountNumber);
01444   }
01445   else if(pAccInfo->authFlags & AUTH_UNKNOWN )
01446   {
01447     err = new CAXMLErrorMessage(CAXMLErrorMessage::ERR_NO_ERROR_GIVEN,
01448                   (UINT8 *) "AI login: error occured while connecting, access denied");
01449     CAMsg::printMsg(LOG_WARNING, "CAAccountingInstance::finishLoginProcess: Unknown error was found for account %llu.\n", accountNumber);
01450   }
01451 
01452   if(err != NULL)
01453   {
01454     err->toXmlDocument(errDoc);
01455     pHashEntry->pAccountingInfo->pControlChannel->sendXMLMessage(errDoc);
01456     delete err;
01457     err = NULL;
01458     if(errDoc != NULL)
01459     {
01460       errDoc->release();
01461       errDoc = NULL;
01462     }
01463     ret |= AUTH_LOGIN_FAILED;
01464   }
01465   else
01466   {
01467 
01468   //send login confirmation to user, but if the message could not be send, login will fail
01469   /* These login confirmation messages are necessary for the new AI login protocol to indicate
01470    * that the process is finished after a settlement.
01471    * They won't bother old JAPs (version <= 00.09.021) because they will ignore
01472    * these confirmations.
01473    */
01474     if(sendAILoginConfirmation(pAccInfo,
01475                   CAXMLErrorMessage::ERR_OK,
01476                   (UINT8*) "AI login successful") != E_SUCCESS)
01477     {
01478       ret |= AUTH_LOGIN_FAILED;
01479     }
01480   }
01481 
01482   /* unlock the loginEntry object for other login threads */
01483   //resetLoginOngoing(loginEntry, pHashEntry);
01484   ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
01485   pAccInfo->mutex->unlock();
01486   return ret;
01487 }
01488 
01489 UINT32 CAAccountingInstance::handleAccountCertificate(tAiAccountingInfo* pAccInfo, DOMElement* root)
01490 {
01491   return handleAccountCertificate_internal(pAccInfo, root);
01492 
01493   INIT_STACK;
01494   FINISH_STACK("CAAccountingInstance::handleAccountCertificate");
01495 }
01496 
01497 
01506 UINT32 CAAccountingInstance::handleAccountCertificate_internal(tAiAccountingInfo* pAccInfo, DOMElement* root)
01507   {
01508     INIT_STACK;
01509     BEGIN_STACK("CAAccountingInstance::handleAccountCertificate");
01510 
01511     //CAMsg::printMsg( LOG_ERR, "CAAccountingInstance::handleAccountCertificate start\n");
01512 
01513     //CAMsg::printMsg(LOG_DEBUG, "started method handleAccountCertificate\n");
01514     DOMElement* elGeneral=NULL;
01515     timespec now;
01516     getcurrentTime(now);
01517 
01518     // check authstate of this user
01519     if (pAccInfo == NULL)
01520     {
01521       return CAXMLErrorMessage::ERR_NO_RECORD_FOUND;
01522     }
01523 
01524     pAccInfo->mutex->lock();
01525 
01526     if (pAccInfo->authFlags & AUTH_DELETE_ENTRY)
01527     {
01528       pAccInfo->mutex->unlock();
01529       return CAXMLErrorMessage::ERR_NO_ERROR_GIVEN;
01530     }
01531 
01532     if (pAccInfo->authFlags & AUTH_GOT_ACCOUNTCERT)
01533     {
01534       #ifdef DEBUG
01535         CAMsg::printMsg(LOG_DEBUG, "Already got an account cert. Ignoring...");
01536       #endif
01537       CAXMLErrorMessage err(
01538           CAXMLErrorMessage::ERR_BAD_REQUEST,
01539           (UINT8*)"You have already sent an Account Certificate"
01540         );
01541       XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
01542       err.toXmlDocument(errDoc);
01543       pAccInfo->pControlChannel->sendXMLMessage(errDoc);
01544       if (errDoc != NULL)
01545       {
01546         errDoc->release();
01547         errDoc = NULL;
01548       }
01549       pAccInfo->mutex->unlock();
01550       return CAXMLErrorMessage::ERR_BAD_REQUEST;
01551     }
01552 
01553     // parse & set accountnumber
01554     if (getDOMChildByName( root, "AccountNumber", elGeneral, false ) != E_SUCCESS ||
01555       getDOMElementValue( elGeneral, pAccInfo->accountNumber ) != E_SUCCESS)
01556     {
01557       CAMsg::printMsg( LOG_ERR, "AccountCertificate has wrong or no accountnumber. Ignoring...\n");
01558       CAXMLErrorMessage err(CAXMLErrorMessage::ERR_WRONG_FORMAT);
01559       XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
01560       err.toXmlDocument(errDoc);
01561       pAccInfo->pControlChannel->sendXMLMessage(errDoc);
01562       if (errDoc != NULL)
01563       {
01564         errDoc->release();
01565         errDoc = NULL;
01566       }
01567       pAccInfo->mutex->unlock();
01568       return CAXMLErrorMessage::ERR_WRONG_FORMAT;
01569     }
01570 
01571     // parse & set payment instance id
01572     UINT32 len=256;
01573     pAccInfo->pstrBIID=new UINT8[256];
01574     if ( getDOMChildByName( root,"BiID", elGeneral, false ) != E_SUCCESS ||
01575        getDOMElementValue( elGeneral,pAccInfo->pstrBIID, &len ) != E_SUCCESS)
01576       {
01577         delete[] pAccInfo->pstrBIID;
01578         pAccInfo->pstrBIID = NULL;
01579         CAMsg::printMsg( LOG_ERR, "AccountCertificate has no Payment Instance ID. Ignoring...\n");
01580         CAXMLErrorMessage err(CAXMLErrorMessage::ERR_WRONG_FORMAT);
01581         XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
01582         err.toXmlDocument(errDoc);
01583         pAccInfo->pControlChannel->sendXMLMessage(errDoc);
01584         if (errDoc != NULL)
01585         {
01586           errDoc->release();
01587           errDoc = NULL;
01588         }
01589         pAccInfo->mutex->unlock();
01590         return CAXMLErrorMessage::ERR_WRONG_FORMAT;
01591       }
01592     #ifdef DEBUG
01593       CAMsg::printMsg(LOG_DEBUG, "Stored payment instance ID: %s\n", pAccInfo->pstrBIID);
01594     #endif
01595 
01596 
01597   // parse & set public key
01598     if ( getDOMChildByName( root, "JapPublicKey", elGeneral, false ) != E_SUCCESS )
01599     {
01600       CAMsg::printMsg( LOG_ERR, "AccountCertificate contains no public key. Ignoring...\n");
01601       CAXMLErrorMessage err(CAXMLErrorMessage::ERR_KEY_NOT_FOUND);
01602       XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
01603       err.toXmlDocument(errDoc);
01604       pAccInfo->pControlChannel->sendXMLMessage(errDoc);
01605       if (errDoc != NULL)
01606       {
01607         errDoc->release();
01608         errDoc = NULL;
01609       }
01610       pAccInfo->mutex->unlock();
01611       return CAXMLErrorMessage::ERR_KEY_NOT_FOUND;
01612     }
01613   #ifdef DEBUG
01614     UINT8* aij;
01615     UINT32 aijsize;
01616     aij = DOM_Output::dumpToMem(elGeneral, &aijsize);
01617     aij[aijsize-1]=0;
01618     CAMsg::printMsg( LOG_DEBUG, "Setting user public key %s>\n", aij );
01619     delete[] aij;
01620     aij = NULL;
01621   #endif
01622   pAccInfo->pPublicKey = new CASignature();
01623   if ( pAccInfo->pPublicKey->setVerifyKey( elGeneral ) != E_SUCCESS )
01624   {
01625     CAXMLErrorMessage err(CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR);
01626     XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
01627     err.toXmlDocument(errDoc);
01628     pAccInfo->pControlChannel->sendXMLMessage(errDoc);
01629     if (errDoc != NULL)
01630     {
01631       errDoc->release();
01632       errDoc = NULL;
01633     }
01634     pAccInfo->mutex->unlock();
01635     return CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR;
01636   }
01637 
01638   //if ((!m_pJpiVerifyingInstance) ||
01639     //(m_pJpiVerifyingInstance->verifyXML( root, (CACertStore *)NULL ) != E_SUCCESS ))
01640   if(CAMultiSignature::verifyXML(root, CALibProxytest::getOptions()->getBI()->getCertificate()))
01641   {
01642     // signature invalid. mark this user as bad guy
01643     CAMsg::printMsg( LOG_INFO, "CAAccountingInstance::handleAccountCertificate(): Bad Jpi signature\n" );
01644     pAccInfo->authFlags |= AUTH_FAKE | AUTH_GOT_ACCOUNTCERT | AUTH_TIMEOUT_STARTED;
01645     pAccInfo->mutex->unlock();
01646     return CAXMLErrorMessage::ERR_BAD_SIGNATURE;
01647   }
01648 
01649 
01650   UINT8 * arbChallenge;
01651   UINT8 b64Challenge[ 512 ];
01652   UINT32 b64Len = 512;
01653 
01654   //CAMsg::printMsg(LOG_DEBUG, "Almost finished handleAccountCertificate, preparing challenge\n");
01655 
01656   // generate random challenge data and Base64 encode it
01657   arbChallenge = new UINT8[222];
01658   getRandom( arbChallenge, 222 );
01659   CABase64::encode( arbChallenge, 222, b64Challenge, &b64Len );
01660 
01661   delete[] pAccInfo->pChallenge;
01662   pAccInfo->pChallenge = arbChallenge; // store challenge for later..
01663 
01664   // generate XML challenge structure
01665   XERCES_CPP_NAMESPACE::DOMDocument* doc = createDOMDocument();
01666   DOMElement* elemRoot = createDOMElement(doc, "Challenge" );
01667   DOMElement* elemPanic = createDOMElement(doc, "DontPanic" );
01668   DOMElement* elemPrepaid = createDOMElement(doc, "PrepaidBytes" );
01669   setDOMElementAttribute(elemPanic, "version",(UINT8*) "1.0" );
01670   doc->appendChild( elemRoot );
01671   elemRoot->appendChild( elemPanic );
01672   elemRoot->appendChild( elemPrepaid );
01673   setDOMElementValue( elemPanic, b64Challenge );
01674   SINT32 prepaidAmount = 0;  //m_dbInterface->getPrepaidAmount(pAccInfo->accountNumber, m_currentCascade, false);
01675 
01676   CAAccountingDBInterface *dbInterface = CAAccountingDBInterface::getConnection();
01677 
01678   //TODO: this is not a good moment to send the prepaid-bytes to the JonDo.
01679   //we cannot be sure that the database contains a consistent value here.
01680   if(dbInterface != NULL)
01681   {
01682     prepaidAmount = dbInterface->getPrepaidAmount(pAccInfo->accountNumber, m_currentCascade, false);
01683     CAAccountingDBInterface::releaseConnection(dbInterface);
01684     dbInterface = NULL;
01685   }
01686 
01687 
01688   SINT32 prepaidIvalLowerBound = 0; //(-1*(SINT32)CALibProxytest::getOptions()->getPrepaidInterval()); /* EXPERIMENTAL: transmit negative prepaid bytes (but not less than -PREPAID_BYTES) */
01689   if (prepaidAmount <  prepaidIvalLowerBound)
01690   {
01691     prepaidAmount = prepaidIvalLowerBound;
01692   }
01693   //CAMsg::printMsg( LOG_DEBUG, "handleAccountCertificate read %i prepaid bytes\n", prepaidAmount);
01694   setDOMElementValue( elemPrepaid, prepaidAmount);
01695 
01696   // send XML struct to Jap & set auth flags
01697   pAccInfo->pControlChannel->sendXMLMessage(doc);
01698   if (doc != NULL)
01699   {
01700     doc->release();
01701     doc = NULL;
01702   }
01703   pAccInfo->authFlags |= AUTH_CHALLENGE_SENT | AUTH_GOT_ACCOUNTCERT | AUTH_TIMEOUT_STARTED;
01704   pAccInfo->challengeSentSeconds = time(NULL);
01705   //CAMsg::printMsg("Last Account Certificate request seconds: for IP %u%u%u%u", (UINT8)pHashEntry->peerIP[0], (UINT8)pHashEntry->peerIP[1],(UINT8) pHashEntry->peerIP[2], (UINT8)pHashEntry->peerIP[3]);
01706 
01707   //CAMsg::printMsg( LOG_ERR, "CAAccountingInstance::handleAccountCertificate stop\n");
01708 
01709 
01710   pAccInfo->mutex->unlock();
01711   return CAXMLErrorMessage::ERR_OK;
01712 }
01713 
01714 
01715 UINT32 CAAccountingInstance::handleChallengeResponse(tAiAccountingInfo* pAccInfo, DOMElement* root)
01716 {
01717   return handleChallengeResponse_internal(pAccInfo, root);
01718   INIT_STACK;
01719   FINISH_STACK("CAAccountingInstance::handleChallengeResponse");
01720 }
01721 
01722 
01729 UINT32 CAAccountingInstance::handleChallengeResponse_internal(tAiAccountingInfo* pAccInfo, DOMElement* root)
01730 {
01731   INIT_STACK;
01732   BEGIN_STACK("CAAccountingInstance::handleChallengeResponse");
01733 
01734 
01735   //CAMsg::printMsg( LOG_ERR, "CAAccountingInstance::handleChallengeResponse start\n");
01736 
01737 
01738   UINT8 decodeBuffer[ 512 ];
01739   UINT32 decodeBufferLen = 512;
01740   UINT32 usedLen;
01741   /* DOMElement* elemPanic=NULL;
01742   DSA_SIG * pDsaSig=NULL; */
01743   SINT32 prepaidAmount = 0;
01744   AccountLoginHashEntry* loginEntry;
01745   CAXMLCostConfirmation* pCC = NULL;
01746   bool bSendCCRequest = true;
01747   UINT32 status;
01748 
01749   // check current authstate
01750 
01751   if (pAccInfo == NULL)
01752   {
01753     return CAXMLErrorMessage::ERR_NO_RECORD_FOUND;
01754   }
01755 
01756   pAccInfo->mutex->lock();
01757 
01758   if (pAccInfo->authFlags & AUTH_DELETE_ENTRY)
01759   {
01760     pAccInfo->mutex->unlock();
01761     return CAXMLErrorMessage::ERR_NO_ERROR_GIVEN;
01762   }
01763 
01764   if( (!(pAccInfo->authFlags & AUTH_GOT_ACCOUNTCERT)) ||
01765       (!(pAccInfo->authFlags & AUTH_CHALLENGE_SENT))
01766     )
01767   {
01768     pAccInfo->mutex->unlock();
01769     return CAXMLErrorMessage::ERR_NO_ERROR_GIVEN;
01770   }
01771   pAccInfo->authFlags &= ~AUTH_CHALLENGE_SENT;
01772 
01773   // get raw bytes of response
01774   if ( getDOMElementValue( root, decodeBuffer, &decodeBufferLen ) != E_SUCCESS )
01775   {
01776     CAMsg::printMsg( LOG_DEBUG, "ChallengeResponse has wrong XML format. Ignoring\n" );
01777     pAccInfo->mutex->unlock();
01778     return CAXMLErrorMessage::ERR_WRONG_FORMAT;
01779   }
01780   DOMElement *elemClientVersion = NULL;
01781   getDOMChildByName(root, "ClientVersion", elemClientVersion, false);
01782   if(elemClientVersion != NULL)
01783   {
01784     UINT32 clientVersionStrLen = CLIENT_VERSION_STR_LEN;
01785     UINT8 *clientVersionStr = new UINT8[clientVersionStrLen];
01786     memset(clientVersionStr, 0, clientVersionStrLen);
01787     if( getDOMElementValue(elemClientVersion, clientVersionStr, &clientVersionStrLen) != E_SUCCESS)
01788     {
01789       delete [] clientVersionStr;
01790       clientVersionStr = NULL;
01791     }
01792 #ifdef DEBUG
01793     CAMsg::printMsg(LOG_DEBUG, "Client Version (account %llu): %s\n",
01794         pAccInfo->accountNumber,
01795         (clientVersionStr != NULL ? clientVersionStr : (UINT8*) "<not set>"));
01796 #endif
01797     pAccInfo->clientVersion = clientVersionStr;
01798   }
01799   else
01800   {
01801     pAccInfo->clientVersion = NULL;
01802   }
01803   decodeBuffer[decodeBufferLen] = 0;
01804 
01805   usedLen = decodeBufferLen;
01806   decodeBufferLen = 512;
01807   CABase64::decode( decodeBuffer, usedLen, decodeBuffer, &decodeBufferLen );
01808 
01809   /*
01810   UINT8 b64Challenge[ 512 ];
01811   UINT32 b64Len = 512;
01812   CABase64::encode(pHashEntry->pAccountingInfo->pChallenge, 222, b64Challenge, &b64Len);
01813   CAMsg::printMsg(LOG_DEBUG, "Challenge:\n%s\n", b64Challenge);
01814   */
01815 
01816   // check signature
01817   //pDsaSig = DSA_SIG_new();
01818   CASignature * sigTester = pAccInfo->pPublicKey;
01819   //sigTester->decodeRS( decodeBuffer, decodeBufferLen, pDsaSig );
01820   if ( sigTester->verifyDER( pAccInfo->pChallenge, 222, decodeBuffer, decodeBufferLen )
01821     != E_SUCCESS )
01822   {
01823     UINT8 accountNrAsString[32];
01824     print64(accountNrAsString, pAccInfo->accountNumber);
01825     CAMsg::printMsg(LOG_ERR, "Challenge-response authentication failed for account %s!\n", accountNrAsString);
01826     pAccInfo->authFlags |= AUTH_FAKE;
01827     pAccInfo->authFlags &= ~AUTH_ACCOUNT_OK;
01828     pAccInfo->mutex->unlock();
01829     return CAXMLErrorMessage::ERR_BAD_SIGNATURE;
01830   }
01831 
01832   pAccInfo->authFlags |= AUTH_ACCOUNT_OK; // authentication successful
01833 
01834   //EXPERIMENTAL NEW CODE for intercepting multiple login attempts
01835   m_currentAccountsHashtable->getMutex()->lock();
01836   loginEntry = (AccountLoginHashEntry*)m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
01837   struct t_fmhashtableentry *ownerRef = NULL;
01838   if(loginEntry != NULL) // (other) user (with same account) already logged in
01839   {
01840     ownerRef  = loginEntry->ownerRef;
01841     if(ownerRef != NULL)
01842     {
01843       bool isLoginFree = testAndSetLoginOwner(loginEntry, ownerRef);
01844       //obtaining ownership and setting loginProcessOngoing also means to cleanup the
01845       //old login entry after the connection belonging to the old login is closed.
01846       //So it can be assured that no other login-thread will find a NULL entry at the above if-statement
01847       m_currentAccountsHashtable->getMutex()->unlock();
01848       //abort if another thread is logging in but ...
01849       if(!isLoginFree)
01850       {
01851         CAMsg::printMsg(LOG_DEBUG, "Exiting because login is occupied for owner %p of account %llu.\n", ownerRef);
01852         pAccInfo->authFlags |= AUTH_MULTIPLE_LOGIN;
01853         pAccInfo->mutex->unlock();
01854         return CAXMLErrorMessage::ERR_MULTIPLE_LOGIN;
01855       }
01856       //...if the former login is finished and the connection is in use: force the previous login-connection to be kicked out.
01857       m_mix->getLoginMutex()->lock();
01858       CAXMLErrorMessage kickoutMsg(CAXMLErrorMessage::ERR_MULTIPLE_LOGIN);
01859       XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
01860       kickoutMsg.toXmlDocument(errDoc);
01861       //Note: the ownerRef hashEntry can already be cleared at that point.
01862       if(  m_mix->forceKickout(ownerRef, errDoc)  )
01863       {
01864         CAMsg::printMsg(LOG_DEBUG, "Kickout was requested for owner %p of account %llu, waiting...\n", ownerRef,
01865             pAccInfo->accountNumber);
01866         //Synchronize until the main thread can sure that the connection is closed. (After FirstMixA::checkConnections()
01867         // in main loop)
01868         //not dangerous if ensured that the cleanup notifier is always locked after loginCV
01869         //but it is necessary to lock cleanupNotifier before releasing loginCV. otherwise we might lose
01870         //the signal from cleanupNotifier. This can't happen if the main thread that
01871         //peforms the cleanup is still blokced by loginCV before it can acquire cleanupNotifier during the cleanup.
01872         ownerRef->cleanupNotifier->lock();
01873         m_mix->getLoginMutex()->unlock();
01874         ownerRef->cleanupNotifier->wait();
01875         ownerRef->cleanupNotifier->unlock();
01876       }
01877       else
01878       {
01879         m_mix->getLoginMutex()->unlock();
01880         //if the forceKickout returns false the ownerRef was already cleared.
01881         //no need to wait any further.
01882         CAMsg::printMsg(LOG_INFO, "ownerRef %p of account %llu already kicked out.\n", ownerRef, pAccInfo->accountNumber);
01883       }
01884       errDoc->release();
01885       errDoc = NULL;
01886       //obtain hashtable lock again.
01887       m_currentAccountsHashtable->getMutex()->lock();
01888       if(loginEntry != NULL)
01889       {
01890         //When login ownership was obtained: cleanup the former entry.
01891         CAMsg::printMsg(LOG_INFO, "finally cleaning up loginEntry %p for former owner %p of account %llu\n",
01892                           loginEntry, loginEntry->ownerRef, pAccInfo->accountNumber);
01893         ms_pInstance->m_currentAccountsHashtable->remove(&(pAccInfo->accountNumber));
01894         delete loginEntry->ownerLock;
01895         delete loginEntry;
01896         loginEntry = NULL;
01897       }
01898     }
01899     else
01900     {
01901       //Impossible or Bug
01902       CAMsg::printMsg(LOG_CRIT, "BUG: ownerRef of an active login entry MUST NOT be null. Please report.\n");
01903       m_currentAccountsHashtable->getMutex()->unlock();
01904       pAccInfo->mutex->unlock();
01905       return CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR;
01906     }
01907   }
01908   //POST CONDITION: old login entry cleared.
01909   loginEntry = new AccountLoginHashEntry;
01910   loginEntry->accountNumber = pAccInfo->accountNumber;
01911   loginEntry->count = 1;
01912   loginEntry->confirmedBytes = 0;
01913   loginEntry->authRemoveFlags = 0;
01914   loginEntry->authFlags = 0;
01915   loginEntry->userID = pAccInfo->userID;
01916   loginEntry->ownerRef = pAccInfo->ownerRef;
01917   loginEntry->loginOngoing = true;
01918   loginEntry->ownerLock = new CAMutex();
01919   m_currentAccountsHashtable->put(&(loginEntry->accountNumber), loginEntry);
01920 
01921   //m_currentAccountsHashtable->getMutex()->unlock();
01922 
01923   // fetch cost confirmation from last session if available, and retrieve information; synchronized with settle thread
01924   bool bSettled;
01925   CAAccountingDBInterface *dbInterface = CAAccountingDBInterface::getConnection();
01926 #ifdef DEBUG
01927   CAMsg::printMsg(LOG_DEBUG, "Checking database for previously prepaid bytes...\n");
01928 #endif
01929 
01930   if(dbInterface != NULL)
01931   {
01932     prepaidAmount = dbInterface->getPrepaidAmount(pAccInfo->accountNumber, m_currentCascade, false);
01933     dbInterface->getCostConfirmation(pAccInfo->accountNumber, m_currentCascade, &pCC, bSettled);
01934   }
01935   else
01936   {
01937     prepaidAmount = 0;
01938   }
01939 
01940 
01941   if (pCC != NULL)
01942   {
01943     if(!cascadeMatchesCC(pCC))
01944     {
01945       delete pCC;
01946       pCC = NULL;
01947       CAMsg::printMsg(LOG_INFO, "CC do not match current Cascade. Discarding CC.\n");
01948     }
01949   }
01950 
01951   if (pCC != NULL)
01952   {
01953     if (bSettled)
01954     {
01955       pAccInfo->authFlags &= ~AUTH_WAITING_FOR_FIRST_SETTLED_CC;
01956     }
01957 #ifdef DEBUG
01958     CAMsg::printMsg(LOG_DEBUG, "pAccInfo->transferredBytes is %llu, confirmedBytes: %llu, pCC->transferredBytes is %llu\n",
01959         pAccInfo->transferredBytes, pAccInfo->confirmedBytes, pCC->getTransferredBytes());
01960 #endif
01961     pAccInfo->transferredBytes += pCC->getTransferredBytes();
01962     pAccInfo->confirmedBytes = pCC->getTransferredBytes();
01963     #ifdef DEBUG
01964       UINT8 tmp[32];
01965       print64(tmp,pAccInfo->transferredBytes);
01966       CAMsg::printMsg(LOG_DEBUG, "Setting confirmedBytes to %llu, pAccInfo->transferredBytes is now %s\n",
01967           pAccInfo->confirmedBytes, tmp);
01968     #endif
01969     //delete pCC;
01970   }
01971   else
01972   {
01973     UINT8 tmp[32];
01974     print64(tmp,pAccInfo->accountNumber);
01975     CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Cost confirmation for account %s not found in database. This seems to be a new user.\n", tmp);
01976   }
01977 
01979   //pAccInfo->mutex->unlock();
01980 //  m_currentAccountsHashtable->getMutex()->lock();
01981 //  pAccInfo->authFlags |= AUTH_ACCOUNT_OK; // authentication successful
01982 //
01983 //  loginEntry = (AccountLoginHashEntry*)m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
01984 //  //now loginEntry == NULL must be asserted
01985 //  if (!loginEntry)
01986 //  {
01987 //    // remember that this user is logged in at least once
01988 //    loginEntry = new AccountLoginHashEntry;
01989 //    loginEntry->accountNumber = pAccInfo->accountNumber;
01990 //    loginEntry->count = 1;
01991 //    loginEntry->confirmedBytes = 0;
01992 //    loginEntry->authRemoveFlags = 0;
01993 //    loginEntry->authFlags = 0;
01994 //    loginEntry->userID = pAccInfo->userID;
01995 //    m_currentAccountsHashtable->put(&(loginEntry->accountNumber), loginEntry);
01996 //    if (!(AccountLoginHashEntry*)m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber)))
01997 //    {
01998 //      UINT8 accountNrAsString[32];
01999 //      print64(accountNrAsString, pAccInfo->accountNumber);
02000 //      CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Could not insert login entry for account %s!", accountNrAsString);
02001 //    }
02002 //  }
02003 //  else
02004 //  {
02005 //    loginEntry->count++;
02006 //  }
02007 //  if (loginEntry->count > 1)
02008 //  {
02009 //    /*
02010 //     * There already is a user logged in with this account.
02011 //     */
02012 //    UINT8 accountNrAsString[32];
02013 //    print64(accountNrAsString, pAccInfo->accountNumber);
02014 //    if (loginEntry->count < MAX_TOLERATED_MULTIPLE_LOGINS)
02015 //    {
02016 //      // There is now more than one user logged in with this account; kick out the other users!
02017 //      CAMsg::printMsg(LOG_INFO,
02018 //              "CAAccountingInstance: Multiple logins (%d) of user with account %s detected! \
02019 //              Kicking out other users with this account...\n",
02020 //              loginEntry->count, accountNrAsString);
02021 //      loginEntry->userID = pAccInfo->userID; // this is the current user; kick out the others
02022 //    }
02023 //    else
02024 //    {
02025 //      /* The maximum of tolerated concurrent logins for this user is exceeded.
02026 //       * He won't get any new access again before the old connections have been closed!
02027 //       * @mod: in this case not more than one login is allowed at a time. The User has to wait until
02028 //       * the old login will be deleted.
02029 //       */
02030 //      CAMsg::printMsg(LOG_INFO,
02031 //              "CAAccountingInstance: Maximum of multiple logins exceeded (%d) for user with account %s! \
02032 //              Kicking out this user!\n",
02033 //              loginEntry->count, accountNrAsString);
02034 //      bSendCCRequest = false; // not needed...
02035 //      pAccInfo->authFlags |= AUTH_MULTIPLE_LOGIN;
02036 //
02037 //      delete pCC;
02038 //      pCC = NULL;
02039 //      m_currentAccountsHashtable->getMutex()->unlock();
02040 //      pAccInfo->mutex->unlock();
02041 //      return CAXMLErrorMessage::ERR_MULTIPLE_LOGIN;
02042 //    }
02043 //  }
02044 
02045   UINT8 tmp[32];
02046   print64(tmp,pAccInfo->accountNumber);
02047   if (prepaidAmount > 0)
02048   {
02049     CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Got %d prepaid bytes for account nr. %s.\n",prepaidAmount, tmp);
02050 
02051     //pAccInfo->authFlags &= ~AUTH_WAITING_FOR_FIRST_SETTLED_CC;
02052 
02053     if (pAccInfo->transferredBytes >= (UINT32)prepaidAmount)
02054     {
02055       pAccInfo->transferredBytes -= prepaidAmount;
02056     }
02057     else
02058     {
02059       UINT8 tmp2[32];
02060       print64(tmp2, pAccInfo->transferredBytes);
02061       CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Transferred bytes of %s for account %s are lower than prepaid amount! "
02062                   "Maybe we lost a CC?\n",tmp2, tmp);
02063       prepaidAmount = 0;
02064     }
02065   }
02066   else
02067   {
02068     prepaidAmount = 0;
02069     CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: No database record for prepaid bytes found for account nr. %s.\n", tmp);
02070   }
02071   //CAMsg::printMsg(LOG_DEBUG, "Number of prepaid (confirmed-transferred) bytes : %d \n",pAccInfo->confirmedBytes-pAccInfo->transferredBytes);
02072 
02078    SINT32 dbRet;
02079   if(dbInterface != NULL);
02080   {
02081     dbRet = dbInterface->getAccountStatus(pAccInfo->accountNumber, status);
02082     CAAccountingDBInterface::releaseConnection(dbInterface);
02083     dbInterface = NULL;
02084   }
02085 
02086   if (dbRet != E_SUCCESS)
02087   {
02088     UINT8 tmp[32];
02089     print64(tmp,pAccInfo->accountNumber);
02090     CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Could not check status for account %s!\n", tmp);
02091   }
02092   else if (status > CAXMLErrorMessage::ERR_OK)
02093   {
02094     //UINT32 authFlags = 0;
02095     //the auth flags are set after this check, but they need to be verified during a forced settlement
02096     //at the end of the login. (see finishLoginProcess())
02097     CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Illegal status %u for account %llu found.\n",
02098         status, pAccInfo->accountNumber);
02099     if (status == CAXMLErrorMessage::ERR_BLOCKED)
02100     {
02101       pAccInfo->authFlags |= AUTH_BLOCKED;
02102     }
02103     else if (status == CAXMLErrorMessage::ERR_KEY_NOT_FOUND)
02104     {
02105       pAccInfo->authFlags |= AUTH_INVALID_ACCOUNT;
02106     }
02107     else if (status == CAXMLErrorMessage::ERR_ACCOUNT_EMPTY)
02108     {
02109       pAccInfo->authFlags |= AUTH_ACCOUNT_EMPTY;
02110     }
02111 
02112     /*if (authFlags)
02113     {
02114       pAccInfo->authFlags |= AUTH_BLOCKED;
02115       if (loginEntry->confirmedBytes == 0)
02116       {
02117         loginEntry->confirmedBytes = pAccInfo->confirmedBytes;
02118       }
02119     }*/
02120   }
02121   m_currentAccountsHashtable->getMutex()->unlock();
02122 
02124   //pAccInfo->mutex->lock();
02125   SINT32 sendStatus = E_SUCCESS;
02126   if (bSendCCRequest)
02127   {
02128     // fetch cost confirmation from last session if available, and send it
02129     //CAXMLCostConfirmation * pCC = NULL;
02130     //m_dbInterface->getCostConfirmation(pAccInfo->accountNumber, m_currentCascade, &pCC);
02131     if(pCC != NULL)
02132     {
02133 #ifdef DEBUG
02134       CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Sending pcc to sign with %llu transferred bytes\n", pCC->getTransferredBytes());
02135 #endif
02136       // the typical case; the user had logged in before
02137       /* there shouldn't be any counting synchronisation problems with the JAP
02138        * because the new login protocol doesn't permit JAPs
02139        * to exchange data before login is finished.
02140        */
02141       UINT32 prepaidIval = CALibProxytest::getOptions()->getPrepaidInterval();
02142       pAccInfo->bytesToConfirm = (prepaidIval - prepaidAmount) + pCC->getTransferredBytes();
02143 #ifdef DEBUG
02144       CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: before CC request, bytesToConfirm: %llu, prepaidIval: %u, "
02145           "prepaidAmount: %d, transferred bytes: %llu\n",
02146           pAccInfo->bytesToConfirm, prepaidIval, prepaidAmount, pAccInfo->transferredBytes);
02147 
02148 #endif
02149       if( (pAccInfo->clientVersion == NULL) ||
02150         (strncmp((char*)pAccInfo->clientVersion, PREPAID_PROTO_CLIENT_VERSION, CLIENT_VERSION_STR_LEN) < 0) )
02151       {
02152         //old CC without payRequest and prepaid bytes.
02153         //CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Account %llu: Old prepaid proto version.\n", pAccInfo->accountNumber);
02154         sendStatus = pAccInfo->pControlChannel->sendXMLMessage(pCC->getXMLDocument());
02155 
02156       }
02157       else
02158       {
02159         //CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Account %llu: New prepaid proto version. prepaid bytes: %d\n",
02160         //    pAccInfo->accountNumber, prepaidAmount);
02161         sendStatus = sendInitialCCRequest(pAccInfo, pCC, prepaidAmount);
02162       }
02163     }
02164     else
02165     {
02166       // there is no CC in the database; typically this is the first connection of this user
02167       if (prepaidAmount > 0)
02168       {
02169         // Delete any previously stored prepaid amount; there should not be any! CC lost?
02170         pAccInfo->transferredBytes += prepaidAmount;
02171       }
02172       sendStatus = sendCCRequest(pAccInfo);
02173     }
02174   }
02175 
02176 
02177   delete pCC;
02178   pCC = NULL;
02179 
02180 
02181   if ( pAccInfo->pChallenge != NULL ) // free mem
02182   {
02183     delete[] pAccInfo->pChallenge;
02184     pAccInfo->pChallenge = NULL;
02185   }
02186   //CAMsg::printMsg( LOG_ERR, "CAAccountingInstance::handleChallengeResponse stop\n");
02187 
02188   pAccInfo->mutex->unlock();
02189   if(sendStatus == E_SUCCESS)
02190   {
02191     return CAXMLErrorMessage::ERR_OK;
02192   }
02193   else
02194   {
02195     return CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR;
02196   }
02197 }
02198 
02199 UINT32 CAAccountingInstance::handleCostConfirmation(tAiAccountingInfo* pAccInfo, DOMElement* root)
02200 {
02201   return handleCostConfirmation_internal(pAccInfo, root);
02202   INIT_STACK;
02203   FINISH_STACK("CAAccountingInstance::handleCostConfirmation");
02204 }
02205 
02209 UINT32 CAAccountingInstance::handleCostConfirmation_internal(tAiAccountingInfo* pAccInfo, DOMElement* root)
02210 {
02211   INIT_STACK;
02212   BEGIN_STACK("CAAccountingInstance::handleCostConfirmation");
02213 
02214   if (pAccInfo == NULL)
02215   {
02216     return CAXMLErrorMessage::ERR_NO_RECORD_FOUND;
02217   }
02218 
02219   pAccInfo->mutex->lock();
02220 
02221   if ( (pAccInfo->authFlags & AUTH_DELETE_ENTRY) ||
02222      (!(pAccInfo->authFlags & AUTH_LOGIN_NOT_FINISHED ) && (pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY )) )
02223   {
02224     CAMsg::printMsg(LOG_ERR,
02225           "CAAccountingInstance::handleCostConfirmation Ignoring CC, restricted flags set: %s %s\n",
02226           ((pAccInfo->authFlags & AUTH_DELETE_ENTRY) ? "AUTH_DELETE_ENTRY" : "") ,
02227           ((pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY) ? "AUTH_ACCOUNT_EMPTY" : ""));
02228     // ignore CCs for this account!
02229     pAccInfo->mutex->unlock();
02230     return CAXMLErrorMessage::ERR_NO_ERROR_GIVEN;
02231   }
02232 
02233   // check authstate
02234   if (!(pAccInfo->authFlags & AUTH_GOT_ACCOUNTCERT) ||
02235     !(pAccInfo->authFlags & AUTH_ACCOUNT_OK) ||
02236     !(pAccInfo->authFlags & AUTH_SENT_CC_REQUEST))
02237   {
02238     CAMsg::printMsg(LOG_ERR,
02239       "CAAccountingInstance::handleCostConfirmation CC was received but has not been requested! Ignoring...\n");
02240 
02241     pAccInfo->mutex->unlock();
02242     return CAXMLErrorMessage::ERR_NO_ERROR_GIVEN;
02243   }
02244 
02245   CAXMLCostConfirmation* pCC = CAXMLCostConfirmation::getInstance(root);
02246   if(pCC==NULL)
02247   {
02248     pAccInfo->mutex->unlock();
02249     return CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR;
02250   }
02251 
02252   // for debugging only: test signature the oldschool way
02253   // warning this removes the signature from doc!!!
02254   if (pAccInfo->pPublicKey==NULL||
02255     pAccInfo->pPublicKey->verifyXML( root ) != E_SUCCESS)
02256   {
02257     // wrong signature
02258     CAMsg::printMsg( LOG_INFO, "CostConfirmation has INVALID SIGNATURE!\n" );
02259     CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_SIGNATURE, (UINT8*)"CostConfirmation has bad signature");
02260     XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
02261     err.toXmlDocument(errDoc);
02262     pAccInfo->pControlChannel->sendXMLMessage(errDoc);
02263     if (errDoc != NULL)
02264     {
02265       errDoc->release();
02266       errDoc = NULL;
02267     }
02268     delete pCC;
02269     pCC = NULL;
02270     pAccInfo->mutex->unlock();
02271     return CAXMLErrorMessage::ERR_BAD_SIGNATURE;
02272   }
02273   #ifdef DEBUG
02274   else
02275     {
02276       CAMsg::printMsg( LOG_DEBUG, "CostConfirmation Signature is OK.\n");
02277     }
02278   #endif
02279 
02280 
02281   if (pCC->getNumberOfHashes() != m_allHashesLen)
02282   {
02283     CAMsg::printMsg( LOG_INFO, "CostConfirmation has illegal number of price cert hashes!\n" );
02284     CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_REQUEST,
02285       (UINT8*)"CostConfirmation has illegal number of price cert hashes");
02286     XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
02287     err.toXmlDocument(errDoc);
02288     pAccInfo->pControlChannel->sendXMLMessage(errDoc);
02289     if (errDoc != NULL)
02290     {
02291       errDoc->release();
02292       errDoc = NULL;
02293     }
02294     delete pCC;
02295     pCC = NULL;
02296     pAccInfo->mutex->unlock();
02297     return CAXMLErrorMessage::ERR_WRONG_FORMAT;
02298   }
02299 
02300   /*Hashtable* certHashCC =
02301     new Hashtable((UINT32 (*)(void *))Hashtable::stringHash, (SINT32 (*)(void *,void *))Hashtable::stringCompare);
02302   UINT8* certHash;*/
02303   //bool bFailed = false;
02304   //for (UINT32 i = 0; i < pCC->getNumberOfHashes(); i++)
02305   //{
02306   //  certHash = pCC->getPriceCertHash(i);
02307   //  certHashCC->put(certHash, certHash);
02308     /*
02309     if ((certHash = (UINT8*)certHashCC->getValue(certHash)) != NULL)
02310     {
02311       CAMsg::printMsg( LOG_INFO, "CC1: %s\n", certHash);
02312     }*/
02313   //}
02314   //for (UINT32 i = 0; i < m_allHashesLen; i++)
02315   //{
02316     //CAMsg::printMsg( LOG_INFO, "CA:  %s\n", m_allHashes[i]);
02317   //  certHash = (UINT8*)certHashCC->remove(m_allHashes[i]);
02318   //  if (certHash == NULL)
02319   //  {
02320   //    bFailed = true;
02321   //    break;
02322   //  }
02323   //  else
02324   //  {
02325   //    delete[] certHash;
02326   //  }
02327   //}
02328   //certHashCC->clear(HASH_EMPTY_NONE, HASH_EMPTY_DELETE);
02329   //delete certHashCC;
02330 
02331   if (!cascadeMatchesCC(pCC))
02332   {
02333     CAMsg::printMsg( LOG_INFO, "CostConfirmation has invalid price cert hashes!\n" );
02334     CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_REQUEST,
02335       (UINT8*)"CostConfirmation has invalid price cert hashes");
02336     XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
02337     err.toXmlDocument(errDoc);
02338     pAccInfo->pControlChannel->sendXMLMessage(errDoc);
02339     if (errDoc != NULL)
02340     {
02341       errDoc->release();
02342       errDoc = NULL;
02343     }
02344     delete pCC;
02345     pCC = NULL;
02346     pAccInfo->mutex->unlock();
02347     return CAXMLErrorMessage::ERR_WRONG_DATA;
02348   }
02349 
02350 
02351 
02352   // parse & set transferredBytes
02353   //when using Prepayment, this check is outdated, but left in to notice the most crude errors/cheats
02354   //The CC's transferredBytes should be equivalent to
02355   //AccInfo's confirmed bytes + the Config's PrepaidInterval - the number of bytes transferred between
02356   //requesting and receiving the CC
02357 #ifdef DEBUG
02358   CAMsg::printMsg( LOG_DEBUG, "received cost confirmation for  %llu transferred bytes where confirmed bytes are %llu, we need %llu bytes to confirm"
02359       ", mix already counted %llu transferred bytes\n",
02360       pCC->getTransferredBytes(), pAccInfo->confirmedBytes, pAccInfo->bytesToConfirm,
02361       pAccInfo->transferredBytes);
02362 #endif
02363 
02364   if(pCC->getTransferredBytes() > (pAccInfo->transferredBytes+CALibProxytest::getOptions()->getPrepaidInterval()) )
02365   {
02366     CAMsg::printMsg( LOG_ERR, "Warning: ignoring this CC for account %llu "
02367         "because it tries to confirm %lld prepaid bytes where only %u prepaid bytes are allowed (cc->tranferredbytes: %llu, accInfo->tranferredBytes: %llu)\n",
02368         pAccInfo->accountNumber, (pCC->getTransferredBytes() - pAccInfo->transferredBytes),
02369         CALibProxytest::getOptions()->getPrepaidInterval(),
02370         pCC->getTransferredBytes(), pAccInfo->transferredBytes);
02371 
02372     CAXMLErrorMessage err(CAXMLErrorMessage::ERR_WRONG_DATA,
02373       (UINT8*)"More bytes confirmed than allowed.");
02374     XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
02375     err.toXmlDocument(errDoc);
02376     pAccInfo->pControlChannel->sendXMLMessage(errDoc);
02377     if (errDoc != NULL)
02378     {
02379       errDoc->release();
02380       errDoc = NULL;
02381     }
02382     //mark as account empty has the effect is that the user can empty his prepaid amount and then will be kicked out.
02383     pAccInfo->authFlags |= AUTH_FAKE;
02384     delete pCC;
02385     pCC = NULL;
02386     pAccInfo->mutex->unlock();
02387     return CAXMLErrorMessage::ERR_WRONG_DATA;
02388   }
02389 
02390   if (pCC->getTransferredBytes() < pAccInfo->confirmedBytes)
02391   {
02392 
02393     CAMsg::printMsg( LOG_ERR, "CostConfirmation has insufficient number of bytes:\n");
02394     CAMsg::printMsg( LOG_ERR, "CC->transferredBytes: %llu < confirmedBytesBytes: %llu\n", pCC->getTransferredBytes(), pAccInfo->confirmedBytes);
02395 
02396     if(pAccInfo->authFlags & AUTH_LOGIN_NOT_FINISHED)
02397     {
02398       //@todo: perhaps we should use another flag to indicate that this user should be kicked out.
02399       pAccInfo->authFlags |= AUTH_FAKE;
02400       delete pCC;
02401       pCC = NULL;
02402       pAccInfo->mutex->unlock();
02403       return CAXMLErrorMessage::ERR_WRONG_DATA;
02404     }
02405 
02406     /*
02407     CAXMLErrorMessage err(CAXMLErrorMessage::ERR_WRONG_DATA,
02408       (UINT8*)"Your CostConfirmation has a wrong number of transferred bytes");
02409     DOM_Document errDoc;
02410     err.toXmlDocument(errDoc);
02411     pAccInfo->pControlChannel->sendXMLMessage(errDoc);*/
02412   }
02413   else if (pCC->getTransferredBytes() == pAccInfo->confirmedBytes && getPrepaidBytes(pAccInfo) != CALibProxytest::getOptions()->getPrepaidInterval())
02414   {
02415     CAMsg::printMsg(LOG_WARNING, "Received CostConfirmation for account %llu has no difference in bytes to current CC (%llu bytes).\n", 
02416       pAccInfo->accountNumber, pCC->getTransferredBytes());
02417   }
02418   else
02419   {
02420     /*
02421     UINT8 tmp[32];
02422     print64(tmp,pCC->getTransferredBytes());
02423     CAMsg::printMsg( LOG_ERR, "Transferredbytes in CC: %s\n", tmp);
02424     */
02425     SINT32 dbRet = E_UNKNOWN;
02426     CAAccountingDBInterface *dbInterface = CAAccountingDBInterface::getConnection();
02427     if(dbInterface != NULL)
02428     {
02429       dbRet = dbInterface->storeCostConfirmation(*pCC, m_currentCascade);
02430       CAAccountingDBInterface::releaseConnection(dbInterface);
02431       dbInterface = NULL;
02432     }
02433     if (dbRet != E_SUCCESS)
02434     {
02435       UINT8 tmp[32];
02436       print64(tmp,pCC->getAccountNumber());
02437       CAMsg::printMsg( LOG_INFO, "CostConfirmation for account %s could not be stored in database!\n", tmp );
02438       pAccInfo->authFlags |= AUTH_DATABASE;
02439     }
02440     else
02441     {
02442 #ifdef DEBUG
02443       CAMsg::printMsg( LOG_INFO, "Handle CC: pCC->transBytes: %llu\n", pCC->getTransferredBytes() );
02444 #endif
02445       pAccInfo->confirmedBytes = pCC->getTransferredBytes();
02446 
02447       if (pAccInfo->authFlags & AUTH_WAITING_FOR_FIRST_SETTLED_CC)
02448       {
02449         // initiate immediate settling
02450 #ifdef DEBUG
02451         UINT64 currentMillis;
02452         UINT8 tmpStrCurrentMillis[50];
02453         getcurrentTimeMillis(currentMillis);
02454         print64(tmpStrCurrentMillis,currentMillis);
02455         CAMsg::printMsg(LOG_DEBUG, "AccountingSettleThread: Settle ini: %s\n", tmpStrCurrentMillis);
02456 #endif
02457         m_pSettleThread->settle();
02458 
02459       }
02460     }
02461   }
02462 #ifdef DEBUG
02463   CAMsg::printMsg(LOG_ERR, "Handle CC request: pAccInfo->confirmedBytes: %llu, ppAccInfo->transferredBytes: %llu\n",
02464       pAccInfo->confirmedBytes, pAccInfo->transferredBytes);
02465 #endif
02466   if (pAccInfo->confirmedBytes >= pAccInfo->bytesToConfirm)
02467   {
02468     // the user confirmed everything we wanted; if a timeout has been set, it should be reset
02469     pAccInfo->authFlags &= ~AUTH_HARD_LIMIT_REACHED;
02470     pAccInfo->lastHardLimitSeconds = time(NULL);
02471   }
02472   else
02473   {
02474     /*UINT8 tmp[32], tmp2[32], tmp3[32];
02475     print64(tmp, pCC->getTransferredBytes());
02476     print64(tmp2, pCC->getAccountNumber());
02477     print64(tmp3, pAccInfo->bytesToConfirm);*/
02478     CAMsg::printMsg(LOG_ERR, "AccountingSettleThread: Requested CC value has NOT been confirmed by account nr %llu! "
02479                  "Received Bytes: %llu/%llu "
02480                 "Client should not be allowed to login.\n",
02481                 pCC->getAccountNumber(),
02482                 pCC->getTransferredBytes(),
02483                 pAccInfo->bytesToConfirm);
02484 
02485     if(pAccInfo->authFlags & AUTH_LOGIN_SKIP_SETTLEMENT)
02486     {
02487       CAMsg::printMsg( LOG_INFO, "Skip settlement revoked.\n");
02488       pAccInfo->authFlags &= ~AUTH_LOGIN_SKIP_SETTLEMENT;
02489     }
02490     /*delete pCC;
02491     pCC = NULL;
02492     pAccInfo->mutex->unlock();
02493     pAccInfo->authFlags |= AUTH_FAKE;
02494     return CAXMLErrorMessage::ERR_WRONG_DATA;*/
02495     //m_pSettleThread->settle();
02496 
02497   }
02498 
02499   pAccInfo->bytesToConfirm = 0;
02500   pAccInfo->authFlags &= ~AUTH_SENT_CC_REQUEST;
02501 
02502   delete pCC;
02503   pCC = NULL;
02504   pAccInfo->mutex->unlock();
02505 
02506   return CAXMLErrorMessage::ERR_OK;
02507 }
02508 
02513 SINT32 CAAccountingInstance::initTableEntry( fmHashTableEntry * pHashEntry )
02514 {
02515   INIT_STACK;
02516   BEGIN_STACK("CAAccountingInstance::initTableEntry");
02517 
02518   //ms_pInstance->m_pMutex->lock();
02519 
02520   if (pHashEntry == NULL)
02521   {
02522     FINISH_STACK("CAAccountingInstance::initTableEntry:NULL");
02523     return E_UNKNOWN;
02524   }
02525 
02526   pHashEntry->pAccountingInfo = new tAiAccountingInfo;
02527   memset( pHashEntry->pAccountingInfo, 0, sizeof( tAiAccountingInfo ) );
02528 
02529   SAVE_STACK("CAAccountingInstance::initTableEntry", "After memset");
02530 
02531   pHashEntry->pAccountingInfo->authFlags =
02532     AUTH_SENT_ACCOUNT_REQUEST | AUTH_TIMEOUT_STARTED |
02533     AUTH_HARD_LIMIT_REACHED | AUTH_WAITING_FOR_FIRST_SETTLED_CC |
02534     AUTH_SENT_CC_REQUEST | AUTH_LOGIN_NOT_FINISHED; // prevents multiple CC requests on login
02535   pHashEntry->pAccountingInfo->authTimeoutStartSeconds = time(NULL);
02536   pHashEntry->pAccountingInfo->lastHardLimitSeconds = time(NULL);
02537   pHashEntry->pAccountingInfo->sessionPackets = 0;
02538   pHashEntry->pAccountingInfo->transferredBytes = 0;
02539   pHashEntry->pAccountingInfo->confirmedBytes = 0;
02540   pHashEntry->pAccountingInfo->bytesToConfirm = 0;
02541   pHashEntry->pAccountingInfo->nrInQueue = 0;
02542   pHashEntry->pAccountingInfo->userID = pHashEntry->id;
02543   pHashEntry->pAccountingInfo->ownerRef = pHashEntry;
02544   pHashEntry->pAccountingInfo->clientVersion = NULL;
02545   pHashEntry->pAccountingInfo->mutex = new CAMutex;
02546   //ms_pInstance->m_pMutex->unlock();
02547 
02548 
02549   FINISH_STACK("CAAccountingInstance::initTableEntry");
02550 
02551   return E_SUCCESS;
02552 }
02553 
02554 
02555 
02561 SINT32 CAAccountingInstance::cleanupTableEntry( fmHashTableEntry *pHashEntry )
02562   {
02563     INIT_STACK;
02564     BEGIN_STACK("CAAccountingInstance::cleanupTableEntry");
02565 
02566     //ms_pInstance->m_pMutex->lock();
02567     tAiAccountingInfo* pAccInfo = pHashEntry->pAccountingInfo;
02568     AccountLoginHashEntry* loginEntry;
02569     SINT32 prepaidBytes = 0;
02570     SINT32 prepaidInterval = CALibProxytest::getOptions()->getPrepaidInterval();
02571 
02572     if (pAccInfo == NULL)
02573     {
02574       SAVE_STACK("CAAccountingInstance::cleanupTableEntry", "acc info null");
02575       //ms_pInstance->m_pMutex->unlock();
02576       return E_UNKNOWN;
02577     }
02578 
02579     //pAccInfo->mutex->lock();
02580 
02581     pHashEntry->pAccountingInfo=NULL;
02582 
02583     if (pAccInfo->accountNumber)
02584     {
02585       CAMsg::printMsg(LOG_INFO, "cleaning up entry %p of accountno. %llu (pAccInfo ref: %p)\n",
02586               pHashEntry, pAccInfo->accountNumber, pAccInfo);
02587       if (pAccInfo->authFlags & AUTH_ACCOUNT_OK)
02588       {
02589         // remove login
02590         ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
02591         loginEntry = (AccountLoginHashEntry*)ms_pInstance->m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
02592 
02593         if (loginEntry)
02594         {
02595           // test: delete CC!!!
02596           //ms_pInstance->m_dbInterface->deleteCC(pAccInfo->accountNumber, ms_pInstance->m_currentCascade);
02597           if (testLoginEntryOwner(loginEntry, pHashEntry))// &&
02599           {
02600             if (loginEntry->authFlags & AUTH_ACCOUNT_EMPTY)
02601             {
02602               // make sure to store the correct number of prepaid bytes
02603               pAccInfo->confirmedBytes = loginEntry->confirmedBytes;
02604             }
02605             //store prepaid bytes in database, so the user wont lose the prepaid amount by disconnecting
02606             prepaidBytes = getPrepaidBytes(pAccInfo);
02607             if (prepaidBytes > 0)
02608             {
02609               if (prepaidBytes > prepaidInterval)
02610               {
02611                 UINT8 tmp[32];
02612                 print64(tmp, pAccInfo->accountNumber);
02613                 /* Client paid more than the prepaid interval -
02614                  * this is beyond specification and not allowed!
02615                  */
02616                 CAMsg::printMsg(LOG_ERR,
02617                   "PrepaidBytes of %d for account %s are higher than prepaid interval! "
02618                   "The client (owner %x) did not behave according to specification. "
02619                   "Deleting prepaid bytes!\n", prepaidBytes, tmp, pHashEntry);
02620                   //"Deleting %d bytes...\n", prepaidBytes, tmp, pHashEntry, prepaidBytes - prepaidInterval);
02621 
02622                 //prepaidBytes = prepaidInterval;
02623                 prepaidBytes = 0;
02624               }
02625             }
02626 
02627             /*if (ms_pInstance->m_dbInterface)
02628             {
02629               ms_pInstance->m_dbInterface->storePrepaidAmount(pAccInfo->accountNumber,prepaidBytes, ms_pInstance->m_currentCascade);
02630             }*/
02631             CAAccountingDBInterface *dbInterface = CAAccountingDBInterface::getConnection();
02632             if(dbInterface != NULL)
02633             {
02634               dbInterface->storePrepaidAmount(pAccInfo->accountNumber,
02635                               prepaidBytes,
02636                               ms_pInstance->m_currentCascade);
02637               CAAccountingDBInterface::releaseConnection(dbInterface);
02638               dbInterface = NULL;
02639             }
02640             if(!isLoginOngoing(loginEntry, pHashEntry))
02641             {
02642               ms_pInstance->m_currentAccountsHashtable->remove(&(pAccInfo->accountNumber));
02643               delete loginEntry->ownerLock;
02644               delete loginEntry;
02645               loginEntry = NULL;
02646             }
02647             else
02648             {
02649               CAMsg::printMsg(LOG_INFO, "Cleaning: Leaving loginEntry %x cleanup of owner %x to the next owner due to double-login of a user.\n",
02650                   loginEntry, loginEntry->ownerRef);
02651             }
02652           }
02653 
02654           /*if (loginEntry->count <= 1)
02655           {
02656             if (loginEntry->count < 1)
02657             {
02658               CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Cleanup found non-positive number of user login hash entries (%d)!\n", loginEntry->count);
02659             }
02660             // this is the last active user connection; delete the entry
02661             ms_pInstance->m_currentAccountsHashtable->remove(&(pAccInfo->accountNumber));
02662             delete loginEntry->ownerLock;
02663             delete loginEntry;
02664             loginEntry = NULL;
02665           }
02666           else
02667           {
02668             // there are other connections from this user
02669             loginEntry->count--;
02670           }*/
02671         }
02672         else
02673         {
02674           CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Cleanup did not find user login hash entry!\n");
02675         }
02676         ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
02677       }
02678     }
02679     else
02680     {
02681       CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Cleanup method found account zero.\n");
02682     }
02683 
02684     //free memory of pAccInfo
02685 
02686     delete pAccInfo->pPublicKey;
02687     pAccInfo->pPublicKey = NULL;
02688 
02689 
02690     delete [] pAccInfo->pChallenge;
02691     pAccInfo->pChallenge = NULL;
02692 
02693     delete [] pAccInfo->pstrBIID;
02694     pAccInfo->pstrBIID = NULL;
02695 
02696     delete [] pAccInfo->clientVersion;
02697     pAccInfo->clientVersion = NULL;
02698 
02699     pHashEntry->pAccountingInfo=NULL;
02700 
02701     if (pAccInfo->nrInQueue > 0)
02702     {
02703       /*
02704       if (pAccInfo->accountNumber == 0)
02705       {
02706         CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: AI queue entries found for account zero: %u!\n", pAccInfo->nrInQueue);
02707       }
02708       else if (!(pAccInfo->authFlags & AUTH_ACCOUNT_OK))
02709       {
02710         UINT8 accountNrAsString[32];
02711         print64(accountNrAsString, pAccInfo->accountNumber);
02712         CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: AI queue entries found for unauthorized account %s: %u!\n", accountNrAsString, pAccInfo->nrInQueue);
02713       }
02714       else*/
02715       {
02716         // there are still entries in the ai queue; empty it before deletion; we cannot delete it now
02717         pAccInfo->authFlags |= AUTH_DELETE_ENTRY;
02718       }
02719     }
02720     else if (pAccInfo->nrInQueue < 0)
02721     {
02722       CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Cleanup method found negative handle queue!\n");
02723     }
02724     //pAccInfo->mutex->unlock();
02725 
02726     if (!(pAccInfo->authFlags & AUTH_DELETE_ENTRY))
02727     {
02728       // there are no handles for this entry in the queue, we can savely delete it now
02729       delete pAccInfo->mutex;
02730       pAccInfo->mutex = NULL;
02731       delete [] pAccInfo->clientVersion;
02732       pAccInfo->clientVersion = NULL;
02733       
02734 #ifdef LOG_CRIME
02735       UINT64 accountNumber = pAccInfo->accountNumber;
02736       UINT64* surveillanceAccounts = CALibProxytest::getOptions()->getCrimeSurveillanceAccounts();
02737       UINT32 nrOfSurveillanceAccounts = CALibProxytest::getOptions()->getNrOfCrimeSurveillanceAccounts();
02738       const UINT8* peerIP = pHashEntry->peerIP;
02739     
02740       for (UINT32 iAccount = 0; iAccount < nrOfSurveillanceAccounts; iAccount++)
02741       {
02742         if (accountNumber == surveillanceAccounts[iAccount])
02743         {
02744           CAMsg::printMsg(LOG_CRIT,"Crime detection: User logged out with account %llu has IP %u.%u.%u.%u\n",accountNumber, peerIP[0], peerIP[1], peerIP[2], peerIP[3]);
02745           break;
02746         }
02747       }
02748 #endif
02749       
02750       delete pAccInfo;
02751       pAccInfo = NULL;
02752     }
02753     else
02754     {
02755       CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Cleanup method sent account deletion request to AI thread!\n");
02756     }
02757     //ms_pInstance->m_pMutex->unlock();
02758 
02759     FINISH_STACK("CAAccountingInstance::cleanupTableEntry");
02760 
02761     return E_SUCCESS;
02762   }
02763 
02764 SINT32 CAAccountingInstance::newSettlementTransaction()
02765 {
02766   UINT32 settledCCs = 0;
02767   SINT32 retVal;
02768   do
02769   {
02770     retVal = __newSettlementTransaction(&settledCCs);
02771   }
02772   while(settledCCs >= MAX_SETTLED_CCS && retVal == E_SUCCESS);
02773   return E_SUCCESS; // change to retVal if you want to block new users on failure; but remember this is not sufficient because prepaid bytes are stored even on failure!
02774 }
02775 
02776 SINT32 CAAccountingInstance::__newSettlementTransaction(UINT32 *nrOfSettledCCs)
02777 {
02778 
02779   CAXMLErrorMessage **pErrMsgs = NULL, *settleException = NULL;
02780   CAXMLCostConfirmation **allUnsettledCCs = NULL;
02781   SettleEntry *entry = NULL, *nextEntry = NULL;
02782   CAAccountingDBInterface *dbInterface = NULL;
02783 
02784   UINT32 nrOfCCs = 0, i = 0;
02785   SINT32 biConnectionStatus = 0, ret = E_SUCCESS;
02786   UINT64 myWaitNr = 0;
02787 
02788 
02789   //settlement transactions need to be synchronized globally because the settlement thread as well as all login threads
02790   //may start a settlement transaction concurrently.
02791   ms_pInstance->m_pSettlementMutex->lock();
02792 
02793   UINT64 iCurrentSettleTransactionNr = (++m_iCurrentSettleTransactionNr) % 50;
02794 
02795   dbInterface = CAAccountingDBInterface::getConnection();
02796   if(dbInterface == NULL)
02797   {
02798     ms_pInstance->m_pSettlementMutex->unlock();
02799     CAMsg::printMsg(LOG_ERR, "Settlement transaction: could not connect to Database. Retry later...\n");
02800     ret = E_NOT_CONNECTED;
02801     goto cleanup;
02802   }
02803   
02804 
02805   /* First part get unsettled CCs from the AI database */
02806   #ifdef DEBUG
02807   CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: DB connections established!\n");
02808   #endif
02809 
02810     dbInterface->getUnsettledCostConfirmations(&allUnsettledCCs, ms_pInstance->m_currentCascade, &nrOfCCs, MAX_SETTLED_CCS);
02811     *nrOfSettledCCs = nrOfCCs;
02812     //no unsettled CCs found.
02813     if (allUnsettledCCs == NULL)
02814     {
02815       CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: thread %x looked for unsettled CCs, found no CCs to settle\n", iCurrentSettleTransactionNr, pthread_self());
02816       ms_pInstance->m_pSettlementMutex->unlock();
02817       ret = E_SUCCESS;
02818       goto cleanup;
02819     }
02820 
02821 
02822     CAMsg::printMsg(LOG_DEBUG, "Settlement transaction %llu: thread %x looked for unsettled CCs, found %u cost confirmations to settle\n", iCurrentSettleTransactionNr, pthread_self(), nrOfCCs);
02823 
02824     //connect to the PI
02825     biConnectionStatus = ms_pInstance->m_pPiInterface->initBIConnection();
02826     if(biConnectionStatus != E_SUCCESS)
02827     {
02828       ms_pInstance->m_seqBIConnErrors++;
02829       if(ms_pInstance->m_seqBIConnErrors >= CRITICAL_SUBSEQUENT_BI_CONN_ERRORS)
02830       {
02831         //transition to critical BI conn payment state
02832         MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionCriticalSubseqFailures);
02833       }
02834       else
02835       {
02836         MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionFailure);
02837       }
02838       ms_pInstance->m_pPiInterface->terminateBIConnection(); // make sure the socket is closed
02839       
02840       CAAccountingDBInterface::releaseConnection(dbInterface);
02841       dbInterface = NULL;
02842       ms_pInstance->m_pSettlementMutex->unlock();
02843 
02844       CAMsg::printMsg(LOG_WARNING, "Settlement transaction: could not connect to BI. Try later...\n");
02845       //ret = E_SUCCESS;
02846       ret = E_NOT_CONNECTED;
02847       goto cleanup;
02848     }
02849     else
02850     {
02851       pErrMsgs = ms_pInstance->m_pPiInterface->settleAll(allUnsettledCCs, nrOfCCs, &settleException);
02852       ms_pInstance->m_pPiInterface->terminateBIConnection();
02853     }
02854 
02855   //workaround because usage of exceptions is not allowed!
02856   if(settleException != NULL)
02857   {
02858     CAAccountingDBInterface::releaseConnection(dbInterface);
02859     dbInterface = NULL;
02860   
02861     ms_pInstance->m_pSettlementMutex->unlock();
02862     CAMsg::printMsg(LOG_ERR, "Settlement transaction: BI reported settlement not successful: "
02863             "code: %i, %s \n", settleException->getErrorCode(),
02864               (settleException->getDescription() != NULL ?
02865                 settleException->getDescription() : (UINT8*) "<no description given>") );
02866     ret = E_UNKNOWN;
02867     goto cleanup;
02868   }
02869 
02870   if(pErrMsgs == NULL)
02871   {
02872     //this must never happen because in any case where NULL is returned for pErrMsgs
02873     //'settleException' must not be NULL.
02874     CAAccountingDBInterface::releaseConnection(dbInterface);
02875     dbInterface = NULL;
02876     
02877     ms_pInstance->m_pSettlementMutex->unlock();
02878     CAMsg::printMsg(LOG_CRIT, "Settlement transaction: ErrorMessages are null.\n");
02879     ret = E_UNKNOWN;
02880     goto cleanup;
02881   }
02882   else
02883   {
02884     for(i = 0; i < nrOfCCs; i++)
02885     {
02886       nextEntry = __handleSettleResult(allUnsettledCCs[i], pErrMsgs[i], dbInterface, iCurrentSettleTransactionNr);
02887       if(nextEntry != NULL)
02888       {
02889         nextEntry->nextEntry = entry;
02890         entry = nextEntry;
02891       }
02892     }
02893   }
02894 
02895   //after settling: apply the corresponding account state changes reported from the PI.
02896   if (entry)
02897   {
02898     //wait numbers are used to obtain a synchronisation with FCFS assertion.
02899     //This additional synchronisation is necessary because before acquiring the login hashtable
02900     //locks the settlementMutex should be released. (Nested locking should be avoided).
02901     if(ms_pInstance->m_nextSettleNr == ms_pInstance->m_settleWaitNr)
02902     {
02903       //CAMsg::printMsg(LOG_INFO, "Thread %x: resetting the wait numbers.\n", pthread_self() );
02904       //no one is waiting, we use this occasion to reset the wait numbers
02905       ms_pInstance->m_nextSettleNr = 0;
02906       ms_pInstance->m_settleWaitNr = 1;
02907     }
02908     else
02909     {
02910       //get global wait number and wait but release the DBConnection first.
02911       CAAccountingDBInterface::releaseConnection(dbInterface);
02912       dbInterface = NULL;
02913       myWaitNr = ms_pInstance->m_settleWaitNr;
02914       ms_pInstance->m_settleWaitNr++;
02915       while(myWaitNr != ms_pInstance->m_nextSettleNr)
02916       {
02917         CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: Thread %x must wait to alter login table after settling (1): %llu before him in the queue\n", 
02918             iCurrentSettleTransactionNr, pthread_self(), (myWaitNr - ms_pInstance->m_nextSettleNr));
02919         ms_pInstance->m_pSettlementMutex->wait();
02920       }
02921       
02922       CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: Thread %x may continue (1).\n", iCurrentSettleTransactionNr, pthread_self());
02923       dbInterface = CAAccountingDBInterface::getConnection();
02924     }
02925     
02926     bool debugWarn = false;
02927     if (iCurrentSettleTransactionNr != (m_iCurrentSettleTransactionNr % 50))
02928     {
02929       debugWarn = true;
02930       // Write debug message in order to find deadlock...
02931       CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: Apply changes to database. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
02932     }
02933 
02934     //first apply changes to the database ...
02935     __commitSettlementToDatabase(entry, dbInterface);
02936     CAAccountingDBInterface::releaseConnection(dbInterface);
02937     dbInterface = NULL;
02938     
02939     
02940     if (debugWarn)
02941     {
02942       // Write debug message in order to find deadlock...
02943       CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: Removing settlement mutex lock. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
02944     }
02945     
02946     ms_pInstance->m_pSettlementMutex->unlock();
02947     
02948     
02949     if (debugWarn)
02950     {
02951       // Write debug message in order to find deadlock...
02952       CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: Entering login hashtable. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);    
02953     }
02954 
02955     //... then to the login hashtable after releasing the global settlement lock.
02956     ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
02957     CAMsg::printMsg(LOG_DEBUG, "Settlement transaction %llu: thread %x with wait nr %llu alters hashtable.\n", iCurrentSettleTransactionNr, pthread_self(), myWaitNr);
02958     __commitSettlementToLoginTable(entry);
02959     ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
02960 
02961     if (debugWarn)
02962     {
02963       // Write debug message in order to find deadlock...
02964       CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: After commiting to login hashtable, before last lock. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);    
02965     }
02966     
02967     //indicate that the next thread may proceed with its settlement changes by incrementing the nextSettleNr.
02968     ms_pInstance->m_pSettlementMutex->lock();
02969     ms_pInstance->m_nextSettleNr++;
02970 // TODO: seems to be a bug; if this "if" is set, some locks are never released
02971 //if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
02972     {
02973       //There are threads waiting for applying their settlement results.
02974       if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
02975       CAMsg::printMsg(LOG_INFO, "Thread %x waking up next Thread. %llu are still waiting.\n", pthread_self(),
02976               (ms_pInstance->m_settleWaitNr - ms_pInstance->m_nextSettleNr));
02977       ms_pInstance->m_pSettlementMutex->signal();
02978     }
02979   }
02980   ms_pInstance->m_pSettlementMutex->unlock();
02981 
02982 cleanup:
02983   if(dbInterface != NULL)
02984   {
02985     CAAccountingDBInterface::releaseConnection(dbInterface);
02986     dbInterface = NULL;
02987   }
02988 
02989   if(allUnsettledCCs != NULL)
02990   {
02991     for(i = 0; i < nrOfCCs; i++)
02992     {
02993       delete allUnsettledCCs[i];
02994       allUnsettledCCs[i] = NULL;
02995     }
02996     delete [] allUnsettledCCs;
02997     allUnsettledCCs = NULL;
02998   }
02999 
03000   if(pErrMsgs != NULL)
03001   {
03002     for(i = 0; i < nrOfCCs; i++)
03003     {
03004       delete pErrMsgs[i];
03005       pErrMsgs[i] = NULL;
03006     }
03007     pErrMsgs = NULL;
03008   }
03009 
03010   while (entry != NULL)
03011   {
03012     nextEntry = entry->nextEntry;
03013     delete entry;
03014     entry = nextEntry;
03015   }
03016 
03017   delete settleException;
03018   settleException = NULL;
03019 
03020   
03021   CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu finished.\n", iCurrentSettleTransactionNr);
03022 
03023   return ret;
03024 }
03025 
03026 SettleEntry *CAAccountingInstance::__handleSettleResult(CAXMLCostConfirmation *pCC, CAXMLErrorMessage *pErrMsg, CAAccountingDBInterface *dbInterface, 
03027   UINT64 a_iCurrentSettleTransactionNr)
03028 {
03029   bool bDeleteCC = false;
03030   UINT32 authFlags = 0;
03031   UINT32 authRemoveFlags = 0;
03032   UINT64 confirmedBytes = 0;
03033   UINT64 diffBytes = 0;
03034   UINT32 storedStatus = 0;
03035   SettleEntry *entry = NULL;
03036 
03037   dbInterface->getAccountStatus(pCC->getAccountNumber(), storedStatus);
03038 
03039   // check returncode
03040   if(pErrMsg == NULL)  //no returncode -> connection error
03041   {
03042     authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // no fault of the client
03043     CAMsg::printMsg(LOG_ERR, "Settlement transaction: Communication with BI failed!\n");
03044   }
03045   else if(pErrMsg->getErrorCode() != pErrMsg->ERR_OK)  //BI reported error
03046   {
03047     CAMsg::printMsg(LOG_WARNING, "Settlement transaction: BI reported error no. %d (%s)\n",
03048       pErrMsg->getErrorCode(), pErrMsg->getDescription() );
03049     if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_KEY_NOT_FOUND)
03050     {
03051       authFlags |= AUTH_INVALID_ACCOUNT;
03052       //dbConn.storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_KEY_NOT_FOUND);
03053       bDeleteCC = true;
03054     }
03055     else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_ACCOUNT_EMPTY)
03056     {
03057       authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03058       authFlags |= AUTH_ACCOUNT_EMPTY;
03059       UINT64* msgConfirmedBytes = (UINT64*)pErrMsg->getMessageObject();
03060       if (msgConfirmedBytes)
03061       {
03062         confirmedBytes = *msgConfirmedBytes;
03063         if (confirmedBytes < pCC->getTransferredBytes())
03064         {
03065           diffBytes = pCC->getTransferredBytes() - confirmedBytes;
03066         }
03067         UINT8 tmp[32];
03068         print64(tmp, confirmedBytes);
03069         UINT8 tmp2[32];
03070         print64(tmp2, diffBytes);
03071         UINT8 tmp3[32];
03072         print64(tmp3, pCC->getTransferredBytes());
03073         CAMsg::printMsg(LOG_INFO, "Settlement transaction: Received %s confirmed bytes and %s diff bytes while having %s transferred bytes!\n", tmp, tmp2, tmp3);
03074       }
03075       else
03076       {
03077         CAMsg::printMsg(LOG_INFO, "Settlement transaction: Account empty, no message object received. User will be kicked out.\n");
03078       }
03079 
03080       dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_ACCOUNT_EMPTY);
03081       authFlags |= AUTH_SETTLED_ONCE;
03082       dbInterface->markAsSettled(pCC->getAccountNumber(), ms_pInstance->m_currentCascade,
03083                     pCC->getTransferredBytes());
03084 //#ifdef DEBUG
03085       CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: settling %llu bytes for account %llu\n",
03086                     pCC->getTransferredBytes(), pCC->getAccountNumber());
03087 //#endif
03088     }
03089     /*
03090     else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INVALID_PRICE_CERT)
03091     {
03092       // this should never happen; the price certs in this CC do not fit to the ones of the cascade
03093       // bDeleteCC = true;
03094     }*/
03095     else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_OUTDATED_CC)
03096     {
03097       authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // this is a Mix not a client error
03098 
03099       //get attached CC from error message
03100       CAXMLCostConfirmation* attachedCC = (CAXMLCostConfirmation*) pErrMsg->getMessageObject();
03101       if (attachedCC)
03102       {
03103         authFlags |= AUTH_OUTDATED_CC;
03104         CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: tried outdated CC, received last valid CC back\n");
03105         //store it in DB
03106         if (dbInterface->storeCostConfirmation(*attachedCC,
03107             ms_pInstance->m_currentCascade) == E_SUCCESS)
03108         {
03109           authFlags |= AUTH_SETTLED_ONCE;
03110           if (dbInterface->markAsSettled(attachedCC->getAccountNumber(), ms_pInstance->m_currentCascade,
03111                       attachedCC->getTransferredBytes()) != E_SUCCESS)
03112           {
03113             CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark last valid CC as settled."
03114               "Maybe a new CC has been added meanwhile?\n");
03115           }
03116         }
03117         else
03118         {
03119           CAMsg::printMsg(LOG_ERR, "Settlement transaction: storing last valid CC in db failed!\n");
03120         }
03121         // set the confirmed bytes to the value of the CC got from the PI
03122         confirmedBytes = attachedCC->getTransferredBytes();
03123       }
03124       else
03125       {
03126         CAMsg::printMsg(LOG_INFO, "Settlement transaction: Did not receive last valid CC - maybe old Payment instance?\n");
03127       }
03128     }
03129     else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_BLOCKED)
03130     {
03131       authFlags |= AUTH_BLOCKED;
03132       bDeleteCC = true;
03133 
03134       dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_BLOCKED);
03135     }
03136 
03137     else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_DATABASE_ERROR)
03138     {
03139       //authFlags |= AUTH_DATABASE;
03140       // the user is not responsible for this!
03141       authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03142     }
03143     else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR ||
03144          pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_SUCCESS_BUT_WITH_ERRORS)
03145     {
03146       // kick out the user and store the CC
03147       authFlags |= AUTH_UNKNOWN;
03148     }
03149     else
03150     {
03151       // an unknown error leads to user kickout
03152       CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: Setting unknown kickout error no. %d.\n", pErrMsg->getErrorCode());
03153       authFlags |= AUTH_UNKNOWN;
03154       bDeleteCC = true;
03155     }
03156 
03157     if (bDeleteCC)
03158     {
03159       //delete costconfirmation to avoid trying to settle an unusable CC again and again
03160       if(dbInterface->deleteCC(pCC->getAccountNumber(), ms_pInstance->m_currentCascade) == E_SUCCESS)
03161       {
03162         CAMsg::printMsg(LOG_ERR, "Settlement transaction: unusable cost confirmation was deleted\n");
03163       }
03164       else
03165       {
03166         CAMsg::printMsg(LOG_ERR, "Settlement transaction: cost confirmation is unusable, but could not delete it from database\n");
03167       }
03168     }
03169   }
03170   else //settling was OK, so mark account as settled
03171   {
03172     authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03173     authFlags |= AUTH_SETTLED_ONCE;
03174     if (dbInterface->markAsSettled(pCC->getAccountNumber(),
03175                 ms_pInstance->m_currentCascade,
03176                 pCC->getTransferredBytes()) != E_SUCCESS)
03177      {
03178       CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark CC as settled. Maybe a new CC has been added meanwhile?\n");
03179      }
03180 #ifdef DEBUG
03181     CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: CC OK for account %llu with %llu transferred bytes!\n", 
03182       a_iCurrentSettleTransactionNr, pCC->getAccountNumber(), pCC->getTransferredBytes());
03183 #endif
03184   }
03185 
03186   if (authFlags || authRemoveFlags)
03187   {
03188     entry = new SettleEntry;
03189     entry->accountNumber = pCC->getAccountNumber();
03190     entry->authFlags = authFlags;
03191     entry->authRemoveFlags = authRemoveFlags;
03192     entry->confirmedBytes = confirmedBytes;
03193     entry->diffBytes = diffBytes;
03194     entry->storedStatus = storedStatus;
03195   }
03196   return entry;
03197 }
03198 
03200 void CAAccountingInstance::__commitSettlementToDatabase(SettleEntry *entryList, CAAccountingDBInterface *dbInterface)
03201 {
03202   SettleEntry *entry = entryList, *nextEntry = NULL;
03203   while (entry != NULL && dbInterface != NULL)
03204   {
03205     if (entry->authFlags & (AUTH_INVALID_ACCOUNT | AUTH_UNKNOWN))
03206     {
03207       dbInterface->storePrepaidAmount(
03208           entry->accountNumber, 0, ms_pInstance->m_currentCascade);
03209     }
03210     else if (entry->diffBytes)
03211     {
03212       // user is currently not logged in; set correct prepaid bytes in DB
03213       SINT32 prepaidBytes =
03214         dbInterface->getPrepaidAmount(entry->accountNumber,
03215             ms_pInstance->m_currentCascade, true);
03216       if (prepaidBytes > 0)
03217       {
03218         if (entry->diffBytes < 0 || entry->diffBytes >= (UINT64)prepaidBytes)
03219         {
03220           prepaidBytes = 0;
03221         }
03222         else
03223         {
03224           prepaidBytes -= entry->diffBytes;
03225         }
03226         dbInterface->storePrepaidAmount(
03227           entry->accountNumber, prepaidBytes, ms_pInstance->m_currentCascade);
03228       }
03229     }
03230 
03231     if( !(entry->authFlags & (AUTH_ACCOUNT_EMPTY | AUTH_BLOCKED | AUTH_INVALID_ACCOUNT)) &&
03232       entry->storedStatus != 0)
03233     {
03234       dbInterface->clearAccountStatus(entry->accountNumber);
03235       switch (entry->storedStatus)
03236       {
03237         case CAXMLErrorMessage::ERR_ACCOUNT_EMPTY:
03238         {
03239           CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account empty status for %llu\n",
03240               entry->accountNumber);
03241           entry->authRemoveFlags |= AUTH_ACCOUNT_EMPTY;
03242           break;
03243         }
03244         case CAXMLErrorMessage::ERR_BLOCKED:
03245         {
03246           CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account blocked status for %llu\n",
03247               entry->accountNumber);
03248           entry->authRemoveFlags |= AUTH_BLOCKED;
03249           break;
03250         }
03251         case CAXMLErrorMessage::ERR_KEY_NOT_FOUND:
03252         {
03253           CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account invalid status for %llu\n",
03254               entry->accountNumber);
03255           entry->authRemoveFlags |= AUTH_INVALID_ACCOUNT;
03256           break;
03257         }
03258       }
03259     }
03260     nextEntry = entry->nextEntry;
03261     entry = nextEntry;
03262   }
03263 }
03264 
03266 void CAAccountingInstance::__commitSettlementToLoginTable(SettleEntry *entryList)
03267 {
03268   SettleEntry *entry = entryList, *nextEntry = NULL;
03269   while (entry != NULL)
03270   {
03271     AccountLoginHashEntry* loginEntry =
03272             (AccountLoginHashEntry*) (ms_pInstance->m_currentAccountsHashtable->getValue(&(entry->accountNumber)));
03273     if (loginEntry)
03274     {
03275       // the user is currently logged in
03276       loginEntry->authFlags |= entry->authFlags;
03277       loginEntry->authRemoveFlags |= entry->authRemoveFlags;
03278       if (entry->confirmedBytes > 0 &&
03279         loginEntry->confirmedBytes < entry->confirmedBytes)
03280       {
03281         loginEntry->confirmedBytes = entry->confirmedBytes;
03282       }
03283     }
03284     nextEntry = entry->nextEntry;
03285     entry = nextEntry;
03286   }
03287 }
03288 
03289 /* Settlement transaction procedure as it is called by the SettleThread
03290  * NEVER INVOKE THIS METHOD IF YOU'RE HOLDING A LOCK ON m_currentAccountsHashtable !!
03291  * */
03292 SINT32 CAAccountingInstance::settlementTransaction()
03293 {
03294   INIT_STACK;
03295   BEGIN_STACK("CAAccountingInstance::settlementTransaction");
03296 
03297   SINT32 ret = 0;
03298   CAXMLErrorMessage * pErrMsg = NULL;
03299   CAXMLCostConfirmation * pCC = NULL;
03300   //CAQueue q;
03301   CAXMLCostConfirmation **allUnsettledCCs = NULL;
03302   UINT32 /*size, qSize, */ nrOfCCs, i;
03303   SettleEntry *entry = NULL, *nextEntry = NULL;
03304 
03305   CAAccountingDBInterface *dbInterface = NULL;
03306 
03307   /* This should never happen */
03308   if(ms_pInstance == NULL)
03309   {
03310     FINISH_STACK("CAAccountingInstance::settlementTransaction");
03311     return E_UNKNOWN;
03312   }
03313   /* This should never happen */
03314   if(ms_pInstance->m_pSettlementMutex == NULL)
03315   {
03316     FINISH_STACK("CAAccountingInstance::settlementTransaction");
03317     return E_UNKNOWN;
03318   }
03319   //sleep(5);
03320   dbInterface = CAAccountingDBInterface::getConnection();
03321   if(dbInterface == NULL)
03322   {
03323     CAMsg::printMsg(LOG_ERR, "Settlement transaction: could not connect to Database. Retry later...\n");
03324     //MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
03325     FINISH_STACK("CAAccountingInstance::settlementTransaction");
03326     return E_NOT_CONNECTED;
03327   }
03328   //MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
03329   ms_pInstance->m_pSettlementMutex->lock();
03330   /* First part get unsettled CCs from the AI database */
03331   #ifdef DEBUG
03332   CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: DB connections established!\n");
03333   #endif
03334 
03335   dbInterface->getUnsettledCostConfirmations(&allUnsettledCCs, ms_pInstance->m_currentCascade, &nrOfCCs, MAX_SETTLED_CCS);
03336   if (nrOfCCs <= 0)
03337   {
03338     CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: finished gettings CCs, found no CCs to settle\n");
03339     if(dbInterface != NULL)
03340     {
03341       CAAccountingDBInterface::releaseConnection(dbInterface);
03342       dbInterface = NULL;
03343     }
03344     ms_pInstance->m_pSettlementMutex->unlock();
03345     FINISH_STACK("CAAccountingInstance::settlementTransaction");
03346     return E_SUCCESS;
03347   }
03348   //qSize = q.getSize();
03349   //nrOfCCs = qSize / sizeof(pCC);
03350   CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: finished gettings CCs, found %u cost confirmations to settle\n",nrOfCCs);
03351 
03352   SAVE_STACK("CAAccountingInstance::settlementTransaction", "After getting unsettled CCs");
03353   /* Second part: We found unsettled CCs. Now contact the Payment Instance to settle them */
03354 
03355   //while(!q.isEmpty())
03356   for(i = 0; i < nrOfCCs; i++)
03357   {
03358     // get the next CC from the queue
03359     /*size = sizeof(pCC);
03360     ret = q.get((UINT8*)(&pCC), &size);
03361     if(ret != E_SUCCESS)
03362     {
03363       CAMsg::printMsg(LOG_ERR, "Settlement transaction: could not get next item from queue\n");
03364       q.clean();
03365       if(dbInterface != NULL)
03366       {
03367         CAAccountingDBInterface::releaseConnection(dbInterface);
03368         dbInterface = NULL;
03369       }
03370       ms_pInstance->m_pSettlementMutex->unlock();
03371       FINISH_STACK("CAAccountingInstance::settlementTransaction");
03372       return ret;
03373       //break;
03374     }*/
03375     pCC = allUnsettledCCs[i];
03376     entry = NULL;
03377     nextEntry = NULL;
03378     if (!pCC)
03379     {
03380       CAMsg::printMsg(LOG_CRIT, "Settlement transaction: Cost confirmation is NULL!\n");
03381       continue;
03382     }
03383 
03384 #ifdef DEBUG
03385     CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: Connecting to payment instance...\n");
03386 #endif
03387     ret = ms_pInstance->m_pPiInterface->initBIConnection();
03388     if(ret != E_SUCCESS)
03389     {
03390       ms_pInstance->m_seqBIConnErrors++;
03391       if(ms_pInstance->m_seqBIConnErrors >= CRITICAL_SUBSEQUENT_BI_CONN_ERRORS)
03392       {
03393         //transition to critical BI conn payment state
03394         MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionCriticalSubseqFailures);
03395       }
03396       else
03397       {
03398         MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionFailure);
03399       }
03400       CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: could not connect to BI. Try later...\n");
03401       //q.clean();
03402       pErrMsg = NULL; // continue in order to tell AUTH_WAITING_FOR_FIRST_SETTLED_CC for all accounts
03403       ms_pInstance->m_pPiInterface->terminateBIConnection(); // make sure the socket is closed
03404     }
03405     else
03406     {
03407       MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionSuccess);
03408 #ifdef DEBUG
03409       CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: successfully connected to payment instance");
03410 #endif
03411       ms_pInstance->m_seqBIConnErrors = 0;
03412       pErrMsg = ms_pInstance->m_pPiInterface->settle( *pCC );
03413       ms_pInstance->m_pPiInterface->terminateBIConnection();
03414       CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: settle done!\n");
03415     }
03416 
03417     bool bDeleteCC = false;
03418     UINT32 authFlags = 0;
03419     UINT32 authRemoveFlags = 0;
03420     UINT64 confirmedBytes = 0;
03421     UINT64 diffBytes = 0;
03422     UINT32 storedStatus = 0;
03423 
03424     dbInterface->getAccountStatus(pCC->getAccountNumber(), storedStatus);
03425 
03426     // check returncode
03427     if(pErrMsg == NULL)  //no returncode -> connection error
03428     {
03429       authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // no fault of the client
03430       CAMsg::printMsg(LOG_ERR, "Settlement transaction: Communication with BI failed!\n");
03431     }
03432     else if(pErrMsg->getErrorCode() != pErrMsg->ERR_OK)  //BI reported error
03433     {
03434       CAMsg::printMsg(LOG_WARNING, "Settlement transaction: BI reported error no. %d (%s)\n",
03435         pErrMsg->getErrorCode(), pErrMsg->getDescription() );
03436       if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_KEY_NOT_FOUND)
03437       {
03438         authFlags |= AUTH_INVALID_ACCOUNT;
03439         //dbConn.storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_KEY_NOT_FOUND);
03440         bDeleteCC = true;
03441       }
03442       else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_ACCOUNT_EMPTY)
03443       {
03444         authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03445         authFlags |= AUTH_ACCOUNT_EMPTY;
03446         UINT64* msgConfirmedBytes = (UINT64*)pErrMsg->getMessageObject();
03447         if (msgConfirmedBytes)
03448         {
03449           confirmedBytes = *msgConfirmedBytes;
03450           if (confirmedBytes < pCC->getTransferredBytes())
03451           {
03452             diffBytes = pCC->getTransferredBytes() - confirmedBytes;
03453           }
03454           UINT8 tmp[32];
03455           print64(tmp, confirmedBytes);
03456           UINT8 tmp2[32];
03457           print64(tmp2, diffBytes);
03458           UINT8 tmp3[32];
03459           print64(tmp3, pCC->getTransferredBytes());
03460           CAMsg::printMsg(LOG_INFO, "Settlement transaction: Received %s confirmed bytes and %s diff bytes while having %s transferred bytes!\n", tmp, tmp2, tmp3);
03461         }
03462         else
03463         {
03464           CAMsg::printMsg(LOG_ERR, "Settlement transaction: Account empty, but no message object received! "
03465               "This may lead to too much prepaid bytes!\n");
03466         }
03467 
03468         dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_ACCOUNT_EMPTY);
03469         authFlags |= AUTH_SETTLED_ONCE;
03470         dbInterface->markAsSettled(pCC->getAccountNumber(), ms_pInstance->m_currentCascade,
03471                       pCC->getTransferredBytes());
03472 //#ifdef DEBUG
03473         CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: settling %llu bytes for account %llu\n",
03474                       pCC->getTransferredBytes(), pCC->getAccountNumber());
03475 //#endif
03476       }
03477       /*
03478       else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INVALID_PRICE_CERT)
03479       {
03480         // this should never happen; the price certs in this CC do not fit to the ones of the cascade
03481         // bDeleteCC = true;
03482       }*/
03483       else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_OUTDATED_CC)
03484       {
03485         authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // this is a Mix not a client error
03486 
03487         //get attached CC from error message
03488         CAXMLCostConfirmation* attachedCC = (CAXMLCostConfirmation*) pErrMsg->getMessageObject();
03489         if (attachedCC)
03490         {
03491           authFlags |= AUTH_OUTDATED_CC;
03492           CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: tried outdated CC, received last valid CC back\n");
03493           //store it in DB
03494           if (dbInterface->storeCostConfirmation(*attachedCC,
03495               ms_pInstance->m_currentCascade) == E_SUCCESS)
03496           {
03497             authFlags |= AUTH_SETTLED_ONCE;
03498             if (dbInterface->markAsSettled(attachedCC->getAccountNumber(), ms_pInstance->m_currentCascade,
03499                         attachedCC->getTransferredBytes()) != E_SUCCESS)
03500             {
03501               CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark last valid CC as settled."
03502                 "Maybe a new CC has been added meanwhile?\n");
03503             }
03504           }
03505           else
03506           {
03507             CAMsg::printMsg(LOG_ERR, "Settlement transaction: storing last valid CC in db failed!\n");
03508           }
03509           // set the confirmed bytes to the value of the CC got from the PI
03510           confirmedBytes = attachedCC->getTransferredBytes();
03511         }
03512         else
03513         {
03514           CAMsg::printMsg(LOG_INFO, "Settlement transaction: Did not receive last valid CC - maybe old Payment instance?\n");
03515         }
03516       }
03517       else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_BLOCKED)
03518       {
03519         authFlags |= AUTH_BLOCKED;
03520         bDeleteCC = true;
03521 
03522         dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_BLOCKED);
03523       }
03524 
03525       else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_DATABASE_ERROR)
03526       {
03527         //authFlags |= AUTH_DATABASE;
03528         // the user is not responsible for this!
03529         authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03530       }
03531       else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR ||
03532              pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_SUCCESS_BUT_WITH_ERRORS)
03533       {
03534         // kick out the user and store the CC
03535         authFlags |= AUTH_UNKNOWN;
03536       }
03537       else
03538       {
03539         // an unknown error leads to user kickout
03540         CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: Setting unknown kickout error no. %d.\n", pErrMsg->getErrorCode());
03541         authFlags |= AUTH_UNKNOWN;
03542         bDeleteCC = true;
03543       }
03544 
03545       if (bDeleteCC)
03546       {
03547         //delete costconfirmation to avoid trying to settle an unusable CC again and again
03548         if(dbInterface->deleteCC(pCC->getAccountNumber(), ms_pInstance->m_currentCascade) == E_SUCCESS)
03549         {
03550           CAMsg::printMsg(LOG_ERR, "Settlement transaction: unusable cost confirmation was deleted\n");
03551         }
03552         else
03553         {
03554           CAMsg::printMsg(LOG_ERR, "Settlement transaction: cost confirmation is unusable, but could not delete it from database\n");
03555         }
03556       }
03557     }
03558     else //settling was OK, so mark account as settled
03559     {
03560       authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03561       authFlags |= AUTH_SETTLED_ONCE;
03562       if (dbInterface->markAsSettled(pCC->getAccountNumber(),
03563                   ms_pInstance->m_currentCascade,
03564                   pCC->getTransferredBytes()) != E_SUCCESS)
03565        {
03566         CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark CC as settled. Maybe a new CC has been added meanwhile?\n");
03567        }
03568       CAMsg::printMsg(LOG_INFO, "Settlement transaction: CC OK!\n");
03569     }
03570 
03571 
03572     if (authFlags || authRemoveFlags)
03573     {
03574       nextEntry = new SettleEntry;
03575       nextEntry->accountNumber = pCC->getAccountNumber();
03576       nextEntry->authFlags = authFlags;
03577       nextEntry->authRemoveFlags = authRemoveFlags;
03578       nextEntry->confirmedBytes = confirmedBytes;
03579       nextEntry->diffBytes = diffBytes;
03580       nextEntry->nextEntry = entry;
03581       nextEntry->storedStatus = storedStatus;
03582       entry = nextEntry;
03583     }
03584 
03585     /*if (pCC != NULL)
03586     {
03587       delete pCC;
03588       pCC = NULL;
03589     }*/
03590     if (pErrMsg != NULL)
03591     {
03592       delete pErrMsg;
03593       pErrMsg = NULL;
03594     }
03595   }
03596 
03597   if(allUnsettledCCs != NULL)
03598   {
03599     for(i = 0; i < nrOfCCs; i++)
03600     {
03601       delete allUnsettledCCs[i];
03602       allUnsettledCCs[i] = NULL;
03603     }
03604     delete [] allUnsettledCCs;
03605     allUnsettledCCs = NULL;
03606   }
03607 
03608   SAVE_STACK("CAAccountingInstance::settlementTransaction", "After settling unsettled CCs with BI");
03609 
03610   SettleEntry *first = entry;
03611   UINT64 myWaitNr = 0;
03612   if (entry)
03613   {
03614     //wait numbers are used to obtain a synchronisation with FCFS assertion.
03615     //This additional synchronisation is necessary because before acquiring the login hashtable
03616     //locks the settlementMutex should be released. (Nested locking should be avoided).
03617     if(ms_pInstance->m_nextSettleNr == ms_pInstance->m_settleWaitNr)
03618     {
03619       //CAMsg::printMsg(LOG_INFO, "Thread %x: resetting the wait numbers.\n", pthread_self() );
03620       //no one is waiting, we use this occasion to reset the wait numbers
03621       ms_pInstance->m_nextSettleNr = 0;
03622       ms_pInstance->m_settleWaitNr = 1;
03623     }
03624     else
03625     {
03626       SAVE_STACK("CAAccountingInstance::settlementTransaction", "wait for altering hashtable");
03627       //get global wait number and wait but release the DBConnection first.
03628       CAAccountingDBInterface::releaseConnection(dbInterface);
03629       dbInterface = NULL;
03630       myWaitNr = ms_pInstance->m_settleWaitNr;
03631       ms_pInstance->m_settleWaitNr++;
03632       while(myWaitNr != ms_pInstance->m_nextSettleNr)
03633       {
03634         CAMsg::printMsg(LOG_INFO, "Thread %x must wait to alter login table after settling (2): %llu before him in the queue\n", pthread_self(),
03635                     (myWaitNr - ms_pInstance->m_nextSettleNr));
03636         ms_pInstance->m_pSettlementMutex->wait();
03637       }
03638       CAMsg::printMsg(LOG_INFO, "Thread %x may continue (2).\n", pthread_self());
03639       dbInterface = CAAccountingDBInterface::getConnection();
03640     }
03641     SAVE_STACK("CAAccountingInstance::settlementTransaction", "altering DB entries");
03642     while (entry != NULL && dbInterface != NULL)
03643     {
03644       if (entry->authFlags & (AUTH_INVALID_ACCOUNT | AUTH_UNKNOWN))
03645       {
03646         dbInterface->storePrepaidAmount(
03647             entry->accountNumber, 0, ms_pInstance->m_currentCascade);
03648       }
03649       else if (entry->diffBytes)
03650       {
03651         // user is currently not logged in; set correct prepaid bytes in DB
03652         SINT32 prepaidBytes =
03653           dbInterface->getPrepaidAmount(entry->accountNumber,
03654               ms_pInstance->m_currentCascade, true);
03655         if (prepaidBytes > 0)
03656         {
03657           if (entry->diffBytes < 0 || entry->diffBytes >= (UINT64)prepaidBytes)
03658           {
03659             prepaidBytes = 0;
03660           }
03661           else
03662           {
03663             prepaidBytes -= entry->diffBytes;
03664           }
03665           dbInterface->storePrepaidAmount(
03666             entry->accountNumber, prepaidBytes, ms_pInstance->m_currentCascade);
03667         }
03668       }
03669 
03670       if( !(entry->authFlags & (AUTH_ACCOUNT_EMPTY | AUTH_BLOCKED | AUTH_INVALID_ACCOUNT)) &&
03671         entry->storedStatus != 0)
03672       {
03673         dbInterface->clearAccountStatus(entry->accountNumber);
03674         switch (entry->storedStatus)
03675         {
03676           case CAXMLErrorMessage::ERR_ACCOUNT_EMPTY:
03677           {
03678             CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account empty status for %llu\n",
03679                 entry->accountNumber);
03680             entry->authRemoveFlags |= AUTH_ACCOUNT_EMPTY;
03681             break;
03682           }
03683           case CAXMLErrorMessage::ERR_BLOCKED:
03684           {
03685             CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account blocked status for %llu\n",
03686                 entry->accountNumber);
03687             entry->authRemoveFlags |= AUTH_BLOCKED;
03688             break;
03689           }
03690           case CAXMLErrorMessage::ERR_KEY_NOT_FOUND:
03691           {
03692             CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account invalid status for %llu\n",
03693                 entry->accountNumber);
03694             entry->authRemoveFlags |= AUTH_INVALID_ACCOUNT;
03695             break;
03696           }
03697         }
03698       }
03699 
03700       nextEntry = entry->nextEntry;
03701       entry = nextEntry;
03702     }
03703   }
03704   CAAccountingDBInterface::releaseConnection(dbInterface);
03705   dbInterface = NULL;
03706   ms_pInstance->m_pSettlementMutex->unlock();
03707 
03708   if(first != NULL)
03709   {
03710     SAVE_STACK("CAAccountingInstance::settlementTransaction", "altering hashtable");
03711 #ifdef DEBUG
03712     CAMsg::printMsg(LOG_DEBUG, "Settlement thread with wait nr %llu alters hashtable.\n", myWaitNr);
03713 #endif
03714     entry = first;
03715     ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
03716     while (entry != NULL)
03717     {
03718       AccountLoginHashEntry* loginEntry =
03719               (AccountLoginHashEntry*) (ms_pInstance->m_currentAccountsHashtable->getValue(&(entry->accountNumber)));
03720       if (loginEntry)
03721       {
03722         // the user is currently logged in
03723         loginEntry->authFlags |= entry->authFlags;
03724         loginEntry->authRemoveFlags |= entry->authRemoveFlags;
03725         if (entry->confirmedBytes > 0 &&
03726           loginEntry->confirmedBytes < entry->confirmedBytes)
03727         {
03728           loginEntry->confirmedBytes = entry->confirmedBytes;
03729         }
03730       }
03731       nextEntry = entry->nextEntry;
03732       delete entry;
03733       entry = nextEntry;
03734     }
03735     ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
03736 
03737     ms_pInstance->m_pSettlementMutex->lock();
03738     ms_pInstance->m_nextSettleNr++;
03739 // TODO: seems to be a bug; if this "if" is set, some locks are never released
03740 //if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
03741     {
03742       SAVE_STACK("CAAccountingInstance::settlementTransaction", "waking up waiting threads for altering hashtable");
03743       //There are threads waiting for applying their settlement results.
03744       if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
03745