Mixe for Privacy and Anonymity in the Internet
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! Kicking out other users with this account...\n",
02019 //              loginEntry->count, accountNrAsString);
02020 //      loginEntry->userID = pAccInfo->userID; // this is the current user; kick out the others
02021 //    }
02022 //    else
02023 //    {
02024 //      /* The maximum of tolerated concurrent logins for this user is exceeded.
02025 //       * He won't get any new access again before the old connections have been closed!
02026 //       * @mod: in this case not more than one login is allowed at a time. The User has to wait until
02027 //       * the old login will be deleted.
02028 //       */
02029 //      CAMsg::printMsg(LOG_INFO,
02030 //              "CAAccountingInstance: Maximum of multiple logins exceeded (%d) for user with account %s! Kicking out this user!\n",
02031 //              loginEntry->count, accountNrAsString);
02032 //      bSendCCRequest = false; // not needed...
02033 //      pAccInfo->authFlags |= AUTH_MULTIPLE_LOGIN;
02034 //
02035 //      delete pCC;
02036 //      pCC = NULL;
02037 //      m_currentAccountsHashtable->getMutex()->unlock();
02038 //      pAccInfo->mutex->unlock();
02039 //      return CAXMLErrorMessage::ERR_MULTIPLE_LOGIN;
02040 //    }
02041 //  }
02042 
02043   UINT8 tmp[32];
02044   print64(tmp,pAccInfo->accountNumber);
02045   if (prepaidAmount > 0)
02046   {
02047     CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Got %d prepaid bytes for account nr. %s.\n",prepaidAmount, tmp);
02048 
02049     //pAccInfo->authFlags &= ~AUTH_WAITING_FOR_FIRST_SETTLED_CC;
02050 
02051     if (pAccInfo->transferredBytes >= (UINT32)prepaidAmount)
02052     {
02053       pAccInfo->transferredBytes -= prepaidAmount;
02054     }
02055     else
02056     {
02057       UINT8 tmp2[32];
02058       print64(tmp2, pAccInfo->transferredBytes);
02059       CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Transferred bytes of %s for account %s are lower than prepaid amount! "
02060                   "Maybe we lost a CC?\n",tmp2, tmp);
02061       prepaidAmount = 0;
02062     }
02063   }
02064   else
02065   {
02066     prepaidAmount = 0;
02067     CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: No database record for prepaid bytes found for account nr. %s.\n", tmp);
02068   }
02069   //CAMsg::printMsg(LOG_DEBUG, "Number of prepaid (confirmed-transferred) bytes : %d \n",pAccInfo->confirmedBytes-pAccInfo->transferredBytes);
02070 
02076    SINT32 dbRet;
02077   if(dbInterface != NULL);
02078   {
02079     dbRet = dbInterface->getAccountStatus(pAccInfo->accountNumber, status);
02080     CAAccountingDBInterface::releaseConnection(dbInterface);
02081     dbInterface = NULL;
02082   }
02083 
02084   if (dbRet != E_SUCCESS)
02085   {
02086     UINT8 tmp[32];
02087     print64(tmp,pAccInfo->accountNumber);
02088     CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Could not check status for account %s!\n", tmp);
02089   }
02090   else if (status > CAXMLErrorMessage::ERR_OK)
02091   {
02092     //UINT32 authFlags = 0;
02093     //the auth flags are set after this check, but they need to be verified during a forced settlement
02094     //at the end of the login. (see finishLoginProcess())
02095     CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Illegal status %u for account %llu found.\n",
02096         status, pAccInfo->accountNumber);
02097     if (status == CAXMLErrorMessage::ERR_BLOCKED)
02098     {
02099       pAccInfo->authFlags |= AUTH_BLOCKED;
02100     }
02101     else if (status == CAXMLErrorMessage::ERR_KEY_NOT_FOUND)
02102     {
02103       pAccInfo->authFlags |= AUTH_INVALID_ACCOUNT;
02104     }
02105     else if (status == CAXMLErrorMessage::ERR_ACCOUNT_EMPTY)
02106     {
02107       pAccInfo->authFlags |= AUTH_ACCOUNT_EMPTY;
02108     }
02109 
02110     /*if (authFlags)
02111     {
02112       pAccInfo->authFlags |= AUTH_BLOCKED;
02113       if (loginEntry->confirmedBytes == 0)
02114       {
02115         loginEntry->confirmedBytes = pAccInfo->confirmedBytes;
02116       }
02117     }*/
02118   }
02119   m_currentAccountsHashtable->getMutex()->unlock();
02120 
02122   //pAccInfo->mutex->lock();
02123   SINT32 sendStatus = E_SUCCESS;
02124   if (bSendCCRequest)
02125   {
02126     // fetch cost confirmation from last session if available, and send it
02127     //CAXMLCostConfirmation * pCC = NULL;
02128     //m_dbInterface->getCostConfirmation(pAccInfo->accountNumber, m_currentCascade, &pCC);
02129     if(pCC != NULL)
02130     {
02131 #ifdef DEBUG
02132       CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Sending pcc to sign with %llu transferred bytes\n", pCC->getTransferredBytes());
02133 #endif
02134       // the typical case; the user had logged in before
02135       /* there shouldn't be any counting synchronisation problems with the JAP
02136        * because the new login protocol doesn't permit JAPs
02137        * to exchange data before login is finished.
02138        */
02139       UINT32 prepaidIval = CALibProxytest::getOptions()->getPrepaidInterval();
02140       pAccInfo->bytesToConfirm = (prepaidIval - prepaidAmount) + pCC->getTransferredBytes();
02141 #ifdef DEBUG
02142       CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: before CC request, bytesToConfirm: %llu, prepaidIval: %u, "
02143           "prepaidAmount: %d, transferred bytes: %llu\n",
02144           pAccInfo->bytesToConfirm, prepaidIval, prepaidAmount, pAccInfo->transferredBytes);
02145 
02146 #endif
02147       if( (pAccInfo->clientVersion == NULL) ||
02148         (strncmp((char*)pAccInfo->clientVersion, PREPAID_PROTO_CLIENT_VERSION, CLIENT_VERSION_STR_LEN) < 0) )
02149       {
02150         //old CC without payRequest and prepaid bytes.
02151         //CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Account %llu: Old prepaid proto version.\n", pAccInfo->accountNumber);
02152         sendStatus = pAccInfo->pControlChannel->sendXMLMessage(pCC->getXMLDocument());
02153 
02154       }
02155       else
02156       {
02157         //CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Account %llu: New prepaid proto version. prepaid bytes: %d\n",
02158         //    pAccInfo->accountNumber, prepaidAmount);
02159         sendStatus = sendInitialCCRequest(pAccInfo, pCC, prepaidAmount);
02160       }
02161     }
02162     else
02163     {
02164       // there is no CC in the database; typically this is the first connection of this user
02165       if (prepaidAmount > 0)
02166       {
02167         // Delete any previously stored prepaid amount; there should not be any! CC lost?
02168         pAccInfo->transferredBytes += prepaidAmount;
02169       }
02170       sendStatus = sendCCRequest(pAccInfo);
02171     }
02172   }
02173 
02174 
02175   delete pCC;
02176   pCC = NULL;
02177 
02178 
02179   if ( pAccInfo->pChallenge != NULL ) // free mem
02180   {
02181     delete[] pAccInfo->pChallenge;
02182     pAccInfo->pChallenge = NULL;
02183   }
02184   //CAMsg::printMsg( LOG_ERR, "CAAccountingInstance::handleChallengeResponse stop\n");
02185 
02186   pAccInfo->mutex->unlock();
02187   if(sendStatus == E_SUCCESS)
02188   {
02189     return CAXMLErrorMessage::ERR_OK;
02190   }
02191   else
02192   {
02193     return CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR;
02194   }
02195 }
02196 
02197 UINT32 CAAccountingInstance::handleCostConfirmation(tAiAccountingInfo* pAccInfo, DOMElement* root)
02198 {
02199   return handleCostConfirmation_internal(pAccInfo, root);
02200   INIT_STACK;
02201   FINISH_STACK("CAAccountingInstance::handleCostConfirmation");
02202 }
02203 
02207 UINT32 CAAccountingInstance::handleCostConfirmation_internal(tAiAccountingInfo* pAccInfo, DOMElement* root)
02208 {
02209   INIT_STACK;
02210   BEGIN_STACK("CAAccountingInstance::handleCostConfirmation");
02211 
02212   if (pAccInfo == NULL)
02213   {
02214     return CAXMLErrorMessage::ERR_NO_RECORD_FOUND;
02215   }
02216 
02217   pAccInfo->mutex->lock();
02218 
02219   if ( (pAccInfo->authFlags & AUTH_DELETE_ENTRY) ||
02220      (!(pAccInfo->authFlags & AUTH_LOGIN_NOT_FINISHED ) && (pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY )) )
02221   {
02222     CAMsg::printMsg(LOG_ERR,
02223           "CAAccountingInstance::handleCostConfirmation Ignoring CC, restricted flags set: %s %s\n",
02224           ((pAccInfo->authFlags & AUTH_DELETE_ENTRY) ? "AUTH_DELETE_ENTRY" : "") ,
02225           ((pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY) ? "AUTH_ACCOUNT_EMPTY" : ""));
02226     // ignore CCs for this account!
02227     pAccInfo->mutex->unlock();
02228     return CAXMLErrorMessage::ERR_NO_ERROR_GIVEN;
02229   }
02230 
02231   // check authstate
02232   if (!(pAccInfo->authFlags & AUTH_GOT_ACCOUNTCERT) ||
02233     !(pAccInfo->authFlags & AUTH_ACCOUNT_OK) ||
02234     !(pAccInfo->authFlags & AUTH_SENT_CC_REQUEST))
02235   {
02236     CAMsg::printMsg(LOG_ERR,
02237       "CAAccountingInstance::handleCostConfirmation CC was received but has not been requested! Ignoring...\n");
02238 
02239     pAccInfo->mutex->unlock();
02240     return CAXMLErrorMessage::ERR_NO_ERROR_GIVEN;
02241   }
02242 
02243   CAXMLCostConfirmation* pCC = CAXMLCostConfirmation::getInstance(root);
02244   if(pCC==NULL)
02245   {
02246     pAccInfo->mutex->unlock();
02247     return CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR;
02248   }
02249 
02250   // for debugging only: test signature the oldschool way
02251   // warning this removes the signature from doc!!!
02252   if (pAccInfo->pPublicKey==NULL||
02253     pAccInfo->pPublicKey->verifyXML( root ) != E_SUCCESS)
02254   {
02255     // wrong signature
02256     CAMsg::printMsg( LOG_INFO, "CostConfirmation has INVALID SIGNATURE!\n" );
02257     CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_SIGNATURE, (UINT8*)"CostConfirmation has bad signature");
02258     XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
02259     err.toXmlDocument(errDoc);
02260     pAccInfo->pControlChannel->sendXMLMessage(errDoc);
02261     if (errDoc != NULL)
02262     {
02263       errDoc->release();
02264       errDoc = NULL;
02265     }
02266     delete pCC;
02267     pCC = NULL;
02268     pAccInfo->mutex->unlock();
02269     return CAXMLErrorMessage::ERR_BAD_SIGNATURE;
02270   }
02271   #ifdef DEBUG
02272   else
02273     {
02274       CAMsg::printMsg( LOG_DEBUG, "CostConfirmation Signature is OK.\n");
02275     }
02276   #endif
02277 
02278 
02279   if (pCC->getNumberOfHashes() != m_allHashesLen)
02280   {
02281     CAMsg::printMsg( LOG_INFO, "CostConfirmation has illegal number of price cert hashes!\n" );
02282     CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_REQUEST,
02283       (UINT8*)"CostConfirmation has illegal number of price cert hashes");
02284     XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
02285     err.toXmlDocument(errDoc);
02286     pAccInfo->pControlChannel->sendXMLMessage(errDoc);
02287     if (errDoc != NULL)
02288     {
02289       errDoc->release();
02290       errDoc = NULL;
02291     }
02292     delete pCC;
02293     pCC = NULL;
02294     pAccInfo->mutex->unlock();
02295     return CAXMLErrorMessage::ERR_WRONG_FORMAT;
02296   }
02297 
02298   /*Hashtable* certHashCC =
02299     new Hashtable((UINT32 (*)(void *))Hashtable::stringHash, (SINT32 (*)(void *,void *))Hashtable::stringCompare);
02300   UINT8* certHash;*/
02301   //bool bFailed = false;
02302   //for (UINT32 i = 0; i < pCC->getNumberOfHashes(); i++)
02303   //{
02304   //  certHash = pCC->getPriceCertHash(i);
02305   //  certHashCC->put(certHash, certHash);
02306     /*
02307     if ((certHash = (UINT8*)certHashCC->getValue(certHash)) != NULL)
02308     {
02309       CAMsg::printMsg( LOG_INFO, "CC1: %s\n", certHash);
02310     }*/
02311   //}
02312   //for (UINT32 i = 0; i < m_allHashesLen; i++)
02313   //{
02314     //CAMsg::printMsg( LOG_INFO, "CA:  %s\n", m_allHashes[i]);
02315   //  certHash = (UINT8*)certHashCC->remove(m_allHashes[i]);
02316   //  if (certHash == NULL)
02317   //  {
02318   //    bFailed = true;
02319   //    break;
02320   //  }
02321   //  else
02322   //  {
02323   //    delete[] certHash;
02324   //  }
02325   //}
02326   //certHashCC->clear(HASH_EMPTY_NONE, HASH_EMPTY_DELETE);
02327   //delete certHashCC;
02328 
02329   if (!cascadeMatchesCC(pCC))
02330   {
02331     CAMsg::printMsg( LOG_INFO, "CostConfirmation has invalid price cert hashes!\n" );
02332     CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_REQUEST,
02333       (UINT8*)"CostConfirmation has invalid price cert hashes");
02334     XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
02335     err.toXmlDocument(errDoc);
02336     pAccInfo->pControlChannel->sendXMLMessage(errDoc);
02337     if (errDoc != NULL)
02338     {
02339       errDoc->release();
02340       errDoc = NULL;
02341     }
02342     delete pCC;
02343     pCC = NULL;
02344     pAccInfo->mutex->unlock();
02345     return CAXMLErrorMessage::ERR_WRONG_DATA;
02346   }
02347 
02348 
02349 
02350   // parse & set transferredBytes
02351   //when using Prepayment, this check is outdated, but left in to notice the most crude errors/cheats
02352   //The CC's transferredBytes should be equivalent to
02353   //AccInfo's confirmed bytes + the Config's PrepaidInterval - the number of bytes transferred between
02354   //requesting and receiving the CC
02355 #ifdef DEBUG
02356   CAMsg::printMsg( LOG_DEBUG, "received cost confirmation for  %llu transferred bytes where confirmed bytes are %llu, we need %llu bytes to confirm"
02357       ", mix already counted %llu transferred bytes\n",
02358       pCC->getTransferredBytes(), pAccInfo->confirmedBytes, pAccInfo->bytesToConfirm,
02359       pAccInfo->transferredBytes);
02360 #endif
02361 
02362   if(pCC->getTransferredBytes() > (pAccInfo->transferredBytes+CALibProxytest::getOptions()->getPrepaidInterval()) )
02363   {
02364     CAMsg::printMsg( LOG_ERR, "Warning: ignoring this CC for account %llu "
02365         "because it tries to confirm %lld prepaid bytes where only %u prepaid bytes are allowed (cc->tranferredbytes: %llu, accInfo->tranferredBytes: %llu)\n",
02366         pAccInfo->accountNumber, (pCC->getTransferredBytes() - pAccInfo->transferredBytes),
02367         CALibProxytest::getOptions()->getPrepaidInterval(),
02368         pCC->getTransferredBytes(), pAccInfo->transferredBytes);
02369 
02370     CAXMLErrorMessage err(CAXMLErrorMessage::ERR_WRONG_DATA,
02371       (UINT8*)"More bytes confirmed than allowed.");
02372     XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
02373     err.toXmlDocument(errDoc);
02374     pAccInfo->pControlChannel->sendXMLMessage(errDoc);
02375     if (errDoc != NULL)
02376     {
02377       errDoc->release();
02378       errDoc = NULL;
02379     }
02380     //mark as account empty has the effect is that the user can empty his prepaid amount and then will be kicked out.
02381     pAccInfo->authFlags |= AUTH_FAKE;
02382     delete pCC;
02383     pCC = NULL;
02384     pAccInfo->mutex->unlock();
02385     return CAXMLErrorMessage::ERR_WRONG_DATA;
02386   }
02387 
02388   if (pCC->getTransferredBytes() < pAccInfo->confirmedBytes)
02389   {
02390 
02391     CAMsg::printMsg( LOG_ERR, "CostConfirmation has insufficient number of bytes:\n");
02392     CAMsg::printMsg( LOG_ERR, "CC->transferredBytes: %llu < confirmedBytesBytes: %llu\n", pCC->getTransferredBytes(), pAccInfo->confirmedBytes);
02393 
02394     if(pAccInfo->authFlags & AUTH_LOGIN_NOT_FINISHED)
02395     {
02396       //@todo: perhaps we should use another flag to indicate that this user should be kicked out.
02397       pAccInfo->authFlags |= AUTH_FAKE;
02398       delete pCC;
02399       pCC = NULL;
02400       pAccInfo->mutex->unlock();
02401       return CAXMLErrorMessage::ERR_WRONG_DATA;
02402     }
02403 
02404     /*
02405     CAXMLErrorMessage err(CAXMLErrorMessage::ERR_WRONG_DATA,
02406       (UINT8*)"Your CostConfirmation has a wrong number of transferred bytes");
02407     DOM_Document errDoc;
02408     err.toXmlDocument(errDoc);
02409     pAccInfo->pControlChannel->sendXMLMessage(errDoc);*/
02410   }
02411   else if (pCC->getTransferredBytes() == pAccInfo->confirmedBytes && getPrepaidBytes(pAccInfo) != CALibProxytest::getOptions()->getPrepaidInterval())
02412   {
02413     CAMsg::printMsg(LOG_WARNING, "Received CostConfirmation for account %llu has no difference in bytes to current CC (%llu bytes).\n", 
02414       pAccInfo->accountNumber, pCC->getTransferredBytes());
02415   }
02416   else
02417   {
02418     /*
02419     UINT8 tmp[32];
02420     print64(tmp,pCC->getTransferredBytes());
02421     CAMsg::printMsg( LOG_ERR, "Transferredbytes in CC: %s\n", tmp);
02422     */
02423     SINT32 dbRet = E_UNKNOWN;
02424     CAAccountingDBInterface *dbInterface = CAAccountingDBInterface::getConnection();
02425     if(dbInterface != NULL)
02426     {
02427       dbRet = dbInterface->storeCostConfirmation(*pCC, m_currentCascade);
02428       CAAccountingDBInterface::releaseConnection(dbInterface);
02429       dbInterface = NULL;
02430     }
02431     if (dbRet != E_SUCCESS)
02432     {
02433       UINT8 tmp[32];
02434       print64(tmp,pCC->getAccountNumber());
02435       CAMsg::printMsg( LOG_INFO, "CostConfirmation for account %s could not be stored in database!\n", tmp );
02436       pAccInfo->authFlags |= AUTH_DATABASE;
02437     }
02438     else
02439     {
02440 #ifdef DEBUG
02441       CAMsg::printMsg( LOG_INFO, "Handle CC: pCC->transBytes: %llu\n", pCC->getTransferredBytes() );
02442 #endif
02443       pAccInfo->confirmedBytes = pCC->getTransferredBytes();
02444 
02445       if (pAccInfo->authFlags & AUTH_WAITING_FOR_FIRST_SETTLED_CC)
02446       {
02447         // initiate immediate settling
02448 #ifdef DEBUG
02449         UINT64 currentMillis;
02450         UINT8 tmpStrCurrentMillis[50];
02451         getcurrentTimeMillis(currentMillis);
02452         print64(tmpStrCurrentMillis,currentMillis);
02453         CAMsg::printMsg(LOG_DEBUG, "AccountingSettleThread: Settle ini: %s\n", tmpStrCurrentMillis);
02454 #endif
02455         m_pSettleThread->settle();
02456 
02457       }
02458     }
02459   }
02460 #ifdef DEBUG
02461   CAMsg::printMsg(LOG_ERR, "Handle CC request: pAccInfo->confirmedBytes: %llu, ppAccInfo->transferredBytes: %llu\n",
02462       pAccInfo->confirmedBytes, pAccInfo->transferredBytes);
02463 #endif
02464   if (pAccInfo->confirmedBytes >= pAccInfo->bytesToConfirm)
02465   {
02466     // the user confirmed everything we wanted; if a timeout has been set, it should be reset
02467     pAccInfo->authFlags &= ~AUTH_HARD_LIMIT_REACHED;
02468     pAccInfo->lastHardLimitSeconds = time(NULL);
02469   }
02470   else
02471   {
02472     /*UINT8 tmp[32], tmp2[32], tmp3[32];
02473     print64(tmp, pCC->getTransferredBytes());
02474     print64(tmp2, pCC->getAccountNumber());
02475     print64(tmp3, pAccInfo->bytesToConfirm);*/
02476     CAMsg::printMsg(LOG_ERR, "AccountingSettleThread: Requested CC value has NOT been confirmed by account nr %llu! "
02477                  "Received Bytes: %llu/%llu "
02478                 "Client should not be allowed to login.\n",
02479                 pCC->getAccountNumber(),
02480                 pCC->getTransferredBytes(),
02481                 pAccInfo->bytesToConfirm);
02482 
02483     if(pAccInfo->authFlags & AUTH_LOGIN_SKIP_SETTLEMENT)
02484     {
02485       CAMsg::printMsg( LOG_INFO, "Skip settlement revoked.\n");
02486       pAccInfo->authFlags &= ~AUTH_LOGIN_SKIP_SETTLEMENT;
02487     }
02488     /*delete pCC;
02489     pCC = NULL;
02490     pAccInfo->mutex->unlock();
02491     pAccInfo->authFlags |= AUTH_FAKE;
02492     return CAXMLErrorMessage::ERR_WRONG_DATA;*/
02493     //m_pSettleThread->settle();
02494 
02495   }
02496 
02497   pAccInfo->bytesToConfirm = 0;
02498   pAccInfo->authFlags &= ~AUTH_SENT_CC_REQUEST;
02499 
02500   delete pCC;
02501   pCC = NULL;
02502   pAccInfo->mutex->unlock();
02503 
02504   return CAXMLErrorMessage::ERR_OK;
02505 }
02506 
02511 SINT32 CAAccountingInstance::initTableEntry( fmHashTableEntry * pHashEntry )
02512 {
02513   INIT_STACK;
02514   BEGIN_STACK("CAAccountingInstance::initTableEntry");
02515 
02516   //ms_pInstance->m_pMutex->lock();
02517 
02518   if (pHashEntry == NULL)
02519   {
02520     FINISH_STACK("CAAccountingInstance::initTableEntry:NULL");
02521     return E_UNKNOWN;
02522   }
02523 
02524   pHashEntry->pAccountingInfo = new tAiAccountingInfo;
02525   memset( pHashEntry->pAccountingInfo, 0, sizeof( tAiAccountingInfo ) );
02526 
02527   SAVE_STACK("CAAccountingInstance::initTableEntry", "After memset");
02528 
02529   pHashEntry->pAccountingInfo->authFlags =
02530     AUTH_SENT_ACCOUNT_REQUEST | AUTH_TIMEOUT_STARTED |
02531     AUTH_HARD_LIMIT_REACHED | AUTH_WAITING_FOR_FIRST_SETTLED_CC |
02532     AUTH_SENT_CC_REQUEST | AUTH_LOGIN_NOT_FINISHED; // prevents multiple CC requests on login
02533   pHashEntry->pAccountingInfo->authTimeoutStartSeconds = time(NULL);
02534   pHashEntry->pAccountingInfo->lastHardLimitSeconds = time(NULL);
02535   pHashEntry->pAccountingInfo->sessionPackets = 0;
02536   pHashEntry->pAccountingInfo->transferredBytes = 0;
02537   pHashEntry->pAccountingInfo->confirmedBytes = 0;
02538   pHashEntry->pAccountingInfo->bytesToConfirm = 0;
02539   pHashEntry->pAccountingInfo->nrInQueue = 0;
02540   pHashEntry->pAccountingInfo->userID = pHashEntry->id;
02541   pHashEntry->pAccountingInfo->ownerRef = pHashEntry;
02542   pHashEntry->pAccountingInfo->clientVersion = NULL;
02543   pHashEntry->pAccountingInfo->mutex = new CAMutex;
02544   //ms_pInstance->m_pMutex->unlock();
02545 
02546 
02547   FINISH_STACK("CAAccountingInstance::initTableEntry");
02548 
02549   return E_SUCCESS;
02550 }
02551 
02552 
02553 
02559 SINT32 CAAccountingInstance::cleanupTableEntry( fmHashTableEntry *pHashEntry )
02560   {
02561     INIT_STACK;
02562     BEGIN_STACK("CAAccountingInstance::cleanupTableEntry");
02563 
02564     //ms_pInstance->m_pMutex->lock();
02565     tAiAccountingInfo* pAccInfo = pHashEntry->pAccountingInfo;
02566     AccountLoginHashEntry* loginEntry;
02567     SINT32 prepaidBytes = 0;
02568     SINT32 prepaidInterval = CALibProxytest::getOptions()->getPrepaidInterval();
02569 
02570     if (pAccInfo == NULL)
02571     {
02572       SAVE_STACK("CAAccountingInstance::cleanupTableEntry", "acc info null");
02573       //ms_pInstance->m_pMutex->unlock();
02574       return E_UNKNOWN;
02575     }
02576 
02577     //pAccInfo->mutex->lock();
02578 
02579     pHashEntry->pAccountingInfo=NULL;
02580 
02581     if (pAccInfo->accountNumber)
02582     {
02583       CAMsg::printMsg(LOG_INFO, "cleaning up entry %p of accountno. %llu (pAccInfo ref: %p)\n",
02584               pHashEntry, pAccInfo->accountNumber, pAccInfo);
02585       if (pAccInfo->authFlags & AUTH_ACCOUNT_OK)
02586       {
02587         // remove login
02588         ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
02589         loginEntry = (AccountLoginHashEntry*)ms_pInstance->m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
02590 
02591         if (loginEntry)
02592         {
02593           // test: delete CC!!!
02594           //ms_pInstance->m_dbInterface->deleteCC(pAccInfo->accountNumber, ms_pInstance->m_currentCascade);
02595           if (testLoginEntryOwner(loginEntry, pHashEntry))// &&
02597           {
02598             if (loginEntry->authFlags & AUTH_ACCOUNT_EMPTY)
02599             {
02600               // make sure to store the correct number of prepaid bytes
02601               pAccInfo->confirmedBytes = loginEntry->confirmedBytes;
02602             }
02603             //store prepaid bytes in database, so the user wont lose the prepaid amount by disconnecting
02604             prepaidBytes = getPrepaidBytes(pAccInfo);
02605             if (prepaidBytes > 0)
02606             {
02607               if (prepaidBytes > prepaidInterval)
02608               {
02609                 UINT8 tmp[32];
02610                 print64(tmp, pAccInfo->accountNumber);
02611                 /* Client paid more than the prepaid interval -
02612                  * this is beyond specification and not allowed!
02613                  */
02614                 CAMsg::printMsg(LOG_ERR,
02615                   "PrepaidBytes of %d for account %s are higher than prepaid interval! "
02616                   "The client (owner %x) did not behave according to specification. "
02617                   "Deleting prepaid bytes!\n", prepaidBytes, tmp, pHashEntry);
02618                   //"Deleting %d bytes...\n", prepaidBytes, tmp, pHashEntry, prepaidBytes - prepaidInterval);
02619 
02620                 //prepaidBytes = prepaidInterval;
02621                 prepaidBytes = 0;
02622               }
02623             }
02624 
02625             /*if (ms_pInstance->m_dbInterface)
02626             {
02627               ms_pInstance->m_dbInterface->storePrepaidAmount(pAccInfo->accountNumber,prepaidBytes, ms_pInstance->m_currentCascade);
02628             }*/
02629             CAAccountingDBInterface *dbInterface = CAAccountingDBInterface::getConnection();
02630             if(dbInterface != NULL)
02631             {
02632               dbInterface->storePrepaidAmount(pAccInfo->accountNumber,
02633                               prepaidBytes,
02634                               ms_pInstance->m_currentCascade);
02635               CAAccountingDBInterface::releaseConnection(dbInterface);
02636               dbInterface = NULL;
02637             }
02638             if(!isLoginOngoing(loginEntry, pHashEntry))
02639             {
02640               ms_pInstance->m_currentAccountsHashtable->remove(&(pAccInfo->accountNumber));
02641               delete loginEntry->ownerLock;
02642               delete loginEntry;
02643               loginEntry = NULL;
02644             }
02645             else
02646             {
02647               CAMsg::printMsg(LOG_INFO, "Cleaning: Leaving loginEntry %x cleanup of owner %x to the next owner due to double-login of a user.\n",
02648                   loginEntry, loginEntry->ownerRef);
02649             }
02650           }
02651 
02652           /*if (loginEntry->count <= 1)
02653           {
02654             if (loginEntry->count < 1)
02655             {
02656               CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Cleanup found non-positive number of user login hash entries (%d)!\n", loginEntry->count);
02657             }
02658             // this is the last active user connection; delete the entry
02659             ms_pInstance->m_currentAccountsHashtable->remove(&(pAccInfo->accountNumber));
02660             delete loginEntry->ownerLock;
02661             delete loginEntry;
02662             loginEntry = NULL;
02663           }
02664           else
02665           {
02666             // there are other connections from this user
02667             loginEntry->count--;
02668           }*/
02669         }
02670         else
02671         {
02672           CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Cleanup did not find user login hash entry!\n");
02673         }
02674         ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
02675       }
02676     }
02677     else
02678     {
02679       CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Cleanup method found account zero.\n");
02680     }
02681 
02682     //free memory of pAccInfo
02683 
02684     delete pAccInfo->pPublicKey;
02685     pAccInfo->pPublicKey = NULL;
02686 
02687 
02688     delete [] pAccInfo->pChallenge;
02689     pAccInfo->pChallenge = NULL;
02690 
02691     delete [] pAccInfo->pstrBIID;
02692     pAccInfo->pstrBIID = NULL;
02693 
02694     delete [] pAccInfo->clientVersion;
02695     pAccInfo->clientVersion = NULL;
02696 
02697     pHashEntry->pAccountingInfo=NULL;
02698 
02699     if (pAccInfo->nrInQueue > 0)
02700     {
02701       /*
02702       if (pAccInfo->accountNumber == 0)
02703       {
02704         CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: AI queue entries found for account zero: %u!\n", pAccInfo->nrInQueue);
02705       }
02706       else if (!(pAccInfo->authFlags & AUTH_ACCOUNT_OK))
02707       {
02708         UINT8 accountNrAsString[32];
02709         print64(accountNrAsString, pAccInfo->accountNumber);
02710         CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: AI queue entries found for unauthorized account %s: %u!\n", accountNrAsString, pAccInfo->nrInQueue);
02711       }
02712       else*/
02713       {
02714         // there are still entries in the ai queue; empty it before deletion; we cannot delete it now
02715         pAccInfo->authFlags |= AUTH_DELETE_ENTRY;
02716       }
02717     }
02718     else if (pAccInfo->nrInQueue < 0)
02719     {
02720       CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Cleanup method found negative handle queue!\n");
02721     }
02722     //pAccInfo->mutex->unlock();
02723 
02724     if (!(pAccInfo->authFlags & AUTH_DELETE_ENTRY))
02725     {
02726       // there are no handles for this entry in the queue, we can savely delete it now
02727       delete pAccInfo->mutex;
02728       pAccInfo->mutex = NULL;
02729       delete [] pAccInfo->clientVersion;
02730       pAccInfo->clientVersion = NULL;
02731       
02732 #ifdef LOG_CRIME
02733       UINT64 accountNumber = pAccInfo->accountNumber;
02734       UINT64* surveillanceAccounts = CALibProxytest::getOptions()->getCrimeSurveillanceAccounts();
02735       UINT32 nrOfSurveillanceAccounts = CALibProxytest::getOptions()->getNrOfCrimeSurveillanceAccounts();
02736       const UINT8* peerIP = pHashEntry->peerIP;
02737     
02738       for (UINT32 iAccount = 0; iAccount < nrOfSurveillanceAccounts; iAccount++)
02739       {
02740         if (accountNumber == surveillanceAccounts[iAccount])
02741         {
02742           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]);
02743           break;
02744         }
02745       }
02746 #endif
02747       
02748       delete pAccInfo;
02749       pAccInfo = NULL;
02750     }
02751     else
02752     {
02753       CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Cleanup method sent account deletion request to AI thread!\n");
02754     }
02755     //ms_pInstance->m_pMutex->unlock();
02756 
02757     FINISH_STACK("CAAccountingInstance::cleanupTableEntry");
02758 
02759     return E_SUCCESS;
02760   }
02761 
02762 SINT32 CAAccountingInstance::newSettlementTransaction()
02763 {
02764   UINT32 settledCCs = 0;
02765   SINT32 retVal;
02766   do
02767   {
02768     retVal = __newSettlementTransaction(&settledCCs);
02769   }
02770   while(settledCCs >= MAX_SETTLED_CCS && retVal == E_SUCCESS);
02771   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!
02772 }
02773 
02774 SINT32 CAAccountingInstance::__newSettlementTransaction(UINT32 *nrOfSettledCCs)
02775 {
02776 
02777   CAXMLErrorMessage **pErrMsgs = NULL, *settleException = NULL;
02778   CAXMLCostConfirmation **allUnsettledCCs = NULL;
02779   SettleEntry *entry = NULL, *nextEntry = NULL;
02780   CAAccountingDBInterface *dbInterface = NULL;
02781 
02782   UINT32 nrOfCCs = 0, i = 0;
02783   SINT32 biConnectionStatus = 0, ret = E_SUCCESS;
02784   UINT64 myWaitNr = 0;
02785 
02786 
02787   //settlement transactions need to be synchronized globally because the settlement thread as well as all login threads
02788   //may start a settlement transaction concurrently.
02789   ms_pInstance->m_pSettlementMutex->lock();
02790 
02791   UINT64 iCurrentSettleTransactionNr = (++m_iCurrentSettleTransactionNr) % 50;
02792 
02793   dbInterface = CAAccountingDBInterface::getConnection();
02794   if(dbInterface == NULL)
02795   {
02796     ms_pInstance->m_pSettlementMutex->unlock();
02797     CAMsg::printMsg(LOG_ERR, "Settlement transaction: could not connect to Database. Retry later...\n");
02798     ret = E_NOT_CONNECTED;
02799     goto cleanup;
02800   }
02801   
02802 
02803   /* First part get unsettled CCs from the AI database */
02804   #ifdef DEBUG
02805   CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: DB connections established!\n");
02806   #endif
02807 
02808     dbInterface->getUnsettledCostConfirmations(&allUnsettledCCs, ms_pInstance->m_currentCascade, &nrOfCCs, MAX_SETTLED_CCS);
02809     *nrOfSettledCCs = nrOfCCs;
02810     //no unsettled CCs found.
02811     if (allUnsettledCCs == NULL)
02812     {
02813       CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: thread %x looked for unsettled CCs, found no CCs to settle\n", iCurrentSettleTransactionNr, pthread_self());
02814       ms_pInstance->m_pSettlementMutex->unlock();
02815       ret = E_SUCCESS;
02816       goto cleanup;
02817     }
02818 
02819 
02820     CAMsg::printMsg(LOG_DEBUG, "Settlement transaction %llu: thread %x looked for unsettled CCs, found %u cost confirmations to settle\n", iCurrentSettleTransactionNr, pthread_self(), nrOfCCs);
02821 
02822     //connect to the PI
02823     biConnectionStatus = ms_pInstance->m_pPiInterface->initBIConnection();
02824     if(biConnectionStatus != E_SUCCESS)
02825     {
02826       ms_pInstance->m_seqBIConnErrors++;
02827       if(ms_pInstance->m_seqBIConnErrors >= CRITICAL_SUBSEQUENT_BI_CONN_ERRORS)
02828       {
02829         //transition to critical BI conn payment state
02830         MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionCriticalSubseqFailures);
02831       }
02832       else
02833       {
02834         MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionFailure);
02835       }
02836       ms_pInstance->m_pPiInterface->terminateBIConnection(); // make sure the socket is closed
02837       
02838       CAAccountingDBInterface::releaseConnection(dbInterface);
02839       dbInterface = NULL;
02840       ms_pInstance->m_pSettlementMutex->unlock();
02841 
02842       CAMsg::printMsg(LOG_WARNING, "Settlement transaction: could not connect to BI. Try later...\n");
02843       //ret = E_SUCCESS;
02844       ret = E_NOT_CONNECTED;
02845       goto cleanup;
02846     }
02847     else
02848     {
02849       pErrMsgs = ms_pInstance->m_pPiInterface->settleAll(allUnsettledCCs, nrOfCCs, &settleException);
02850       ms_pInstance->m_pPiInterface->terminateBIConnection();
02851     }
02852 
02853   //workaround because usage of exceptions is not allowed!
02854   if(settleException != NULL)
02855   {
02856     CAAccountingDBInterface::releaseConnection(dbInterface);
02857     dbInterface = NULL;
02858   
02859     ms_pInstance->m_pSettlementMutex->unlock();
02860     CAMsg::printMsg(LOG_ERR, "Settlement transaction: BI reported settlement not successful: "
02861             "code: %i, %s \n", settleException->getErrorCode(),
02862               (settleException->getDescription() != NULL ?
02863                 settleException->getDescription() : (UINT8*) "<no description given>") );
02864     ret = E_UNKNOWN;
02865     goto cleanup;
02866   }
02867 
02868   if(pErrMsgs == NULL)
02869   {
02870     //this must never happen because in any case where NULL is returned for pErrMsgs
02871     //'settleException' must not be NULL.
02872     CAAccountingDBInterface::releaseConnection(dbInterface);
02873     dbInterface = NULL;
02874     
02875     ms_pInstance->m_pSettlementMutex->unlock();
02876     CAMsg::printMsg(LOG_CRIT, "Settlement transaction: ErrorMessages are null.\n");
02877     ret = E_UNKNOWN;
02878     goto cleanup;
02879   }
02880   else
02881   {
02882     for(i = 0; i < nrOfCCs; i++)
02883     {
02884       nextEntry = __handleSettleResult(allUnsettledCCs[i], pErrMsgs[i], dbInterface, iCurrentSettleTransactionNr);
02885       if(nextEntry != NULL)
02886       {
02887         nextEntry->nextEntry = entry;
02888         entry = nextEntry;
02889       }
02890     }
02891   }
02892 
02893   //after settling: apply the corresponding account state changes reported from the PI.
02894   if (entry)
02895   {
02896     //wait numbers are used to obtain a synchronisation with FCFS assertion.
02897     //This additional synchronisation is necessary because before acquiring the login hashtable
02898     //locks the settlementMutex should be released. (Nested locking should be avoided).
02899     if(ms_pInstance->m_nextSettleNr == ms_pInstance->m_settleWaitNr)
02900     {
02901       //CAMsg::printMsg(LOG_INFO, "Thread %x: resetting the wait numbers.\n", pthread_self() );
02902       //no one is waiting, we use this occasion to reset the wait numbers
02903       ms_pInstance->m_nextSettleNr = 0;
02904       ms_pInstance->m_settleWaitNr = 1;
02905     }
02906     else
02907     {
02908       //get global wait number and wait but release the DBConnection first.
02909       CAAccountingDBInterface::releaseConnection(dbInterface);
02910       dbInterface = NULL;
02911       myWaitNr = ms_pInstance->m_settleWaitNr;
02912       ms_pInstance->m_settleWaitNr++;
02913       while(myWaitNr != ms_pInstance->m_nextSettleNr)
02914       {
02915         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", 
02916             iCurrentSettleTransactionNr, pthread_self(), (myWaitNr - ms_pInstance->m_nextSettleNr));
02917         ms_pInstance->m_pSettlementMutex->wait();
02918       }
02919       
02920       CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: Thread %x may continue (1).\n", iCurrentSettleTransactionNr, pthread_self());
02921       dbInterface = CAAccountingDBInterface::getConnection();
02922     }
02923     
02924     bool debugWarn = false;
02925     if (iCurrentSettleTransactionNr != (m_iCurrentSettleTransactionNr % 50))
02926     {
02927       debugWarn = true;
02928       // Write debug message in order to find deadlock...
02929       CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: Apply changes to database. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
02930     }
02931 
02932     //first apply changes to the database ...
02933     __commitSettlementToDatabase(entry, dbInterface);
02934     CAAccountingDBInterface::releaseConnection(dbInterface);
02935     dbInterface = NULL;
02936     
02937     
02938     if (debugWarn)
02939     {
02940       // Write debug message in order to find deadlock...
02941       CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: Removing settlement mutex lock. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
02942     }
02943     
02944     ms_pInstance->m_pSettlementMutex->unlock();
02945     
02946     
02947     if (debugWarn)
02948     {
02949       // Write debug message in order to find deadlock...
02950       CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: Entering login hashtable. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);    
02951     }
02952 
02953     //... then to the login hashtable after releasing the global settlement lock.
02954     ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
02955     CAMsg::printMsg(LOG_DEBUG, "Settlement transaction %llu: thread %x with wait nr %llu alters hashtable.\n", iCurrentSettleTransactionNr, pthread_self(), myWaitNr);
02956     __commitSettlementToLoginTable(entry);
02957     ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
02958 
02959     if (debugWarn)
02960     {
02961       // Write debug message in order to find deadlock...
02962       CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: After commiting to login hashtable, before last lock. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);    
02963     }
02964     
02965     //indicate that the next thread may proceed with its settlement changes by incrementing the nextSettleNr.
02966     ms_pInstance->m_pSettlementMutex->lock();
02967     ms_pInstance->m_nextSettleNr++;
02968 // TODO: seems to be a bug; if this "if" is set, some locks are never released
02969 //if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
02970     {
02971       //There are threads waiting for applying their settlement results.
02972       if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
02973       CAMsg::printMsg(LOG_INFO, "Thread %x waking up next Thread. %llu are still waiting.\n", pthread_self(),
02974               (ms_pInstance->m_settleWaitNr - ms_pInstance->m_nextSettleNr));
02975       ms_pInstance->m_pSettlementMutex->signal();
02976     }
02977   }
02978   ms_pInstance->m_pSettlementMutex->unlock();
02979 
02980 cleanup:
02981   if(dbInterface != NULL)
02982   {
02983     CAAccountingDBInterface::releaseConnection(dbInterface);
02984     dbInterface = NULL;
02985   }
02986 
02987   if(allUnsettledCCs != NULL)
02988   {
02989     for(i = 0; i < nrOfCCs; i++)
02990     {
02991       delete allUnsettledCCs[i];
02992       allUnsettledCCs[i] = NULL;
02993     }
02994     delete [] allUnsettledCCs;
02995     allUnsettledCCs = NULL;
02996   }
02997 
02998   if(pErrMsgs != NULL)
02999   {
03000     for(i = 0; i < nrOfCCs; i++)
03001     {
03002       delete pErrMsgs[i];
03003       pErrMsgs[i] = NULL;
03004     }
03005     pErrMsgs = NULL;
03006   }
03007 
03008   while (entry != NULL)
03009   {
03010     nextEntry = entry->nextEntry;
03011     delete entry;
03012     entry = nextEntry;
03013   }
03014 
03015   delete settleException;
03016   settleException = NULL;
03017 
03018   
03019   CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu finished.\n", iCurrentSettleTransactionNr);
03020 
03021   return ret;
03022 }
03023 
03024 SettleEntry *CAAccountingInstance::__handleSettleResult(CAXMLCostConfirmation *pCC, CAXMLErrorMessage *pErrMsg, CAAccountingDBInterface *dbInterface, 
03025   UINT64 a_iCurrentSettleTransactionNr)
03026 {
03027   bool bDeleteCC = false;
03028   UINT32 authFlags = 0;
03029   UINT32 authRemoveFlags = 0;
03030   UINT64 confirmedBytes = 0;
03031   UINT64 diffBytes = 0;
03032   UINT32 storedStatus = 0;
03033   SettleEntry *entry = NULL;
03034 
03035   dbInterface->getAccountStatus(pCC->getAccountNumber(), storedStatus);
03036 
03037   // check returncode
03038   if(pErrMsg == NULL)  //no returncode -> connection error
03039   {
03040     authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // no fault of the client
03041     CAMsg::printMsg(LOG_ERR, "Settlement transaction: Communication with BI failed!\n");
03042   }
03043   else if(pErrMsg->getErrorCode() != pErrMsg->ERR_OK)  //BI reported error
03044   {
03045     CAMsg::printMsg(LOG_WARNING, "Settlement transaction: BI reported error no. %d (%s)\n",
03046       pErrMsg->getErrorCode(), pErrMsg->getDescription() );
03047     if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_KEY_NOT_FOUND)
03048     {
03049       authFlags |= AUTH_INVALID_ACCOUNT;
03050       //dbConn.storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_KEY_NOT_FOUND);
03051       bDeleteCC = true;
03052     }
03053     else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_ACCOUNT_EMPTY)
03054     {
03055       authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03056       authFlags |= AUTH_ACCOUNT_EMPTY;
03057       UINT64* msgConfirmedBytes = (UINT64*)pErrMsg->getMessageObject();
03058       if (msgConfirmedBytes)
03059       {
03060         confirmedBytes = *msgConfirmedBytes;
03061         if (confirmedBytes < pCC->getTransferredBytes())
03062         {
03063           diffBytes = pCC->getTransferredBytes() - confirmedBytes;
03064         }
03065         UINT8 tmp[32];
03066         print64(tmp, confirmedBytes);
03067         UINT8 tmp2[32];
03068         print64(tmp2, diffBytes);
03069         UINT8 tmp3[32];
03070         print64(tmp3, pCC->getTransferredBytes());
03071         CAMsg::printMsg(LOG_INFO, "Settlement transaction: Received %s confirmed bytes and %s diff bytes while having %s transferred bytes!\n", tmp, tmp2, tmp3);
03072       }
03073       else
03074       {
03075         CAMsg::printMsg(LOG_INFO, "Settlement transaction: Account empty, no message object received. User will be kicked out.\n");
03076       }
03077 
03078       dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_ACCOUNT_EMPTY);
03079       authFlags |= AUTH_SETTLED_ONCE;
03080       dbInterface->markAsSettled(pCC->getAccountNumber(), ms_pInstance->m_currentCascade,
03081                     pCC->getTransferredBytes());
03082 //#ifdef DEBUG
03083       CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: settling %llu bytes for account %llu\n",
03084                     pCC->getTransferredBytes(), pCC->getAccountNumber());
03085 //#endif
03086     }
03087     /*
03088     else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INVALID_PRICE_CERT)
03089     {
03090       // this should never happen; the price certs in this CC do not fit to the ones of the cascade
03091       // bDeleteCC = true;
03092     }*/
03093     else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_OUTDATED_CC)
03094     {
03095       authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // this is a Mix not a client error
03096 
03097       //get attached CC from error message
03098       CAXMLCostConfirmation* attachedCC = (CAXMLCostConfirmation*) pErrMsg->getMessageObject();
03099       if (attachedCC)
03100       {
03101         authFlags |= AUTH_OUTDATED_CC;
03102         CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: tried outdated CC, received last valid CC back\n");
03103         //store it in DB
03104         if (dbInterface->storeCostConfirmation(*attachedCC,
03105             ms_pInstance->m_currentCascade) == E_SUCCESS)
03106         {
03107           authFlags |= AUTH_SETTLED_ONCE;
03108           if (dbInterface->markAsSettled(attachedCC->getAccountNumber(), ms_pInstance->m_currentCascade,
03109                       attachedCC->getTransferredBytes()) != E_SUCCESS)
03110           {
03111             CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark last valid CC as settled."
03112               "Maybe a new CC has been added meanwhile?\n");
03113           }
03114         }
03115         else
03116         {
03117           CAMsg::printMsg(LOG_ERR, "Settlement transaction: storing last valid CC in db failed!\n");
03118         }
03119         // set the confirmed bytes to the value of the CC got from the PI
03120         confirmedBytes = attachedCC->getTransferredBytes();
03121       }
03122       else
03123       {
03124         CAMsg::printMsg(LOG_INFO, "Settlement transaction: Did not receive last valid CC - maybe old Payment instance?\n");
03125       }
03126     }
03127     else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_BLOCKED)
03128     {
03129       authFlags |= AUTH_BLOCKED;
03130       bDeleteCC = true;
03131 
03132       dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_BLOCKED);
03133     }
03134 
03135     else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_DATABASE_ERROR)
03136     {
03137       //authFlags |= AUTH_DATABASE;
03138       // the user is not responsible for this!
03139       authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03140     }
03141     else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR ||
03142          pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_SUCCESS_BUT_WITH_ERRORS)
03143     {
03144       // kick out the user and store the CC
03145       authFlags |= AUTH_UNKNOWN;
03146     }
03147     else
03148     {
03149       // an unknown error leads to user kickout
03150       CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: Setting unknown kickout error no. %d.\n", pErrMsg->getErrorCode());
03151       authFlags |= AUTH_UNKNOWN;
03152       bDeleteCC = true;
03153     }
03154 
03155     if (bDeleteCC)
03156     {
03157       //delete costconfirmation to avoid trying to settle an unusable CC again and again
03158       if(dbInterface->deleteCC(pCC->getAccountNumber(), ms_pInstance->m_currentCascade) == E_SUCCESS)
03159       {
03160         CAMsg::printMsg(LOG_ERR, "Settlement transaction: unusable cost confirmation was deleted\n");
03161       }
03162       else
03163       {
03164         CAMsg::printMsg(LOG_ERR, "Settlement transaction: cost confirmation is unusable, but could not delete it from database\n");
03165       }
03166     }
03167   }
03168   else //settling was OK, so mark account as settled
03169   {
03170     authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03171     authFlags |= AUTH_SETTLED_ONCE;
03172     if (dbInterface->markAsSettled(pCC->getAccountNumber(),
03173                 ms_pInstance->m_currentCascade,
03174                 pCC->getTransferredBytes()) != E_SUCCESS)
03175      {
03176       CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark CC as settled. Maybe a new CC has been added meanwhile?\n");
03177      }
03178 #ifdef DEBUG
03179     CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: CC OK for account %llu with %llu transferred bytes!\n", 
03180       a_iCurrentSettleTransactionNr, pCC->getAccountNumber(), pCC->getTransferredBytes());
03181 #endif
03182   }
03183 
03184   if (authFlags || authRemoveFlags)
03185   {
03186     entry = new SettleEntry;
03187     entry->accountNumber = pCC->getAccountNumber();
03188     entry->authFlags = authFlags;
03189     entry->authRemoveFlags = authRemoveFlags;
03190     entry->confirmedBytes = confirmedBytes;
03191     entry->diffBytes = diffBytes;
03192     entry->storedStatus = storedStatus;
03193   }
03194   return entry;
03195 }
03196 
03198 void CAAccountingInstance::__commitSettlementToDatabase(SettleEntry *entryList, CAAccountingDBInterface *dbInterface)
03199 {
03200   SettleEntry *entry = entryList, *nextEntry = NULL;
03201   while (entry != NULL && dbInterface != NULL)
03202   {
03203     if (entry->authFlags & (AUTH_INVALID_ACCOUNT | AUTH_UNKNOWN))
03204     {
03205       dbInterface->storePrepaidAmount(
03206           entry->accountNumber, 0, ms_pInstance->m_currentCascade);
03207     }
03208     else if (entry->diffBytes)
03209     {
03210       // user is currently not logged in; set correct prepaid bytes in DB
03211       SINT32 prepaidBytes =
03212         dbInterface->getPrepaidAmount(entry->accountNumber,
03213             ms_pInstance->m_currentCascade, true);
03214       if (prepaidBytes > 0)
03215       {
03216         if (entry->diffBytes < 0 || entry->diffBytes >= (UINT64)prepaidBytes)
03217         {
03218           prepaidBytes = 0;
03219         }
03220         else
03221         {
03222           prepaidBytes -= entry->diffBytes;
03223         }
03224         dbInterface->storePrepaidAmount(
03225           entry->accountNumber, prepaidBytes, ms_pInstance->m_currentCascade);
03226       }
03227     }
03228 
03229     if( !(entry->authFlags & (AUTH_ACCOUNT_EMPTY | AUTH_BLOCKED | AUTH_INVALID_ACCOUNT)) &&
03230       entry->storedStatus != 0)
03231     {
03232       dbInterface->clearAccountStatus(entry->accountNumber);
03233       switch (entry->storedStatus)
03234       {
03235         case CAXMLErrorMessage::ERR_ACCOUNT_EMPTY:
03236         {
03237           CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account empty status for %llu\n",
03238               entry->accountNumber);
03239           entry->authRemoveFlags |= AUTH_ACCOUNT_EMPTY;
03240           break;
03241         }
03242         case CAXMLErrorMessage::ERR_BLOCKED:
03243         {
03244           CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account blocked status for %llu\n",
03245               entry->accountNumber);
03246           entry->authRemoveFlags |= AUTH_BLOCKED;
03247           break;
03248         }
03249         case CAXMLErrorMessage::ERR_KEY_NOT_FOUND:
03250         {
03251           CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account invalid status for %llu\n",
03252               entry->accountNumber);
03253           entry->authRemoveFlags |= AUTH_INVALID_ACCOUNT;
03254           break;
03255         }
03256       }
03257     }
03258     nextEntry = entry->nextEntry;
03259     entry = nextEntry;
03260   }
03261 }
03262 
03264 void CAAccountingInstance::__commitSettlementToLoginTable(SettleEntry *entryList)
03265 {
03266   SettleEntry *entry = entryList, *nextEntry = NULL;
03267   while (entry != NULL)
03268   {
03269     AccountLoginHashEntry* loginEntry =
03270             (AccountLoginHashEntry*) (ms_pInstance->m_currentAccountsHashtable->getValue(&(entry->accountNumber)));
03271     if (loginEntry)
03272     {
03273       // the user is currently logged in
03274       loginEntry->authFlags |= entry->authFlags;
03275       loginEntry->authRemoveFlags |= entry->authRemoveFlags;
03276       if (entry->confirmedBytes > 0 &&
03277         loginEntry->confirmedBytes < entry->confirmedBytes)
03278       {
03279         loginEntry->confirmedBytes = entry->confirmedBytes;
03280       }
03281     }
03282     nextEntry = entry->nextEntry;
03283     entry = nextEntry;
03284   }
03285 }
03286 
03287 /* Settlement transaction procedure as it is called by the SettleThread
03288  * NEVER INVOKE THIS METHOD IF YOU'RE HOLDING A LOCK ON m_currentAccountsHashtable !!
03289  * */
03290 SINT32 CAAccountingInstance::settlementTransaction()
03291 {
03292   INIT_STACK;
03293   BEGIN_STACK("CAAccountingInstance::settlementTransaction");
03294 
03295   SINT32 ret = 0;
03296   CAXMLErrorMessage * pErrMsg = NULL;
03297   CAXMLCostConfirmation * pCC = NULL;
03298   //CAQueue q;
03299   CAXMLCostConfirmation **allUnsettledCCs = NULL;
03300   UINT32 /*size, qSize, */ nrOfCCs, i;
03301   SettleEntry *entry = NULL, *nextEntry = NULL;
03302 
03303   CAAccountingDBInterface *dbInterface = NULL;
03304 
03305   /* This should never happen */
03306   if(ms_pInstance == NULL)
03307   {
03308     FINISH_STACK("CAAccountingInstance::settlementTransaction");
03309     return E_UNKNOWN;
03310   }
03311   /* This should never happen */
03312   if(ms_pInstance->m_pSettlementMutex == NULL)
03313   {
03314     FINISH_STACK("CAAccountingInstance::settlementTransaction");
03315     return E_UNKNOWN;
03316   }
03317   //sleep(5);
03318   dbInterface = CAAccountingDBInterface::getConnection();
03319   if(dbInterface == NULL)
03320   {
03321     CAMsg::printMsg(LOG_ERR, "Settlement transaction: could not connect to Database. Retry later...\n");
03322     //MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionFailure);
03323     FINISH_STACK("CAAccountingInstance::settlementTransaction");
03324     return E_NOT_CONNECTED;
03325   }
03326   //MONITORING_FIRE_PAY_EVENT(ev_pay_dbConnectionSuccess);
03327   ms_pInstance->m_pSettlementMutex->lock();
03328   /* First part get unsettled CCs from the AI database */
03329   #ifdef DEBUG
03330   CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: DB connections established!\n");
03331   #endif
03332 
03333   dbInterface->getUnsettledCostConfirmations(&allUnsettledCCs, ms_pInstance->m_currentCascade, &nrOfCCs, MAX_SETTLED_CCS);
03334   if (nrOfCCs <= 0)
03335   {
03336     CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: finished gettings CCs, found no CCs to settle\n");
03337     if(dbInterface != NULL)
03338     {
03339       CAAccountingDBInterface::releaseConnection(dbInterface);
03340       dbInterface = NULL;
03341     }
03342     ms_pInstance->m_pSettlementMutex->unlock();
03343     FINISH_STACK("CAAccountingInstance::settlementTransaction");
03344     return E_SUCCESS;
03345   }
03346   //qSize = q.getSize();
03347   //nrOfCCs = qSize / sizeof(pCC);
03348   CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: finished gettings CCs, found %u cost confirmations to settle\n",nrOfCCs);
03349 
03350   SAVE_STACK("CAAccountingInstance::settlementTransaction", "After getting unsettled CCs");
03351   /* Second part: We found unsettled CCs. Now contact the Payment Instance to settle them */
03352 
03353   //while(!q.isEmpty())
03354   for(i = 0; i < nrOfCCs; i++)
03355   {
03356     // get the next CC from the queue
03357     /*size = sizeof(pCC);
03358     ret = q.get((UINT8*)(&pCC), &size);
03359     if(ret != E_SUCCESS)
03360     {
03361       CAMsg::printMsg(LOG_ERR, "Settlement transaction: could not get next item from queue\n");
03362       q.clean();
03363       if(dbInterface != NULL)
03364       {
03365         CAAccountingDBInterface::releaseConnection(dbInterface);
03366         dbInterface = NULL;
03367       }
03368       ms_pInstance->m_pSettlementMutex->unlock();
03369       FINISH_STACK("CAAccountingInstance::settlementTransaction");
03370       return ret;
03371       //break;
03372     }*/
03373     pCC = allUnsettledCCs[i];
03374     entry = NULL;
03375     nextEntry = NULL;
03376     if (!pCC)
03377     {
03378       CAMsg::printMsg(LOG_CRIT, "Settlement transaction: Cost confirmation is NULL!\n");
03379       continue;
03380     }
03381 
03382 #ifdef DEBUG
03383     CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: Connecting to payment instance...\n");
03384 #endif
03385     ret = ms_pInstance->m_pPiInterface->initBIConnection();
03386     if(ret != E_SUCCESS)
03387     {
03388       ms_pInstance->m_seqBIConnErrors++;
03389       if(ms_pInstance->m_seqBIConnErrors >= CRITICAL_SUBSEQUENT_BI_CONN_ERRORS)
03390       {
03391         //transition to critical BI conn payment state
03392         MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionCriticalSubseqFailures);
03393       }
03394       else
03395       {
03396         MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionFailure);
03397       }
03398       CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: could not connect to BI. Try later...\n");
03399       //q.clean();
03400       pErrMsg = NULL; // continue in order to tell AUTH_WAITING_FOR_FIRST_SETTLED_CC for all accounts
03401       ms_pInstance->m_pPiInterface->terminateBIConnection(); // make sure the socket is closed
03402     }
03403     else
03404     {
03405       MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionSuccess);
03406 #ifdef DEBUG
03407       CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: successfully connected to payment instance");
03408 #endif
03409       ms_pInstance->m_seqBIConnErrors = 0;
03410       pErrMsg = ms_pInstance->m_pPiInterface->settle( *pCC );
03411       ms_pInstance->m_pPiInterface->terminateBIConnection();
03412       CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: settle done!\n");
03413     }
03414 
03415     bool bDeleteCC = false;
03416     UINT32 authFlags = 0;
03417     UINT32 authRemoveFlags = 0;
03418     UINT64 confirmedBytes = 0;
03419     UINT64 diffBytes = 0;
03420     UINT32 storedStatus = 0;
03421 
03422     dbInterface->getAccountStatus(pCC->getAccountNumber(), storedStatus);
03423 
03424     // check returncode
03425     if(pErrMsg == NULL)  //no returncode -> connection error
03426     {
03427       authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // no fault of the client
03428       CAMsg::printMsg(LOG_ERR, "Settlement transaction: Communication with BI failed!\n");
03429     }
03430     else if(pErrMsg->getErrorCode() != pErrMsg->ERR_OK)  //BI reported error
03431     {
03432       CAMsg::printMsg(LOG_WARNING, "Settlement transaction: BI reported error no. %d (%s)\n",
03433         pErrMsg->getErrorCode(), pErrMsg->getDescription() );
03434       if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_KEY_NOT_FOUND)
03435       {
03436         authFlags |= AUTH_INVALID_ACCOUNT;
03437         //dbConn.storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_KEY_NOT_FOUND);
03438         bDeleteCC = true;
03439       }
03440       else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_ACCOUNT_EMPTY)
03441       {
03442         authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03443         authFlags |= AUTH_ACCOUNT_EMPTY;
03444         UINT64* msgConfirmedBytes = (UINT64*)pErrMsg->getMessageObject();
03445         if (msgConfirmedBytes)
03446         {
03447           confirmedBytes = *msgConfirmedBytes;
03448           if (confirmedBytes < pCC->getTransferredBytes())
03449           {
03450             diffBytes = pCC->getTransferredBytes() - confirmedBytes;
03451           }
03452           UINT8 tmp[32];
03453           print64(tmp, confirmedBytes);
03454           UINT8 tmp2[32];
03455           print64(tmp2, diffBytes);
03456           UINT8 tmp3[32];
03457           print64(tmp3, pCC->getTransferredBytes());
03458           CAMsg::printMsg(LOG_INFO, "Settlement transaction: Received %s confirmed bytes and %s diff bytes while having %s transferred bytes!\n", tmp, tmp2, tmp3);
03459         }
03460         else
03461         {
03462           CAMsg::printMsg(LOG_ERR, "Settlement transaction: Account empty, but no message object received! "
03463               "This may lead to too much prepaid bytes!\n");
03464         }
03465 
03466         dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_ACCOUNT_EMPTY);
03467         authFlags |= AUTH_SETTLED_ONCE;
03468         dbInterface->markAsSettled(pCC->getAccountNumber(), ms_pInstance->m_currentCascade,
03469                       pCC->getTransferredBytes());
03470 //#ifdef DEBUG
03471         CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: settling %llu bytes for account %llu\n",
03472                       pCC->getTransferredBytes(), pCC->getAccountNumber());
03473 //#endif
03474       }
03475       /*
03476       else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INVALID_PRICE_CERT)
03477       {
03478         // this should never happen; the price certs in this CC do not fit to the ones of the cascade
03479         // bDeleteCC = true;
03480       }*/
03481       else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_OUTDATED_CC)
03482       {
03483         authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC; // this is a Mix not a client error
03484 
03485         //get attached CC from error message
03486         CAXMLCostConfirmation* attachedCC = (CAXMLCostConfirmation*) pErrMsg->getMessageObject();
03487         if (attachedCC)
03488         {
03489           authFlags |= AUTH_OUTDATED_CC;
03490           CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: tried outdated CC, received last valid CC back\n");
03491           //store it in DB
03492           if (dbInterface->storeCostConfirmation(*attachedCC,
03493               ms_pInstance->m_currentCascade) == E_SUCCESS)
03494           {
03495             authFlags |= AUTH_SETTLED_ONCE;
03496             if (dbInterface->markAsSettled(attachedCC->getAccountNumber(), ms_pInstance->m_currentCascade,
03497                         attachedCC->getTransferredBytes()) != E_SUCCESS)
03498             {
03499               CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark last valid CC as settled."
03500                 "Maybe a new CC has been added meanwhile?\n");
03501             }
03502           }
03503           else
03504           {
03505             CAMsg::printMsg(LOG_ERR, "Settlement transaction: storing last valid CC in db failed!\n");
03506           }
03507           // set the confirmed bytes to the value of the CC got from the PI
03508           confirmedBytes = attachedCC->getTransferredBytes();
03509         }
03510         else
03511         {
03512           CAMsg::printMsg(LOG_INFO, "Settlement transaction: Did not receive last valid CC - maybe old Payment instance?\n");
03513         }
03514       }
03515       else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_BLOCKED)
03516       {
03517         authFlags |= AUTH_BLOCKED;
03518         bDeleteCC = true;
03519 
03520         dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_BLOCKED);
03521       }
03522 
03523       else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_DATABASE_ERROR)
03524       {
03525         //authFlags |= AUTH_DATABASE;
03526         // the user is not responsible for this!
03527         authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03528       }
03529       else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR ||
03530              pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_SUCCESS_BUT_WITH_ERRORS)
03531       {
03532         // kick out the user and store the CC
03533         authFlags |= AUTH_UNKNOWN;
03534       }
03535       else
03536       {
03537         // an unknown error leads to user kickout
03538         CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: Setting unknown kickout error no. %d.\n", pErrMsg->getErrorCode());
03539         authFlags |= AUTH_UNKNOWN;
03540         bDeleteCC = true;
03541       }
03542 
03543       if (bDeleteCC)
03544       {
03545         //delete costconfirmation to avoid trying to settle an unusable CC again and again
03546         if(dbInterface->deleteCC(pCC->getAccountNumber(), ms_pInstance->m_currentCascade) == E_SUCCESS)
03547         {
03548           CAMsg::printMsg(LOG_ERR, "Settlement transaction: unusable cost confirmation was deleted\n");
03549         }
03550         else
03551         {
03552           CAMsg::printMsg(LOG_ERR, "Settlement transaction: cost confirmation is unusable, but could not delete it from database\n");
03553         }
03554       }
03555     }
03556     else //settling was OK, so mark account as settled
03557     {
03558       authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03559       authFlags |= AUTH_SETTLED_ONCE;
03560       if (dbInterface->markAsSettled(pCC->getAccountNumber(),
03561                   ms_pInstance->m_currentCascade,
03562                   pCC->getTransferredBytes()) != E_SUCCESS)
03563        {
03564         CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark CC as settled. Maybe a new CC has been added meanwhile?\n");
03565        }
03566       CAMsg::printMsg(LOG_INFO, "Settlement transaction: CC OK!\n");
03567     }
03568 
03569 
03570     if (authFlags || authRemoveFlags)
03571     {
03572       nextEntry = new SettleEntry;
03573       nextEntry->accountNumber = pCC->getAccountNumber();
03574       nextEntry->authFlags = authFlags;
03575       nextEntry->authRemoveFlags = authRemoveFlags;
03576       nextEntry->confirmedBytes = confirmedBytes;
03577       nextEntry->diffBytes = diffBytes;
03578       nextEntry->nextEntry = entry;
03579       nextEntry->storedStatus = storedStatus;
03580       entry = nextEntry;
03581     }
03582 
03583     /*if (pCC != NULL)
03584     {
03585       delete pCC;
03586       pCC = NULL;
03587     }*/
03588     if (pErrMsg != NULL)
03589     {
03590       delete pErrMsg;
03591       pErrMsg = NULL;
03592     }
03593   }
03594 
03595   if(allUnsettledCCs != NULL)
03596   {
03597     for(i = 0; i < nrOfCCs; i++)
03598     {
03599       delete allUnsettledCCs[i];
03600       allUnsettledCCs[i] = NULL;
03601     }
03602     delete [] allUnsettledCCs;
03603     allUnsettledCCs = NULL;
03604   }
03605 
03606   SAVE_STACK("CAAccountingInstance::settlementTransaction", "After settling unsettled CCs with BI");
03607 
03608   SettleEntry *first = entry;
03609   UINT64 myWaitNr = 0;
03610   if (entry)
03611   {
03612     //wait numbers are used to obtain a synchronisation with FCFS assertion.
03613     //This additional synchronisation is necessary because before acquiring the login hashtable
03614     //locks the settlementMutex should be released. (Nested locking should be avoided).
03615     if(ms_pInstance->m_nextSettleNr == ms_pInstance->m_settleWaitNr)
03616     {
03617       //CAMsg::printMsg(LOG_INFO, "Thread %x: resetting the wait numbers.\n", pthread_self() );
03618       //no one is waiting, we use this occasion to reset the wait numbers
03619       ms_pInstance->m_nextSettleNr = 0;
03620       ms_pInstance->m_settleWaitNr = 1;
03621     }
03622     else
03623     {
03624       SAVE_STACK("CAAccountingInstance::settlementTransaction", "wait for altering hashtable");
03625       //get global wait number and wait but release the DBConnection first.
03626       CAAccountingDBInterface::releaseConnection(dbInterface);
03627       dbInterface = NULL;
03628       myWaitNr = ms_pInstance->m_settleWaitNr;
03629       ms_pInstance->m_settleWaitNr++;
03630       while(myWaitNr != ms_pInstance->m_nextSettleNr)
03631       {
03632         CAMsg::printMsg(LOG_INFO, "Thread %x must wait to alter login table after settling (2): %llu before him in the queue\n", pthread_self(),
03633                     (myWaitNr - ms_pInstance->m_nextSettleNr));
03634         ms_pInstance->m_pSettlementMutex->wait();
03635       }
03636       CAMsg::printMsg(LOG_INFO, "Thread %x may continue (2).\n", pthread_self());
03637       dbInterface = CAAccountingDBInterface::getConnection();
03638     }
03639     SAVE_STACK("CAAccountingInstance::settlementTransaction", "altering DB entries");
03640     while (entry != NULL && dbInterface != NULL)
03641     {
03642       if (entry->authFlags & (AUTH_INVALID_ACCOUNT | AUTH_UNKNOWN))
03643       {
03644         dbInterface->storePrepaidAmount(
03645             entry->accountNumber, 0, ms_pInstance->m_currentCascade);
03646       }
03647       else if (entry->diffBytes)
03648       {
03649         // user is currently not logged in; set correct prepaid bytes in DB
03650         SINT32 prepaidBytes =
03651           dbInterface->getPrepaidAmount(entry->accountNumber,
03652               ms_pInstance->m_currentCascade, true);
03653         if (prepaidBytes > 0)
03654         {
03655           if (entry->diffBytes < 0 || entry->diffBytes >= (UINT64)prepaidBytes)
03656           {
03657             prepaidBytes = 0;
03658           }
03659           else
03660           {
03661             prepaidBytes -= entry->diffBytes;
03662           }
03663           dbInterface->storePrepaidAmount(
03664             entry->accountNumber, prepaidBytes, ms_pInstance->m_currentCascade);
03665         }
03666       }
03667 
03668       if( !(entry->authFlags & (AUTH_ACCOUNT_EMPTY | AUTH_BLOCKED | AUTH_INVALID_ACCOUNT)) &&
03669         entry->storedStatus != 0)
03670       {
03671         dbInterface->clearAccountStatus(entry->accountNumber);
03672         switch (entry->storedStatus)
03673         {
03674           case CAXMLErrorMessage::ERR_ACCOUNT_EMPTY:
03675           {
03676             CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account empty status for %llu\n",
03677                 entry->accountNumber);
03678             entry->authRemoveFlags |= AUTH_ACCOUNT_EMPTY;
03679             break;
03680           }
03681           case CAXMLErrorMessage::ERR_BLOCKED:
03682           {
03683             CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account blocked status for %llu\n",
03684                 entry->accountNumber);
03685             entry->authRemoveFlags |= AUTH_BLOCKED;
03686             break;
03687           }
03688           case CAXMLErrorMessage::ERR_KEY_NOT_FOUND:
03689           {
03690             CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account invalid status for %llu\n",
03691                 entry->accountNumber);
03692             entry->authRemoveFlags |= AUTH_INVALID_ACCOUNT;
03693             break;
03694           }
03695         }
03696       }
03697 
03698       nextEntry = entry->nextEntry;
03699       entry = nextEntry;
03700     }
03701   }
03702   CAAccountingDBInterface::releaseConnection(dbInterface);
03703   dbInterface = NULL;
03704   ms_pInstance->m_pSettlementMutex->unlock();
03705 
03706   if(first != NULL)
03707   {
03708     SAVE_STACK("CAAccountingInstance::settlementTransaction", "altering hashtable");
03709 #ifdef DEBUG
03710     CAMsg::printMsg(LOG_DEBUG, "Settlement thread with wait nr %llu alters hashtable.\n", myWaitNr);
03711 #endif
03712     entry = first;
03713     ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
03714     while (entry != NULL)
03715     {
03716       AccountLoginHashEntry* loginEntry =
03717               (AccountLoginHashEntry*) (ms_pInstance->m_currentAccountsHashtable->getValue(&(entry->accountNumber)));
03718       if (loginEntry)
03719       {
03720         // the user is currently logged in
03721         loginEntry->authFlags |= entry->authFlags;
03722         loginEntry->authRemoveFlags |= entry->authRemoveFlags;
03723         if (entry->confirmedBytes > 0 &&
03724           loginEntry->confirmedBytes < entry->confirmedBytes)
03725         {
03726           loginEntry->confirmedBytes = entry->confirmedBytes;
03727         }
03728       }
03729       nextEntry = entry->nextEntry;
03730       delete entry;
03731       entry = nextEntry;
03732     }
03733     ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
03734 
03735     ms_pInstance->m_pSettlementMutex->lock();
03736     ms_pInstance->m_nextSettleNr++;
03737 // TODO: seems to be a bug; if this "if" is set, some locks are never released
03738 //if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
03739     {
03740       SAVE_STACK("CAAccountingInstance::settlementTransaction", "waking up waiting threads for altering hashtable");
03741       //There are threads waiting for applying their settlement results.
03742       if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
03743       CAMsg::printMsg(LOG_INFO, "Thread %x Waking up next Thread %llu are waiting.\n", pthread_self(),
03744               (ms_pInstance->m_settleWaitNr - ms_pInstance->m_nextSettleNr));   
03745       ms_pInstance->m_pSettlementMutex->signal();
03746     }
03747     ms_pInstance->m_pSettlementMutex->unlock();
03748   }
03749 
03750   /*if(dbInterface != NULL)
03751   {
03752     CAAccountingDBInterface::releaseConnection(dbInterface);
03753     dbInterface = NULL;
03754   }*/
03755   FINISH_STACK("CAAccountingInstance::settlementTransaction");
03756   return E_SUCCESS;
03757 }
03758 
03763 bool testAndSetLoginOwner(struct AccountLoginHashEntry *loginEntry, fmHashTableEntry *ownerRef)
03764 {
03765   bool success = false;
03766   loginEntry->ownerLock->lock();
03767   success = !loginEntry->loginOngoing;
03768   if(success)
03769   {
03770     //CAMsg::printMsg(LOG_DEBUG,"login free, owner %x \n", loginEntry->ownerRef);
03771     loginEntry->ownerRef = ownerRef;
03772     loginEntry->loginOngoing = true;
03773   }
03774   /*else
03775   {
03776     CAMsg::printMsg(LOG_DEBUG,"login ongoing, owner %x \n", loginEntry->ownerRef);
03777   }*/
03778   loginEntry->ownerLock->unlock();
03779   return success;
03780 }
03781 
03786 UINT64 CAAccountingInstance::unlockLogin(fmHashTableEntry *ownerRef)
03787 {
03788   if(ownerRef == NULL || ownerRef->pAccountingInfo == NULL)
03789   {
03790     return 0;
03791   }
03792   UINT64 accountNumber = ownerRef->pAccountingInfo->accountNumber;
03793   ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
03794   AccountLoginHashEntry *loginEntry = (AccountLoginHashEntry*)ms_pInstance->m_currentAccountsHashtable->getValue(&accountNumber);
03795   if (loginEntry != NULL)
03796   {
03797     resetLoginOngoing(loginEntry, ownerRef);
03798   }
03799   ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
03800   return accountNumber;
03801 }
03802 
03806 bool resetLoginOngoing(struct AccountLoginHashEntry *loginEntry, fmHashTableEntry *ownerRef)
03807 {
03808   bool success = false;
03809   loginEntry->ownerLock->lock();
03810   success = testLoginEntryOwner_internal(loginEntry, ownerRef);
03811   if(success)
03812   {
03813     loginEntry->loginOngoing = false;
03814     //CAMsg::printMsg(LOG_DEBUG,"resetted for %x.\n", loginEntry->ownerRef);
03815   }
03816   /*else
03817   {
03818     CAMsg::printMsg(LOG_DEBUG,"not resetted for %x.\n", loginEntry->ownerRef);
03819   }*/
03820   loginEntry->ownerLock->unlock();
03821   return success;
03822 }
03823 
03827 bool testLoginEntryOwner(struct AccountLoginHashEntry *loginEntry, fmHashTableEntry *ownerRef)
03828 {
03829   bool ret;
03830   loginEntry->ownerLock->lock();
03831   ret = testLoginEntryOwner_internal(loginEntry, ownerRef);
03832   loginEntry->ownerLock->unlock();
03833   return ret;
03834 }
03835 
03839 bool isLoginOngoing(struct AccountLoginHashEntry *loginEntry, fmHashTableEntry *ownerRef)
03840 {
03841   bool ret;
03842   loginEntry->ownerLock->lock();
03843   ret = loginEntry->loginOngoing;
03844   loginEntry->ownerLock->unlock();
03845   return ret;
03846 }
03847 
03848 inline bool testLoginEntryOwner_internal(struct AccountLoginHashEntry *loginEntry, fmHashTableEntry *ownerRef)
03849 {
03850   return (loginEntry->ownerRef == ownerRef);
03851 }
03852 #endif /* ifdef PAYMENT */