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