00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
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
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
00083 m_pSettlementMutex = new CAConditionVariable();
00084
00085 m_nextSettleNr = 0;
00086 m_settleWaitNr = 0;
00087
00088
00089
00090 m_pPiInterface = new CAAccountingBIInterface();
00091 m_mix = callingMix;
00092
00093
00094
00095
00096
00097
00098
00099 m_AiName = new UINT8[256];
00100 CALibProxytest::getOptions()->getAiID(m_AiName, 256);
00101 if (CALibProxytest::getOptions()->getBI() != NULL)
00102 {
00103
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
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
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
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
00159
00160
00161
00162
00163
00164
00165
00166
00167 delete m_pPiInterface;
00168 m_pPiInterface = NULL;
00169
00170 delete m_pSettlementMutex;
00171 m_pSettlementMutex = NULL;
00172
00173
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
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
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
00285
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
00360
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
00369
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
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
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
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
00411 return returnKickout(pAccInfo);
00412 }
00413
00414 ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
00415
00416 loginEntry = (AccountLoginHashEntry*)ms_pInstance->m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
00417 if (loginEntry)
00418 {
00419 pAccInfo->authFlags &= ~loginEntry->authRemoveFlags;
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
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
00439 CAXMLCostConfirmation * pCC = NULL;
00440 bool bSettled;
00441
00442 dbInterface = CAAccountingDBInterface::getConnection();
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
00453
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
00483
00484 pAccInfo->authFlags |= AUTH_ACCOUNT_EMPTY;
00485
00486
00487
00488 pAccInfo->confirmedBytes = loginEntry->confirmedBytes;
00489 if (pAccInfo->confirmedBytes < pAccInfo->transferredBytes)
00490 {
00491
00492 pAccInfo->transferredBytes = pAccInfo->confirmedBytes;
00493 }
00494
00495
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
00541 pAccInfo->lastHardLimitSeconds = time(NULL);
00542
00543
00544
00545
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
00569
00570 SAVE_STACK("CAAccountingInstance::handleJapPacket", "before err");
00571
00572 if (err)
00573 {
00574 return returnPrepareKickout(pAccInfo, err);
00575 }
00576
00577
00578
00579
00580
00581
00582
00583
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
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
00619
00620
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
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 {
00646
00647 sendCCRequest(pAccInfo);
00648 }
00649 }
00650
00651
00652 pAccInfo->mutex->unlock();
00653 return HANDLE_PACKET_CONNECTION_OK;
00654 }
00655
00656
00657
00658
00659
00660
00661 SINT32 CAAccountingInstance::getPrepaidBytes(tAiAccountingInfo* pAccInfo)
00662 {
00663 if (pAccInfo == NULL)
00664 {
00665 return 0;
00666 }
00667
00668
00669
00670
00671 SINT64 prepaidBytes = pAccInfo->confirmedBytes - pAccInfo->transferredBytes;
00672
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
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
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
00732 inline void CAAccountingInstance::setPrepaidBytesToZero_internal(tAiAccountingInfo* pAccInfo)
00733 {
00734 pAccInfo->transferredBytes = pAccInfo->confirmedBytes;
00735 }
00736
00737
00738
00739
00740
00741
00742
00743
00744 SINT32 CAAccountingInstance::returnPrepareKickout(tAiAccountingInfo* pAccInfo, CAXMLErrorMessage* a_error)
00745 {
00746 pAccInfo->authFlags |= AUTH_FATAL_ERROR;
00747
00748 if (a_error)
00749 {
00750
00751 XERCES_CPP_NAMESPACE::DOMDocument* doc=NULL;
00752 a_error->toXmlDocument(doc);
00753 delete a_error;
00754 a_error = NULL;
00755
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
00812 return E_SUCCESS;
00813 }
00814
00815
00816
00817 pAccInfo->bytesToConfirm = (prepaidInterval) + pAccInfo->transferredBytes;
00818 makeCCRequest(pAccInfo->accountNumber, pAccInfo->bytesToConfirm, doc);
00819
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
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
00901
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];
00909
00910 DOMNode* curMixNode=NULL;
00911 for (UINT32 i = 0, j = 0, count = nrOfMixes; i < count; i++, j++){
00912
00913 curMixNode = allMixes->item(i);
00914 if (getDOMChildByName(curMixNode,"PriceCertificate",mixNodes[j],true) != E_SUCCESS)
00915 {
00916 j--;
00917 nrOfMixes--;
00918 }
00919 }
00920
00921
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
00946
00947
00948
00949 strtrim(tmpBuff);
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
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
00964 m_currentCascade = new UINT8[256];
00965 memset(m_currentCascade, 0, (sizeof(UINT8)*256 ));
00966 for (UINT32 j = 0; j < nrOfMixes; j++)
00967 {
00968
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
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
00991 setDOMElementValue(elemCert,m_allHashes[i]);
00992
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
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
01127 if ( strcmp( docElementName, "AccountCertificate" ) == 0 )
01128 {
01129 #ifdef DEBUG
01130 CAMsg::printMsg( LOG_DEBUG, "Received an AccountCertificate. Calling handleAccountCertificate()\n" );
01131 #endif
01132
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
01142 hf_ret = ms_pInstance->handleChallengeResponse( pHashEntry->pAccountingInfo, root );
01143 processJapMessageLoginHelper(pHashEntry, hf_ret, false);
01144
01145
01146
01147
01148
01149 if(hf_ret == (SINT32) CAXMLErrorMessage::ERR_OK)
01150 {
01151
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
01167 hf_ret = ms_pInstance->handleCostConfirmation( pHashEntry->pAccountingInfo, root );
01168 processJapMessageLoginHelper(pHashEntry, hf_ret, true);
01169
01170
01171
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
01212
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
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254 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
01285
01286
01287 }
01288 else if(lastLoginMessage)
01289 {
01290
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
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
01397
01398
01399
01400 CAXMLErrorMessage *err = NULL;
01401 XERCES_CPP_NAMESPACE::DOMDocument *errDoc = NULL;
01402
01403
01404
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
01422 pAccInfo->transferredBytes = pAccInfo->confirmedBytes;
01423 }
01424 if (getPrepaidBytes(pAccInfo) > 0)
01425 {
01426
01427 delete err;
01428 err = NULL;
01429 }
01430 }
01431 else
01432 {
01433
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
01469
01470
01471
01472
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
01483
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
01512
01513
01514 DOMElement* elGeneral=NULL;
01515 timespec now;
01516 getcurrentTime(now);
01517
01518
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
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
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
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
01639
01640 if(CAMultiSignature::verifyXML(root, CALibProxytest::getOptions()->getBI()->getCertificate()))
01641 {
01642
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
01655
01656
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;
01663
01664
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;
01675
01676 CAAccountingDBInterface *dbInterface = CAAccountingDBInterface::getConnection();
01677
01678
01679
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;
01689 if (prepaidAmount < prepaidIvalLowerBound)
01690 {
01691 prepaidAmount = prepaidIvalLowerBound;
01692 }
01693
01694 setDOMElementValue( elemPrepaid, prepaidAmount);
01695
01696
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
01706
01707
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
01736
01737
01738 UINT8 decodeBuffer[ 512 ];
01739 UINT32 decodeBufferLen = 512;
01740 UINT32 usedLen;
01741
01742
01743 SINT32 prepaidAmount = 0;
01744 AccountLoginHashEntry* loginEntry;
01745 CAXMLCostConfirmation* pCC = NULL;
01746 bool bSendCCRequest = true;
01747 UINT32 status;
01748
01749
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
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
01811
01812
01813
01814
01815
01816
01817
01818 CASignature * sigTester = pAccInfo->pPublicKey;
01819
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;
01833
01834
01835 m_currentAccountsHashtable->getMutex()->lock();
01836 loginEntry = (AccountLoginHashEntry*)m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
01837 struct t_fmhashtableentry *ownerRef = NULL;
01838 if(loginEntry != NULL)
01839 {
01840 ownerRef = loginEntry->ownerRef;
01841 if(ownerRef != NULL)
01842 {
01843 bool isLoginFree = testAndSetLoginOwner(loginEntry, ownerRef);
01844
01845
01846
01847 m_currentAccountsHashtable->getMutex()->unlock();
01848
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
01857 m_mix->getLoginMutex()->lock();
01858 CAXMLErrorMessage kickoutMsg(CAXMLErrorMessage::ERR_MULTIPLE_LOGIN);
01859 XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
01860 kickoutMsg.toXmlDocument(errDoc);
01861
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
01867
01868
01869
01870
01871
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
01881
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
01887 m_currentAccountsHashtable->getMutex()->lock();
01888 if(loginEntry != NULL)
01889 {
01890
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
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
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
01922
01923
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
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
01980
01981
01982
01983
01984
01985
01986
01987
01988
01989
01990
01991
01992
01993
01994
01995
01996
01997
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035
02036
02037
02038
02039
02040
02041
02042
02043
02044
02045 UINT8 tmp[32];
02046 print64(tmp,pAccInfo->accountNumber);
02047 if (prepaidAmount > 0)
02048 {
02049 CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Got %d prepaid bytes for account nr. %s.\n",prepaidAmount, tmp);
02050
02051
02052
02053 if (pAccInfo->transferredBytes >= (UINT32)prepaidAmount)
02054 {
02055 pAccInfo->transferredBytes -= prepaidAmount;
02056 }
02057 else
02058 {
02059 UINT8 tmp2[32];
02060 print64(tmp2, pAccInfo->transferredBytes);
02061 CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Transferred bytes of %s for account %s are lower than prepaid amount! "
02062 "Maybe we lost a CC?\n",tmp2, tmp);
02063 prepaidAmount = 0;
02064 }
02065 }
02066 else
02067 {
02068 prepaidAmount = 0;
02069 CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: No database record for prepaid bytes found for account nr. %s.\n", tmp);
02070 }
02071
02072
02078 SINT32 dbRet;
02079 if(dbInterface != NULL);
02080 {
02081 dbRet = dbInterface->getAccountStatus(pAccInfo->accountNumber, status);
02082 CAAccountingDBInterface::releaseConnection(dbInterface);
02083 dbInterface = NULL;
02084 }
02085
02086 if (dbRet != E_SUCCESS)
02087 {
02088 UINT8 tmp[32];
02089 print64(tmp,pAccInfo->accountNumber);
02090 CAMsg::printMsg(LOG_ERR, "CAAccountingInstance: Could not check status for account %s!\n", tmp);
02091 }
02092 else if (status > CAXMLErrorMessage::ERR_OK)
02093 {
02094
02095
02096
02097 CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Illegal status %u for account %llu found.\n",
02098 status, pAccInfo->accountNumber);
02099 if (status == CAXMLErrorMessage::ERR_BLOCKED)
02100 {
02101 pAccInfo->authFlags |= AUTH_BLOCKED;
02102 }
02103 else if (status == CAXMLErrorMessage::ERR_KEY_NOT_FOUND)
02104 {
02105 pAccInfo->authFlags |= AUTH_INVALID_ACCOUNT;
02106 }
02107 else if (status == CAXMLErrorMessage::ERR_ACCOUNT_EMPTY)
02108 {
02109 pAccInfo->authFlags |= AUTH_ACCOUNT_EMPTY;
02110 }
02111
02112
02113
02114
02115
02116
02117
02118
02119
02120 }
02121 m_currentAccountsHashtable->getMutex()->unlock();
02122
02124
02125 SINT32 sendStatus = E_SUCCESS;
02126 if (bSendCCRequest)
02127 {
02128
02129
02130
02131 if(pCC != NULL)
02132 {
02133 #ifdef DEBUG
02134 CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Sending pcc to sign with %llu transferred bytes\n", pCC->getTransferredBytes());
02135 #endif
02136
02137
02138
02139
02140
02141 UINT32 prepaidIval = CALibProxytest::getOptions()->getPrepaidInterval();
02142 pAccInfo->bytesToConfirm = (prepaidIval - prepaidAmount) + pCC->getTransferredBytes();
02143 #ifdef DEBUG
02144 CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: before CC request, bytesToConfirm: %llu, prepaidIval: %u, "
02145 "prepaidAmount: %d, transferred bytes: %llu\n",
02146 pAccInfo->bytesToConfirm, prepaidIval, prepaidAmount, pAccInfo->transferredBytes);
02147
02148 #endif
02149 if( (pAccInfo->clientVersion == NULL) ||
02150 (strncmp((char*)pAccInfo->clientVersion, PREPAID_PROTO_CLIENT_VERSION, CLIENT_VERSION_STR_LEN) < 0) )
02151 {
02152
02153
02154 sendStatus = pAccInfo->pControlChannel->sendXMLMessage(pCC->getXMLDocument());
02155
02156 }
02157 else
02158 {
02159
02160
02161 sendStatus = sendInitialCCRequest(pAccInfo, pCC, prepaidAmount);
02162 }
02163 }
02164 else
02165 {
02166
02167 if (prepaidAmount > 0)
02168 {
02169
02170 pAccInfo->transferredBytes += prepaidAmount;
02171 }
02172 sendStatus = sendCCRequest(pAccInfo);
02173 }
02174 }
02175
02176
02177 delete pCC;
02178 pCC = NULL;
02179
02180
02181 if ( pAccInfo->pChallenge != NULL )
02182 {
02183 delete[] pAccInfo->pChallenge;
02184 pAccInfo->pChallenge = NULL;
02185 }
02186
02187
02188 pAccInfo->mutex->unlock();
02189 if(sendStatus == E_SUCCESS)
02190 {
02191 return CAXMLErrorMessage::ERR_OK;
02192 }
02193 else
02194 {
02195 return CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR;
02196 }
02197 }
02198
02199 UINT32 CAAccountingInstance::handleCostConfirmation(tAiAccountingInfo* pAccInfo, DOMElement* root)
02200 {
02201 return handleCostConfirmation_internal(pAccInfo, root);
02202 INIT_STACK;
02203 FINISH_STACK("CAAccountingInstance::handleCostConfirmation");
02204 }
02205
02209 UINT32 CAAccountingInstance::handleCostConfirmation_internal(tAiAccountingInfo* pAccInfo, DOMElement* root)
02210 {
02211 INIT_STACK;
02212 BEGIN_STACK("CAAccountingInstance::handleCostConfirmation");
02213
02214 if (pAccInfo == NULL)
02215 {
02216 return CAXMLErrorMessage::ERR_NO_RECORD_FOUND;
02217 }
02218
02219 pAccInfo->mutex->lock();
02220
02221 if ( (pAccInfo->authFlags & AUTH_DELETE_ENTRY) ||
02222 (!(pAccInfo->authFlags & AUTH_LOGIN_NOT_FINISHED ) && (pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY )) )
02223 {
02224 CAMsg::printMsg(LOG_ERR,
02225 "CAAccountingInstance::handleCostConfirmation Ignoring CC, restricted flags set: %s %s\n",
02226 ((pAccInfo->authFlags & AUTH_DELETE_ENTRY) ? "AUTH_DELETE_ENTRY" : "") ,
02227 ((pAccInfo->authFlags & AUTH_ACCOUNT_EMPTY) ? "AUTH_ACCOUNT_EMPTY" : ""));
02228
02229 pAccInfo->mutex->unlock();
02230 return CAXMLErrorMessage::ERR_NO_ERROR_GIVEN;
02231 }
02232
02233
02234 if (!(pAccInfo->authFlags & AUTH_GOT_ACCOUNTCERT) ||
02235 !(pAccInfo->authFlags & AUTH_ACCOUNT_OK) ||
02236 !(pAccInfo->authFlags & AUTH_SENT_CC_REQUEST))
02237 {
02238 CAMsg::printMsg(LOG_ERR,
02239 "CAAccountingInstance::handleCostConfirmation CC was received but has not been requested! Ignoring...\n");
02240
02241 pAccInfo->mutex->unlock();
02242 return CAXMLErrorMessage::ERR_NO_ERROR_GIVEN;
02243 }
02244
02245 CAXMLCostConfirmation* pCC = CAXMLCostConfirmation::getInstance(root);
02246 if(pCC==NULL)
02247 {
02248 pAccInfo->mutex->unlock();
02249 return CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR;
02250 }
02251
02252
02253
02254 if (pAccInfo->pPublicKey==NULL||
02255 pAccInfo->pPublicKey->verifyXML( root ) != E_SUCCESS)
02256 {
02257
02258 CAMsg::printMsg( LOG_INFO, "CostConfirmation has INVALID SIGNATURE!\n" );
02259 CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_SIGNATURE, (UINT8*)"CostConfirmation has bad signature");
02260 XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
02261 err.toXmlDocument(errDoc);
02262 pAccInfo->pControlChannel->sendXMLMessage(errDoc);
02263 if (errDoc != NULL)
02264 {
02265 errDoc->release();
02266 errDoc = NULL;
02267 }
02268 delete pCC;
02269 pCC = NULL;
02270 pAccInfo->mutex->unlock();
02271 return CAXMLErrorMessage::ERR_BAD_SIGNATURE;
02272 }
02273 #ifdef DEBUG
02274 else
02275 {
02276 CAMsg::printMsg( LOG_DEBUG, "CostConfirmation Signature is OK.\n");
02277 }
02278 #endif
02279
02280
02281 if (pCC->getNumberOfHashes() != m_allHashesLen)
02282 {
02283 CAMsg::printMsg( LOG_INFO, "CostConfirmation has illegal number of price cert hashes!\n" );
02284 CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_REQUEST,
02285 (UINT8*)"CostConfirmation has illegal number of price cert hashes");
02286 XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
02287 err.toXmlDocument(errDoc);
02288 pAccInfo->pControlChannel->sendXMLMessage(errDoc);
02289 if (errDoc != NULL)
02290 {
02291 errDoc->release();
02292 errDoc = NULL;
02293 }
02294 delete pCC;
02295 pCC = NULL;
02296 pAccInfo->mutex->unlock();
02297 return CAXMLErrorMessage::ERR_WRONG_FORMAT;
02298 }
02299
02300
02301
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324
02325
02326
02327
02328
02329
02330
02331 if (!cascadeMatchesCC(pCC))
02332 {
02333 CAMsg::printMsg( LOG_INFO, "CostConfirmation has invalid price cert hashes!\n" );
02334 CAXMLErrorMessage err(CAXMLErrorMessage::ERR_BAD_REQUEST,
02335 (UINT8*)"CostConfirmation has invalid price cert hashes");
02336 XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
02337 err.toXmlDocument(errDoc);
02338 pAccInfo->pControlChannel->sendXMLMessage(errDoc);
02339 if (errDoc != NULL)
02340 {
02341 errDoc->release();
02342 errDoc = NULL;
02343 }
02344 delete pCC;
02345 pCC = NULL;
02346 pAccInfo->mutex->unlock();
02347 return CAXMLErrorMessage::ERR_WRONG_DATA;
02348 }
02349
02350
02351
02352
02353
02354
02355
02356
02357 #ifdef DEBUG
02358 CAMsg::printMsg( LOG_DEBUG, "received cost confirmation for %llu transferred bytes where confirmed bytes are %llu, we need %llu bytes to confirm"
02359 ", mix already counted %llu transferred bytes\n",
02360 pCC->getTransferredBytes(), pAccInfo->confirmedBytes, pAccInfo->bytesToConfirm,
02361 pAccInfo->transferredBytes);
02362 #endif
02363
02364 if(pCC->getTransferredBytes() > (pAccInfo->transferredBytes+CALibProxytest::getOptions()->getPrepaidInterval()) )
02365 {
02366 CAMsg::printMsg( LOG_ERR, "Warning: ignoring this CC for account %llu "
02367 "because it tries to confirm %lld prepaid bytes where only %u prepaid bytes are allowed (cc->tranferredbytes: %llu, accInfo->tranferredBytes: %llu)\n",
02368 pAccInfo->accountNumber, (pCC->getTransferredBytes() - pAccInfo->transferredBytes),
02369 CALibProxytest::getOptions()->getPrepaidInterval(),
02370 pCC->getTransferredBytes(), pAccInfo->transferredBytes);
02371
02372 CAXMLErrorMessage err(CAXMLErrorMessage::ERR_WRONG_DATA,
02373 (UINT8*)"More bytes confirmed than allowed.");
02374 XERCES_CPP_NAMESPACE::DOMDocument* errDoc=NULL;
02375 err.toXmlDocument(errDoc);
02376 pAccInfo->pControlChannel->sendXMLMessage(errDoc);
02377 if (errDoc != NULL)
02378 {
02379 errDoc->release();
02380 errDoc = NULL;
02381 }
02382
02383 pAccInfo->authFlags |= AUTH_FAKE;
02384 delete pCC;
02385 pCC = NULL;
02386 pAccInfo->mutex->unlock();
02387 return CAXMLErrorMessage::ERR_WRONG_DATA;
02388 }
02389
02390 if (pCC->getTransferredBytes() < pAccInfo->confirmedBytes)
02391 {
02392
02393 CAMsg::printMsg( LOG_ERR, "CostConfirmation has insufficient number of bytes:\n");
02394 CAMsg::printMsg( LOG_ERR, "CC->transferredBytes: %llu < confirmedBytesBytes: %llu\n", pCC->getTransferredBytes(), pAccInfo->confirmedBytes);
02395
02396 if(pAccInfo->authFlags & AUTH_LOGIN_NOT_FINISHED)
02397 {
02398
02399 pAccInfo->authFlags |= AUTH_FAKE;
02400 delete pCC;
02401 pCC = NULL;
02402 pAccInfo->mutex->unlock();
02403 return CAXMLErrorMessage::ERR_WRONG_DATA;
02404 }
02405
02406
02407
02408
02409
02410
02411
02412 }
02413 else if (pCC->getTransferredBytes() == pAccInfo->confirmedBytes && getPrepaidBytes(pAccInfo) != CALibProxytest::getOptions()->getPrepaidInterval())
02414 {
02415 CAMsg::printMsg(LOG_WARNING, "Received CostConfirmation for account %llu has no difference in bytes to current CC (%llu bytes).\n",
02416 pAccInfo->accountNumber, pCC->getTransferredBytes());
02417 }
02418 else
02419 {
02420
02421
02422
02423
02424
02425 SINT32 dbRet = E_UNKNOWN;
02426 CAAccountingDBInterface *dbInterface = CAAccountingDBInterface::getConnection();
02427 if(dbInterface != NULL)
02428 {
02429 dbRet = dbInterface->storeCostConfirmation(*pCC, m_currentCascade);
02430 CAAccountingDBInterface::releaseConnection(dbInterface);
02431 dbInterface = NULL;
02432 }
02433 if (dbRet != E_SUCCESS)
02434 {
02435 UINT8 tmp[32];
02436 print64(tmp,pCC->getAccountNumber());
02437 CAMsg::printMsg( LOG_INFO, "CostConfirmation for account %s could not be stored in database!\n", tmp );
02438 pAccInfo->authFlags |= AUTH_DATABASE;
02439 }
02440 else
02441 {
02442 #ifdef DEBUG
02443 CAMsg::printMsg( LOG_INFO, "Handle CC: pCC->transBytes: %llu\n", pCC->getTransferredBytes() );
02444 #endif
02445 pAccInfo->confirmedBytes = pCC->getTransferredBytes();
02446
02447 if (pAccInfo->authFlags & AUTH_WAITING_FOR_FIRST_SETTLED_CC)
02448 {
02449
02450 #ifdef DEBUG
02451 UINT64 currentMillis;
02452 UINT8 tmpStrCurrentMillis[50];
02453 getcurrentTimeMillis(currentMillis);
02454 print64(tmpStrCurrentMillis,currentMillis);
02455 CAMsg::printMsg(LOG_DEBUG, "AccountingSettleThread: Settle ini: %s\n", tmpStrCurrentMillis);
02456 #endif
02457 m_pSettleThread->settle();
02458
02459 }
02460 }
02461 }
02462 #ifdef DEBUG
02463 CAMsg::printMsg(LOG_ERR, "Handle CC request: pAccInfo->confirmedBytes: %llu, ppAccInfo->transferredBytes: %llu\n",
02464 pAccInfo->confirmedBytes, pAccInfo->transferredBytes);
02465 #endif
02466 if (pAccInfo->confirmedBytes >= pAccInfo->bytesToConfirm)
02467 {
02468
02469 pAccInfo->authFlags &= ~AUTH_HARD_LIMIT_REACHED;
02470 pAccInfo->lastHardLimitSeconds = time(NULL);
02471 }
02472 else
02473 {
02474
02475
02476
02477
02478 CAMsg::printMsg(LOG_ERR, "AccountingSettleThread: Requested CC value has NOT been confirmed by account nr %llu! "
02479 "Received Bytes: %llu/%llu "
02480 "Client should not be allowed to login.\n",
02481 pCC->getAccountNumber(),
02482 pCC->getTransferredBytes(),
02483 pAccInfo->bytesToConfirm);
02484
02485 if(pAccInfo->authFlags & AUTH_LOGIN_SKIP_SETTLEMENT)
02486 {
02487 CAMsg::printMsg( LOG_INFO, "Skip settlement revoked.\n");
02488 pAccInfo->authFlags &= ~AUTH_LOGIN_SKIP_SETTLEMENT;
02489 }
02490
02491
02492
02493
02494
02495
02496
02497 }
02498
02499 pAccInfo->bytesToConfirm = 0;
02500 pAccInfo->authFlags &= ~AUTH_SENT_CC_REQUEST;
02501
02502 delete pCC;
02503 pCC = NULL;
02504 pAccInfo->mutex->unlock();
02505
02506 return CAXMLErrorMessage::ERR_OK;
02507 }
02508
02513 SINT32 CAAccountingInstance::initTableEntry( fmHashTableEntry * pHashEntry )
02514 {
02515 INIT_STACK;
02516 BEGIN_STACK("CAAccountingInstance::initTableEntry");
02517
02518
02519
02520 if (pHashEntry == NULL)
02521 {
02522 FINISH_STACK("CAAccountingInstance::initTableEntry:NULL");
02523 return E_UNKNOWN;
02524 }
02525
02526 pHashEntry->pAccountingInfo = new tAiAccountingInfo;
02527 memset( pHashEntry->pAccountingInfo, 0, sizeof( tAiAccountingInfo ) );
02528
02529 SAVE_STACK("CAAccountingInstance::initTableEntry", "After memset");
02530
02531 pHashEntry->pAccountingInfo->authFlags =
02532 AUTH_SENT_ACCOUNT_REQUEST | AUTH_TIMEOUT_STARTED |
02533 AUTH_HARD_LIMIT_REACHED | AUTH_WAITING_FOR_FIRST_SETTLED_CC |
02534 AUTH_SENT_CC_REQUEST | AUTH_LOGIN_NOT_FINISHED;
02535 pHashEntry->pAccountingInfo->authTimeoutStartSeconds = time(NULL);
02536 pHashEntry->pAccountingInfo->lastHardLimitSeconds = time(NULL);
02537 pHashEntry->pAccountingInfo->sessionPackets = 0;
02538 pHashEntry->pAccountingInfo->transferredBytes = 0;
02539 pHashEntry->pAccountingInfo->confirmedBytes = 0;
02540 pHashEntry->pAccountingInfo->bytesToConfirm = 0;
02541 pHashEntry->pAccountingInfo->nrInQueue = 0;
02542 pHashEntry->pAccountingInfo->userID = pHashEntry->id;
02543 pHashEntry->pAccountingInfo->ownerRef = pHashEntry;
02544 pHashEntry->pAccountingInfo->clientVersion = NULL;
02545 pHashEntry->pAccountingInfo->mutex = new CAMutex;
02546
02547
02548
02549 FINISH_STACK("CAAccountingInstance::initTableEntry");
02550
02551 return E_SUCCESS;
02552 }
02553
02554
02555
02561 SINT32 CAAccountingInstance::cleanupTableEntry( fmHashTableEntry *pHashEntry )
02562 {
02563 INIT_STACK;
02564 BEGIN_STACK("CAAccountingInstance::cleanupTableEntry");
02565
02566
02567 tAiAccountingInfo* pAccInfo = pHashEntry->pAccountingInfo;
02568 AccountLoginHashEntry* loginEntry;
02569 SINT32 prepaidBytes = 0;
02570 SINT32 prepaidInterval = CALibProxytest::getOptions()->getPrepaidInterval();
02571
02572 if (pAccInfo == NULL)
02573 {
02574 SAVE_STACK("CAAccountingInstance::cleanupTableEntry", "acc info null");
02575
02576 return E_UNKNOWN;
02577 }
02578
02579
02580
02581 pHashEntry->pAccountingInfo=NULL;
02582
02583 if (pAccInfo->accountNumber)
02584 {
02585 CAMsg::printMsg(LOG_INFO, "cleaning up entry %p of accountno. %llu (pAccInfo ref: %p)\n",
02586 pHashEntry, pAccInfo->accountNumber, pAccInfo);
02587 if (pAccInfo->authFlags & AUTH_ACCOUNT_OK)
02588 {
02589
02590 ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
02591 loginEntry = (AccountLoginHashEntry*)ms_pInstance->m_currentAccountsHashtable->getValue(&(pAccInfo->accountNumber));
02592
02593 if (loginEntry)
02594 {
02595
02596
02597 if (testLoginEntryOwner(loginEntry, pHashEntry))
02599 {
02600 if (loginEntry->authFlags & AUTH_ACCOUNT_EMPTY)
02601 {
02602
02603 pAccInfo->confirmedBytes = loginEntry->confirmedBytes;
02604 }
02605
02606 prepaidBytes = getPrepaidBytes(pAccInfo);
02607 if (prepaidBytes > 0)
02608 {
02609 if (prepaidBytes > prepaidInterval)
02610 {
02611 UINT8 tmp[32];
02612 print64(tmp, pAccInfo->accountNumber);
02613
02614
02615
02616 CAMsg::printMsg(LOG_ERR,
02617 "PrepaidBytes of %d for account %s are higher than prepaid interval! "
02618 "The client (owner %x) did not behave according to specification. "
02619 "Deleting prepaid bytes!\n", prepaidBytes, tmp, pHashEntry);
02620
02621
02622
02623 prepaidBytes = 0;
02624 }
02625 }
02626
02627
02628
02629
02630
02631 CAAccountingDBInterface *dbInterface = CAAccountingDBInterface::getConnection();
02632 if(dbInterface != NULL)
02633 {
02634 dbInterface->storePrepaidAmount(pAccInfo->accountNumber,
02635 prepaidBytes,
02636 ms_pInstance->m_currentCascade);
02637 CAAccountingDBInterface::releaseConnection(dbInterface);
02638 dbInterface = NULL;
02639 }
02640 if(!isLoginOngoing(loginEntry, pHashEntry))
02641 {
02642 ms_pInstance->m_currentAccountsHashtable->remove(&(pAccInfo->accountNumber));
02643 delete loginEntry->ownerLock;
02644 delete loginEntry;
02645 loginEntry = NULL;
02646 }
02647 else
02648 {
02649 CAMsg::printMsg(LOG_INFO, "Cleaning: Leaving loginEntry %x cleanup of owner %x to the next owner due to double-login of a user.\n",
02650 loginEntry, loginEntry->ownerRef);
02651 }
02652 }
02653
02654
02655
02656
02657
02658
02659
02660
02661
02662
02663
02664
02665
02666
02667
02668
02669
02670
02671 }
02672 else
02673 {
02674 CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Cleanup did not find user login hash entry!\n");
02675 }
02676 ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
02677 }
02678 }
02679 else
02680 {
02681 CAMsg::printMsg(LOG_DEBUG, "CAAccountingInstance: Cleanup method found account zero.\n");
02682 }
02683
02684
02685
02686 delete pAccInfo->pPublicKey;
02687 pAccInfo->pPublicKey = NULL;
02688
02689
02690 delete [] pAccInfo->pChallenge;
02691 pAccInfo->pChallenge = NULL;
02692
02693 delete [] pAccInfo->pstrBIID;
02694 pAccInfo->pstrBIID = NULL;
02695
02696 delete [] pAccInfo->clientVersion;
02697 pAccInfo->clientVersion = NULL;
02698
02699 pHashEntry->pAccountingInfo=NULL;
02700
02701 if (pAccInfo->nrInQueue > 0)
02702 {
02703
02704
02705
02706
02707
02708
02709
02710
02711
02712
02713
02714
02715 {
02716
02717 pAccInfo->authFlags |= AUTH_DELETE_ENTRY;
02718 }
02719 }
02720 else if (pAccInfo->nrInQueue < 0)
02721 {
02722 CAMsg::printMsg(LOG_CRIT, "CAAccountingInstance: Cleanup method found negative handle queue!\n");
02723 }
02724
02725
02726 if (!(pAccInfo->authFlags & AUTH_DELETE_ENTRY))
02727 {
02728
02729 delete pAccInfo->mutex;
02730 pAccInfo->mutex = NULL;
02731 delete [] pAccInfo->clientVersion;
02732 pAccInfo->clientVersion = NULL;
02733
02734 #ifdef LOG_CRIME
02735 UINT64 accountNumber = pAccInfo->accountNumber;
02736 UINT64* surveillanceAccounts = CALibProxytest::getOptions()->getCrimeSurveillanceAccounts();
02737 UINT32 nrOfSurveillanceAccounts = CALibProxytest::getOptions()->getNrOfCrimeSurveillanceAccounts();
02738 const UINT8* peerIP = pHashEntry->peerIP;
02739
02740 for (UINT32 iAccount = 0; iAccount < nrOfSurveillanceAccounts; iAccount++)
02741 {
02742 if (accountNumber == surveillanceAccounts[iAccount])
02743 {
02744 CAMsg::printMsg(LOG_CRIT,"Crime detection: User logged out with account %llu has IP %u.%u.%u.%u\n",accountNumber, peerIP[0], peerIP[1], peerIP[2], peerIP[3]);
02745 break;
02746 }
02747 }
02748 #endif
02749
02750 delete pAccInfo;
02751 pAccInfo = NULL;
02752 }
02753 else
02754 {
02755 CAMsg::printMsg(LOG_INFO, "CAAccountingInstance: Cleanup method sent account deletion request to AI thread!\n");
02756 }
02757
02758
02759 FINISH_STACK("CAAccountingInstance::cleanupTableEntry");
02760
02761 return E_SUCCESS;
02762 }
02763
02764 SINT32 CAAccountingInstance::newSettlementTransaction()
02765 {
02766 UINT32 settledCCs = 0;
02767 SINT32 retVal;
02768 do
02769 {
02770 retVal = __newSettlementTransaction(&settledCCs);
02771 }
02772 while(settledCCs >= MAX_SETTLED_CCS && retVal == E_SUCCESS);
02773 return E_SUCCESS;
02774 }
02775
02776 SINT32 CAAccountingInstance::__newSettlementTransaction(UINT32 *nrOfSettledCCs)
02777 {
02778
02779 CAXMLErrorMessage **pErrMsgs = NULL, *settleException = NULL;
02780 CAXMLCostConfirmation **allUnsettledCCs = NULL;
02781 SettleEntry *entry = NULL, *nextEntry = NULL;
02782 CAAccountingDBInterface *dbInterface = NULL;
02783
02784 UINT32 nrOfCCs = 0, i = 0;
02785 SINT32 biConnectionStatus = 0, ret = E_SUCCESS;
02786 UINT64 myWaitNr = 0;
02787
02788
02789
02790
02791 ms_pInstance->m_pSettlementMutex->lock();
02792
02793 UINT64 iCurrentSettleTransactionNr = (++m_iCurrentSettleTransactionNr) % 50;
02794
02795 dbInterface = CAAccountingDBInterface::getConnection();
02796 if(dbInterface == NULL)
02797 {
02798 ms_pInstance->m_pSettlementMutex->unlock();
02799 CAMsg::printMsg(LOG_ERR, "Settlement transaction: could not connect to Database. Retry later...\n");
02800 ret = E_NOT_CONNECTED;
02801 goto cleanup;
02802 }
02803
02804
02805
02806 #ifdef DEBUG
02807 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: DB connections established!\n");
02808 #endif
02809
02810 dbInterface->getUnsettledCostConfirmations(&allUnsettledCCs, ms_pInstance->m_currentCascade, &nrOfCCs, MAX_SETTLED_CCS);
02811 *nrOfSettledCCs = nrOfCCs;
02812
02813 if (allUnsettledCCs == NULL)
02814 {
02815 CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: thread %x looked for unsettled CCs, found no CCs to settle\n", iCurrentSettleTransactionNr, pthread_self());
02816 ms_pInstance->m_pSettlementMutex->unlock();
02817 ret = E_SUCCESS;
02818 goto cleanup;
02819 }
02820
02821
02822 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction %llu: thread %x looked for unsettled CCs, found %u cost confirmations to settle\n", iCurrentSettleTransactionNr, pthread_self(), nrOfCCs);
02823
02824
02825 biConnectionStatus = ms_pInstance->m_pPiInterface->initBIConnection();
02826 if(biConnectionStatus != E_SUCCESS)
02827 {
02828 ms_pInstance->m_seqBIConnErrors++;
02829 if(ms_pInstance->m_seqBIConnErrors >= CRITICAL_SUBSEQUENT_BI_CONN_ERRORS)
02830 {
02831
02832 MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionCriticalSubseqFailures);
02833 }
02834 else
02835 {
02836 MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionFailure);
02837 }
02838 ms_pInstance->m_pPiInterface->terminateBIConnection();
02839
02840 CAAccountingDBInterface::releaseConnection(dbInterface);
02841 dbInterface = NULL;
02842 ms_pInstance->m_pSettlementMutex->unlock();
02843
02844 CAMsg::printMsg(LOG_WARNING, "Settlement transaction: could not connect to BI. Try later...\n");
02845
02846 ret = E_NOT_CONNECTED;
02847 goto cleanup;
02848 }
02849 else
02850 {
02851 pErrMsgs = ms_pInstance->m_pPiInterface->settleAll(allUnsettledCCs, nrOfCCs, &settleException);
02852 ms_pInstance->m_pPiInterface->terminateBIConnection();
02853 }
02854
02855
02856 if(settleException != NULL)
02857 {
02858 CAAccountingDBInterface::releaseConnection(dbInterface);
02859 dbInterface = NULL;
02860
02861 ms_pInstance->m_pSettlementMutex->unlock();
02862 CAMsg::printMsg(LOG_ERR, "Settlement transaction: BI reported settlement not successful: "
02863 "code: %i, %s \n", settleException->getErrorCode(),
02864 (settleException->getDescription() != NULL ?
02865 settleException->getDescription() : (UINT8*) "<no description given>") );
02866 ret = E_UNKNOWN;
02867 goto cleanup;
02868 }
02869
02870 if(pErrMsgs == NULL)
02871 {
02872
02873
02874 CAAccountingDBInterface::releaseConnection(dbInterface);
02875 dbInterface = NULL;
02876
02877 ms_pInstance->m_pSettlementMutex->unlock();
02878 CAMsg::printMsg(LOG_CRIT, "Settlement transaction: ErrorMessages are null.\n");
02879 ret = E_UNKNOWN;
02880 goto cleanup;
02881 }
02882 else
02883 {
02884 for(i = 0; i < nrOfCCs; i++)
02885 {
02886 nextEntry = __handleSettleResult(allUnsettledCCs[i], pErrMsgs[i], dbInterface, iCurrentSettleTransactionNr);
02887 if(nextEntry != NULL)
02888 {
02889 nextEntry->nextEntry = entry;
02890 entry = nextEntry;
02891 }
02892 }
02893 }
02894
02895
02896 if (entry)
02897 {
02898
02899
02900
02901 if(ms_pInstance->m_nextSettleNr == ms_pInstance->m_settleWaitNr)
02902 {
02903
02904
02905 ms_pInstance->m_nextSettleNr = 0;
02906 ms_pInstance->m_settleWaitNr = 1;
02907 }
02908 else
02909 {
02910
02911 CAAccountingDBInterface::releaseConnection(dbInterface);
02912 dbInterface = NULL;
02913 myWaitNr = ms_pInstance->m_settleWaitNr;
02914 ms_pInstance->m_settleWaitNr++;
02915 while(myWaitNr != ms_pInstance->m_nextSettleNr)
02916 {
02917 CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: Thread %x must wait to alter login table after settling (1): %llu before him in the queue\n",
02918 iCurrentSettleTransactionNr, pthread_self(), (myWaitNr - ms_pInstance->m_nextSettleNr));
02919 ms_pInstance->m_pSettlementMutex->wait();
02920 }
02921
02922 CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: Thread %x may continue (1).\n", iCurrentSettleTransactionNr, pthread_self());
02923 dbInterface = CAAccountingDBInterface::getConnection();
02924 }
02925
02926 bool debugWarn = false;
02927 if (iCurrentSettleTransactionNr != (m_iCurrentSettleTransactionNr % 50))
02928 {
02929 debugWarn = true;
02930
02931 CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: Apply changes to database. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
02932 }
02933
02934
02935 __commitSettlementToDatabase(entry, dbInterface);
02936 CAAccountingDBInterface::releaseConnection(dbInterface);
02937 dbInterface = NULL;
02938
02939
02940 if (debugWarn)
02941 {
02942
02943 CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: Removing settlement mutex lock. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
02944 }
02945
02946 ms_pInstance->m_pSettlementMutex->unlock();
02947
02948
02949 if (debugWarn)
02950 {
02951
02952 CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: Entering login hashtable. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
02953 }
02954
02955
02956 ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
02957 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction %llu: thread %x with wait nr %llu alters hashtable.\n", iCurrentSettleTransactionNr, pthread_self(), myWaitNr);
02958 __commitSettlementToLoginTable(entry);
02959 ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
02960
02961 if (debugWarn)
02962 {
02963
02964 CAMsg::printMsg(LOG_WARNING, "Settlement transaction %llu: After commiting to login hashtable, before last lock. Other settlement transactions seem to wait...\n", iCurrentSettleTransactionNr);
02965 }
02966
02967
02968 ms_pInstance->m_pSettlementMutex->lock();
02969 ms_pInstance->m_nextSettleNr++;
02970
02971
02972 {
02973
02974 if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
02975 CAMsg::printMsg(LOG_INFO, "Thread %x waking up next Thread. %llu are still waiting.\n", pthread_self(),
02976 (ms_pInstance->m_settleWaitNr - ms_pInstance->m_nextSettleNr));
02977 ms_pInstance->m_pSettlementMutex->signal();
02978 }
02979 }
02980 ms_pInstance->m_pSettlementMutex->unlock();
02981
02982 cleanup:
02983 if(dbInterface != NULL)
02984 {
02985 CAAccountingDBInterface::releaseConnection(dbInterface);
02986 dbInterface = NULL;
02987 }
02988
02989 if(allUnsettledCCs != NULL)
02990 {
02991 for(i = 0; i < nrOfCCs; i++)
02992 {
02993 delete allUnsettledCCs[i];
02994 allUnsettledCCs[i] = NULL;
02995 }
02996 delete [] allUnsettledCCs;
02997 allUnsettledCCs = NULL;
02998 }
02999
03000 if(pErrMsgs != NULL)
03001 {
03002 for(i = 0; i < nrOfCCs; i++)
03003 {
03004 delete pErrMsgs[i];
03005 pErrMsgs[i] = NULL;
03006 }
03007 pErrMsgs = NULL;
03008 }
03009
03010 while (entry != NULL)
03011 {
03012 nextEntry = entry->nextEntry;
03013 delete entry;
03014 entry = nextEntry;
03015 }
03016
03017 delete settleException;
03018 settleException = NULL;
03019
03020
03021 CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu finished.\n", iCurrentSettleTransactionNr);
03022
03023 return ret;
03024 }
03025
03026 SettleEntry *CAAccountingInstance::__handleSettleResult(CAXMLCostConfirmation *pCC, CAXMLErrorMessage *pErrMsg, CAAccountingDBInterface *dbInterface,
03027 UINT64 a_iCurrentSettleTransactionNr)
03028 {
03029 bool bDeleteCC = false;
03030 UINT32 authFlags = 0;
03031 UINT32 authRemoveFlags = 0;
03032 UINT64 confirmedBytes = 0;
03033 UINT64 diffBytes = 0;
03034 UINT32 storedStatus = 0;
03035 SettleEntry *entry = NULL;
03036
03037 dbInterface->getAccountStatus(pCC->getAccountNumber(), storedStatus);
03038
03039
03040 if(pErrMsg == NULL)
03041 {
03042 authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03043 CAMsg::printMsg(LOG_ERR, "Settlement transaction: Communication with BI failed!\n");
03044 }
03045 else if(pErrMsg->getErrorCode() != pErrMsg->ERR_OK)
03046 {
03047 CAMsg::printMsg(LOG_WARNING, "Settlement transaction: BI reported error no. %d (%s)\n",
03048 pErrMsg->getErrorCode(), pErrMsg->getDescription() );
03049 if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_KEY_NOT_FOUND)
03050 {
03051 authFlags |= AUTH_INVALID_ACCOUNT;
03052
03053 bDeleteCC = true;
03054 }
03055 else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_ACCOUNT_EMPTY)
03056 {
03057 authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03058 authFlags |= AUTH_ACCOUNT_EMPTY;
03059 UINT64* msgConfirmedBytes = (UINT64*)pErrMsg->getMessageObject();
03060 if (msgConfirmedBytes)
03061 {
03062 confirmedBytes = *msgConfirmedBytes;
03063 if (confirmedBytes < pCC->getTransferredBytes())
03064 {
03065 diffBytes = pCC->getTransferredBytes() - confirmedBytes;
03066 }
03067 UINT8 tmp[32];
03068 print64(tmp, confirmedBytes);
03069 UINT8 tmp2[32];
03070 print64(tmp2, diffBytes);
03071 UINT8 tmp3[32];
03072 print64(tmp3, pCC->getTransferredBytes());
03073 CAMsg::printMsg(LOG_INFO, "Settlement transaction: Received %s confirmed bytes and %s diff bytes while having %s transferred bytes!\n", tmp, tmp2, tmp3);
03074 }
03075 else
03076 {
03077 CAMsg::printMsg(LOG_INFO, "Settlement transaction: Account empty, no message object received. User will be kicked out.\n");
03078 }
03079
03080 dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_ACCOUNT_EMPTY);
03081 authFlags |= AUTH_SETTLED_ONCE;
03082 dbInterface->markAsSettled(pCC->getAccountNumber(), ms_pInstance->m_currentCascade,
03083 pCC->getTransferredBytes());
03084
03085 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: settling %llu bytes for account %llu\n",
03086 pCC->getTransferredBytes(), pCC->getAccountNumber());
03087
03088 }
03089
03090
03091
03092
03093
03094
03095 else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_OUTDATED_CC)
03096 {
03097 authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03098
03099
03100 CAXMLCostConfirmation* attachedCC = (CAXMLCostConfirmation*) pErrMsg->getMessageObject();
03101 if (attachedCC)
03102 {
03103 authFlags |= AUTH_OUTDATED_CC;
03104 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: tried outdated CC, received last valid CC back\n");
03105
03106 if (dbInterface->storeCostConfirmation(*attachedCC,
03107 ms_pInstance->m_currentCascade) == E_SUCCESS)
03108 {
03109 authFlags |= AUTH_SETTLED_ONCE;
03110 if (dbInterface->markAsSettled(attachedCC->getAccountNumber(), ms_pInstance->m_currentCascade,
03111 attachedCC->getTransferredBytes()) != E_SUCCESS)
03112 {
03113 CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark last valid CC as settled."
03114 "Maybe a new CC has been added meanwhile?\n");
03115 }
03116 }
03117 else
03118 {
03119 CAMsg::printMsg(LOG_ERR, "Settlement transaction: storing last valid CC in db failed!\n");
03120 }
03121
03122 confirmedBytes = attachedCC->getTransferredBytes();
03123 }
03124 else
03125 {
03126 CAMsg::printMsg(LOG_INFO, "Settlement transaction: Did not receive last valid CC - maybe old Payment instance?\n");
03127 }
03128 }
03129 else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_BLOCKED)
03130 {
03131 authFlags |= AUTH_BLOCKED;
03132 bDeleteCC = true;
03133
03134 dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_BLOCKED);
03135 }
03136
03137 else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_DATABASE_ERROR)
03138 {
03139
03140
03141 authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03142 }
03143 else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR ||
03144 pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_SUCCESS_BUT_WITH_ERRORS)
03145 {
03146
03147 authFlags |= AUTH_UNKNOWN;
03148 }
03149 else
03150 {
03151
03152 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: Setting unknown kickout error no. %d.\n", pErrMsg->getErrorCode());
03153 authFlags |= AUTH_UNKNOWN;
03154 bDeleteCC = true;
03155 }
03156
03157 if (bDeleteCC)
03158 {
03159
03160 if(dbInterface->deleteCC(pCC->getAccountNumber(), ms_pInstance->m_currentCascade) == E_SUCCESS)
03161 {
03162 CAMsg::printMsg(LOG_ERR, "Settlement transaction: unusable cost confirmation was deleted\n");
03163 }
03164 else
03165 {
03166 CAMsg::printMsg(LOG_ERR, "Settlement transaction: cost confirmation is unusable, but could not delete it from database\n");
03167 }
03168 }
03169 }
03170 else
03171 {
03172 authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03173 authFlags |= AUTH_SETTLED_ONCE;
03174 if (dbInterface->markAsSettled(pCC->getAccountNumber(),
03175 ms_pInstance->m_currentCascade,
03176 pCC->getTransferredBytes()) != E_SUCCESS)
03177 {
03178 CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark CC as settled. Maybe a new CC has been added meanwhile?\n");
03179 }
03180 #ifdef DEBUG
03181 CAMsg::printMsg(LOG_INFO, "Settlement transaction %llu: CC OK for account %llu with %llu transferred bytes!\n",
03182 a_iCurrentSettleTransactionNr, pCC->getAccountNumber(), pCC->getTransferredBytes());
03183 #endif
03184 }
03185
03186 if (authFlags || authRemoveFlags)
03187 {
03188 entry = new SettleEntry;
03189 entry->accountNumber = pCC->getAccountNumber();
03190 entry->authFlags = authFlags;
03191 entry->authRemoveFlags = authRemoveFlags;
03192 entry->confirmedBytes = confirmedBytes;
03193 entry->diffBytes = diffBytes;
03194 entry->storedStatus = storedStatus;
03195 }
03196 return entry;
03197 }
03198
03200 void CAAccountingInstance::__commitSettlementToDatabase(SettleEntry *entryList, CAAccountingDBInterface *dbInterface)
03201 {
03202 SettleEntry *entry = entryList, *nextEntry = NULL;
03203 while (entry != NULL && dbInterface != NULL)
03204 {
03205 if (entry->authFlags & (AUTH_INVALID_ACCOUNT | AUTH_UNKNOWN))
03206 {
03207 dbInterface->storePrepaidAmount(
03208 entry->accountNumber, 0, ms_pInstance->m_currentCascade);
03209 }
03210 else if (entry->diffBytes)
03211 {
03212
03213 SINT32 prepaidBytes =
03214 dbInterface->getPrepaidAmount(entry->accountNumber,
03215 ms_pInstance->m_currentCascade, true);
03216 if (prepaidBytes > 0)
03217 {
03218 if (entry->diffBytes < 0 || entry->diffBytes >= (UINT64)prepaidBytes)
03219 {
03220 prepaidBytes = 0;
03221 }
03222 else
03223 {
03224 prepaidBytes -= entry->diffBytes;
03225 }
03226 dbInterface->storePrepaidAmount(
03227 entry->accountNumber, prepaidBytes, ms_pInstance->m_currentCascade);
03228 }
03229 }
03230
03231 if( !(entry->authFlags & (AUTH_ACCOUNT_EMPTY | AUTH_BLOCKED | AUTH_INVALID_ACCOUNT)) &&
03232 entry->storedStatus != 0)
03233 {
03234 dbInterface->clearAccountStatus(entry->accountNumber);
03235 switch (entry->storedStatus)
03236 {
03237 case CAXMLErrorMessage::ERR_ACCOUNT_EMPTY:
03238 {
03239 CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account empty status for %llu\n",
03240 entry->accountNumber);
03241 entry->authRemoveFlags |= AUTH_ACCOUNT_EMPTY;
03242 break;
03243 }
03244 case CAXMLErrorMessage::ERR_BLOCKED:
03245 {
03246 CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account blocked status for %llu\n",
03247 entry->accountNumber);
03248 entry->authRemoveFlags |= AUTH_BLOCKED;
03249 break;
03250 }
03251 case CAXMLErrorMessage::ERR_KEY_NOT_FOUND:
03252 {
03253 CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account invalid status for %llu\n",
03254 entry->accountNumber);
03255 entry->authRemoveFlags |= AUTH_INVALID_ACCOUNT;
03256 break;
03257 }
03258 }
03259 }
03260 nextEntry = entry->nextEntry;
03261 entry = nextEntry;
03262 }
03263 }
03264
03266 void CAAccountingInstance::__commitSettlementToLoginTable(SettleEntry *entryList)
03267 {
03268 SettleEntry *entry = entryList, *nextEntry = NULL;
03269 while (entry != NULL)
03270 {
03271 AccountLoginHashEntry* loginEntry =
03272 (AccountLoginHashEntry*) (ms_pInstance->m_currentAccountsHashtable->getValue(&(entry->accountNumber)));
03273 if (loginEntry)
03274 {
03275
03276 loginEntry->authFlags |= entry->authFlags;
03277 loginEntry->authRemoveFlags |= entry->authRemoveFlags;
03278 if (entry->confirmedBytes > 0 &&
03279 loginEntry->confirmedBytes < entry->confirmedBytes)
03280 {
03281 loginEntry->confirmedBytes = entry->confirmedBytes;
03282 }
03283 }
03284 nextEntry = entry->nextEntry;
03285 entry = nextEntry;
03286 }
03287 }
03288
03289
03290
03291
03292 SINT32 CAAccountingInstance::settlementTransaction()
03293 {
03294 INIT_STACK;
03295 BEGIN_STACK("CAAccountingInstance::settlementTransaction");
03296
03297 SINT32 ret = 0;
03298 CAXMLErrorMessage * pErrMsg = NULL;
03299 CAXMLCostConfirmation * pCC = NULL;
03300
03301 CAXMLCostConfirmation **allUnsettledCCs = NULL;
03302 UINT32 nrOfCCs, i;
03303 SettleEntry *entry = NULL, *nextEntry = NULL;
03304
03305 CAAccountingDBInterface *dbInterface = NULL;
03306
03307
03308 if(ms_pInstance == NULL)
03309 {
03310 FINISH_STACK("CAAccountingInstance::settlementTransaction");
03311 return E_UNKNOWN;
03312 }
03313
03314 if(ms_pInstance->m_pSettlementMutex == NULL)
03315 {
03316 FINISH_STACK("CAAccountingInstance::settlementTransaction");
03317 return E_UNKNOWN;
03318 }
03319
03320 dbInterface = CAAccountingDBInterface::getConnection();
03321 if(dbInterface == NULL)
03322 {
03323 CAMsg::printMsg(LOG_ERR, "Settlement transaction: could not connect to Database. Retry later...\n");
03324
03325 FINISH_STACK("CAAccountingInstance::settlementTransaction");
03326 return E_NOT_CONNECTED;
03327 }
03328
03329 ms_pInstance->m_pSettlementMutex->lock();
03330
03331 #ifdef DEBUG
03332 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: DB connections established!\n");
03333 #endif
03334
03335 dbInterface->getUnsettledCostConfirmations(&allUnsettledCCs, ms_pInstance->m_currentCascade, &nrOfCCs, MAX_SETTLED_CCS);
03336 if (nrOfCCs <= 0)
03337 {
03338 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: finished gettings CCs, found no CCs to settle\n");
03339 if(dbInterface != NULL)
03340 {
03341 CAAccountingDBInterface::releaseConnection(dbInterface);
03342 dbInterface = NULL;
03343 }
03344 ms_pInstance->m_pSettlementMutex->unlock();
03345 FINISH_STACK("CAAccountingInstance::settlementTransaction");
03346 return E_SUCCESS;
03347 }
03348
03349
03350 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: finished gettings CCs, found %u cost confirmations to settle\n",nrOfCCs);
03351
03352 SAVE_STACK("CAAccountingInstance::settlementTransaction", "After getting unsettled CCs");
03353
03354
03355
03356 for(i = 0; i < nrOfCCs; i++)
03357 {
03358
03359
03360
03361
03362
03363
03364
03365
03366
03367
03368
03369
03370
03371
03372
03373
03374
03375 pCC = allUnsettledCCs[i];
03376 entry = NULL;
03377 nextEntry = NULL;
03378 if (!pCC)
03379 {
03380 CAMsg::printMsg(LOG_CRIT, "Settlement transaction: Cost confirmation is NULL!\n");
03381 continue;
03382 }
03383
03384 #ifdef DEBUG
03385 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: Connecting to payment instance...\n");
03386 #endif
03387 ret = ms_pInstance->m_pPiInterface->initBIConnection();
03388 if(ret != E_SUCCESS)
03389 {
03390 ms_pInstance->m_seqBIConnErrors++;
03391 if(ms_pInstance->m_seqBIConnErrors >= CRITICAL_SUBSEQUENT_BI_CONN_ERRORS)
03392 {
03393
03394 MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionCriticalSubseqFailures);
03395 }
03396 else
03397 {
03398 MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionFailure);
03399 }
03400 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: could not connect to BI. Try later...\n");
03401
03402 pErrMsg = NULL;
03403 ms_pInstance->m_pPiInterface->terminateBIConnection();
03404 }
03405 else
03406 {
03407 MONITORING_FIRE_PAY_EVENT(ev_pay_biConnectionSuccess);
03408 #ifdef DEBUG
03409 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: successfully connected to payment instance");
03410 #endif
03411 ms_pInstance->m_seqBIConnErrors = 0;
03412 pErrMsg = ms_pInstance->m_pPiInterface->settle( *pCC );
03413 ms_pInstance->m_pPiInterface->terminateBIConnection();
03414 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: settle done!\n");
03415 }
03416
03417 bool bDeleteCC = false;
03418 UINT32 authFlags = 0;
03419 UINT32 authRemoveFlags = 0;
03420 UINT64 confirmedBytes = 0;
03421 UINT64 diffBytes = 0;
03422 UINT32 storedStatus = 0;
03423
03424 dbInterface->getAccountStatus(pCC->getAccountNumber(), storedStatus);
03425
03426
03427 if(pErrMsg == NULL)
03428 {
03429 authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03430 CAMsg::printMsg(LOG_ERR, "Settlement transaction: Communication with BI failed!\n");
03431 }
03432 else if(pErrMsg->getErrorCode() != pErrMsg->ERR_OK)
03433 {
03434 CAMsg::printMsg(LOG_WARNING, "Settlement transaction: BI reported error no. %d (%s)\n",
03435 pErrMsg->getErrorCode(), pErrMsg->getDescription() );
03436 if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_KEY_NOT_FOUND)
03437 {
03438 authFlags |= AUTH_INVALID_ACCOUNT;
03439
03440 bDeleteCC = true;
03441 }
03442 else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_ACCOUNT_EMPTY)
03443 {
03444 authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03445 authFlags |= AUTH_ACCOUNT_EMPTY;
03446 UINT64* msgConfirmedBytes = (UINT64*)pErrMsg->getMessageObject();
03447 if (msgConfirmedBytes)
03448 {
03449 confirmedBytes = *msgConfirmedBytes;
03450 if (confirmedBytes < pCC->getTransferredBytes())
03451 {
03452 diffBytes = pCC->getTransferredBytes() - confirmedBytes;
03453 }
03454 UINT8 tmp[32];
03455 print64(tmp, confirmedBytes);
03456 UINT8 tmp2[32];
03457 print64(tmp2, diffBytes);
03458 UINT8 tmp3[32];
03459 print64(tmp3, pCC->getTransferredBytes());
03460 CAMsg::printMsg(LOG_INFO, "Settlement transaction: Received %s confirmed bytes and %s diff bytes while having %s transferred bytes!\n", tmp, tmp2, tmp3);
03461 }
03462 else
03463 {
03464 CAMsg::printMsg(LOG_ERR, "Settlement transaction: Account empty, but no message object received! "
03465 "This may lead to too much prepaid bytes!\n");
03466 }
03467
03468 dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_ACCOUNT_EMPTY);
03469 authFlags |= AUTH_SETTLED_ONCE;
03470 dbInterface->markAsSettled(pCC->getAccountNumber(), ms_pInstance->m_currentCascade,
03471 pCC->getTransferredBytes());
03472
03473 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: settling %llu bytes for account %llu\n",
03474 pCC->getTransferredBytes(), pCC->getAccountNumber());
03475
03476 }
03477
03478
03479
03480
03481
03482
03483 else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_OUTDATED_CC)
03484 {
03485 authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03486
03487
03488 CAXMLCostConfirmation* attachedCC = (CAXMLCostConfirmation*) pErrMsg->getMessageObject();
03489 if (attachedCC)
03490 {
03491 authFlags |= AUTH_OUTDATED_CC;
03492 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: tried outdated CC, received last valid CC back\n");
03493
03494 if (dbInterface->storeCostConfirmation(*attachedCC,
03495 ms_pInstance->m_currentCascade) == E_SUCCESS)
03496 {
03497 authFlags |= AUTH_SETTLED_ONCE;
03498 if (dbInterface->markAsSettled(attachedCC->getAccountNumber(), ms_pInstance->m_currentCascade,
03499 attachedCC->getTransferredBytes()) != E_SUCCESS)
03500 {
03501 CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark last valid CC as settled."
03502 "Maybe a new CC has been added meanwhile?\n");
03503 }
03504 }
03505 else
03506 {
03507 CAMsg::printMsg(LOG_ERR, "Settlement transaction: storing last valid CC in db failed!\n");
03508 }
03509
03510 confirmedBytes = attachedCC->getTransferredBytes();
03511 }
03512 else
03513 {
03514 CAMsg::printMsg(LOG_INFO, "Settlement transaction: Did not receive last valid CC - maybe old Payment instance?\n");
03515 }
03516 }
03517 else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_BLOCKED)
03518 {
03519 authFlags |= AUTH_BLOCKED;
03520 bDeleteCC = true;
03521
03522 dbInterface->storeAccountStatus(pCC->getAccountNumber(), CAXMLErrorMessage::ERR_BLOCKED);
03523 }
03524
03525 else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_DATABASE_ERROR)
03526 {
03527
03528
03529 authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03530 }
03531 else if (pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_INTERNAL_SERVER_ERROR ||
03532 pErrMsg->getErrorCode() == CAXMLErrorMessage::ERR_SUCCESS_BUT_WITH_ERRORS)
03533 {
03534
03535 authFlags |= AUTH_UNKNOWN;
03536 }
03537 else
03538 {
03539
03540 CAMsg::printMsg(LOG_DEBUG, "Settlement transaction: Setting unknown kickout error no. %d.\n", pErrMsg->getErrorCode());
03541 authFlags |= AUTH_UNKNOWN;
03542 bDeleteCC = true;
03543 }
03544
03545 if (bDeleteCC)
03546 {
03547
03548 if(dbInterface->deleteCC(pCC->getAccountNumber(), ms_pInstance->m_currentCascade) == E_SUCCESS)
03549 {
03550 CAMsg::printMsg(LOG_ERR, "Settlement transaction: unusable cost confirmation was deleted\n");
03551 }
03552 else
03553 {
03554 CAMsg::printMsg(LOG_ERR, "Settlement transaction: cost confirmation is unusable, but could not delete it from database\n");
03555 }
03556 }
03557 }
03558 else
03559 {
03560 authRemoveFlags |= AUTH_WAITING_FOR_FIRST_SETTLED_CC;
03561 authFlags |= AUTH_SETTLED_ONCE;
03562 if (dbInterface->markAsSettled(pCC->getAccountNumber(),
03563 ms_pInstance->m_currentCascade,
03564 pCC->getTransferredBytes()) != E_SUCCESS)
03565 {
03566 CAMsg::printMsg(LOG_ERR, "Settlement transaction: Could not mark CC as settled. Maybe a new CC has been added meanwhile?\n");
03567 }
03568 CAMsg::printMsg(LOG_INFO, "Settlement transaction: CC OK!\n");
03569 }
03570
03571
03572 if (authFlags || authRemoveFlags)
03573 {
03574 nextEntry = new SettleEntry;
03575 nextEntry->accountNumber = pCC->getAccountNumber();
03576 nextEntry->authFlags = authFlags;
03577 nextEntry->authRemoveFlags = authRemoveFlags;
03578 nextEntry->confirmedBytes = confirmedBytes;
03579 nextEntry->diffBytes = diffBytes;
03580 nextEntry->nextEntry = entry;
03581 nextEntry->storedStatus = storedStatus;
03582 entry = nextEntry;
03583 }
03584
03585
03586
03587
03588
03589
03590 if (pErrMsg != NULL)
03591 {
03592 delete pErrMsg;
03593 pErrMsg = NULL;
03594 }
03595 }
03596
03597 if(allUnsettledCCs != NULL)
03598 {
03599 for(i = 0; i < nrOfCCs; i++)
03600 {
03601 delete allUnsettledCCs[i];
03602 allUnsettledCCs[i] = NULL;
03603 }
03604 delete [] allUnsettledCCs;
03605 allUnsettledCCs = NULL;
03606 }
03607
03608 SAVE_STACK("CAAccountingInstance::settlementTransaction", "After settling unsettled CCs with BI");
03609
03610 SettleEntry *first = entry;
03611 UINT64 myWaitNr = 0;
03612 if (entry)
03613 {
03614
03615
03616
03617 if(ms_pInstance->m_nextSettleNr == ms_pInstance->m_settleWaitNr)
03618 {
03619
03620
03621 ms_pInstance->m_nextSettleNr = 0;
03622 ms_pInstance->m_settleWaitNr = 1;
03623 }
03624 else
03625 {
03626 SAVE_STACK("CAAccountingInstance::settlementTransaction", "wait for altering hashtable");
03627
03628 CAAccountingDBInterface::releaseConnection(dbInterface);
03629 dbInterface = NULL;
03630 myWaitNr = ms_pInstance->m_settleWaitNr;
03631 ms_pInstance->m_settleWaitNr++;
03632 while(myWaitNr != ms_pInstance->m_nextSettleNr)
03633 {
03634 CAMsg::printMsg(LOG_INFO, "Thread %x must wait to alter login table after settling (2): %llu before him in the queue\n", pthread_self(),
03635 (myWaitNr - ms_pInstance->m_nextSettleNr));
03636 ms_pInstance->m_pSettlementMutex->wait();
03637 }
03638 CAMsg::printMsg(LOG_INFO, "Thread %x may continue (2).\n", pthread_self());
03639 dbInterface = CAAccountingDBInterface::getConnection();
03640 }
03641 SAVE_STACK("CAAccountingInstance::settlementTransaction", "altering DB entries");
03642 while (entry != NULL && dbInterface != NULL)
03643 {
03644 if (entry->authFlags & (AUTH_INVALID_ACCOUNT | AUTH_UNKNOWN))
03645 {
03646 dbInterface->storePrepaidAmount(
03647 entry->accountNumber, 0, ms_pInstance->m_currentCascade);
03648 }
03649 else if (entry->diffBytes)
03650 {
03651
03652 SINT32 prepaidBytes =
03653 dbInterface->getPrepaidAmount(entry->accountNumber,
03654 ms_pInstance->m_currentCascade, true);
03655 if (prepaidBytes > 0)
03656 {
03657 if (entry->diffBytes < 0 || entry->diffBytes >= (UINT64)prepaidBytes)
03658 {
03659 prepaidBytes = 0;
03660 }
03661 else
03662 {
03663 prepaidBytes -= entry->diffBytes;
03664 }
03665 dbInterface->storePrepaidAmount(
03666 entry->accountNumber, prepaidBytes, ms_pInstance->m_currentCascade);
03667 }
03668 }
03669
03670 if( !(entry->authFlags & (AUTH_ACCOUNT_EMPTY | AUTH_BLOCKED | AUTH_INVALID_ACCOUNT)) &&
03671 entry->storedStatus != 0)
03672 {
03673 dbInterface->clearAccountStatus(entry->accountNumber);
03674 switch (entry->storedStatus)
03675 {
03676 case CAXMLErrorMessage::ERR_ACCOUNT_EMPTY:
03677 {
03678 CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account empty status for %llu\n",
03679 entry->accountNumber);
03680 entry->authRemoveFlags |= AUTH_ACCOUNT_EMPTY;
03681 break;
03682 }
03683 case CAXMLErrorMessage::ERR_BLOCKED:
03684 {
03685 CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account blocked status for %llu\n",
03686 entry->accountNumber);
03687 entry->authRemoveFlags |= AUTH_BLOCKED;
03688 break;
03689 }
03690 case CAXMLErrorMessage::ERR_KEY_NOT_FOUND:
03691 {
03692 CAMsg::printMsg(LOG_INFO, "Settlement transaction: clearing account invalid status for %llu\n",
03693 entry->accountNumber);
03694 entry->authRemoveFlags |= AUTH_INVALID_ACCOUNT;
03695 break;
03696 }
03697 }
03698 }
03699
03700 nextEntry = entry->nextEntry;
03701 entry = nextEntry;
03702 }
03703 }
03704 CAAccountingDBInterface::releaseConnection(dbInterface);
03705 dbInterface = NULL;
03706 ms_pInstance->m_pSettlementMutex->unlock();
03707
03708 if(first != NULL)
03709 {
03710 SAVE_STACK("CAAccountingInstance::settlementTransaction", "altering hashtable");
03711 #ifdef DEBUG
03712 CAMsg::printMsg(LOG_DEBUG, "Settlement thread with wait nr %llu alters hashtable.\n", myWaitNr);
03713 #endif
03714 entry = first;
03715 ms_pInstance->m_currentAccountsHashtable->getMutex()->lock();
03716 while (entry != NULL)
03717 {
03718 AccountLoginHashEntry* loginEntry =
03719 (AccountLoginHashEntry*) (ms_pInstance->m_currentAccountsHashtable->getValue(&(entry->accountNumber)));
03720 if (loginEntry)
03721 {
03722
03723 loginEntry->authFlags |= entry->authFlags;
03724 loginEntry->authRemoveFlags |= entry->authRemoveFlags;
03725 if (entry->confirmedBytes > 0 &&
03726 loginEntry->confirmedBytes < entry->confirmedBytes)
03727 {
03728 loginEntry->confirmedBytes = entry->confirmedBytes;
03729 }
03730 }
03731 nextEntry = entry->nextEntry;
03732 delete entry;
03733 entry = nextEntry;
03734 }
03735 ms_pInstance->m_currentAccountsHashtable->getMutex()->unlock();
03736
03737 ms_pInstance->m_pSettlementMutex->lock();
03738 ms_pInstance->m_nextSettleNr++;
03739
03740
03741 {
03742 SAVE_STACK("CAAccountingInstance::settlementTransaction", "waking up waiting threads for altering hashtable");
03743
03744 if(ms_pInstance->m_settleWaitNr != ms_pInstance->m_nextSettleNr)
03745